beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luatex.c
blobc00fe17792837b31d7f8fa0c2f6b0297163068d3
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.
6 This file is public domain. */
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. */
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
21 #include "ptexlib.h"
22 #include "luatex.h"
23 #include "lua/luatex-api.h"
25 #include "luatex_svnversion.h"
29 #define TeX
31 int luatex_version = 89; /* \.{\\luatexversion} */
32 int luatex_revision = '2'; /* \.{\\luatexrevision} */
33 int luatex_date_info = 2016022700; /* the compile date is now hardwired */
34 const char *luatex_version_string = "beta-0.89.2";
35 const char *engine_name = my_name; /* the name of this engine */
37 #include <kpathsea/c-ctype.h>
38 #include <kpathsea/line.h>
39 #include <kpathsea/readable.h>
40 #include <kpathsea/variable.h>
41 #include <kpathsea/absolute.h>
42 #ifdef WIN32
43 #include <kpathsea/concatn.h>
44 #endif
46 #ifdef _MSC_VER
47 #undef timezone
48 #endif
50 #include <time.h> /* For `struct tm'. */
51 #if defined (HAVE_SYS_TIME_H)
52 # include <sys/time.h>
53 #elif defined (HAVE_SYS_TIMEB_H)
54 # include <sys/timeb.h>
55 #endif
57 #if defined(__STDC__)
58 # include <locale.h>
59 #endif
61 #include <signal.h> /* Catch interrupts. */
64 /* {tex,mf}d.h defines TeX, MF, INI, and other such symbols.
65 Unfortunately there's no way to get the banner into this code, so
66 just repeat the text. */
67 #define edit_var "TEXEDIT"
69 /* Shell escape.
71 If shellenabledp == 0, all shell escapes are forbidden.
72 If (shellenabledp == 1 && restrictedshell == 0), any command
73 is allowed for a shell escape.
74 If (shellenabledp == 1 && restrictedshell == 1), only commands
75 given in the configuration file as
76 shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun,...
77 (no spaces between commands) in texmf.cnf are allowed for a shell
78 escape in a restricted form: command name and arguments should be
79 separated by a white space. The first word should be a command
80 name. The quotation character for an argument with spaces,
81 including a pathname, should be ". ' should not be used.
83 Internally, all arguments are quoted by ' (Unix) or " (Windows)
84 before calling the system() function in order to forbid execution
85 of any embedded command.
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.
109 #ifdef TeX
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. */
115 static char **cmdlist = NULL;
117 void mk_shellcmdlist(char *v)
119 char **p;
120 char *q, *r;
121 size_t n;
123 q = v;
124 n = 1;
126 /* analyze the variable shell_escape_commands = foo,bar,...
127 spaces before and after (,) are not allowed. */
129 while ((r = strchr(q, ',')) != 0) {
130 n++;
131 q = r + 1;
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;
143 if (*q)
144 *p++ = xstrdup (q);
145 *p = NULL;
148 /* Called from maininit. Not static because also called from
149 luatexdir/lua/luainit.c. */
151 void init_shell_escape(void)
153 if (shellenabledp < 0) { /* --no-shell-escape on cmd line */
154 shellenabledp = 0;
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;
166 free(v1);
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);
181 # ifdef WIN32
182 # define QUOTE '"'
183 # else
184 # define QUOTE '\''
185 # endif
187 # if 0
188 # ifdef WIN32
189 static int char_needs_quote(int c)
191 /* special characters of cmd.exe */
193 return (c == '&' || c == '|' || c == '%' || c == '<' ||
194 c == '>' || c == ';' || c == ',' || c == '(' || c == ')');
196 # endif
197 # endif
199 static int Isspace(char c)
201 return (c == ' ' || c == '\t');
204 /* return values:
205 -1 : invalid quotation of an argument
206 0 : command is not allowed
207 2 : restricted shell escape, CMD is allowed.
209 We set *SAFECMD to a safely-quoted version of *CMD; this is what
210 should get executed. And we set CMDNAME to its first word; this is
211 what is checked against the shell_escape_commands list. */
213 int shell_cmd_is_allowed(const char *cmd, char **safecmd, char **cmdname)
215 char **p;
216 char *buf;
217 char *c, *d;
218 const char *s;
219 int pre;
220 unsigned spaces;
221 int allow = 0;
223 /* pre == 1 means that the previous character is a white space
224 pre == 0 means that the previous character is not a white space */
225 buf = xmalloc(strlen(cmd) + 1);
226 strcpy(buf, cmd);
227 c = buf;
228 while (Isspace(*c))
229 c++;
230 d = c;
231 while (!Isspace(*d) && *d)
232 d++;
233 *d = '\0';
235 /* *cmdname is the first word of the command line. For example,
236 *cmdname == "kpsewhich" for
237 \write18{kpsewhich --progname=dvipdfm --format="other text files" config}
239 *cmdname = xstrdup(c);
240 free(buf);
242 /* Is *cmdname listed in a texmf.cnf vriable as
243 shell_escape_commands = foo,bar,... ? */
244 p = cmdlist;
245 if (p) {
246 while (*p) {
247 if (strcmp(*p, *cmdname) == 0) {
248 /* *cmdname is found in the list, so restricted shell escape
249 is allowed */
250 allow = 2;
251 break;
253 p++;
256 if (allow == 2) {
257 spaces = 0;
258 for (s = cmd; *s; s++) {
259 if (Isspace(*s))
260 spaces++;
263 /* allocate enough memory (too much?) */
264 # ifdef WIN32
265 *safecmd = xmalloc(2 * strlen(cmd) + 3 + 2 * spaces);
266 # else
267 *safecmd = xmalloc(strlen(cmd) + 3 + 2 * spaces);
268 # endif
270 /* make a safe command line *safecmd */
271 s = cmd;
272 while (Isspace(*s))
273 s++;
274 d = *safecmd;
275 while (!Isspace(*s) && *s)
276 *d++ = *s++;
278 pre = 1;
279 while (*s) {
280 /* Quotation given by a user. " should always be used; we
281 transform it below. On Unix, if ' is used, simply immediately
282 return a quotation error. */
283 if (*s == '\'') {
284 return -1;
287 if (*s == '"') {
288 /* All arguments are quoted as 'foo' (Unix) or "foo" (Windows)
289 before calling system(). Therefore closing QUOTE is necessary
290 if the previous character is not a white space.
291 example:
292 --format="other text files" becomes
293 '--format=''other text files' (Unix)
294 "--format"="other text files" (Windows) */
296 if (pre == 0) {
297 # ifdef WIN32
298 if (*(s-1) == '=') {
299 *(d-1) = QUOTE;
300 *d++ = '=';
301 } else {
302 *d++ = QUOTE;
304 # else
305 *d++ = QUOTE;
306 # endif
309 pre = 0;
310 /* output the quotation mark for the quoted argument */
311 *d++ = QUOTE;
312 s++;
314 while (*s != '"') {
315 /* Illegal use of ', or closing quotation mark is missing */
316 if (*s == '\'' || *s == '\0')
317 return -1;
318 # if 0
319 # ifdef WIN32
320 if (char_needs_quote(*s))
321 *d++ = '^';
322 # endif
323 # endif
324 *d++ = *s++;
327 /* Closing quotation mark will be output afterwards, so
328 we do nothing here */
329 s++;
331 /* The character after the closing quotation mark
332 should be a white space or NULL */
333 if (!Isspace(*s) && *s)
334 return -1;
336 /* Beginning of a usual argument */
337 } else if (pre == 1 && !Isspace(*s)) {
338 pre = 0;
339 *d++ = QUOTE;
340 # if 0
341 # ifdef WIN32
342 if (char_needs_quote(*s))
343 *d++ = '^';
344 # endif
345 # endif
346 *d++ = *s++;
347 /* Ending of a usual argument */
349 } else if (pre == 0 && Isspace(*s)) {
350 pre = 1;
351 /* Closing quotation mark */
352 *d++ = QUOTE;
353 *d++ = *s++;
354 } else {
355 /* Copy a character from cmd to *safecmd. */
356 # if 0
357 # ifdef WIN32
358 if (char_needs_quote(*s))
359 *d++ = '^';
360 # endif
361 # endif
362 *d++ = *s++;
365 /* End of the command line */
366 if (pre == 0) {
367 *d++ = QUOTE;
369 *d = '\0';
370 #ifdef WIN32
372 char *p, *q, *r;
373 p = *safecmd;
374 if (strlen (p) > 2 && p[1] == ':' && !IS_DIR_SEP (p[2])) {
375 q = xmalloc (strlen (p) + 2);
376 q[0] = p[0];
377 q[1] = p[1];
378 q[2] = '/';
379 q[3] = '\0';
380 strcat (q, (p + 2));
381 free (*safecmd);
382 *safecmd = q;
383 } else if (!IS_DIR_SEP (p[0]) && !(p[1] == ':' && IS_DIR_SEP (p[2]))) {
384 p = kpse_var_value ("SELFAUTOLOC");
385 if (p) {
386 r = *safecmd;
387 while (*r && !Isspace(*r))
388 r++;
389 if (*r == '\0')
390 q = concatn ("\"", p, "/", *safecmd, "\"", NULL);
391 else {
392 *r = '\0';
393 r++;
394 while (*r && Isspace(*r))
395 r++;
396 if (*r)
397 q = concatn ("\"", p, "/", *safecmd, "\" ", r, NULL);
398 else
399 q = concatn ("\"", p, "/", *safecmd, "\"", NULL);
401 free (p);
402 free (*safecmd);
403 *safecmd = q;
407 #endif
410 return allow;
413 #endif
416 /* What we were invoked as and with. */
417 char **argv;
418 int argc;
420 /* The C version of what might wind up in |TEX_format_default|. */
421 string dump_name;
423 /* The C version of the jobname, if given. */
424 const_string c_job_name;
426 const char *luatex_banner;
428 #ifdef _MSC_VER
429 /* Invalid parameter handler */
430 static void myInvalidParameterHandler(const wchar_t * expression,
431 const wchar_t * function,
432 const wchar_t * file,
433 unsigned int line,
434 uintptr_t pReserved)
437 printf(L"Invalid parameter detected in function %s."
438 L" File: %s Line: %d\n", function, file, line);
439 printf(L"Expression: %s\n", expression);
442 I return silently to avoid an exit with the error 0xc0000417
443 (invalid parameter) when we use non-embedded fonts in luatex-ja,
444 which works without any problem on Unix systems.
445 I hope it is not dangerous.
447 return;
449 #endif
451 /* The entry point: set up for reading the command line, which will
452 happen in `topenin', then call the main body. */
455 #if defined(DLLPROC)
456 DLLPROC (int ac, string *av)
457 #else
458 main (int ac, string *av)
459 #endif
461 # ifdef __EMX__
462 _wildcard(&ac, &av);
463 _response(&ac, &av);
464 # endif
466 # ifdef WIN32
467 # ifdef _MSC_VER
468 _set_invalid_parameter_handler(myInvalidParameterHandler);
469 # endif
470 av[0] = kpse_program_basename (av[0]);
471 _setmaxstdio(2048);
472 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
473 setmode(fileno(stdin), _O_BINARY);
474 # endif
476 lua_initialize(ac, av);
478 # ifdef WIN32
479 if (ac > 1) {
480 char *pp;
481 if ((strlen(av[ac-1]) > 2) &&
482 isalpha(av[ac-1][0]) &&
483 (av[ac-1][1] == ':') &&
484 (av[ac-1][2] == '\\')) {
485 for (pp=av[ac-1]+2; *pp; pp++) {
486 if (IS_KANJI(pp)) {
487 pp++;
488 continue;
490 if (*pp == '\\')
491 *pp = '/';
495 # endif
497 /* Call the real main program. */
498 main_body();
500 return EXIT_SUCCESS;
504 /* This is supposed to ``open the terminal for input'', but what we
505 really do is copy command line arguments into TeX's or Metafont's
506 buffer, so they can handle them. If nothing is available, or we've
507 been called already (and hence, argc==0), we return with
508 `last=first'. */
510 void topenin(void)
512 int i;
515 buffer[first] = 0; /* In case there are no arguments. */
517 if (optind < argc) { /* We have command line arguments. */
518 int k = first;
519 for (i = optind; i < argc; i++) {
520 char *ptr = &(argv[i][0]);
521 /* Don't use strcat, since in Aleph the buffer elements aren't
522 single bytes. */
523 while (*ptr) {
524 buffer[k++] = (packed_ASCII_code) * (ptr++);
526 buffer[k++] = ' ';
528 argc = 0; /* Don't do this again. */
529 buffer[k] = 0;
532 /* Find the end of the buffer. */
533 for (last = first; buffer[last]; ++last);
535 /* Make `last' be one past the last non-blank character in `buffer'. */
536 /* ??? The test for '\r' should not be necessary. */
537 for (--last; last >= first
538 && ISBLANK(buffer[last]) && buffer[last] != '\r'; --last);
539 last++;
541 /* One more time, this time converting to TeX's internal character
542 representation. */
545 /* IPC for TeX. By Tom Rokicki for the NeXT; it makes TeX ship out the
546 DVI file in a pipe to TeXView so that the output can be displayed
547 incrementally. Shamim Mohamed adapted it for Web2c. */
548 #if defined (TeX) && defined (IPC)
550 #ifdef WIN32
551 #undef _WINSOCKAPI_
552 #include <winsock2.h>
553 #else
554 #include <sys/socket.h>
555 #include <fcntl.h>
556 #ifndef O_NONBLOCK /* POSIX */
557 #ifdef O_NDELAY /* BSD */
558 #define O_NONBLOCK O_NDELAY
559 #elif defined(O_FNDELAY) /* NeXT */
560 #define O_NONBLOCK O_FNDELAY
561 #else
562 what the fcntl? cannot implement IPC without equivalent for O_NONBLOCK.
563 #endif
564 #endif /* no O_NONBLOCK */
565 #endif /* !WIN32 */
567 #ifdef WIN32
568 # define IPC_AF AF_INET
569 # ifndef IPC_LOCAL_HOST
570 # define IPC_LOCAL_HOST "127.0.0.1"
571 # define FIXED_PORT (unsigned short)4242
572 # endif
573 #else
574 # define IPC_AF AF_UNIX
575 # ifndef IPC_PIPE_NAME /* $HOME is prepended to this. */
576 # define IPC_PIPE_NAME "/.TeXview_Pipe"
577 # endif
578 #endif
579 #ifndef IPC_SERVER_CMD /* Command to run to start the server. */
580 # ifdef WIN32
581 # define IPC_SERVER_CMD "texview.exe"
582 # else
583 # define IPC_SERVER_CMD "open `which TeXview`"
584 # endif
585 #endif
587 struct msg
589 int namelength; /* length of auxiliary data */
590 int eof; /* new eof for dvi file */
591 #if 0 /* see usage of struct msg below */
592 char more_data[0]; /* where the rest of the stuff goes */
593 #endif
596 static struct sockaddr *ipc_addr;
597 static int ipc_addr_len;
599 static int
600 ipc_make_name (void)
602 if (ipc_addr_len == 0) {
603 #ifdef WIN32
604 unsigned long remote_addr = inet_addr(IPC_LOCAL_HOST);
605 if (remote_addr != INADDR_NONE) {
606 struct sockaddr_in *ipc_sin_addr = xmalloc (sizeof (struct sockaddr_in));
607 ipc_sin_addr->sin_family = AF_INET;
608 ipc_sin_addr->sin_addr.s_addr = remote_addr;
609 ipc_sin_addr->sin_port = htons (FIXED_PORT);
610 ipc_addr = ((struct sockaddr *) ipc_sin_addr);
611 ipc_addr_len = sizeof(struct sockaddr_in);
613 #else
614 string s = getenv ("HOME");
615 if (s) {
616 char *ipc_name;
617 ipc_addr = xmalloc (strlen (s) + 40);
618 ipc_addr->sa_family = 0;
619 ipc_name = ipc_addr->sa_data;
620 strcpy (ipc_name, s);
621 strcat (ipc_name, IPC_PIPE_NAME);
622 ipc_addr_len = strlen (ipc_name) + 3;
624 #endif
626 return ipc_addr_len;
629 static int sock = -1;
631 #ifdef WIN32
632 # define CLOSE_SOCKET(s) closesocket (s); WSACleanup ()
633 #else
634 # define CLOSE_SOCKET(s) close (s)
635 #endif
637 static int
638 ipc_is_open (void)
640 return sock != -1;
643 static void
644 ipc_open_out (void) {
645 #ifdef WIN32
646 struct WSAData wsaData;
647 int nCode;
648 unsigned long mode = 1;
649 #endif
650 #ifdef IPC_DEBUG
651 fputs ("tex: Opening socket for IPC output ...\n", stderr);
652 #endif
653 if (sock != -1) {
654 return;
657 #ifdef WIN32
658 if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
659 fprintf(stderr,"WSAStartup() returned error code %d.\n", nCode);
660 return;
662 #endif
664 if (ipc_make_name () <= 0)
665 return;
667 sock = socket (IPC_AF, SOCK_STREAM, 0);
668 #ifdef IPC_DEBUG
669 if(sock != -1)
670 fprintf(stderr, "tex: Socket handle is %d\n", sock);
671 else
672 fprintf(stderr, "tex: Socket is invalid.\n");
673 #endif
675 if (sock != -1) {
676 if (connect (sock, ipc_addr, ipc_addr_len) != 0 ||
677 #ifdef WIN32
678 ioctlsocket (sock, FIONBIO, &mode) < 0
679 #else
680 fcntl (sock, F_SETFL, O_NONBLOCK) < 0
681 #endif
683 CLOSE_SOCKET (sock);
684 sock = -1;
685 #ifdef IPC_DEBUG
686 fputs ("tex: IPC socket cannot be connected.\n", stderr);
687 fputs ("tex: Socket is closed.\n", stderr);
688 #endif
689 return;
691 #ifdef IPC_DEBUG
692 fputs ("tex: Successfully opened IPC socket.\n", stderr);
693 #endif
697 static void
698 ipc_close_out (void)
700 #ifdef IPC_DEBUG
701 fputs ("tex: Closing output socket ...\n", stderr);
702 #endif
703 if (ipc_is_open ()) {
704 CLOSE_SOCKET (sock);
705 sock = -1;
709 static void
710 ipc_snd (int n, int is_eof, char *data)
712 struct
714 struct msg msg;
715 char more_data[1024];
716 } ourmsg;
718 if (!ipc_is_open ()) {
719 return;
722 #ifdef IPC_DEBUG
723 fprintf(stderr, "%d\t%d\n", ourmsg.msg.namelength, ourmsg.msg.eof);
724 fputs ("tex: Sending message to socket ...\n", stderr);
725 #endif
726 ourmsg.msg.namelength = n;
727 ourmsg.msg.eof = is_eof;
728 if (n) {
729 strcpy (ourmsg.more_data, data);
731 n += sizeof (struct msg);
732 #ifdef IPC_DEBUG
733 fprintf(stderr, "%d\t%d\n", ourmsg.msg.namelength, ourmsg.msg.eof);
734 fputs ("tex: Writing to socket...\n", stderr);
735 #endif
736 #if defined(WIN32)
737 if (send (sock, (char *)&ourmsg, n, 0) != n) {
738 #else
739 if (write (sock, &ourmsg, n) != n) {
740 #endif
741 ipc_close_out ();
743 #ifdef IPC_DEBUG
744 fputs ("tex: IPC message sent.\n", stderr);
745 #endif
748 /* This routine notifies the server if there is an eof, or the filename
749 if a new DVI file is starting. This is the routine called by TeX.
750 Aleph defines str_start(#) as str_start_ar[# - too_big_char], with
751 too_big_char = biggest_char + 1 = 65536 (omstr.ch). */
753 void
754 ipcpage (int is_eof)
756 static boolean begun = false;
757 unsigned len = 0;
758 string p = NULL;
760 if (!begun) {
761 string name; /* Just the filename. */
762 string cwd = xgetcwd ();
764 ipc_open_out ();
766 /* Have to pass whole filename to the other end, since it may have
767 been started up and running as a daemon, e.g., as with the NeXT
768 preview program. */
769 name = static_pdf->file_name;
770 p = concat3 (cwd, DIR_SEP_STRING, name);
771 free (cwd);
772 free (name);
774 #if defined (WIN32)
775 { char *q;
776 for (q = p; *q; q++) {
777 if (*q == '\\')
778 *q = '/';
779 else if (IS_KANJI(q))
780 q++;
783 #endif
784 len = strlen(p);
785 begun = true;
787 ipc_snd (len, is_eof, p);
789 if (p)
790 free (p);
792 #endif /* TeX && IPC */
794 /* Normalize quoting of filename -- that is, only quote if there is a space,
795 and always use the quote-name-quote style. */
796 string normalize_quotes(const_string name, const_string mesg)
798 boolean quoted = false;
799 boolean must_quote = (strchr(name, ' ') != NULL);
800 /* Leave room for quotes and NUL. */
801 string ret = (string) xmalloc((unsigned) strlen(name) + 3);
802 string p;
803 const_string q;
804 p = ret;
805 if (must_quote)
806 *p++ = '"';
807 for (q = name; *q; q++) {
808 if (*q == '"')
809 quoted = !quoted;
810 else
811 *p++ = *q;
813 if (must_quote)
814 *p++ = '"';
815 *p = '\0';
816 if (quoted) {
817 fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
818 uexit(1);
820 return ret;
824 /* All our interrupt handler has to do is set TeX's or Metafont's global
825 variable `interrupt'; then they will do everything needed. */
826 #ifdef WIN32
827 /* Win32 doesn't set SIGINT ... */
828 static BOOL WINAPI catch_interrupt(DWORD arg)
830 switch (arg) {
831 case CTRL_C_EVENT:
832 case CTRL_BREAK_EVENT:
833 interrupt = 1;
834 return TRUE;
835 default:
836 /* No need to set interrupt as we are exiting anyway */
837 return FALSE;
840 #else /* not WIN32 */
841 static RETSIGTYPE catch_interrupt(int arg)
843 (void) arg;
844 interrupt = 1;
845 # ifdef OS2
846 (void) signal(SIGINT, SIG_ACK);
847 # else
848 (void) signal(SIGINT, catch_interrupt);
849 # endif /* not OS2 */
851 #endif /* not WIN32 */
853 /* Besides getting the date and time here, we also set up the interrupt
854 handler, for no particularly good reason. It's just that since the
855 `fix_date_and_time' routine is called early on (section 1337 in TeX,
856 ``Get the first line of input and prepare to start''), this is as
857 good a place as any. */
859 void get_date_and_time(int *minutes, int *day, int *month, int *year)
861 time_t myclock = time((time_t *) 0);
862 struct tm *tmptr = localtime(&myclock);
864 *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
865 *day = tmptr->tm_mday;
866 *month = tmptr->tm_mon + 1;
867 *year = tmptr->tm_year + 1900;
870 #ifdef SA_INTERRUPT
871 /* Under SunOS 4.1.x, the default action after return from the
872 signal handler is to restart the I/O if nothing has been
873 transferred. The effect on TeX is that interrupts are ignored if
874 we are waiting for input. The following tells the system to
875 return EINTR from read() in this case. From ken@cs.toronto.edu. */
877 struct sigaction a, oa;
879 a.sa_handler = catch_interrupt;
880 sigemptyset(&a.sa_mask);
881 sigaddset(&a.sa_mask, SIGINT);
882 a.sa_flags = SA_INTERRUPT;
883 sigaction(SIGINT, &a, &oa);
884 if (oa.sa_handler != SIG_DFL)
885 sigaction(SIGINT, &oa, (struct sigaction *) 0);
886 #else /* no SA_INTERRUPT */
887 # ifdef WIN32
888 SetConsoleCtrlHandler(catch_interrupt, TRUE);
889 # else /* not WIN32 */
890 RETSIGTYPE(*old_handler) (int);
892 old_handler = signal(SIGINT, catch_interrupt);
893 if (old_handler != SIG_DFL)
894 signal(SIGINT, old_handler);
895 # endif /* not WIN32 */
896 #endif /* no SA_INTERRUPT */
901 Getting a high resolution time.
903 void get_seconds_and_micros(int *seconds, int *micros)
905 #if defined (HAVE_GETTIMEOFDAY)
906 struct timeval tv;
907 gettimeofday(&tv, NULL);
908 *seconds = (int)tv.tv_sec;
909 *micros = (int)tv.tv_usec;
910 #elif defined (HAVE_FTIME)
911 struct timeb tb;
912 ftime(&tb);
913 *seconds = tb.time;
914 *micros = tb.millitm * 1000;
915 #else
916 time_t myclock = time((time_t *) NULL);
917 *seconds = (int) myclock;
918 *micros = 0;
919 #endif
923 Generating a better seed numbers
925 int getrandomseed(void)
927 #if defined (HAVE_GETTIMEOFDAY)
928 struct timeval tv;
929 gettimeofday(&tv, NULL);
930 return (int)(tv.tv_usec + 1000000 * tv.tv_usec);
931 #elif defined (HAVE_FTIME)
932 struct timeb tb;
933 ftime(&tb);
934 return (tb.millitm + 1000 * tb.time);
935 #else
936 time_t myclock = time((time_t *) NULL);
937 struct tm *tmptr = localtime(&myclock);
938 return (tmptr->tm_sec + 60 * (tmptr->tm_min + 60 * tmptr->tm_hour));
939 #endif
942 /* Read a line of input as efficiently as possible while still looking
943 like Pascal. We set `last' to `first' and return `false' if we get
944 to eof. Otherwise, we return `true' and set last = first +
945 length(line except trailing whitespace). */
947 boolean input_line(FILE * f)
949 int i = EOF;
951 #ifdef WIN32
952 if (f != Poptr && fileno (f) != fileno (stdin)) {
953 long position = ftell (f);
955 if (position == 0L) { /* Detect and skip Byte order marks. */
956 int k1 = getc (f);
958 if (k1 != 0xff && k1 != 0xfe && k1 != 0xef)
959 rewind (f);
960 else {
961 int k2 = getc (f);
963 if (k2 != 0xff && k2 != 0xfe && k2 != 0xbb)
964 rewind (f);
965 else if ((k1 == 0xff && k2 == 0xfe) || /* UTF-16(LE) */
966 (k1 == 0xfe && k2 == 0xff)) /* UTF-16(BE) */
968 else {
969 int k3 = getc (f);
971 if (k1 == 0xef && k2 == 0xbb && k3 == 0xbf) /* UTF-8 */
973 else
974 rewind (f);
979 #endif
980 /* Recognize either LF or CR as a line terminator. */
981 last = first;
982 while (last < buf_size && (i = getc(f)) != EOF && i != '\n' && i != '\r')
983 buffer[last++] = (packed_ASCII_code) i;
985 if (i == EOF && errno != EINTR && last == first)
986 return false;
988 /* We didn't get the whole line because our buffer was too small. */
989 if (i != EOF && i != '\n' && i != '\r') {
990 fprintf(stderr, "! Unable to read an entire line---bufsize=%u.\n",
991 (unsigned) buf_size);
992 fputs("Please increase buf_size in texmf.cnf.\n", stderr);
993 uexit(1);
996 buffer[last] = ' ';
997 if (last >= max_buf_stack)
998 max_buf_stack = last;
1000 /* If next char is LF of a CRLF, read it. */
1001 if (i == '\r') {
1002 while ((i = getc(f)) == EOF && errno == EINTR);
1003 if (i != '\n')
1004 ungetc(i, f);
1007 /* Trim trailing whitespace. */
1008 while (last > first && ISBLANK(buffer[last - 1]))
1009 --last;
1011 /* Don't bother using xord if we don't need to. */
1013 return true;
1019 /* Get the job name to be used, which may have been set from the
1020 command line. */
1021 str_number getjobname(str_number name)
1023 str_number ret = name;
1024 if (c_job_name != NULL)
1025 ret = maketexstring(c_job_name);
1026 return ret;