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