1 /* luatex.c: Hand-coded routines for TeX or Metafont in C.  Originally
2    written by Tim Morgan, drawing from other Unix ports of TeX.  This is
3    a collection of miscellany, everything that's easier (or only
4    possible) to do in C.
5 
6    This file is public domain.  */
7 
8 /* This file is used to create texextra.c etc., with this line
9    changed to include texd.h or mfd.h.  The ?d.h file is what
10    #defines TeX or MF, which avoids the need for a special
11    Makefile rule.  */
12 
13 /* We |#define DLLPROC| in order to build LuaTeX and LuajitTeX as DLL
14    for W32TeX.  */
15 #if defined LuajitTeX
16 #define DLLPROC dllluajittexmain
17 #else
18 #define DLLPROC dllluatexmain
19 #endif
20 
21 #include "ptexlib.h"
22 #include "luatex.h"
23 #include "lua/luatex-api.h"
24 #include "luatex_svnversion.h"
25 
26 
27 #define TeX
28 
29 int luatex_svn = 5238;
30 int luatex_version = 80;        /* \.{\\luatexversion}  */
31 int luatex_revision = '0';      /* \.{\\luatexrevision}  */
32 int luatex_date_info = 2015051900;     /* the compile date is now hardwired */
33 const char *luatex_version_string = "beta-0.80.0";
34 const char *engine_name = my_name;     /* the name of this engine */
35 
36 #include <kpathsea/c-ctype.h>
37 #include <kpathsea/line.h>
38 #include <kpathsea/readable.h>
39 #include <kpathsea/variable.h>
40 #include <kpathsea/absolute.h>
41 #ifdef WIN32
42 #include <kpathsea/concatn.h>
43 #endif
44 
45 #ifdef _MSC_VER
46 #undef timezone
47 #endif
48 
49 #include <time.h>               /* For `struct tm'.  */
50 #if defined (HAVE_SYS_TIME_H)
51 #  include <sys/time.h>
52 #elif defined (HAVE_SYS_TIMEB_H)
53 #  include <sys/timeb.h>
54 #endif
55 
56 #if defined(__STDC__)
57 #  include <locale.h>
58 #endif
59 
60 #include <signal.h>             /* Catch interrupts.  */
61 
62 
63 /* {tex,mf}d.h defines TeX, MF, INI, and other such symbols.
64    Unfortunately there's no way to get the banner into this code, so
65    just repeat the text.  */
66 #define edit_var "TEXEDIT"
67 
68 /* Shell escape.
69 
70    If shellenabledp == 0, all shell escapes are forbidden.
71    If (shellenabledp == 1 && restrictedshell == 0), any command
72      is allowed for a shell escape.
73    If (shellenabledp == 1 && restrictedshell == 1), only commands
74      given in the configuration file as
75    shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun,...
76      (no spaces between commands) in texmf.cnf are allowed for a shell
77      escape in a restricted form: command name and arguments should be
78      separated by a white space. The first word should be a command
79      name. The quotation character for an argument with spaces,
80      including a pathname, should be ".  ' should not be used.
81 
82      Internally, all arguments are quoted by ' (Unix) or " (Windows)
83      before calling the system() function in order to forbid execution
84      of any embedded command.  In addition, on Windows, special
85      characters of cmd.exe are escaped by using (^).
86 
87    If the --shell-escape option is given, we set
88      shellenabledp = 1 and restrictedshell = 0, i.e., any command is allowed.
89    If the --shell-restricted option is given, we set
90      shellenabledp = 1 and restrictedshell = 1, i.e., only given cmds allowed.
91    If the --no-shell-escape option is given, we set
92      shellenabledp = -1 (and restrictedshell is irrelevant).
93    If none of these option are given, there are three cases:
94    (1) In the case where
95        shell_escape = y or
96        shell_escape = t or
97        shell_escape = 1
98        it becomes shellenabledp = 1 and restrictedshell = 0,
99        that is, any command is allowed.
100    (2) In the case where
101        shell_escape = p
102        it becomes shellenabledp = 1 and restrictedshell = 1,
103        that is, restricted shell escape is allowed.
104    (3) In all other cases, shellenabledp = 0, that is, shell
105        escape is forbidden. The value of restrictedshell is
106        irrelevant if shellenabledp == 0.
107 */
108 
109 #ifdef TeX
110 
111 /* cmdlist is a list of allowed commands which are given like this:
112    shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun
113    in texmf.cnf. */
114 
115 static char **cmdlist = NULL;
116 
mk_shellcmdlist(char * v)117 void mk_shellcmdlist(char *v)
118 {
119     char **p;
120     char *q, *r;
121     size_t n;
122 
123     q = v;
124     n = 1;
125 
126 /* analyze the variable shell_escape_commands = foo,bar,...
127    spaces before and after (,) are not allowed. */
128 
129     while ((r = strchr(q, ',')) != 0) {
130         n++;
131         q = r + 1;
132     }
133     if (*q)
134         n++;
135     cmdlist = (char **) xmalloc(n * sizeof (char *));
136     p = cmdlist;
137     q = v;
138     while ((r = strchr(q, ',')) != 0) {
139         *r = '\0';
140         *p++ = xstrdup (q);
141         q = r + 1;
142     }
143     if (*q)
144         *p++ = xstrdup (q);
145     *p = NULL;
146 }
147 
148 /* Called from maininit.  Not static because also called from
149    luatexdir/lua/luainit.c.  */
150 
init_shell_escape(void)151 void init_shell_escape(void)
152 {
153     if (shellenabledp < 0) {    /* --no-shell-escape on cmd line */
154         shellenabledp = 0;
155 
156     } else {
157         if (shellenabledp == 0) {       /* no shell options on cmd line, check cnf */
158             char *v1 = kpse_var_value("shell_escape");
159             if (v1) {
160                 if (*v1 == 't' || *v1 == 'y' || *v1 == '1') {
161                     shellenabledp = 1;
162                 } else if (*v1 == 'p') {
163                     shellenabledp = 1;
164                     restrictedshell = 1;
165                 }
166                 free(v1);
167             }
168         }
169 
170         /* If shell escapes are restricted, get allowed cmds from cnf.  */
171         if (shellenabledp && restrictedshell == 1) {
172             char *v2 = kpse_var_value("shell_escape_commands");
173             if (v2) {
174                 mk_shellcmdlist(v2);
175                 free(v2);
176             }
177         }
178     }
179 }
180 
181 #  ifdef WIN32
182 #    define QUOTE '"'
183 #  else
184 #    define QUOTE '\''
185 #  endif
186 
187 #  ifdef WIN32
char_needs_quote(int c)188 static int char_needs_quote(int c)
189 {
190 /* special characters of cmd.exe */
191 
192     return (c == '&' || c == '|' || c == '%' || c == '<' ||
193             c == '>' || c == ';' || c == ',' || c == '(' || c == ')');
194 }
195 #  endif
196 
Isspace(char c)197 static int Isspace(char c)
198 {
199     return (c == ' ' || c == '\t');
200 }
201 
202 /* return values:
203   -1 : invalid quotation of an argument
204    0 : command is not allowed
205    2 : restricted shell escape, CMD is allowed.
206 
207    We set *SAFECMD to a safely-quoted version of *CMD; this is what
208    should get executed.  And we set CMDNAME to its first word; this is
209    what is checked against the shell_escape_commands list.  */
210 
shell_cmd_is_allowed(const char * cmd,char ** safecmd,char ** cmdname)211 int shell_cmd_is_allowed(const char *cmd, char **safecmd, char **cmdname)
212 {
213     char **p;
214     char *buf;
215     char *c, *d;
216     const char *s;
217     int pre;
218     unsigned spaces;
219     int allow = 0;
220 
221     /* pre == 1 means that the previous character is a white space
222        pre == 0 means that the previous character is not a white space */
223     buf = xmalloc(strlen(cmd) + 1);
224     strcpy(buf, cmd);
225     c = buf;
226     while (Isspace(*c))
227         c++;
228     d = c;
229     while (!Isspace(*d) && *d)
230         d++;
231     *d = '\0';
232 
233     /* *cmdname is the first word of the command line.  For example,
234      *cmdname == "kpsewhich" for
235      \write18{kpsewhich --progname=dvipdfm --format="other text files" config}
236      */
237     *cmdname = xstrdup(c);
238     free(buf);
239 
240     /* Is *cmdname listed in a texmf.cnf vriable as
241        shell_escape_commands = foo,bar,... ? */
242     p = cmdlist;
243     if (p) {
244         while (*p) {
245             if (strcmp(*p, *cmdname) == 0) {
246                 /* *cmdname is found in the list, so restricted shell escape
247                    is allowed */
248                 allow = 2;
249                 break;
250             }
251             p++;
252         }
253     }
254     if (allow == 2) {
255         spaces = 0;
256         for (s = cmd; *s; s++) {
257             if (Isspace(*s))
258                 spaces++;
259         }
260 
261         /* allocate enough memory (too much?) */
262 #  ifdef WIN32
263         *safecmd = xmalloc(2 * strlen(cmd) + 3 + 2 * spaces);
264 #  else
265         *safecmd = xmalloc(strlen(cmd) + 3 + 2 * spaces);
266 #  endif
267 
268         /* make a safe command line *safecmd */
269         s = cmd;
270         while (Isspace(*s))
271             s++;
272         d = *safecmd;
273         while (!Isspace(*s) && *s)
274             *d++ = *s++;
275 
276         pre = 1;
277         while (*s) {
278             /* Quotation given by a user.  " should always be used; we
279                transform it below.  On Unix, if ' is used, simply immediately
280                return a quotation error.  */
281             if (*s == '\'') {
282                 return -1;
283             }
284 
285             if (*s == '"') {
286                 /* All arguments are quoted as 'foo' (Unix) or "foo" (Windows)
287                    before calling system(). Therefore closing QUOTE is necessary
288                    if the previous character is not a white space.
289                    example:
290                    --format="other text files" becomes
291                    '--format=''other text files' (Unix)
292                    "--format=""other test files" (Windows) */
293 
294                 if (pre == 0)
295                     *d++ = QUOTE;
296 
297                 pre = 0;
298                 /* output the quotation mark for the quoted argument */
299                 *d++ = QUOTE;
300                 s++;
301 
302                 while (*s != '"') {
303                     /* Illegal use of ', or closing quotation mark is missing */
304                     if (*s == '\'' || *s == '\0')
305                         return -1;
306 #  ifdef WIN32
307                     if (char_needs_quote(*s))
308                         *d++ = '^';
309 #  endif
310                     *d++ = *s++;
311                 }
312 
313                 /* Closing quotation mark will be output afterwards, so
314                    we do nothing here */
315                 s++;
316 
317                 /* The character after the closing quotation mark
318                    should be a white space or NULL */
319                 if (!Isspace(*s) && *s)
320                     return -1;
321 
322                 /* Beginning of a usual argument */
323             } else if (pre == 1 && !Isspace(*s)) {
324                 pre = 0;
325                 *d++ = QUOTE;
326 #  ifdef WIN32
327                 if (char_needs_quote(*s))
328                     *d++ = '^';
329 #  endif
330                 *d++ = *s++;
331                 /* Ending of a usual argument */
332 
333             } else if (pre == 0 && Isspace(*s)) {
334                 pre = 1;
335                 /* Closing quotation mark */
336                 *d++ = QUOTE;
337                 *d++ = *s++;
338             } else {
339                 /* Copy a character from cmd to *safecmd. */
340 #  ifdef WIN32
341                 if (char_needs_quote(*s))
342                     *d++ = '^';
343 #  endif
344                 *d++ = *s++;
345             }
346         }
347         /* End of the command line */
348         if (pre == 0) {
349             *d++ = QUOTE;
350         }
351         *d = '\0';
352 #ifdef WIN32
353         {
354           char *p, *q, *r;
355           p = *safecmd;
356           if (strlen (p) > 2 && p[1] == ':' && !IS_DIR_SEP (p[2])) {
357               q = xmalloc (strlen (p) + 2);
358               q[0] = p[0];
359               q[1] = p[1];
360               q[2] = '/';
361               q[3] = '\0';
362               strcat (q, (p + 2));
363               free (*safecmd);
364               *safecmd = q;
365           } else if (!IS_DIR_SEP (p[0]) && !(p[1] == ':' && IS_DIR_SEP (p[2]))) {
366             p = kpse_var_value ("SELFAUTOLOC");
367             if (p) {
368               r = *safecmd;
369               while (*r && !Isspace(*r))
370                 r++;
371               if (*r == '\0')
372                 q = concatn ("\"", p, "/", *safecmd, "\"", NULL);
373               else {
374                 *r = '\0';
375                 r++;
376                 while (*r && Isspace(*r))
377                   r++;
378                 if (*r)
379                   q = concatn ("\"", p, "/", *safecmd, "\" ", r, NULL);
380                 else
381                   q = concatn ("\"", p, "/", *safecmd, "\"", NULL);
382               }
383               free (p);
384               free (*safecmd);
385               *safecmd = q;
386             }
387           }
388         }
389 #endif
390     }
391 
392     return allow;
393 }
394 
395 /* We should only be called with shellenabledp == 1.
396    Return value:
397    -1 if a quotation syntax error.
398    0 if CMD is not allowed; given shellenabledp==1, this is because
399       shell escapes are restricted and CMD is not allowed.
400    1 if shell escapes are not restricted, hence any command is allowed.
401    2 if shell escapes are restricted and CMD is allowed.  */
402 
runsystem(const char * cmd)403 int runsystem(const char *cmd)
404 {
405     int allow = 0;
406     char *safecmd = NULL;
407     char *cmdname = NULL;
408 
409     if (shellenabledp <= 0) {
410         return 0;
411     }
412 
413     /* If restrictedshell == 0, any command is allowed. */
414     if (restrictedshell == 0)
415         allow = 1;
416     else
417         allow = shell_cmd_is_allowed(cmd, &safecmd, &cmdname);
418 
419     if (allow == 1)
420         (void) system(cmd);
421     else if (allow == 2)
422         (void) system(safecmd);
423 
424     if (safecmd)
425         free(safecmd);
426     if (cmdname)
427         free(cmdname);
428 
429     return allow;
430 }
431 
432 #endif
433 
434 
435 /* What we were invoked as and with.  */
436 char **argv;
437 int argc;
438 
439 /* The C version of what might wind up in |TEX_format_default|.  */
440 string dump_name;
441 
442 /* The C version of the jobname, if given. */
443 const_string c_job_name;
444 
445 const char *luatex_banner;
446 
447 #ifdef _MSC_VER
448 /* Invalid parameter handler */
myInvalidParameterHandler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t pReserved)449 static void myInvalidParameterHandler(const wchar_t * expression,
450    const wchar_t * function,
451    const wchar_t * file,
452    unsigned int line,
453    uintptr_t pReserved)
454 {
455 /*
456    printf(L"Invalid parameter detected in function %s."
457             L" File: %s Line: %d\n", function, file, line);
458    printf(L"Expression: %s\n", expression);
459 */
460 /*
461    I return silently to avoid an exit with the error 0xc0000417
462    (invalid parameter) when we use non-embedded fonts in luatex-ja,
463    which works without any problem on Unix systems.
464    I hope it is not dangerous.
465 */
466    return;
467 }
468 #endif
469 
470 /* The entry point: set up for reading the command line, which will
471    happen in `topenin', then call the main body.  */
472 
473 int
474 #if defined(DLLPROC)
DLLPROC(int ac,string * av)475 DLLPROC (int ac, string *av)
476 #else
477 main (int ac, string *av)
478 #endif
479 {
480 #  ifdef __EMX__
481     _wildcard(&ac, &av);
482     _response(&ac, &av);
483 #  endif
484 
485 #  ifdef WIN32
486 #    ifdef _MSC_VER
487     _set_invalid_parameter_handler(myInvalidParameterHandler);
488 #    endif
489     av[0] = kpse_program_basename (av[0]);
490     _setmaxstdio(2048);
491     SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
492     setmode(fileno(stdin), _O_BINARY);
493 #  endif
494 
495     lua_initialize(ac, av);
496 
497 #  ifdef WIN32
498     if (ac > 1) {
499       char *pp;
500       if ((strlen(av[ac-1]) > 2) &&
501           isalpha(av[ac-1][0]) &&
502           (av[ac-1][1] == ':') &&
503           (av[ac-1][2] == '\\')) {
504         for (pp=av[ac-1]+2; *pp; pp++) {
505           if (IS_KANJI(pp)) {
506             pp++;
507             continue;
508           }
509           if (*pp == '\\')
510             *pp = '/';
511         }
512       }
513     }
514 #  endif
515 
516     /* Call the real main program.  */
517     main_body();
518 
519     return EXIT_SUCCESS;
520 }
521 
522 
523 /* This is supposed to ``open the terminal for input'', but what we
524    really do is copy command line arguments into TeX's or Metafont's
525    buffer, so they can handle them.  If nothing is available, or we've
526    been called already (and hence, argc==0), we return with
527    `last=first'.  */
528 
topenin(void)529 void topenin(void)
530 {
531     int i;
532 
533 
534     buffer[first] = 0;          /* In case there are no arguments.  */
535 
536     if (optind < argc) {        /* We have command line arguments.  */
537         int k = first;
538         for (i = optind; i < argc; i++) {
539             char *ptr = &(argv[i][0]);
540             /* Don't use strcat, since in Aleph the buffer elements aren't
541                single bytes.  */
542             while (*ptr) {
543                 buffer[k++] = (packed_ASCII_code) * (ptr++);
544             }
545             buffer[k++] = ' ';
546         }
547         argc = 0;               /* Don't do this again.  */
548         buffer[k] = 0;
549     }
550 
551     /* Find the end of the buffer.  */
552     for (last = first; buffer[last]; ++last);
553 
554     /* Make `last' be one past the last non-blank character in `buffer'.  */
555     /* ??? The test for '\r' should not be necessary.  */
556     for (--last; last >= first
557          && ISBLANK(buffer[last]) && buffer[last] != '\r'; --last);
558     last++;
559 
560     /* One more time, this time converting to TeX's internal character
561        representation.  */
562 }
563 
564 /* IPC for TeX.  By Tom Rokicki for the NeXT; it makes TeX ship out the
565    DVI file in a pipe to TeXView so that the output can be displayed
566    incrementally.  Shamim Mohamed adapted it for Web2c.  */
567 #if defined (TeX) && defined (IPC)
568 
569 #ifdef WIN32
570 #undef _WINSOCKAPI_
571 #include <winsock2.h>
572 #else
573 #include <sys/socket.h>
574 #include <fcntl.h>
575 #ifndef O_NONBLOCK /* POSIX */
576 #ifdef O_NDELAY    /* BSD */
577 #define O_NONBLOCK O_NDELAY
578 #elif defined(O_FNDELAY)     /* NeXT */
579 #define O_NONBLOCK O_FNDELAY
580 #else
581 what the fcntl? cannot implement IPC without equivalent for O_NONBLOCK.
582 #endif
583 #endif /* no O_NONBLOCK */
584 #endif /* !WIN32 */
585 
586 #ifdef WIN32
587 # define IPC_AF AF_INET
588 # ifndef IPC_LOCAL_HOST
589 #  define IPC_LOCAL_HOST "127.0.0.1"
590 #  define FIXED_PORT     (unsigned short)4242
591 # endif
592 #else
593 # define IPC_AF AF_UNIX
594 # ifndef IPC_PIPE_NAME /* $HOME is prepended to this.  */
595 #  define IPC_PIPE_NAME "/.TeXview_Pipe"
596 # endif
597 #endif
598 #ifndef IPC_SERVER_CMD /* Command to run to start the server.  */
599 # ifdef WIN32
600 #  define IPC_SERVER_CMD "texview.exe"
601 # else
602 #  define IPC_SERVER_CMD "open `which TeXview`"
603 # endif
604 #endif
605 
606 struct msg
607 {
608   int   namelength; /* length of auxiliary data */
609   int   eof;        /* new eof for dvi file */
610 #if 0  /* see usage of struct msg below */
611   char more_data[0]; /* where the rest of the stuff goes */
612 #endif
613 };
614 
615 static struct sockaddr *ipc_addr;
616 static int ipc_addr_len;
617 
618 static int
619 ipc_make_name (void)
620 {
621   if (ipc_addr_len == 0) {
622 #ifdef WIN32
623     unsigned long remote_addr = inet_addr(IPC_LOCAL_HOST);
624     if (remote_addr != INADDR_NONE) {
625       struct sockaddr_in *ipc_sin_addr = xmalloc (sizeof (struct sockaddr_in));
626       ipc_sin_addr->sin_family = AF_INET;
627       ipc_sin_addr->sin_addr.s_addr = remote_addr;
628       ipc_sin_addr->sin_port = htons (FIXED_PORT);
629       ipc_addr = ((struct sockaddr *) ipc_sin_addr);
630       ipc_addr_len = sizeof(struct sockaddr_in);
631     }
632 #else
633     string s = getenv ("HOME");
634     if (s) {
635       char *ipc_name;
636       ipc_addr = xmalloc (strlen (s) + 40);
637       ipc_addr->sa_family = 0;
638       ipc_name = ipc_addr->sa_data;
639       strcpy (ipc_name, s);
640       strcat (ipc_name, IPC_PIPE_NAME);
641       ipc_addr_len = strlen (ipc_name) + 3;
642     }
643 #endif
644   }
645   return ipc_addr_len;
646 }
647 
648 static int sock = -1;
649 
650 #ifdef WIN32
651 # define CLOSE_SOCKET(s) closesocket (s); WSACleanup ()
652 #else
653 # define CLOSE_SOCKET(s) close (s)
654 #endif
655 
656 static int
657 ipc_is_open (void)
658 {
659    return sock != -1;
660 }
661 
662 static void
663 ipc_open_out (void) {
664 #ifdef WIN32
665   struct WSAData wsaData;
666   int nCode;
667   unsigned long mode = 1;
668 #endif
669 #ifdef IPC_DEBUG
670   fputs ("tex: Opening socket for IPC output ...\n", stderr);
671 #endif
672   if (sock != -1) {
673     return;
674   }
675 
676 #ifdef WIN32
677   if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
678     fprintf(stderr,"WSAStartup() returned error code %d.\n", nCode);
679     return;
680   }
681 #endif
682 
683   if (ipc_make_name () <= 0)
684     return;
685 
686   sock = socket (IPC_AF, SOCK_STREAM, 0);
687 #ifdef IPC_DEBUG
688   if(sock != -1)
689     fprintf(stderr, "tex: Socket handle is %d\n", sock);
690   else
691     fprintf(stderr, "tex: Socket is invalid.\n");
692 #endif
693 
694   if (sock != -1) {
695     if (connect (sock, ipc_addr, ipc_addr_len) != 0 ||
696 #ifdef WIN32
697         ioctlsocket (sock, FIONBIO, &mode) < 0
698 #else
699         fcntl (sock, F_SETFL, O_NONBLOCK) < 0
700 #endif
701         ) {
702       CLOSE_SOCKET (sock);
703       sock = -1;
704 #ifdef IPC_DEBUG
705       fputs ("tex: IPC socket cannot be connected.\n", stderr);
706       fputs ("tex: Socket is closed.\n", stderr);
707 #endif
708       return;
709     }
710 #ifdef IPC_DEBUG
711     fputs ("tex: Successfully opened IPC socket.\n", stderr);
712 #endif
713   }
714 }
715 
716 static void
717 ipc_close_out (void)
718 {
719 #ifdef IPC_DEBUG
720   fputs ("tex: Closing output socket ...\n", stderr);
721 #endif
722   if (ipc_is_open ()) {
723     CLOSE_SOCKET (sock);
724     sock = -1;
725   }
726 }
727 
728 static void
729 ipc_snd (int n, int is_eof, char *data)
730 {
731   struct
732   {
733     struct msg msg;
734     char more_data[1024];
735   } ourmsg;
736 
737   if (!ipc_is_open ()) {
738     return;
739   }
740 
741 #ifdef IPC_DEBUG
742   fprintf(stderr, "%d\t%d\n", ourmsg.msg.namelength, ourmsg.msg.eof);
743   fputs ("tex: Sending message to socket ...\n", stderr);
744 #endif
745   ourmsg.msg.namelength = n;
746   ourmsg.msg.eof = is_eof;
747   if (n) {
748     strcpy (ourmsg.more_data, data);
749   }
750   n += sizeof (struct msg);
751 #ifdef IPC_DEBUG
752   fprintf(stderr, "%d\t%d\n", ourmsg.msg.namelength, ourmsg.msg.eof);
753   fputs ("tex: Writing to socket...\n", stderr);
754 #endif
755 #if defined(WIN32)
756   if (send (sock, (char *)&ourmsg, n, 0) != n) {
757 #else
758   if (write (sock, &ourmsg, n) != n) {
759 #endif
760     ipc_close_out ();
761   }
762 #ifdef IPC_DEBUG
763   fputs ("tex: IPC message sent.\n", stderr);
764 #endif
765 }
766 
767 /* This routine notifies the server if there is an eof, or the filename
768    if a new DVI file is starting.  This is the routine called by TeX.
769    Aleph defines str_start(#) as str_start_ar[# - too_big_char], with
770    too_big_char = biggest_char + 1 = 65536 (omstr.ch).  */
771 
772 void
773 ipcpage (int is_eof)
774 {
775   static boolean begun = false;
776   unsigned len = 0;
777   string p = NULL;
778 
779   if (!begun) {
780     string name; /* Just the filename.  */
781     string cwd = xgetcwd ();
782 
783     ipc_open_out ();
784 
785     /* Have to pass whole filename to the other end, since it may have
786        been started up and running as a daemon, e.g., as with the NeXT
787        preview program.  */
788     name = static_pdf->file_name;
789     p = concat3 (cwd, DIR_SEP_STRING, name);
790     free (cwd);
791     free (name);
792 
793 #if defined (WIN32)
794     { char *q;
795       for (q = p; *q; q++) {
796         if (*q == '\\')
797           *q = '/';
798         else if (IS_KANJI(q))
799           q++;
800       }
801     }
802 #endif
803     len = strlen(p);
804     begun = true;
805   }
806   ipc_snd (len, is_eof, p);
807 
808   if (p)
809     free (p);
810 }
811 #endif /* TeX && IPC */
812 
813 /* Normalize quoting of filename -- that is, only quote if there is a space,
814    and always use the quote-name-quote style. */
815 string normalize_quotes(const_string name, const_string mesg)
816 {
817     boolean quoted = false;
818     boolean must_quote = (strchr(name, ' ') != NULL);
819     /* Leave room for quotes and NUL. */
820     string ret = (string) xmalloc((unsigned) strlen(name) + 3);
821     string p;
822     const_string q;
823     p = ret;
824     if (must_quote)
825         *p++ = '"';
826     for (q = name; *q; q++) {
827         if (*q == '"')
828             quoted = !quoted;
829         else
830             *p++ = *q;
831     }
832     if (must_quote)
833         *p++ = '"';
834     *p = '\0';
835     if (quoted) {
836         fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
837         uexit(1);
838     }
839     return ret;
840 }
841 
842 
843 /* All our interrupt handler has to do is set TeX's or Metafont's global
844    variable `interrupt'; then they will do everything needed.  */
845 #ifdef WIN32
846 /* Win32 doesn't set SIGINT ... */
847 static BOOL WINAPI catch_interrupt(DWORD arg)
848 {
849     switch (arg) {
850     case CTRL_C_EVENT:
851     case CTRL_BREAK_EVENT:
852         interrupt = 1;
853         return TRUE;
854     default:
855         /* No need to set interrupt as we are exiting anyway */
856         return FALSE;
857     }
858 }
859 #else                           /* not WIN32 */
860 static RETSIGTYPE catch_interrupt(int arg)
861 {
862     (void) arg;
863     interrupt = 1;
864 #  ifdef OS2
865     (void) signal(SIGINT, SIG_ACK);
866 #  else
867     (void) signal(SIGINT, catch_interrupt);
868 #  endif                        /* not OS2 */
869 }
870 #endif                          /* not WIN32 */
871 
872 /* Besides getting the date and time here, we also set up the interrupt
873    handler, for no particularly good reason.  It's just that since the
874    `fix_date_and_time' routine is called early on (section 1337 in TeX,
875    ``Get the first line of input and prepare to start''), this is as
876    good a place as any.  */
877 
878 void get_date_and_time(int *minutes, int *day, int *month, int *year)
879 {
880     time_t myclock = time((time_t *) 0);
881     struct tm *tmptr = localtime(&myclock);
882 
883     *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
884     *day = tmptr->tm_mday;
885     *month = tmptr->tm_mon + 1;
886     *year = tmptr->tm_year + 1900;
887 
888     {
889 #ifdef SA_INTERRUPT
890         /* Under SunOS 4.1.x, the default action after return from the
891            signal handler is to restart the I/O if nothing has been
892            transferred.  The effect on TeX is that interrupts are ignored if
893            we are waiting for input.  The following tells the system to
894            return EINTR from read() in this case.  From ken@cs.toronto.edu.  */
895 
896         struct sigaction a, oa;
897 
898         a.sa_handler = catch_interrupt;
899         sigemptyset(&a.sa_mask);
900         sigaddset(&a.sa_mask, SIGINT);
901         a.sa_flags = SA_INTERRUPT;
902         sigaction(SIGINT, &a, &oa);
903         if (oa.sa_handler != SIG_DFL)
904             sigaction(SIGINT, &oa, (struct sigaction *) 0);
905 #else                           /* no SA_INTERRUPT */
906 #  ifdef WIN32
907         SetConsoleCtrlHandler(catch_interrupt, TRUE);
908 #  else                         /* not WIN32 */
909         RETSIGTYPE(*old_handler) (int);
910 
911         old_handler = signal(SIGINT, catch_interrupt);
912         if (old_handler != SIG_DFL)
913             signal(SIGINT, old_handler);
914 #  endif                        /* not WIN32 */
915 #endif                          /* no SA_INTERRUPT */
916     }
917 }
918 
919 /*
920  Getting a high resolution time.
921  */
922 void get_seconds_and_micros(int *seconds, int *micros)
923 {
924 #if defined (HAVE_GETTIMEOFDAY)
925     struct timeval tv;
926     gettimeofday(&tv, NULL);
927     *seconds = (int)tv.tv_sec;
928     *micros = (int)tv.tv_usec;
929 #elif defined (HAVE_FTIME)
930     struct timeb tb;
931     ftime(&tb);
932     *seconds = tb.time;
933     *micros = tb.millitm * 1000;
934 #else
935     time_t myclock = time((time_t *) NULL);
936     *seconds = (int) myclock;
937     *micros = 0;
938 #endif
939 }
940 
941 /*
942   Generating a better seed numbers
943   */
944 int getrandomseed(void)
945 {
946 #if defined (HAVE_GETTIMEOFDAY)
947     struct timeval tv;
948     gettimeofday(&tv, NULL);
949     return (int)(tv.tv_usec + 1000000 * tv.tv_usec);
950 #elif defined (HAVE_FTIME)
951     struct timeb tb;
952     ftime(&tb);
953     return (tb.millitm + 1000 * tb.time);
954 #else
955     time_t myclock = time((time_t *) NULL);
956     struct tm *tmptr = localtime(&myclock);
957     return (tmptr->tm_sec + 60 * (tmptr->tm_min + 60 * tmptr->tm_hour));
958 #endif
959 }
960 
961 /* Read a line of input as efficiently as possible while still looking
962    like Pascal.  We set `last' to `first' and return `false' if we get
963    to eof.  Otherwise, we return `true' and set last = first +
964    length(line except trailing whitespace).  */
965 
966 boolean input_line(FILE * f)
967 {
968     int i = EOF;
969 
970 #ifdef WIN32
971     if (f != Poptr && fileno (f) != fileno (stdin)) {
972         long position = ftell (f);
973 
974         if (position == 0L) {  /* Detect and skip Byte order marks.  */
975             int k1 = getc (f);
976 
977             if (k1 != 0xff && k1 != 0xfe && k1 != 0xef)
978                 rewind (f);
979             else {
980                 int k2 = getc (f);
981 
982                 if (k2 != 0xff && k2 != 0xfe && k2 != 0xbb)
983                     rewind (f);
984                 else if ((k1 == 0xff && k2 == 0xfe) || /* UTF-16(LE) */
985                          (k1 == 0xfe && k2 == 0xff))   /* UTF-16(BE) */
986                     ;
987                 else {
988                     int k3 = getc (f);
989 
990                     if (k1 == 0xef && k2 == 0xbb && k3 == 0xbf) /* UTF-8 */
991                         ;
992                     else
993                         rewind (f);
994                 }
995             }
996         }
997     }
998 #endif
999     /* Recognize either LF or CR as a line terminator.  */
1000     last = first;
1001     while (last < buf_size && (i = getc(f)) != EOF && i != '\n' && i != '\r')
1002         buffer[last++] = (packed_ASCII_code) i;
1003 
1004     if (i == EOF && errno != EINTR && last == first)
1005         return false;
1006 
1007     /* We didn't get the whole line because our buffer was too small.  */
1008     if (i != EOF && i != '\n' && i != '\r') {
1009         fprintf(stderr, "! Unable to read an entire line---bufsize=%u.\n",
1010                 (unsigned) buf_size);
1011         fputs("Please increase buf_size in texmf.cnf.\n", stderr);
1012         uexit(1);
1013     }
1014 
1015     buffer[last] = ' ';
1016     if (last >= max_buf_stack)
1017         max_buf_stack = last;
1018 
1019     /* If next char is LF of a CRLF, read it.  */
1020     if (i == '\r') {
1021         while ((i = getc(f)) == EOF && errno == EINTR);
1022         if (i != '\n')
1023             ungetc(i, f);
1024     }
1025 
1026     /* Trim trailing whitespace.  */
1027     while (last > first && ISBLANK(buffer[last - 1]))
1028         --last;
1029 
1030     /* Don't bother using xord if we don't need to.  */
1031 
1032     return true;
1033 }
1034 
1035 
1036 
1037 
1038 /* Get the job name to be used, which may have been set from the
1039    command line. */
1040 str_number getjobname(str_number name)
1041 {
1042     str_number ret = name;
1043     if (c_job_name != NULL)
1044         ret = maketexstring(c_job_name);
1045     return ret;
1046 }
1047