diff options
author | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-02-25 19:22:25 +0000 |
commit | ad547a6b5986815fda458221149728d9d9ab1d87 (patch) | |
tree | 16296910eb3eca724371474ea9aea3994dc69614 /Build/source/texk/web2c/luatexdir/luatex.c | |
parent | 947b43de3dd21d58ccc2ffadefc4441ea1c2a813 (diff) |
restore Build,TODO from r57911
git-svn-id: svn://tug.org/texlive/trunk@57915 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luatex.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/luatex.c | 959 |
1 files changed, 959 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luatex.c b/Build/source/texk/web2c/luatexdir/luatex.c new file mode 100644 index 00000000000..d7414ef3fd9 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/luatex.c @@ -0,0 +1,959 @@ +/* luatex.c: Hand-coded routines for TeX or Metafont in C. Originally + written by Tim Morgan, drawing from other Unix ports of TeX. This is + a collection of miscellany, everything that's easier (or only + possible) to do in C. + + This file is public domain. */ + +/* This file is used to create texextra.c etc., with this line + changed to include texd.h or mfd.h. The ?d.h file is what + #defines TeX or MF, which avoids the need for a special + Makefile rule. */ + +/* We |#define DLLPROC| in order to build LuaTeX and LuajitTeX as DLL + for W32TeX. */ + +#if defined LuajitTeX +#define DLLPROC dllluajittexmain +#else +#define DLLPROC dllluatexmain +#endif + +#include "ptexlib.h" +#include "luatex.h" +#include "lua/luatex-api.h" + +#define TeX + +/* + The version number can be queried with \.{\\luatexversion} and the revision with + with \.{\\luatexrevision}. Traditionally the revision can be any character and + pdf\TeX\ occasionally used no digits. Here we still use a character but we will + stick to "0" upto "9" so users can expect a number represented as string. +*/ + +int luatex_version = 113; +int luatex_revision = '0'; +const char *luatex_version_string = "1.13.0"; +const char *engine_name = my_name; + +#include <kpathsea/c-ctype.h> +#include <kpathsea/line.h> +#include <kpathsea/readable.h> +#include <kpathsea/variable.h> +#include <kpathsea/absolute.h> +#ifdef WIN32 +#include <kpathsea/concatn.h> +#endif + +#ifdef _MSC_VER +#undef timezone +#endif + +#include <time.h> /* For `struct tm'. */ +#if defined (HAVE_SYS_TIME_H) +# include <sys/time.h> +#elif defined (HAVE_SYS_TIMEB_H) +# include <sys/timeb.h> +#endif + +#if defined(__STDC__) +# include <locale.h> +#endif + +#include <signal.h> /* Catch interrupts. */ + +/* + Shell escape. + + If shellenabledp == 0, all shell escapes are forbidden. + + If (shellenabledp == 1 && restrictedshell == 0), any command is allowed for a + shell escape. + + If (shellenabledp == 1 && restrictedshell == 1), only commands given in the + configuration file as shell_escape_commands = + kpsewhich,ebb,extractbb,mpost,metafun,... (no spaces between commands) in + texmf.cnf are allowed for a shell escape in a restricted form: command name + and arguments should be separated by a white space. The first word should be + a command name. The quotation character for an argument with spaces, + including a pathname, should be ". ' should not be used. Internally, all + arguments are quoted by ' (Unix) or " (Windows) before calling the system() + function in order to forbid execution of any embedded command. + + If the --shell-escape option is given, we set shellenabledp = 1 and + restrictedshell = 0, i.e., any command is allowed. + + If the --shell-restricted option is given, we set shellenabledp = 1 and + restrictedshell = 1, i.e., only given cmds allowed. + + If the --no-shell-escape option is given, we set shellenabledp = -1 (and + restrictedshell is irrelevant). + + If none of these option are given, there are three cases: + + (1) In the case where shell_escape = y or shell_escape = t or shell_escape = + 1 it becomes shellenabledp = 1 and restrictedshell = 0, that is, any + command is allowed. + (2) In the case where shell_escape = p it becomes shellenabledp = 1 and + restrictedshell = 1, that is, restricted shell escape is allowed. + (3) In all other cases, shellenabledp = 0, that is, shell escape is + forbidden. The value of restrictedshell is irrelevant if shellenabledp == + 0. +*/ + +#ifdef TeX + +/* + The cmdlist is a list of allowed commands which are given like this: + shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun in texmf.cnf. +*/ + +static char **cmdlist = NULL; + +void mk_shellcmdlist(char *v) +{ + char **p; + char *q, *r; + size_t n; + + q = v; + n = 1; + + /* + Analyze the variable shell_escape_commands = foo,bar,... spaces before + and after (,) are not allowed. + */ + + while ((r = strchr(q, ',')) != 0) { + n++; + q = r + 1; + } + if (*q) + n++; + cmdlist = (char **) xmalloc(n * sizeof (char *)); + p = cmdlist; + q = v; + while ((r = strchr(q, ',')) != 0) { + *r = '\0'; + *p++ = xstrdup (q); + q = r + 1; + } + if (*q) + *p++ = xstrdup (q); + *p = NULL; +} + +/* + Called from maininit. Not static because also called from + luatexdir/lua/luainit.c. + + In order to avoid all kind of time code in the backend code we use a + function. The start time can be overloaded in several ways: + + (1) By setting the environmment variable SOURCE_DATE_EPOCH. This will + influence the tex parameters, random seed, pdf timestamp and pdf id that is + derived from the time. This variable is consulted when the kpse library is + enabled which is analogue to other properties. + + (2) By setting the texconfig.start_time variable (as with other variables we + use the internal name there). This has the same effect as (1) and is provided + for when kpse is not used to set these variables or when an overloaded is + wanted. This is analogue to other properties. + + When an utc time is needed one can provide the flag --utc. This property is + independent of this time hackery. This flag has a corresponding texconfig + option use_utc_time. + + To some extend a cleaner solution would be to have a flag that disables all + variable data in one go (like filenames and so) but we just follow the method + implemented in pdftex where primitives are used tod disable it. + +*/ + +static int start_time = -1; + +int get_start_time(void) { + if (start_time < 0) { + start_time = time((time_t *) NULL); + } + return start_time; +} + +/* + This one is called as part of the kpse initialization which only happens when + this library is enabled. +*/ + +#if defined(_MSC_VER) +#define strtoull _strtoui64 +#endif + +void init_start_time(void) { + if (start_time < 0) { + unsigned long long epoch; + char *endptr; + /* + We don't really care how kpse sets up this variable but we prefer to + just use its abstract interface. + */ + char *source_date_epoch = kpse_var_value("SOURCE_DATE_EPOCH"); + if (source_date_epoch) { + errno = 0; + epoch = strtoull(source_date_epoch, &endptr, 10); + if (*endptr != '\0' || errno != 0) { + epoch = 0; + } +#if defined(_MSC_VER) + /* + We avoid to crash if users test a large value which is not + supported by Visual Studio 2010: a later time than 3001/01/01 + 20:59:59. + */ + if (epoch > 32535291599ULL) + epoch = 32535291599ULL; +#endif + start_time = epoch; + } + } +} + +/* + This one is used to fetch a value from texconfig which can also be used to + set properties. This might come in handy when one has other ways to get date + info in the pdf file. +*/ + +void set_start_time(int s) { + if (s >= 0) { + start_time = s ; + } +} + +void init_shell_escape(void) +{ + if (shellenabledp < 0) { + /* --no-shell-escape on cmd line */ + shellenabledp = 0; + + } else { + if (shellenabledp == 0) { + /* no shell options on cmd line, check cnf */ + char *v1 = kpse_var_value("shell_escape"); + if (v1) { + if (*v1 == 't' || *v1 == 'y' || *v1 == '1') { + shellenabledp = 1; + } else if (*v1 == 'p') { + shellenabledp = 1; + restrictedshell = 1; + } + free(v1); + } + } + /* If shell escapes are restricted, get allowed cmds from cnf. */ + if (shellenabledp && restrictedshell == 1) { + char *v2 = kpse_var_value("shell_escape_commands"); + if (v2) { + mk_shellcmdlist(v2); + free(v2); + } + } + } +} + +# ifdef WIN32 +# define QUOTE '"' +# else +# define QUOTE '\'' +# endif + +# if 0 +# ifdef WIN32 +static int char_needs_quote(int c) +{ + /* special characters of cmd.exe */ + return (c == '&' || c == '|' || c == '%' || c == '<' || + c == '>' || c == ';' || c == ',' || c == '(' || c == ')'); +} +# endif +# endif + +static int Isspace(char c) +{ + return (c == ' ' || c == '\t'); +} + +/* + Return values: + + -1 : invalid quotation of an argument + 0 : command is not allowed + 2 : restricted shell escape, CMD is allowed. + + We set *SAFECMD to a safely-quoted version of *CMD; this is what should get + executed. And we set CMDNAME to its first word; this is what is checked + against the shell_escape_commands list. +*/ + +int shell_cmd_is_allowed(const char *cmd, char **safecmd, char **cmdname) +{ + char **p; + char *buf; + char *c, *d; + const char *s; + int pre; + unsigned spaces; + int allow = 0; + + /* + pre == 1 means that the previous character is a white space + pre == 0 means that the previous character is not a white space + */ + buf = xmalloc(strlen(cmd) + 1); + strcpy(buf, cmd); + c = buf; + while (Isspace(*c)) + c++; + d = c; + while (!Isspace(*d) && *d) + d++; + *d = '\0'; + + /* + *cmdname is the first word of the command line. For example, *cmdname == + "kpsewhich" for: + + \write18{kpsewhich --progname=dvipdfm --format="other text files" config} + */ + *cmdname = xstrdup(c); + free(buf); + + /* + Is *cmdname listed in a texmf.cnf vriable as shell_escape_commands = + foo,bar,... ? + */ + p = cmdlist; + if (p) { + while (*p) { + if (strcmp(*p, *cmdname) == 0) { + /* + *cmdname is found in the list, so restricted shell escape is + allowed + */ + allow = 2; + break; + } + p++; + } + } + if (allow == 2) { + spaces = 0; + for (s = cmd; *s; s++) { + if (Isspace(*s)) + spaces++; + } + + /* allocate enough memory (too much?) */ +# ifdef WIN32 + *safecmd = xmalloc(2 * strlen(cmd) + 3 + 2 * spaces); +# else + *safecmd = xmalloc(strlen(cmd) + 3 + 2 * spaces); +# endif + + /* make a safe command line *safecmd */ + s = cmd; + while (Isspace(*s)) + s++; + d = *safecmd; + while (!Isspace(*s) && *s) + *d++ = *s++; + + pre = 1; + while (*s) { + /* + Quotation given by a user. " should always be used; we transform + it below. On Unix, if ' is used, simply immediately return a + quotation error. + */ + if (*s == '\'') { + return -1; + } + + if (*s == '"') { + /* + All arguments are quoted as 'foo' (Unix) or "foo" (Windows) + before calling system(). Therefore closing QUOTE is necessary + if the previous character is not a white space. For example: + + --format="other text files" becomes + '--format=''other text files' (Unix) + "--format"="other text files" (Windows) + */ + if (pre == 0) { +# ifdef WIN32 + if (*(s-1) == '=') { + *(d-1) = QUOTE; + *d++ = '='; + } else { + *d++ = QUOTE; + } +# else + *d++ = QUOTE; +# endif + } + pre = 0; + /* + Output the quotation mark for the quoted argument. + */ + *d++ = QUOTE; + s++; + + while (*s != '"') { + /* + Illegal use of ', or closing quotation mark is missing + */ + if (*s == '\'' || *s == '\0') + return -1; +# if 0 +# ifdef WIN32 + if (char_needs_quote(*s)) + *d++ = '^'; +# endif +# endif + *d++ = *s++; + } + /* + Closing quotation mark will be output afterwards, so we do + nothing here. + */ + s++; + /* + The character after the closing quotation mark should be a + white space or NULL. + */ + if (!Isspace(*s) && *s) + return -1; + /* + Beginning of a usual argument. + */ + } else if (pre == 1 && !Isspace(*s)) { + pre = 0; + *d++ = QUOTE; +# if 0 +# ifdef WIN32 + if (char_needs_quote(*s)) + *d++ = '^'; +# endif +# endif + *d++ = *s++; + /* + Ending of a usual argument. + */ + } else if (pre == 0 && Isspace(*s)) { + pre = 1; + /* Closing quotation mark */ + *d++ = QUOTE; + *d++ = *s++; + } else { + /* + Copy a character from cmd to *safecmd. + */ +# if 0 +# ifdef WIN32 + if (char_needs_quote(*s)) + *d++ = '^'; +# endif +# endif + *d++ = *s++; + } + } + /* + End of the command line. + */ + if (pre == 0) { + *d++ = QUOTE; + } + *d = '\0'; +#ifdef WIN32 + { + char *p, *q, *r; + p = *safecmd; + if (strlen (p) > 2 && p[1] == ':' && !IS_DIR_SEP (p[2])) { + q = xmalloc (strlen (p) + 2); + q[0] = p[0]; + q[1] = p[1]; + q[2] = '/'; + q[3] = '\0'; + strcat (q, (p + 2)); + free (*safecmd); + *safecmd = q; + } else if (!IS_DIR_SEP (p[0]) && !(p[1] == ':' && IS_DIR_SEP (p[2]))) { + p = kpse_var_value ("SELFAUTOLOC"); + if (p) { + r = *safecmd; + while (*r && !Isspace(*r)) + r++; + if (*r == '\0') + q = concatn ("\"", p, "/", *safecmd, "\"", NULL); + else { + *r = '\0'; + r++; + while (*r && Isspace(*r)) + r++; + if (*r) + q = concatn ("\"", p, "/", *safecmd, "\" ", r, NULL); + else + q = concatn ("\"", p, "/", *safecmd, "\"", NULL); + } + free (p); + free (*safecmd); + *safecmd = q; + } + } + } +#endif + } + return allow; +} + +#endif + +/* What we were invoked as and with. */ + +char **argv; +int argc; + +/* The C version of what might wind up in |TEX_format_default|. */ + +string dump_name; + +/* The C version of the jobname, if given. */ + +const_string c_job_name; + +const char *luatex_banner; + +#ifdef _MSC_VER +/* Invalid parameter handler */ +static void myInvalidParameterHandler(const wchar_t * expression, + const wchar_t * function, + const wchar_t * file, + unsigned int line, + uintptr_t pReserved) +{ +/* + printf(L"Invalid parameter detected in function %s." + L" File: %s Line: %d\n", function, file, line); + printf(L"Expression: %s\n", expression); + + I return silently to avoid an exit with the error 0xc0000417 (invalid + parameter) when we use non-embedded fonts in luatex-ja, which works without + any problem on Unix systems. I hope it is not dangerous. +*/ + return; +} +#endif + +/* + The entry point: set up for reading the command line, which will happen in + `topenin', then call the main body. +*/ + +int +#if defined(DLLPROC) +DLLPROC (int ac, string *av) +#else +main (int ac, string *av) +#endif +{ +# ifdef __EMX__ + _wildcard(&ac, &av); + _response(&ac, &av); +# endif + +# ifdef WIN32 +# ifdef _MSC_VER + _set_invalid_parameter_handler(myInvalidParameterHandler); +# endif + av[0] = kpse_program_basename (av[0]); + _setmaxstdio(2048); +/* + We choose to crash for fatal errors: + + SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +*/ + setmode(fileno(stdin), _O_BINARY); +# endif + + lua_initialize(ac, av); + +# ifdef WIN32 + if (ac > 1) { + char *pp; + if ((strlen(av[ac-1]) > 2) && isalpha(av[ac-1][0]) && (av[ac-1][1] == ':') && (av[ac-1][2] == '\\')) { + for (pp=av[ac-1]+2; *pp; pp++) { + if (IS_KANJI(pp)) { + pp++; + continue; + } + if (*pp == '\\') + *pp = '/'; + } + } + } +# endif + + /* + Call the real main program. + */ + main_body(); + + return EXIT_SUCCESS; +} + + +/* + This is supposed to ``open the terminal for input'', but what we really do is + copy command line arguments into TeX's or Metafont's buffer, so they can + handle them. If nothing is available, or we've been called already (and + hence, argc==0), we return with `last=first'. +*/ + +void topenin(void) +{ + int i; + + buffer[first] = 0; /* In case there are no arguments. */ + + if (optind < argc) { + /* We have command line arguments. */ + int k = first; + for (i = optind; i < argc; i++) { + char *ptr = &(argv[i][0]); + /* + We cannot use strcat, because we have multibyte UTF-8 input. + */ + while (*ptr) { + buffer[k++] = (packed_ASCII_code) * (ptr++); + } + buffer[k++] = ' '; + } + /* Don't do this again. */ + argc = 0; + buffer[k] = 0; + } + + /* + Find the end of the buffer looking at spaces and newlines. + */ + + for (last = first; buffer[last]; ++last); + + /* + We conform to the way Web2c does handle trailing tabs and spaces. This + decade old behaviour was changed in September 2017 and can introduce + compatibility issues in existing workflows. Because we don't want too + many differences with upstream TeXlive we just follow up on that patch + and it's up to macro packages to deal with possible issues (which can be + done via the usual callbacks. One can wonder why we then still prune + spaces but we leave that to the reader. + */ + + /* Patched original comment: + + Make `last' be one past the last non-space character in `buffer', + ignoring line terminators (but not, e.g., tabs). This is because + we are supposed to treat this like a line of TeX input. Although + there are pathological cases (SPC CR SPC CR) where this differs + from input_line below, and from previous behavior of removing all + whitespace, the simplicity of removing all trailing line terminators + seems more in keeping with actual command line processing. + */ + + /* + The IS_SPC_OR_EOL macro deals with space characters (SPACE 32) and + newlines (CR and LF) and no longer looks at tabs (TAB 9). + + */ + +#define IS_SPC_OR_EOL(c) ((c) == ' ' || (c) == '\r' || (c) == '\n') + for (--last; last >= first && IS_SPC_OR_EOL (buffer[last]); --last); + last++; + /* + One more time, this time converting to TeX's internal character + representation. + */ +} + +/* + Normalize quoting of filename -- that is, only quote if there is a space, and + always use the quote-name-quote style. +*/ + +string normalize_quotes(const_string name, const_string mesg) +{ + boolean quoted = false; + boolean must_quote = (strchr(name, ' ') != NULL); + /* Leave room for quotes and NUL. */ + string ret = (string) xmalloc((unsigned) strlen(name) + 3); + string p; + const_string q; + p = ret; + if (must_quote) + *p++ = '"'; + for (q = name; *q; q++) { + if (*q == '"') + quoted = !quoted; + else + *p++ = *q; + } + if (must_quote) + *p++ = '"'; + *p = '\0'; + if (quoted) { + fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name); + uexit(1); + } + return ret; +} + + +/* + All our interrupt handler has to do is set TeX's or Metafont's global + variable `interrupt'; then they will do everything needed. +*/ + +#ifdef WIN32 +/* Win32 doesn't set SIGINT ... */ +static BOOL WINAPI catch_interrupt(DWORD arg) +{ + switch (arg) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + interrupt = 1; + return TRUE; + default: + /* No need to set interrupt as we are exiting anyway */ + return FALSE; + } +} +#else /* not WIN32 */ +static RETSIGTYPE catch_interrupt(int arg) +{ + (void) arg; + interrupt = 1; +# ifdef OS2 + (void) signal(SIGINT, SIG_ACK); +# else + (void) signal(SIGINT, catch_interrupt); +# endif /* not OS2 */ +} +#endif /* not WIN32 */ + +/* + Besides getting the date and time here, we also set up the interrupt handler, + for no particularly good reason. It's just that since the `fix_date_and_time' + routine is called early on (section 1337 in TeX, ``Get the first line of + input and prepare to start''), this is as good a place as any. +*/ + +void get_date_and_time(int *minutes, int *day, int *month, int *year) +{ + time_t myclock = get_start_time(); + struct tm *tmptr ; + if (utc_option) { + tmptr = gmtime(&myclock); + } else { + tmptr = localtime(&myclock); + } + + *minutes = tmptr->tm_hour * 60 + tmptr->tm_min; + *day = tmptr->tm_mday; + *month = tmptr->tm_mon + 1; + *year = tmptr->tm_year + 1900; + + { +#ifdef SA_INTERRUPT + + /* + Under SunOS 4.1.x, the default action after return from the signal + handler is to restart the I/O if nothing has been transferred. The + effect on TeX is that interrupts are ignored if we are waiting for + input. The following tells the system to return EINTR from read() in + this case. From ken@cs.toronto.edu. + */ + + struct sigaction a, oa; + + a.sa_handler = catch_interrupt; + sigemptyset(&a.sa_mask); + sigaddset(&a.sa_mask, SIGINT); + a.sa_flags = SA_INTERRUPT; + sigaction(SIGINT, &a, &oa); + if (oa.sa_handler != SIG_DFL) + sigaction(SIGINT, &oa, (struct sigaction *) 0); +#else /* no SA_INTERRUPT */ +# ifdef WIN32 + SetConsoleCtrlHandler(catch_interrupt, TRUE); +# else /* not WIN32 */ + RETSIGTYPE(*old_handler) (int); + + old_handler = signal(SIGINT, catch_interrupt); + if (old_handler != SIG_DFL) + signal(SIGINT, old_handler); +# endif /* not WIN32 */ +#endif /* no SA_INTERRUPT */ + } +} + +/* + Getting a high resolution time. +*/ + +void get_seconds_and_micros(int *seconds, int *micros) +{ +#if defined (HAVE_GETTIMEOFDAY) + struct timeval tv; + gettimeofday(&tv, NULL); + *seconds = (int)tv.tv_sec; + *micros = (int)tv.tv_usec; +#elif defined (HAVE_FTIME) + struct timeb tb; + ftime(&tb); + *seconds = tb.time; + *micros = tb.millitm * 1000; +#else + time_t myclock = time((time_t *) NULL); + *seconds = (int) myclock; + *micros = 0; +#endif +} + +/* + Generating a better seed numbers +*/ + +int getrandomseed(void) +{ +#if defined (HAVE_GETTIMEOFDAY) + struct timeval tv; + gettimeofday(&tv, NULL); + return (int)(tv.tv_usec + 1000000 * tv.tv_usec); +#elif defined (HAVE_FTIME) + struct timeb tb; + ftime(&tb); + return (tb.millitm + 1000 * tb.time); +#else + time_t myclock = get_start_time((time_t *) NULL); + struct tm *tmptr ; + if (utc_option) { + tmptr = gmtime(&myclock); + } else { + tmptr = localtime(&myclock); + } + return (tmptr->tm_sec + 60 * (tmptr->tm_min + 60 * tmptr->tm_hour)); +#endif +} + +/* + Read a line of input as efficiently as possible while still looking like + Pascal. We set `last' to `first' and return `false' if we get to eof. + Otherwise, we return `true' and set last = first + length(line except + trailing whitespace). +*/ + +boolean input_line(FILE * f) +{ + int i = EOF; + +#ifdef WIN32 + if (f != Poptr && fileno (f) != fileno (stdin)) { + long position = ftell (f); + if (position == 0L) { + /* Detect and skip Byte order marks. */ + int k1 = getc (f); + + if (k1 != 0xff && k1 != 0xfe && k1 != 0xef) + rewind (f); + else { + int k2 = getc (f); + if (k2 != 0xff && k2 != 0xfe && k2 != 0xbb) + rewind (f); + else if ((k1 == 0xff && k2 == 0xfe) || /* UTF-16(LE) */ + (k1 == 0xfe && k2 == 0xff)) /* UTF-16(BE) */ + ; + else { + int k3 = getc (f); + int k4 = getc (f); + if (k1 == 0xef && k2 == 0xbb && k3 == 0xbf && + k4 >= 0 && k4 <= 0x7e) /* UTF-8 */ + ungetc (k4, f); + else + rewind (f); + } + } + } + } +#endif + /* + Recognize either LF or CR as a line terminator. + */ + last = first; + while (last < buf_size && (i = getc(f)) != EOF && i != '\n' && i != '\r') + buffer[last++] = (packed_ASCII_code) i; + + if (i == EOF && errno != EINTR && last == first) + return false; + + /* + We didn't get the whole line because our buffer was too small. + */ + if (i != EOF && i != '\n' && i != '\r') { + fprintf(stderr, "! Unable to read an entire line---bufsize=%u.\n", + (unsigned) buf_size); + fputs("Please increase buf_size in texmf.cnf.\n", stderr); + uexit(1); + } + + buffer[last] = ' '; + if (last >= max_buf_stack) + max_buf_stack = last; + + /* + If next char is LF of a CRLF, read it. + */ + if (i == '\r') { + while ((i = getc(f)) == EOF && errno == EINTR); + if (i != '\n') + ungetc(i, f); + } + + /* + Trim trailing space character (but not, e.g., tabs). We can't have line + terminators because we stopped reading at the first \r or \n. TeX's rule + is to strip only trailing spaces (and eols). David Fuchs mentions that + this stripping was done to ensure portability of TeX documents given the + padding with spaces on fixed-record "lines" on some systems of the time, + e.g., IBM VM/CMS and OS/360. + */ + while (last > first && buffer[last - 1] == ' ') + --last; + + /* + Don't bother using xord if we don't need to. + */ + + return true; +} + +/* + Get the job name to be used, which may have been set from the command line. +*/ + +str_number getjobname(str_number name) +{ + str_number ret = name; + if (c_job_name != NULL) + ret = maketexstring(c_job_name); + return ret; +} |