fix getsup (HH)
[luatex.git] / source / texk / web2c / lib / texmfmp.c
blob47086d9bc0a53fb6d91ea1ef6d3d9589e73f36a3
1 /* texmfmp.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 included from, e.g., texextra,c after
9 #define EXTERN
10 #include <texd.h>
11 to instantiate data from texd.h here. The ?d.h file is what
12 #defines TeX or MF, which avoids the need for a special
13 Makefile rule. */
15 #include <kpathsea/config.h>
16 #include <kpathsea/c-ctype.h>
17 #include <kpathsea/line.h>
18 #include <kpathsea/readable.h>
19 #include <kpathsea/variable.h>
20 #include <kpathsea/absolute.h>
21 #ifdef WIN32
22 #include <kpathsea/concatn.h>
23 #endif
25 #if defined (HAVE_SYS_TIME_H)
26 #include <sys/time.h>
27 #elif defined (HAVE_SYS_TIMEB_H)
28 #include <sys/timeb.h>
29 #endif
30 #include <time.h> /* For `struct tm'. Moved here for Visual Studio 2005. */
32 #if defined(__STDC__)
33 #include <locale.h>
34 #endif
36 #include <signal.h> /* Catch interrupts. */
38 #include <texmfmp-help.h>
40 /* {tex,mf}d.h defines TeX, MF, INI, and other such symbols.
41 Unfortunately there's no way to get the banner into this code, so
42 just repeat the text. */
43 /* We also define predicates, e.g., IS_eTeX for all e-TeX like engines, so
44 the rest of this file can remain unchanged when adding a new engine. */
45 #ifdef TeX
46 #if defined(XeTeX)
47 #define IS_eTeX 1
48 #include <xetexdir/xetexextra.h>
49 #elif defined (eTeX)
50 #define IS_eTeX 1
51 #include <etexdir/etexextra.h>
52 #elif defined (pdfTeX)
53 #define IS_eTeX 1
54 #include <pdftexdir/pdftexextra.h>
55 #include <pdftexdir/ptexlib.h>
56 #elif defined (Aleph)
57 #define IS_eTeX 1
58 #include <alephdir/alephextra.h>
59 #elif defined (pTeX)
60 #define IS_pTeX 1
61 #include <ptexdir/ptexextra.h>
62 #elif defined (epTeX)
63 #define IS_eTeX 1
64 #define IS_pTeX 1
65 #include <eptexdir/eptexextra.h>
66 #elif defined (upTeX)
67 #define IS_pTeX 1
68 #define IS_upTeX 1
69 #include <uptexdir/uptexextra.h>
70 #elif defined (eupTeX)
71 #define IS_eTeX 1
72 #define IS_pTeX 1
73 #define IS_upTeX 1
74 #include <euptexdir/euptexextra.h>
75 #else
76 #define BANNER "This is TeX, Version 3.14159265"
77 #define COPYRIGHT_HOLDER "D.E. Knuth"
78 #define AUTHOR NULL
79 #define PROGRAM_HELP TEXHELP
80 #define BUG_ADDRESS "tex-k@tug.org"
81 #define DUMP_VAR TEXformatdefault
82 #define DUMP_LENGTH_VAR formatdefaultlength
83 #define DUMP_OPTION "fmt"
84 #define DUMP_EXT ".fmt"
85 #define INPUT_FORMAT kpse_tex_format
86 #define INI_PROGRAM "initex"
87 #define VIR_PROGRAM "virtex"
88 #endif
89 #define edit_var "TEXEDIT"
90 #endif /* TeX */
91 #ifdef MF
92 #if defined(MFLua)
93 #include <mfluadir/mfluaextra.h>
94 #elif defined(MFLuaJIT)
95 #include <mfluajitdir/mfluajitextra.h>
96 #else
97 #define BANNER "This is Metafont, Version 2.7182818"
98 #define COPYRIGHT_HOLDER "D.E. Knuth"
99 #define AUTHOR NULL
100 #define PROGRAM_HELP MFHELP
101 #define BUG_ADDRESS "tex-k@tug.org"
102 #define DUMP_VAR MFbasedefault
103 #define DUMP_LENGTH_VAR basedefaultlength
104 #define DUMP_OPTION "base"
105 #ifdef DOS
106 #define DUMP_EXT ".bas"
107 #else
108 #define DUMP_EXT ".base"
109 #endif
110 #define INPUT_FORMAT kpse_mf_format
111 #define INI_PROGRAM "inimf"
112 #define VIR_PROGRAM "virmf"
113 #endif
114 #define edit_var "MFEDIT"
115 #endif /* MF */
117 #if !defined(IS_eTeX)
118 # define IS_eTeX 0
119 #endif
120 #if !defined(IS_pTeX)
121 # define IS_pTeX 0
122 #endif
123 #if !defined(IS_upTeX)
124 # define IS_upTeX 0
125 #endif
127 #if defined(__SyncTeX__)
129 SyncTeX file name should be full path in the case where
130 --output-directory option is given.
131 Borrowed from LuaTeX.
133 char *generic_synctex_get_current_name (void)
135 char *pwdbuf, *ret;
136 if (!fullnameoffile) {
137 ret = xstrdup("");
138 return ret;
140 if (kpse_absolute_p(fullnameoffile, false)) {
141 return xstrdup(fullnameoffile);
143 pwdbuf = xgetcwd();
144 ret = concat3(pwdbuf, DIR_SEP_STRING, fullnameoffile);
145 free(pwdbuf) ;
146 return ret;
148 #endif
150 #ifdef WIN32
151 #if !IS_pTeX
152 FILE *Poptr;
153 #endif
154 #endif
156 #if defined(TeX) || (defined(MF) && defined(WIN32))
157 static int
158 Isspace (char c)
160 return (c == ' ' || c == '\t');
162 #endif /* TeX || (MF && WIN32) */
164 #ifdef TeX
166 /* Shell escape.
168 If shellenabledp == 0, all shell escapes are forbidden.
169 If (shellenabledp == 1 && restrictedshell == 0), any command
170 is allowed for a shell escape.
171 If (shellenabledp == 1 && restrictedshell == 1), only commands
172 given in the configuration file as
173 shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun,...
174 (no spaces between commands) in texmf.cnf are allowed for a shell
175 escape in a restricted form: command name and arguments should be
176 separated by a white space. The first word should be a command
177 name. The quotation character for an argument with spaces,
178 including a pathname, should be ". ' should not be used.
180 Internally, all arguments are quoted by ' (Unix) or " (Windows)
181 before calling the system() function in order to forbid execution
182 of any embedded command.
184 If the --shell-escape option is given, we set
185 shellenabledp = 1 and restrictedshell = 0, i.e., any command is allowed.
186 If the --shell-restricted option is given, we set
187 shellenabledp = 1 and restrictedshell = 1, i.e., only given cmds allowed.
188 If the --no-shell-escape option is given, we set
189 shellenabledp = -1 (and restrictedshell is irrelevant).
190 If none of these option are given, there are three cases:
191 (1) In the case where
192 shell_escape = y or
193 shell_escape = t or
194 shell_escape = 1
195 it becomes shellenabledp = 1 and restrictedshell = 0,
196 that is, any command is allowed.
197 (2) In the case where
198 shell_escape = p
199 it becomes shellenabledp = 1 and restrictedshell = 1,
200 that is, restricted shell escape is allowed.
201 (3) In all other cases, shellenabledp = 0, that is, shell
202 escape is forbidden. The value of restrictedshell is
203 irrelevant if shellenabledp == 0.
206 /* cmdlist is a list of allowed commands which are given like this:
207 shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun
208 in texmf.cnf. */
210 static char **cmdlist = NULL;
212 static void
213 mk_shellcmdlist (char *v)
215 char **p;
216 char *q, *r;
217 size_t n;
219 q = v;
220 n = 1;
222 /* analyze the variable shell_escape_commands = foo,bar,...
223 spaces before and after (,) are not allowed. */
225 while ((r = strchr (q, ',')) != 0) {
226 n++;
227 q = r + 1;
229 if (*q)
230 n++;
231 cmdlist = xmalloc (n * sizeof (char *));
232 p = cmdlist;
233 q = v;
234 while ((r = strchr (q, ',')) != 0) {
235 *r = '\0';
236 *p++ = xstrdup (q);
237 q = r + 1;
239 if (*q)
240 *p++ = xstrdup (q);
241 *p = NULL;
244 static void
245 init_shell_escape (void)
247 if (shellenabledp < 0) { /* --no-shell-escape on cmd line */
248 shellenabledp = 0;
250 } else {
251 if (shellenabledp == 0) { /* no shell options on cmd line, check cnf */
252 char *v1 = kpse_var_value ("shell_escape");
253 if (v1) {
254 if (*v1 == 't' || *v1 == 'y' || *v1 == '1') {
255 shellenabledp = 1;
256 } else if (*v1 == 'p') {
257 shellenabledp = 1;
258 restrictedshell = 1;
260 free (v1);
264 /* If shell escapes are restricted, get allowed cmds from cnf. */
265 if (shellenabledp && restrictedshell == 1) {
266 char *v2 = kpse_var_value ("shell_escape_commands");
267 if (v2) {
268 mk_shellcmdlist (v2);
269 free (v2);
275 #ifdef WIN32
276 #define QUOTE '"'
277 #else
278 #define QUOTE '\''
279 #endif
281 #if 0
282 #ifdef WIN32
283 static int
284 char_needs_quote (int c)
286 /* special characters of cmd.exe */
288 return (c == '&' || c == '|' || c == '%' || c == '<' ||
289 c == '>' || c == ';' || c == ',' || c == '(' ||
290 c == ')');
292 #endif
293 #endif
295 /* return values:
296 -1 : invalid quotation of an argument
297 0 : command is not allowed
298 2 : restricted shell escape, CMD is allowed.
300 We set *SAFECMD to a safely-quoted version of *CMD; this is what
301 should get executed. And we set CMDNAME to its first word; this is
302 what is checked against the shell_escape_commands list. */
304 static int
305 shell_cmd_is_allowed (const char *cmd, char **safecmd, char **cmdname)
307 char **p;
308 char *buf;
309 char *c, *d;
310 const char *s;
311 int pre, spaces;
312 int allow = 0;
314 /* pre == 1 means that the previous character is a white space
315 pre == 0 means that the previous character is not a white space */
316 buf = xmalloc (strlen (cmd) + 1);
317 strcpy (buf, cmd);
318 c = buf;
319 while (Isspace (*c))
320 c++;
321 d = c;
322 while (!Isspace(*d) && *d)
323 d++;
324 *d = '\0';
326 /* *cmdname is the first word of the command line. For example,
327 *cmdname == "kpsewhich" for
328 \write18{kpsewhich --progname=dvipdfm --format="other text files" config}
330 *cmdname = xstrdup (c);
331 free (buf);
333 /* Is *cmdname listed in a texmf.cnf vriable as
334 shell_escape_commands = foo,bar,... ? */
335 p = cmdlist;
336 if (p) {
337 while (*p) {
338 if (strcmp (*p, *cmdname) == 0) {
339 /* *cmdname is found in the list, so restricted shell escape
340 is allowed */
341 allow = 2;
342 break;
344 p++;
347 if (allow == 2) {
348 spaces = 0;
349 for (s = cmd; *s; s++) {
350 if (Isspace (*s))
351 spaces++;
354 /* allocate enough memory (too much?) */
355 #ifdef WIN32
356 *safecmd = xmalloc (2 * strlen (cmd) + 3 + 2 * spaces);
357 #else
358 *safecmd = xmalloc (strlen (cmd) + 3 + 2 * spaces);
359 #endif
361 /* make a safe command line *safecmd */
362 s = cmd;
363 while (Isspace (*s))
364 s++;
365 d = *safecmd;
366 while (!Isspace (*s) && *s)
367 *d++ = *s++;
369 pre = 1;
370 while (*s) {
371 /* Quotation given by a user. " should always be used; we
372 transform it below. If ' is used, simply immediately
373 return a quotation error. */
374 if (*s == '\'') {
375 return -1;
378 if (*s == '"') {
379 /* All arguments are quoted as 'foo' (Unix) or "foo" (Windows)
380 before calling system(). Therefore closing QUOTE is necessary
381 if the previous character is not a white space.
382 example:
383 --format="other text files" becomes
384 '--format=''other text files' (Unix)
385 "--format"="other text files" (Windows) */
387 if (pre == 0) {
388 #ifdef WIN32
389 if (*(s-1) == '=') {
390 *(d-1) = QUOTE;
391 *d++ = '=';
392 } else {
393 *d++ = QUOTE;
395 #else
396 *d++ = QUOTE;
397 #endif
399 pre = 0;
400 /* output the quotation mark for the quoted argument */
401 *d++ = QUOTE;
402 s++;
404 while (*s != '"') {
405 /* Illegal use of ', or closing quotation mark is missing */
406 if (*s == '\'' || *s == '\0')
407 return -1;
408 #if 0
410 The following in WIN32 may not be necessary, because
411 all arguments are quoted.
413 #ifdef WIN32
414 if (char_needs_quote (*s))
415 *d++ = '^';
416 #endif
417 #endif
418 *d++ = *s++;
421 /* Closing quotation mark will be output afterwards, so
422 we do nothing here */
423 s++;
425 /* The character after the closing quotation mark
426 should be a white space or NULL */
427 if (!Isspace (*s) && *s)
428 return -1;
430 /* Beginning of a usual argument */
431 } else if (pre == 1 && !Isspace (*s)) {
432 pre = 0;
433 *d++ = QUOTE;
434 #if 0
436 The following in WIN32 may not be necessary, because
437 all arguments are quoted.
439 #ifdef WIN32
440 if (char_needs_quote (*s))
441 *d++ = '^';
442 #endif
443 #endif
444 *d++ = *s++;
445 /* Ending of a usual argument */
447 } else if (pre == 0 && Isspace (*s)) {
448 pre = 1;
449 /* Closing quotation mark */
450 *d++ = QUOTE;
451 *d++ = *s++;
452 } else {
453 /* Copy a character from cmd to *safecmd. */
454 #if 0
456 The following in WIN32 may not be necessary, because
457 all arguments are quoted.
459 #ifdef WIN32
460 if (char_needs_quote (*s))
461 *d++ = '^';
462 #endif
463 #endif
464 *d++ = *s++;
467 /* End of the command line */
468 if (pre == 0) {
469 *d++ = QUOTE;
471 *d = '\0';
472 #ifdef WIN32
474 char *p, *q, *r;
475 p = *safecmd;
476 if (strlen (p) > 2 && p[1] == ':' && !IS_DIR_SEP (p[2])) {
477 q = xmalloc (strlen (p) + 2);
478 q[0] = p[0];
479 q[1] = p[1];
480 q[2] = '/';
481 q[3] = '\0';
482 strcat (q, (p + 2));
483 free (*safecmd);
484 *safecmd = q;
485 } else if (!IS_DIR_SEP (p[0]) && !(p[1] == ':' && IS_DIR_SEP (p[2]))) {
486 p = kpse_var_value ("SELFAUTOLOC");
487 if (p) {
488 r = *safecmd;
489 while (*r && !Isspace(*r))
490 r++;
491 if (*r == '\0')
492 q = concatn ("\"", p, "/", *safecmd, "\"", NULL);
493 else {
494 *r = '\0';
495 r++;
496 while (*r && Isspace(*r))
497 r++;
498 if (*r)
499 q = concatn ("\"", p, "/", *safecmd, "\" ", r, NULL);
500 else
501 q = concatn ("\"", p, "/", *safecmd, "\"", NULL);
503 free (p);
504 free (*safecmd);
505 *safecmd = q;
509 #endif
512 return allow;
515 /* We should only be called with shellenabledp == 1.
516 Return value:
517 -1 if a quotation syntax error.
518 0 if CMD is not allowed; given shellenabledp==1, this is because
519 shell escapes are restricted and CMD is not allowed.
520 1 if shell escapes are not restricted, hence any command is allowed.
521 2 if shell escapes are restricted and CMD is allowed (possibly after
522 quoting). */
524 #ifdef WIN32
525 #undef system
526 #define system fsyscp_system
527 #if ENABLE_PIPES
528 #undef popen
529 #define popen fsyscp_popen
530 #endif /* ENABLE_PIPES */
531 #endif /* WIN32 */
534 runsystem (const char *cmd)
536 int allow = 0;
537 char *safecmd = NULL;
538 char *cmdname = NULL;
539 int status = 0;
541 if (shellenabledp <= 0) {
542 return 0;
545 /* If restrictedshell == 0, any command is allowed. */
546 if (restrictedshell == 0)
547 allow = 1;
548 else
549 allow = shell_cmd_is_allowed (cmd, &safecmd, &cmdname);
551 if (allow == 1)
552 status = system (cmd);
553 else if (allow == 2)
554 status = system (safecmd);
556 /* Not really meaningful, but we have to manage the return value of system. */
557 if (status != 0)
558 fprintf(stderr,"system returned with code %d\n", status);
560 if (safecmd)
561 free (safecmd);
562 if (cmdname)
563 free (cmdname);
565 return allow;
567 #endif /* TeX */
569 #if ENABLE_PIPES
570 /* Like runsystem(), the runpopen() function is called only when
571 shellenabledp == 1. Unlike runsystem(), here we write errors to
572 stderr, since we have nowhere better to use; and of course we return
573 a file handle (or NULL) instead of a status indicator. */
575 static FILE *
576 runpopen (char *cmd, const char *mode)
578 FILE *f = NULL;
579 char *safecmd = NULL;
580 char *cmdname = NULL;
581 int allow;
583 #ifdef WIN32
584 char *pp;
586 for (pp = cmd; *pp; pp++) {
587 if (*pp == '\'') *pp = '"';
589 #endif
591 /* If restrictedshell == 0, any command is allowed. */
592 if (restrictedshell == 0)
593 allow = 1;
594 else
595 allow = shell_cmd_is_allowed (cmd, &safecmd, &cmdname);
597 if (allow == 1)
598 f = popen (cmd, mode);
599 else if (allow == 2)
600 f = popen (safecmd, mode);
601 else if (allow == -1)
602 fprintf (stderr, "\nrunpopen quotation error in command line: %s\n",
603 cmd);
604 else
605 fprintf (stderr, "\nrunpopen command not allowed: %s\n", cmdname);
607 if (safecmd)
608 free (safecmd);
609 if (cmdname)
610 free (cmdname);
611 return f;
613 #endif /* ENABLE_PIPES */
615 /* The main program, etc. */
617 #ifdef XeTeX
618 #include "xetexdir/XeTeX_ext.h"
619 #endif
621 /* What we were invoked as and with. */
622 char **argv;
623 int argc;
625 /* If the user overrides argv[0] with -progname. */
626 static const_string user_progname;
628 /* The C version of the jobname, if given. */
629 static const_string c_job_name;
631 /* The filename for dynamic character translation, or NULL. */
632 string translate_filename;
633 string default_translate_filename;
635 #if defined(TeX)
636 /* Needed for --src-specials option. */
637 static char *last_source_name;
638 static int last_lineno;
639 static boolean srcspecialsoption = false;
640 static void parse_src_specials_option (const_string);
641 #endif
643 /* Parsing a first %&-line in the input file. */
644 static void parse_first_line (const_string);
646 /* Parse option flags. */
647 static void parse_options (int, string *);
649 /* Try to figure out if we have been given a filename. */
650 static string get_input_file_name (void);
652 /* Get a true/false value for a variable from texmf.cnf and the environment. */
653 static boolean
654 texmf_yesno(const_string var)
656 string value = kpse_var_value (var);
657 return value && (*value == 't' || *value == 'y' || *value == '1');
660 #ifdef pdfTeX
661 const char *ptexbanner = BANNER;
662 #endif
664 #ifdef WIN32
665 /* forward declaration */
666 static string
667 normalize_quotes (const_string name, const_string mesg);
668 #ifndef TeX
669 int srcspecialsp = 0;
670 #endif
671 /* Support of 8.3-name convention. If *buffer == NULL, nothing is done. */
672 static void change_to_long_name (char **buffer)
674 if (*buffer) {
675 char inbuf[260];
676 char outbuf[260];
678 memset (outbuf, 0, 260);
679 strcpy (inbuf, *buffer);
680 if (GetLongPathName (inbuf, outbuf, 260)) {
681 *buffer = (char *)realloc(*buffer, strlen(outbuf) + 1);
682 strcpy (*buffer, outbuf);
686 #endif /* WIN32 */
688 /* The entry point: set up for reading the command line, which will
689 happen in `topenin', then call the main body. */
691 void
692 maininit (int ac, string *av)
694 string main_input_file;
695 #if (IS_upTeX || defined(XeTeX)) && defined(WIN32)
696 string enc;
697 #endif
698 /* Save to pass along to topenin. */
699 argc = ac;
700 argv = av;
702 /* Must be initialized before options are parsed. */
703 interactionoption = 4;
705 /* Have things to record as we go along. */
706 kpse_record_input = recorder_record_input;
707 kpse_record_output = recorder_record_output;
709 #if defined(__SyncTeX__)
710 /* 0 means "disable Synchronize TeXnology".
711 synctexoption is a *.web variable.
712 We initialize it to a weird value to catch the -synctex command line flag.
713 At runtime, if synctexoption is not INT_MAX, then it contains the
714 command line option provided; otherwise, no such option was given
715 by the user. */
716 # define SYNCTEX_NO_OPTION INT_MAX
717 synctexoption = SYNCTEX_NO_OPTION;
718 #endif
720 #if IS_pTeX
721 kpse_set_program_name (argv[0], NULL);
722 initkanji ();
723 #endif
724 #if defined(XeTeX) && defined(WIN32)
725 kpse_set_program_name (argv[0], NULL);
726 #endif
727 #if (IS_upTeX || defined(XeTeX)) && defined(WIN32)
728 enc = kpse_var_value("command_line_encoding");
729 get_command_line_args_utf8(enc, &argc, &argv);
730 #endif
732 /* If the user says --help or --version, we need to notice early. And
733 since we want the --ini option, have to do it before getting into
734 the web (which would read the base file, etc.). */
735 #if (IS_upTeX || defined(XeTeX)) && defined(WIN32)
736 parse_options (argc, argv);
737 #else
738 parse_options (ac, av);
739 #endif
741 #if IS_pTeX
742 /* In pTeX and friends, texmf.cnf is not recorded in the case of --recorder,
743 because parse_options() is executed after the start of kpathsea due to
744 special initializations. Therefore we record texmf.cnf here. */
745 if (recorder_enabled) {
746 string p = kpse_find_file ("texmf.cnf", kpse_cnf_format, 0);
747 if (p)
748 recorder_record_input (p);
750 #endif
752 /* If -progname was not specified, default to the dump name. */
753 if (!user_progname)
754 user_progname = dump_name;
756 /* Do this early so we can inspect kpse_invocation_name and
757 kpse_program_name below, and because we have to do this before
758 any path searching. */
759 #if IS_pTeX || (defined(XeTeX) && defined(WIN32))
760 if (user_progname)
761 kpse_reset_program_name (user_progname);
762 #else
763 kpse_set_program_name (argv[0], user_progname);
764 #endif
766 #if defined(MF)
767 #if defined(MFLua)
768 /* If the program name is "mflua-nowin", then reset the name as "mflua". */
769 if (strncasecmp (kpse_invocation_name, "mflua-nowin", 11) == 0)
770 kpse_reset_program_name ("mflua");
771 #elif defined(MFLuaJIT)
772 /* If the program name is "mfluajit-nowin", then reset the name as "mfluajit". */
773 if (strncasecmp (kpse_invocation_name, "mfluajit-nowin", 14) == 0)
774 kpse_reset_program_name ("mfluajit");
775 #else
776 /* If the program name is "mf-nowin", then reset the name as "mf". */
777 if (strncasecmp (kpse_invocation_name, "mf-nowin", 8) == 0)
778 kpse_reset_program_name ("mf");
779 #endif
780 #endif
782 /* FIXME: gather engine names in a single spot. */
783 xputenv ("engine", TEXMFENGINENAME);
785 /* Were we given a simple filename? */
786 main_input_file = get_input_file_name();
788 #ifdef WIN32
789 if (main_input_file == NULL) {
790 string name;
791 #ifndef XeTeX
792 boolean quoted;
793 #endif
795 name = argv[argc-1];
796 if (name && name[0] != '-' && name[0] != '&' && name[0] != '\\') {
797 if (strlen (name) > 2 && isalpha (name[0]) && name[1] == ':' &&
798 name[2] == '\\') {
799 string pp;
800 for (pp = name; *pp; pp++) {
801 if (IS_KANJI (pp))
802 pp++;
803 else if (*pp == '\\')
804 *pp = '/';
807 #ifdef XeTeX
808 name = normalize_quotes(argv[argc-1], "argument");
809 main_input_file = kpse_find_file(argv[argc-1], INPUT_FORMAT, false);
810 if (!srcspecialsp) {
811 change_to_long_name (&main_input_file);
812 if (main_input_file)
813 name = normalize_quotes(main_input_file, "argument");
815 argv[argc-1] = name;
816 #else
817 name = normalize_quotes(argv[argc-1], "argument");
818 quoted = (name[0] == '"');
819 if (quoted) {
820 /* Overwrite last quote and skip first quote. */
821 name[strlen(name)-1] = '\0';
822 name++;
824 main_input_file = kpse_find_file(name, INPUT_FORMAT, false);
825 if (!srcspecialsp)
826 change_to_long_name (&main_input_file);
827 if (quoted) {
828 /* Undo modifications */
829 name[strlen(name)] = '"';
830 name--;
832 if (!srcspecialsp) {
833 if (main_input_file)
834 name = normalize_quotes(main_input_file, "argument");
836 argv[argc-1] = name;
837 #endif
840 #endif /* WIN32 */
842 /* Second chance to activate file:line:error style messages, this
843 time from texmf.cnf. */
844 if (filelineerrorstylep < 0) {
845 filelineerrorstylep = 0;
846 } else if (!filelineerrorstylep) {
847 filelineerrorstylep = texmf_yesno ("file_line_error_style");
850 /* If no dump default yet, and we're not doing anything special on
851 this run, we may want to look at the first line of the main input
852 file for a %&<dumpname> specifier. */
853 if (parsefirstlinep < 0) {
854 parsefirstlinep = 0;
855 } else if (!parsefirstlinep) {
856 parsefirstlinep = texmf_yesno ("parse_first_line");
858 if (parsefirstlinep && (!dump_name || !translate_filename)) {
859 parse_first_line (main_input_file);
861 /* Check whether there still is no translate_filename known. If so,
862 use the default_translate_filename. */
863 /* FIXME: deprecated. */
864 if (!translate_filename) {
865 translate_filename = default_translate_filename;
867 /* If we're preloaded, I guess everything is set up. I don't really
868 know any more, it's been so long since anyone preloaded. */
869 if (readyalready != 314159) {
870 /* The `ini_version' variable is declared/used in the change files. */
871 boolean virversion = false;
872 if (FILESTRCASEEQ (kpse_program_name, INI_PROGRAM)) {
873 iniversion = true;
874 } else if (FILESTRCASEEQ (kpse_program_name, VIR_PROGRAM)) {
875 virversion = true;
876 #ifdef TeX
877 } else if (FILESTRCASEEQ (kpse_program_name, "initex")) {
878 iniversion = true;
879 } else if (FILESTRCASEEQ (kpse_program_name, "virtex")) {
880 virversion = true;
881 #ifndef Aleph
882 } else if (FILESTRCASEEQ (kpse_program_name, "mltex")) {
883 mltexp = true;
884 #endif /* !Aleph */
885 #endif /* TeX */
888 if (!dump_name) {
889 /* If called as *vir{mf,tex,mpost} use `plain'. Otherwise, use the
890 name we were invoked under. */
891 dump_name = (virversion ? "plain" : kpse_program_name);
895 #ifdef TeX
896 /* Sanity check: -mltex, -enc, -etex only work in combination with -ini. */
897 if (!iniversion) {
898 #if !defined(Aleph)
899 if (mltexp) {
900 fprintf(stderr, "-mltex only works with -ini\n");
902 #if !defined(XeTeX) && !IS_pTeX
903 if (enctexp) {
904 fprintf(stderr, "-enc only works with -ini\n");
906 #endif
907 #endif
908 #if IS_eTeX
909 if (etexp) {
910 fprintf(stderr, "-etex only works with -ini\n");
912 #endif
914 #endif
916 /* If we've set up the fmt/base default in any of the various ways
917 above, also set its length. */
918 if (dump_name) {
919 const_string with_ext = NULL;
920 unsigned name_len = strlen (dump_name);
921 unsigned ext_len = strlen (DUMP_EXT);
923 /* Provide extension if not there already. */
924 if (name_len > ext_len
925 && FILESTRCASEEQ (dump_name + name_len - ext_len, DUMP_EXT)) {
926 with_ext = dump_name;
927 } else {
928 with_ext = concat (dump_name, DUMP_EXT);
930 DUMP_VAR = concat (" ", with_ext); /* adjust array for Pascal */
931 DUMP_LENGTH_VAR = strlen (DUMP_VAR + 1);
932 } else {
933 /* For dump_name to be NULL is a bug. */
934 abort();
937 /* Additional initializations. No particular reason for doing them
938 here instead of first thing in the change file; less symbols to
939 propagate through Webc, that's all. */
940 #ifdef MF
941 kpse_set_program_enabled (kpse_mf_format, MAKE_TEX_MF_BY_DEFAULT,
942 kpse_src_compile);
943 kpse_set_program_enabled (kpse_base_format, MAKE_TEX_FMT_BY_DEFAULT,
944 kpse_src_compile);
945 #endif /* MF */
946 #ifdef TeX
947 #if defined (Aleph)
948 kpse_set_program_enabled (kpse_ocp_format, MAKE_OMEGA_OCP_BY_DEFAULT,
949 kpse_src_compile);
950 kpse_set_program_enabled (kpse_ofm_format, MAKE_OMEGA_OFM_BY_DEFAULT,
951 kpse_src_compile);
952 kpse_set_program_enabled (kpse_tfm_format, false, kpse_src_compile);
953 #else /* !Aleph */
954 kpse_set_program_enabled (kpse_tfm_format, MAKE_TEX_TFM_BY_DEFAULT,
955 kpse_src_compile);
956 #endif /* !Aleph */
957 kpse_set_program_enabled (kpse_tex_format, MAKE_TEX_TEX_BY_DEFAULT,
958 kpse_src_compile);
959 kpse_set_program_enabled (kpse_fmt_format, MAKE_TEX_FMT_BY_DEFAULT,
960 kpse_src_compile);
962 init_shell_escape ();
964 if (!outputcomment) {
965 outputcomment = kpse_var_value ("output_comment");
967 #endif /* TeX */
970 /* The entry point: set up for reading the command line, which will
971 happen in `topenin', then call the main body. */
974 #if defined(DLLPROC)
975 DLLPROC (int ac, string *av)
976 #else
977 main (int ac, string *av)
978 #endif
980 #ifdef __EMX__
981 _wildcard (&ac, &av);
982 _response (&ac, &av);
983 #endif
985 #ifdef WIN32
986 av[0] = kpse_program_basename (av[0]);
987 _setmaxstdio(2048);
988 setmode(fileno(stdin), _O_BINARY);
989 #endif
991 maininit (ac, av);
993 #ifdef WIN32
994 if (ac > 1) {
995 char *pp;
996 if ((strlen(av[ac-1]) > 2) &&
997 isalpha(av[ac-1][0]) &&
998 (av[ac-1][1] == ':') &&
999 (av[ac-1][2] == '\\')) {
1000 for (pp=av[ac-1]+2; *pp; pp++) {
1001 if (IS_KANJI(pp)) {
1002 pp++;
1003 continue;
1005 if (*pp == '\\')
1006 *pp = '/';
1010 #endif
1012 /* Call the real main program. */
1013 mainbody ();
1015 return EXIT_SUCCESS;
1018 /* This is supposed to ``open the terminal for input'', but what we
1019 really do is copy command line arguments into TeX's or Metafont's
1020 buffer, so they can handle them. If nothing is available, or we've
1021 been called already (and hence, argc==0), we return with
1022 `last=first'. */
1024 void
1025 topenin (void)
1027 int i;
1029 #ifdef XeTeX
1030 static UFILE termin_file;
1031 if (termin == 0) {
1032 termin = &termin_file;
1033 termin->f = stdin;
1034 termin->savedChar = -1;
1035 termin->skipNextLF = 0;
1036 termin->encodingMode = UTF8;
1037 termin->conversionData = 0;
1038 inputfile[0] = termin;
1040 #endif
1042 buffer[first] = 0; /* In case there are no arguments. */
1044 if (optind < argc) { /* We have command line arguments. */
1045 int k = first;
1046 for (i = optind; i < argc; i++) {
1047 #ifdef XeTeX
1048 unsigned char *ptr = (unsigned char *)&(argv[i][0]);
1049 /* need to interpret UTF8 from the command line */
1050 UInt32 rval;
1051 while ((rval = *(ptr++)) != 0) {
1052 UInt16 extraBytes = bytesFromUTF8[rval];
1053 switch (extraBytes) { /* note: code falls through cases! */
1054 case 5: rval <<= 6; if (*ptr) rval += *(ptr++);
1055 case 4: rval <<= 6; if (*ptr) rval += *(ptr++);
1056 case 3: rval <<= 6; if (*ptr) rval += *(ptr++);
1057 case 2: rval <<= 6; if (*ptr) rval += *(ptr++);
1058 case 1: rval <<= 6; if (*ptr) rval += *(ptr++);
1059 case 0: ;
1061 rval -= offsetsFromUTF8[extraBytes];
1062 buffer[k++] = rval;
1064 #else
1065 char *ptr = &(argv[i][0]);
1066 /* Don't use strcat, since in Aleph the buffer elements aren't
1067 single bytes. */
1068 while (*ptr) {
1069 buffer[k++] = *(ptr++);
1071 #endif
1072 buffer[k++] = ' ';
1074 argc = 0; /* Don't do this again. */
1075 buffer[k] = 0;
1078 /* Find the end of the buffer. */
1079 for (last = first; buffer[last]; ++last)
1082 /* Make `last' be one past the last non-blank character in `buffer'. */
1083 /* ??? The test for '\r' should not be necessary. */
1084 for (--last; last >= first
1085 && ISBLANK (buffer[last]) && buffer[last] != '\r'; --last)
1087 last++;
1089 /* One more time, this time converting to TeX's internal character
1090 representation. */
1091 #if !defined(Aleph) && !defined(XeTeX)
1092 for (i = first; i < last; i++)
1093 buffer[i] = xord[buffer[i]];
1094 #endif
1097 /* IPC for TeX. By Tom Rokicki for the NeXT; it makes TeX ship out the
1098 DVI file in a pipe to TeXView so that the output can be displayed
1099 incrementally. Shamim Mohamed adapted it for Web2c. */
1100 #if defined (TeX) && defined (IPC)
1102 #ifdef WIN32
1103 #undef _WINSOCKAPI_
1104 #include <winsock2.h>
1105 #else
1106 #include <sys/socket.h>
1107 #include <fcntl.h>
1108 #ifndef O_NONBLOCK /* POSIX */
1109 #ifdef O_NDELAY /* BSD */
1110 #define O_NONBLOCK O_NDELAY
1111 #elif defined(O_FNDELAY) /* NeXT */
1112 #define O_NONBLOCK O_FNDELAY
1113 #else
1114 what the fcntl? cannot implement IPC without equivalent for O_NONBLOCK.
1115 #endif
1116 #endif /* no O_NONBLOCK */
1117 #endif /* !WIN32 */
1119 #ifdef WIN32
1120 # define IPC_AF AF_INET
1121 # ifndef IPC_LOCAL_HOST
1122 # define IPC_LOCAL_HOST "127.0.0.1"
1123 # define FIXED_PORT (unsigned short)4242
1124 # endif
1125 #else
1126 # define IPC_AF AF_UNIX
1127 # ifndef IPC_PIPE_NAME /* $HOME is prepended to this. */
1128 # define IPC_PIPE_NAME "/.TeXview_Pipe"
1129 # endif
1130 #endif
1131 #ifndef IPC_SERVER_CMD /* Command to run to start the server. */
1132 # ifdef WIN32
1133 # define IPC_SERVER_CMD "texview.exe"
1134 # else
1135 # define IPC_SERVER_CMD "open `which TeXview`"
1136 # endif
1137 #endif
1139 struct msg
1141 int namelength; /* length of auxiliary data */
1142 int eof; /* new eof for dvi file */
1143 #if 0 /* see usage of struct msg below */
1144 char more_data[0]; /* where the rest of the stuff goes */
1145 #endif
1148 static struct sockaddr *ipc_addr;
1149 static int ipc_addr_len;
1151 static int
1152 ipc_make_name (void)
1154 if (ipc_addr_len == 0) {
1155 #ifdef WIN32
1156 unsigned long remote_addr = inet_addr(IPC_LOCAL_HOST);
1157 if (remote_addr != INADDR_NONE) {
1158 struct sockaddr_in *ipc_sin_addr = xmalloc (sizeof (struct sockaddr_in));
1159 ipc_sin_addr->sin_family = AF_INET;
1160 ipc_sin_addr->sin_addr.s_addr = remote_addr;
1161 ipc_sin_addr->sin_port = htons (FIXED_PORT);
1162 ipc_addr = ((struct sockaddr *) ipc_sin_addr);
1163 ipc_addr_len = sizeof(struct sockaddr_in);
1165 #else
1166 string s = getenv ("HOME");
1167 if (s) {
1168 char *ipc_name;
1169 ipc_addr = xmalloc (strlen (s) + 40);
1170 ipc_addr->sa_family = 0;
1171 ipc_name = ipc_addr->sa_data;
1172 strcpy (ipc_name, s);
1173 strcat (ipc_name, IPC_PIPE_NAME);
1174 ipc_addr_len = strlen (ipc_name) + 3;
1176 #endif
1178 return ipc_addr_len;
1181 static int sock = -1;
1183 #ifdef WIN32
1184 # define CLOSE_SOCKET(s) closesocket (s); WSACleanup ()
1185 #else
1186 # define CLOSE_SOCKET(s) close (s)
1187 #endif
1189 static int
1190 ipc_is_open (void)
1192 return sock != -1;
1195 static void
1196 ipc_open_out (void) {
1197 #ifdef WIN32
1198 struct WSAData wsaData;
1199 int nCode;
1200 unsigned long mode = 1;
1201 #endif
1202 #ifdef IPC_DEBUG
1203 fputs ("tex: Opening socket for IPC output ...\n", stderr);
1204 #endif
1205 if (sock != -1) {
1206 return;
1209 #ifdef WIN32
1210 if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
1211 fprintf(stderr,"WSAStartup() returned error code %d.\n", nCode);
1212 return;
1214 #endif
1216 if (ipc_make_name () <= 0)
1217 return;
1219 sock = socket (IPC_AF, SOCK_STREAM, 0);
1220 #ifdef IPC_DEBUG
1221 if(sock != -1)
1222 fprintf(stderr, "tex: Socket handle is %d\n", sock);
1223 else
1224 fprintf(stderr, "tex: Socket is invalid.\n");
1225 #endif
1227 if (sock != -1) {
1228 if (connect (sock, ipc_addr, ipc_addr_len) != 0 ||
1229 #ifdef WIN32
1230 ioctlsocket (sock, FIONBIO, &mode) < 0
1231 #else
1232 fcntl (sock, F_SETFL, O_NONBLOCK) < 0
1233 #endif
1235 CLOSE_SOCKET (sock);
1236 sock = -1;
1237 #ifdef IPC_DEBUG
1238 fputs ("tex: IPC socket cannot be connected.\n", stderr);
1239 fputs ("tex: Socket is closed.\n", stderr);
1240 #endif
1241 return;
1243 #ifdef IPC_DEBUG
1244 fputs ("tex: Successfully opened IPC socket.\n", stderr);
1245 #endif
1249 static void
1250 ipc_close_out (void)
1252 #ifdef IPC_DEBUG
1253 fputs ("tex: Closing output socket ...\n", stderr);
1254 #endif
1255 if (ipc_is_open ()) {
1256 CLOSE_SOCKET (sock);
1257 sock = -1;
1261 static void
1262 ipc_snd (int n, int is_eof, char *data)
1264 struct
1266 struct msg msg;
1267 char more_data[1024];
1268 } ourmsg;
1270 if (!ipc_is_open ()) {
1271 return;
1274 #ifdef IPC_DEBUG
1275 fprintf(stderr, "%d\t%d\n", ourmsg.msg.namelength, ourmsg.msg.eof);
1276 fputs ("tex: Sending message to socket ...\n", stderr);
1277 #endif
1278 ourmsg.msg.namelength = n;
1279 ourmsg.msg.eof = is_eof;
1280 if (n) {
1281 strcpy (ourmsg.more_data, data);
1283 n += sizeof (struct msg);
1284 #ifdef IPC_DEBUG
1285 fprintf(stderr, "%d\t%d\n", ourmsg.msg.namelength, ourmsg.msg.eof);
1286 fputs ("tex: Writing to socket...\n", stderr);
1287 #endif
1288 #if defined(WIN32)
1289 if (send (sock, (char *)&ourmsg, n, 0) != n) {
1290 #else
1291 if (write (sock, &ourmsg, n) != n) {
1292 #endif
1293 ipc_close_out ();
1295 #ifdef IPC_DEBUG
1296 fputs ("tex: IPC message sent.\n", stderr);
1297 #endif
1300 /* This routine notifies the server if there is an eof, or the filename
1301 if a new DVI file is starting. This is the routine called by TeX.
1302 Aleph defines str_start(#) as str_start_ar[# - too_big_char], with
1303 too_big_char = biggest_char + 1 = 65536 (omstr.ch). */
1305 void
1306 ipcpage (int is_eof)
1308 static boolean begun = false;
1309 unsigned len = 0;
1310 string p = NULL;
1312 if (!begun) {
1313 string name; /* Just the filename. */
1314 string cwd = xgetcwd ();
1316 ipc_open_out ();
1317 #if !defined(Aleph)
1318 len = strstart[outputfilename + 1] - strstart[outputfilename];
1319 #else
1320 len = strstartar[outputfilename + 1 - 65536L] -
1321 strstartar[outputfilename - 65536L];
1322 #endif
1323 name = xmalloc (len + 1);
1324 #if !defined(Aleph)
1325 strncpy (name, (string)&strpool[strstart[outputfilename]], len);
1326 #else
1328 unsigned i;
1329 for (i=0; i<len; i++)
1330 name[i] = strpool[i+strstartar[outputfilename - 65536L]];
1332 #endif
1333 name[len] = 0;
1335 /* Have to pass whole filename to the other end, since it may have
1336 been started up and running as a daemon, e.g., as with the NeXT
1337 preview program. */
1338 p = concat3 (cwd, DIR_SEP_STRING, name);
1339 free (cwd);
1340 free (name);
1342 #if defined (WIN32)
1343 { char *q;
1344 for (q = p; *q; q++) {
1345 if (*q == '\\')
1346 *q = '/';
1347 else if (IS_KANJI(q))
1348 q++;
1351 #endif
1352 len = strlen(p);
1353 begun = true;
1355 ipc_snd (len, is_eof, p);
1357 if (p)
1358 free (p);
1360 #endif /* TeX && IPC */
1362 #if defined (TeX) || defined (MF)
1363 /* TCX and Aleph&Co get along like sparks and gunpowder. */
1364 #if !defined(Aleph) && !defined(XeTeX)
1366 /* Return the next number following START, setting POST to the following
1367 character, as in strtol. Issue a warning and return -1 if no number
1368 can be parsed. */
1370 static int
1371 tcx_get_num (int upb,
1372 unsigned line_count,
1373 string start,
1374 string *post)
1376 int num = strtol (start, post, 0);
1377 assert (post && *post);
1378 if (*post == start) {
1379 /* Could not get a number. If blank line, fine. Else complain. */
1380 string p = start;
1381 while (*p && ISSPACE (*p))
1382 p++;
1383 if (*p != 0)
1384 fprintf (stderr, "%s:%d: Expected numeric constant, not `%s'.\n",
1385 translate_filename, line_count, start);
1386 num = -1;
1387 } else if (num < 0 || num > upb) {
1388 fprintf (stderr, "%s:%d: Destination charcode %d <0 or >%d.\n",
1389 translate_filename, line_count, num, upb);
1390 num = -1;
1393 return num;
1396 /* Update the xchr, xord, and xprn arrays for TeX, allowing a
1397 translation table specified at runtime via an external file.
1398 Look for the character translation file FNAME along the same path as
1399 tex.pool. If no suffix in FNAME, use .tcx (don't bother trying to
1400 support extension-less names for these files). */
1402 /* FIXME: A new format ought to be introduced for these files. */
1404 void
1405 readtcxfile (void)
1407 string orig_filename;
1408 if (!find_suffix (translate_filename)) {
1409 translate_filename = concat (translate_filename, ".tcx");
1411 orig_filename = translate_filename;
1412 translate_filename
1413 = kpse_find_file (translate_filename, kpse_web2c_format, true);
1414 if (translate_filename) {
1415 string line;
1416 unsigned line_count = 0;
1417 FILE *translate_file = xfopen (translate_filename, FOPEN_R_MODE);
1418 while ((line = read_line (translate_file))) {
1419 int first;
1420 string start2;
1421 string comment_loc = strchr (line, '%');
1422 if (comment_loc)
1423 *comment_loc = 0;
1425 line_count++;
1427 first = tcx_get_num (255, line_count, line, &start2);
1428 if (first >= 0) {
1429 string start3;
1430 int second;
1431 int printable;
1433 second = tcx_get_num (255, line_count, start2, &start3);
1434 if (second >= 0) {
1435 /* I suppose we could check for nonempty junk following the
1436 "printable" code, but let's not bother. */
1437 string extra;
1439 /* If they mention a second code, make that the internal number. */
1440 xord[first] = second;
1441 xchr[second] = first;
1443 printable = tcx_get_num (1, line_count, start3, &extra);
1444 /* Not-a-number, may be a comment. */
1445 if (printable == -1)
1446 printable = 1;
1447 /* Don't allow the 7bit ASCII set to become unprintable. */
1448 if (32 <= second && second <= 126)
1449 printable = 1;
1450 } else {
1451 second = first; /* else make internal the same as external */
1452 /* If they mention a charcode, call it printable. */
1453 printable = 1;
1456 xprn[second] = printable;
1458 free (line);
1460 xfclose(translate_file, translate_filename);
1461 } else {
1462 WARNING1 ("Could not open char translation file `%s'", orig_filename);
1465 #endif /* !Aleph && !XeTeX */
1466 #endif /* TeX || MF [character translation] */
1468 #ifdef XeTeX /* XeTeX handles this differently, and allows odd quotes within names */
1469 static string
1470 normalize_quotes (const_string name, const_string mesg)
1472 int quote_char = 0;
1473 boolean must_quote = false;
1474 int len = strlen(name);
1475 /* Leave room for quotes and NUL. */
1476 string ret;
1477 string p;
1478 const_string q;
1479 for (q = name; *q; q++) {
1480 if (*q == ' ') {
1481 if (!must_quote) {
1482 len += 2;
1483 must_quote = true;
1486 else if (*q == '\"' || *q == '\'') {
1487 must_quote = true;
1488 if (quote_char == 0)
1489 quote_char = '\"' + '\'' - *q;
1490 len += 2; /* this could sometimes add length we don't need */
1493 ret = xmalloc(len + 1);
1494 p = ret;
1495 if (must_quote) {
1496 if (quote_char == 0)
1497 quote_char = '\"';
1498 *p++ = quote_char;
1500 for (q = name; *q; q++) {
1501 if (*q == quote_char) {
1502 *p++ = quote_char;
1503 quote_char = '\"' + '\'' - quote_char;
1504 *p++ = quote_char;
1506 *p++ = *q;
1508 if (quote_char != 0)
1509 *p++ = quote_char;
1510 *p = '\0';
1511 return ret;
1513 #else
1514 /* Normalize quoting of filename -- that is, only quote if there is a space,
1515 and always use the quote-name-quote style. */
1516 static string
1517 normalize_quotes (const_string name, const_string mesg)
1519 boolean quoted = false;
1520 boolean must_quote = (strchr(name, ' ') != NULL);
1521 /* Leave room for quotes and NUL. */
1522 string ret = xmalloc(strlen(name)+3);
1523 string p;
1524 const_string q;
1525 p = ret;
1526 if (must_quote)
1527 *p++ = '"';
1528 for (q = name; *q; q++) {
1529 if (*q == '"')
1530 quoted = !quoted;
1531 else
1532 *p++ = *q;
1534 if (must_quote)
1535 *p++ = '"';
1536 *p = '\0';
1537 if (quoted) {
1538 fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
1539 uexit(1);
1541 return ret;
1543 #endif
1545 /* Getting the input filename. */
1546 string
1547 get_input_file_name (void)
1549 string input_file_name = NULL;
1551 if (argv[optind] && argv[optind][0] != '&' && argv[optind][0] != '\\') {
1552 /* Not &format, not \input, so assume simple filename. */
1553 string name;
1554 #ifndef XeTeX
1555 boolean quoted;
1556 #endif
1558 #ifdef WIN32
1559 if (strlen (argv[optind]) > 2 && isalpha (argv[optind][0]) &&
1560 argv[optind][1] == ':' && argv[optind][2] == '\\') {
1561 char *pp;
1562 for (pp = argv[optind]; *pp; pp++) {
1563 if (*pp == '\\')
1564 *pp = '/';
1565 else if (IS_KANJI(pp))
1566 pp++;
1569 #endif
1571 name = normalize_quotes(argv[optind], "argument");
1572 #ifdef XeTeX
1573 input_file_name = kpse_find_file(argv[optind], INPUT_FORMAT, false);
1574 #ifdef WIN32
1575 if (!srcspecialsp)
1576 change_to_long_name (&input_file_name);
1577 #endif
1578 #else
1579 quoted = (name[0] == '"');
1580 if (quoted) {
1581 /* Overwrite last quote and skip first quote. */
1582 name[strlen(name)-1] = '\0';
1583 name++;
1585 input_file_name = kpse_find_file(name, INPUT_FORMAT, false);
1586 #ifdef WIN32
1587 if (!srcspecialsp)
1588 change_to_long_name (&input_file_name);
1589 #endif
1590 if (quoted) {
1591 /* Undo modifications */
1592 name[strlen(name)] = '"';
1593 name--;
1595 #endif
1596 #ifdef WIN32
1597 if (!srcspecialsp) {
1598 if (input_file_name)
1599 name = normalize_quotes (input_file_name, "argument");
1601 #endif
1602 argv[optind] = name;
1604 return input_file_name;
1607 /* Reading the options. */
1609 /* Test whether getopt found an option ``A''.
1610 Assumes the option index is in the variable `option_index', and the
1611 option table in a variable `long_options'. */
1612 #define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
1614 /* SunOS cc can't initialize automatic structs, so make this static. */
1615 static struct option long_options[]
1616 = { { DUMP_OPTION, 1, 0, 0 },
1617 #ifdef TeX
1618 /* FIXME: Obsolete -- for backward compatibility only. */
1619 { "efmt", 1, 0, 0 },
1620 #endif
1621 { "help", 0, 0, 0 },
1622 { "ini", 0, &iniversion, 1 },
1623 { "interaction", 1, 0, 0 },
1624 { "halt-on-error", 0, &haltonerrorp, 1 },
1625 { "kpathsea-debug", 1, 0, 0 },
1626 { "progname", 1, 0, 0 },
1627 { "version", 0, 0, 0 },
1628 { "recorder", 0, &recorder_enabled, 1 },
1629 #ifdef TeX
1630 #ifdef IPC
1631 { "ipc", 0, &ipcon, 1 },
1632 { "ipc-start", 0, &ipcon, 2 },
1633 #endif /* IPC */
1634 #if !defined(Aleph)
1635 { "mltex", 0, &mltexp, 1 },
1636 #if !defined(XeTeX) && !IS_pTeX
1637 { "enc", 0, &enctexp, 1 },
1638 #endif
1639 #endif /* !Aleph */
1640 #if IS_eTeX
1641 { "etex", 0, &etexp, 1 },
1642 #endif
1643 { "output-comment", 1, 0, 0 },
1644 #if defined(pdfTeX)
1645 { "draftmode", 0, 0, 0 },
1646 { "output-format", 1, 0, 0 },
1647 #endif /* pdfTeX */
1648 { "shell-escape", 0, &shellenabledp, 1 },
1649 { "no-shell-escape", 0, &shellenabledp, -1 },
1650 { "enable-write18", 0, &shellenabledp, 1 },
1651 { "disable-write18", 0, &shellenabledp, -1 },
1652 { "shell-restricted", 0, 0, 0 },
1653 { "debug-format", 0, &debugformatfile, 1 },
1654 { "src-specials", 2, 0, 0 },
1655 #if defined(__SyncTeX__)
1656 /* Synchronization: just like "interaction" above */
1657 { "synctex", 1, 0, 0 },
1658 #endif
1659 #endif /* TeX */
1660 #if defined (TeX) || defined (MF)
1661 { "file-line-error-style", 0, &filelineerrorstylep, 1 },
1662 { "no-file-line-error-style", 0, &filelineerrorstylep, -1 },
1663 /* Shorter option names for the above. */
1664 { "file-line-error", 0, &filelineerrorstylep, 1 },
1665 { "no-file-line-error", 0, &filelineerrorstylep, -1 },
1666 { "jobname", 1, 0, 0 },
1667 { "output-directory", 1, 0, 0 },
1668 { "parse-first-line", 0, &parsefirstlinep, 1 },
1669 { "no-parse-first-line", 0, &parsefirstlinep, -1 },
1670 #if !defined(Aleph)
1671 { "translate-file", 1, 0, 0 },
1672 { "default-translate-file", 1, 0, 0 },
1673 { "8bit", 0, &eightbitp, 1 },
1674 #endif /* !Aleph */
1675 #if defined(XeTeX)
1676 { "no-pdf", 0, &nopdfoutput, 1 },
1677 { "output-driver", 1, 0, 0 },
1678 { "papersize", 1, 0, 0 },
1679 #endif /* XeTeX */
1680 { "mktex", 1, 0, 0 },
1681 { "no-mktex", 1, 0, 0 },
1682 #endif /* TeX or MF */
1683 #if IS_pTeX
1684 #ifdef WIN32
1685 { "sjis-terminal", 0, &sjisterminal, 1 },
1686 { "guess-input-enc", 0, &infile_enc_auto, 1 },
1687 { "no-guess-input-enc", 0, &infile_enc_auto, 0 },
1688 #endif
1689 { "kanji", 1, 0, 0 },
1690 { "kanji-internal", 1, 0, 0 },
1691 #endif /* IS_pTeX */
1692 { 0, 0, 0, 0 } };
1694 static void
1695 parse_options (int argc, string *argv)
1697 int g; /* `getopt' return code. */
1698 int option_index;
1700 for (;;) {
1701 g = getopt_long_only (argc, argv, "+", long_options, &option_index);
1703 if (g == -1) /* End of arguments, exit the loop. */
1704 break;
1706 if (g == '?') { /* Unknown option. */
1707 /* FIXME: usage (argv[0]); replaced by continue. */
1708 continue;
1711 assert (g == 0); /* We have no short option names. */
1713 if (ARGUMENT_IS ("kpathsea-debug")) {
1714 kpathsea_debug |= atoi (optarg);
1716 #ifdef XeTeX
1717 } else if (ARGUMENT_IS ("papersize")) {
1718 papersize = optarg;
1719 } else if (ARGUMENT_IS ("output-driver")) {
1720 outputdriver = optarg;
1721 #endif
1723 } else if (ARGUMENT_IS ("progname")) {
1724 user_progname = optarg;
1726 } else if (ARGUMENT_IS ("jobname")) {
1727 #ifdef XeTeX
1728 c_job_name = optarg;
1729 #else
1730 c_job_name = normalize_quotes (optarg, "jobname");
1731 #endif
1733 } else if (ARGUMENT_IS (DUMP_OPTION)) {
1734 dump_name = optarg;
1735 dumpoption = true;
1737 #ifdef TeX
1738 /* FIXME: Obsolete -- for backward compatibility only. */
1739 } else if (ARGUMENT_IS ("efmt")) {
1740 dump_name = optarg;
1741 dumpoption = true;
1742 #endif
1744 } else if (ARGUMENT_IS ("output-directory")) {
1745 output_directory = optarg;
1747 #ifdef TeX
1748 } else if (ARGUMENT_IS ("output-comment")) {
1749 unsigned len = strlen (optarg);
1750 if (len < 256) {
1751 outputcomment = optarg;
1752 } else {
1753 WARNING2 ("Comment truncated to 255 characters from %d. (%s)",
1754 len, optarg);
1755 outputcomment = xmalloc (256);
1756 strncpy (outputcomment, optarg, 255);
1757 outputcomment[255] = 0;
1760 #ifdef IPC
1761 } else if (ARGUMENT_IS ("ipc-start")) {
1762 ipc_open_out ();
1763 /* Try to start up the other end if it's not already. */
1764 if (!ipc_is_open ()) {
1765 #ifdef WIN32
1766 if (_spawnlp (_P_NOWAIT, IPC_SERVER_CMD, IPC_SERVER_CMD, NULL) != -1) {
1767 #else
1768 if (system (IPC_SERVER_CMD) == 0) {
1769 #endif
1770 unsigned i;
1771 for (i = 0; i < 20 && !ipc_is_open (); i++) {
1772 #ifdef WIN32
1773 Sleep (100); /* 2000ms is too long for a simple w32 example */
1774 #else
1775 sleep (2);
1776 #endif
1777 ipc_open_out ();
1781 #endif /* IPC */
1783 } else if (ARGUMENT_IS ("shell-restricted")) {
1784 shellenabledp = 1;
1785 restrictedshell = 1;
1787 } else if (ARGUMENT_IS ("src-specials")) {
1788 last_source_name = xstrdup("");
1789 /* Option `--src" without any value means `auto' mode. */
1790 if (optarg == NULL) {
1791 insertsrcspecialeverypar = true;
1792 insertsrcspecialauto = true;
1793 srcspecialsoption = true;
1794 srcspecialsp = true;
1795 } else {
1796 parse_src_specials_option(optarg);
1798 #endif /* TeX */
1799 #if defined(pdfTeX)
1800 } else if (ARGUMENT_IS ("output-format")) {
1801 pdfoutputoption = 1;
1802 if (strcmp(optarg, "dvi") == 0) {
1803 pdfoutputvalue = 0;
1804 } else if (strcmp(optarg, "pdf") == 0) {
1805 pdfoutputvalue = 2;
1806 } else {
1807 WARNING1 ("Ignoring unknown value `%s' for --output-format", optarg);
1808 pdfoutputoption = 0;
1810 } else if (ARGUMENT_IS ("draftmode")) {
1811 pdfdraftmodeoption = 1;
1812 pdfdraftmodevalue = 1;
1813 #endif /* pdfTeX */
1814 #if defined (TeX) || defined (MF)
1815 #if !defined(Aleph)
1816 } else if (ARGUMENT_IS ("translate-file")) {
1817 translate_filename = optarg;
1818 } else if (ARGUMENT_IS ("default-translate-file")) {
1819 default_translate_filename = optarg;
1820 #endif /* !Aleph */
1821 } else if (ARGUMENT_IS ("mktex")) {
1822 kpse_maketex_option (optarg, true);
1823 } else if (ARGUMENT_IS ("no-mktex")) {
1824 kpse_maketex_option (optarg, false);
1825 #endif /* TeX or MF */
1826 } else if (ARGUMENT_IS ("interaction")) {
1827 /* These numbers match @d's in *.ch */
1828 if (STREQ (optarg, "batchmode")) {
1829 interactionoption = 0;
1830 } else if (STREQ (optarg, "nonstopmode")) {
1831 interactionoption = 1;
1832 } else if (STREQ (optarg, "scrollmode")) {
1833 interactionoption = 2;
1834 } else if (STREQ (optarg, "errorstopmode")) {
1835 interactionoption = 3;
1836 } else {
1837 WARNING1 ("Ignoring unknown argument `%s' to --interaction", optarg);
1839 #if IS_pTeX
1840 } else if (ARGUMENT_IS ("kanji")) {
1841 if (!set_enc_string (optarg, NULL)) {
1842 WARNING1 ("Ignoring unknown argument `%s' to --kanji", optarg);
1844 } else if (ARGUMENT_IS ("kanji-internal")) {
1845 if (!set_enc_string (NULL, optarg)) {
1846 WARNING1 ("Ignoring unknown argument `%s' to --kanji-internal", optarg);
1848 #endif
1850 } else if (ARGUMENT_IS ("help")) {
1851 usagehelp (PROGRAM_HELP, BUG_ADDRESS);
1853 #if defined(__SyncTeX__)
1854 } else if (ARGUMENT_IS ("synctex")) {
1855 /* Synchronize TeXnology: catching the command line option as a long */
1856 synctexoption = (int) strtol(optarg, NULL, 0);
1857 #endif
1859 } else if (ARGUMENT_IS ("version")) {
1860 char *versions;
1861 #if defined (pdfTeX) || defined(XeTeX)
1862 initversionstring(&versions);
1863 #else
1864 versions = NULL;
1865 #endif
1866 printversionandexit (BANNER, COPYRIGHT_HOLDER, AUTHOR, versions);
1868 } /* Else it was a flag; getopt has already done the assignment. */
1872 #if defined(TeX)
1873 void
1874 parse_src_specials_option (const_string opt_list)
1876 char * toklist = xstrdup(opt_list);
1877 char * tok;
1878 insertsrcspecialauto = false;
1879 tok = strtok (toklist, ", ");
1880 while (tok) {
1881 if (strcmp (tok, "everypar") == 0
1882 || strcmp (tok, "par") == 0
1883 || strcmp (tok, "auto") == 0) {
1884 insertsrcspecialauto = true;
1885 insertsrcspecialeverypar = true;
1886 } else if (strcmp (tok, "everyparend") == 0
1887 || strcmp (tok, "parend") == 0)
1888 insertsrcspecialeveryparend = true;
1889 else if (strcmp (tok, "everycr") == 0
1890 || strcmp (tok, "cr") == 0)
1891 insertsrcspecialeverycr = true;
1892 else if (strcmp (tok, "everymath") == 0
1893 || strcmp (tok, "math") == 0)
1894 insertsrcspecialeverymath = true;
1895 else if (strcmp (tok, "everyhbox") == 0
1896 || strcmp (tok, "hbox") == 0)
1897 insertsrcspecialeveryhbox = true;
1898 else if (strcmp (tok, "everyvbox") == 0
1899 || strcmp (tok, "vbox") == 0)
1900 insertsrcspecialeveryvbox = true;
1901 else if (strcmp (tok, "everydisplay") == 0
1902 || strcmp (tok, "display") == 0)
1903 insertsrcspecialeverydisplay = true;
1904 else if (strcmp (tok, "none") == 0) {
1905 /* This one allows to reset an option that could appear in texmf.cnf */
1906 insertsrcspecialauto = insertsrcspecialeverypar =
1907 insertsrcspecialeveryparend = insertsrcspecialeverycr =
1908 insertsrcspecialeverymath = insertsrcspecialeveryhbox =
1909 insertsrcspecialeveryvbox = insertsrcspecialeverydisplay = false;
1910 } else {
1911 WARNING1 ("Ignoring unknown argument `%s' to --src-specials", tok);
1913 tok = strtok(0, ", ");
1915 free(toklist);
1916 srcspecialsp=insertsrcspecialauto | insertsrcspecialeverypar |
1917 insertsrcspecialeveryparend | insertsrcspecialeverycr |
1918 insertsrcspecialeverymath | insertsrcspecialeveryhbox |
1919 insertsrcspecialeveryvbox | insertsrcspecialeverydisplay;
1920 srcspecialsoption = true;
1922 #endif
1924 /* If the first thing on the command line (we use the globals `argv' and
1925 `optind') is a normal filename (i.e., does not start with `&' or
1926 `\'), and if we can open it, and if its first line is %&FORMAT, and
1927 FORMAT is a readable dump file, then set DUMP_VAR to FORMAT.
1928 Also call kpse_reset_program_name to ensure the correct paths for the
1929 format are used. */
1930 static void
1931 parse_first_line (const_string filename)
1933 FILE *f = filename ? fopen (filename, FOPEN_R_MODE) : NULL;
1934 if (f) {
1935 string first_line = read_line (f);
1936 xfclose (f, filename);
1938 /* We deal with the general format "%&fmt --translate-file=tcx" */
1939 /* The idea of using this format came from Wlodzimierz Bzyl
1940 <matwb@monika.univ.gda.pl> */
1941 if (first_line && first_line[0] == '%' && first_line[1] == '&') {
1942 /* Parse the first line into at most three space-separated parts. */
1943 char *s;
1944 char *part[4];
1945 int npart;
1946 char **parse;
1948 for (s = first_line+2; ISBLANK(*s); ++s)
1950 npart = 0;
1951 while (*s && npart != 3) {
1952 part[npart++] = s;
1953 while (*s && *s != ' ') s++;
1954 while (*s == ' ') *s++ = '\0';
1956 part[npart] = NULL;
1957 parse = part;
1958 /* Look at what we've got. Very crude! */
1959 if (*parse && **parse != '-') {
1960 /* A format name */
1961 if (dump_name) {
1962 /* format already determined, do nothing. */
1963 } else {
1964 string f_name = concat (part[0], DUMP_EXT);
1965 string d_name = kpse_find_file (f_name, DUMP_FORMAT, false);
1966 if (d_name && kpse_readable_file (d_name)) {
1967 dump_name = xstrdup (part[0]);
1968 kpse_reset_program_name (dump_name);
1969 /* Tell TeX/MF/MP we have a %&name line... */
1970 dumpline = true;
1972 free (f_name);
1974 parse++;
1976 /* The tcx stuff, if any. Should we support the -translate-file
1977 form as well as --translate-file? */
1978 if (*parse) {
1979 s = NULL;
1980 if (translate_filename) {
1981 /* TCX file already set, do nothing. */
1982 } else if (STREQ (*parse, "--translate-file")) {
1983 s = *(parse+1);
1984 } else if (STREQ (*parse, "-translate-file")) {
1985 s = *(parse+1);
1986 } else if (STRNEQ (*parse, "--translate-file=", 17)) {
1987 s = *parse+17;
1988 } else if (STRNEQ (*parse, "-translate-file=", 16)) {
1989 s = *parse+16;
1991 /* Just set the name, no sanity checks here. */
1992 /* FIXME: remove trailing spaces. */
1993 if (s && *s) {
1994 translate_filename = xstrdup(s);
1998 if (first_line)
1999 free (first_line);
2004 piped I/O
2007 /* The code that implements popen() needs an array for tracking
2008 possible pipe file pointers, because these need to be
2009 closed using pclose().
2012 #if ENABLE_PIPES
2014 #define NUM_PIPES 16
2016 static FILE *pipes [NUM_PIPES];
2018 boolean
2019 open_in_or_pipe (FILE **f_ptr, int filefmt, const_string fopen_mode)
2021 string fname = NULL;
2022 int i; /* iterator */
2024 /* opening a read pipe is straightforward, only have to
2025 skip past the pipe symbol in the file name. filename
2026 quoting is assumed to happen elsewhere (it does :-)) */
2028 if (shellenabledp && *(nameoffile+1) == '|') {
2029 /* the user requested a pipe */
2030 *f_ptr = NULL;
2031 fname = xmalloc(strlen((const_string)(nameoffile+1))+1);
2032 strcpy(fname,(const_string)(nameoffile+1));
2033 if (fullnameoffile)
2034 free(fullnameoffile);
2035 fullnameoffile = xstrdup(fname);
2036 recorder_record_input (fname + 1);
2037 *f_ptr = runpopen(fname+1,"r");
2038 free(fname);
2039 for (i=0; i<NUM_PIPES; i++) {
2040 if (pipes[i]==NULL) {
2041 pipes[i] = *f_ptr;
2042 break;
2045 if (*f_ptr)
2046 setvbuf (*f_ptr,NULL,_IONBF,0);
2047 #ifdef WIN32
2048 Poptr = *f_ptr;
2049 #endif
2051 return *f_ptr != NULL;
2054 return open_input(f_ptr,filefmt,fopen_mode) ;
2057 #ifdef XeTeX
2058 boolean
2059 u_open_in_or_pipe(unicodefile* f, integer filefmt, const_string fopen_mode, integer mode, integer encodingData)
2061 string fname = NULL;
2062 int i; /* iterator */
2064 /* opening a read pipe is straightforward, only have to
2065 skip past the pipe symbol in the file name. filename
2066 quoting is assumed to happen elsewhere (it does :-)) */
2068 if (shellenabledp && *(nameoffile+1) == '|') {
2069 /* the user requested a pipe */
2070 *f = malloc(sizeof(UFILE));
2071 (*f)->encodingMode = (mode == AUTO) ? UTF8 : mode;
2072 (*f)->conversionData = 0;
2073 (*f)->savedChar = -1;
2074 (*f)->skipNextLF = 0;
2075 (*f)->f = NULL;
2076 fname = xmalloc(strlen((const_string)(nameoffile+1))+1);
2077 strcpy(fname,(const_string)(nameoffile+1));
2078 if (fullnameoffile)
2079 free(fullnameoffile);
2080 fullnameoffile = xstrdup(fname);
2081 recorder_record_input (fname + 1);
2082 (*f)->f = runpopen(fname+1,"r");
2083 free(fname);
2084 for (i=0; i<NUM_PIPES; i++) {
2085 if (pipes[i]==NULL) {
2086 pipes[i] = (*f)->f;
2087 break;
2090 if ((*f)->f)
2091 setvbuf ((*f)->f,NULL,_IONBF,0);
2092 #ifdef WIN32
2093 Poptr = (*f)->f;
2094 #endif
2096 return (*f)->f != NULL;
2099 return u_open_in(f, filefmt, fopen_mode, mode, encodingData);
2101 #endif
2103 boolean
2104 open_out_or_pipe (FILE **f_ptr, const_string fopen_mode)
2106 string fname;
2107 int i; /* iterator */
2109 /* opening a write pipe takes a little bit more work, because TeX
2110 will perhaps have appended ".tex". To avoid user confusion as
2111 much as possible, this extension is stripped only when the command
2112 is a bare word. Some small string trickery is needed to make
2113 sure the correct number of bytes is free()-d afterwards */
2115 if (shellenabledp && *(nameoffile+1) == '|') {
2116 /* the user requested a pipe */
2117 fname = xmalloc(strlen((const_string)(nameoffile+1))+1);
2118 strcpy(fname,(const_string)(nameoffile+1));
2119 if (strchr (fname,' ')==NULL && strchr(fname,'>')==NULL) {
2120 /* mp and mf currently do not use this code, but it
2121 is better to be prepared */
2122 if (STREQ((fname+strlen(fname)-4),".tex"))
2123 *(fname+strlen(fname)-4) = 0;
2124 *f_ptr = runpopen(fname+1,"w");
2125 *(fname+strlen(fname)) = '.';
2126 } else {
2127 *f_ptr = runpopen(fname+1,"w");
2129 recorder_record_output (fname + 1);
2130 free(fname);
2132 for (i=0; i<NUM_PIPES; i++) {
2133 if (pipes[i]==NULL) {
2134 pipes[i] = *f_ptr;
2135 break;
2139 if (*f_ptr)
2140 setvbuf(*f_ptr,NULL,_IONBF,0);
2142 return *f_ptr != NULL;
2145 return open_output(f_ptr,fopen_mode);
2149 void
2150 close_file_or_pipe (FILE *f)
2152 int i; /* iterator */
2154 if (shellenabledp) {
2155 /* if this file was a pipe, pclose() it and return */
2156 for (i=0; i<NUM_PIPES; i++) {
2157 if (pipes[i] == f) {
2158 if (f) {
2159 pclose (f);
2160 #ifdef WIN32
2161 Poptr = NULL;
2162 #endif
2164 pipes[i] = NULL;
2165 return;
2169 close_file(f);
2171 #endif /* ENABLE_PIPES */
2173 /* All our interrupt handler has to do is set TeX's or Metafont's global
2174 variable `interrupt'; then they will do everything needed. */
2175 #ifdef WIN32
2176 /* Win32 doesn't set SIGINT ... */
2177 static BOOL WINAPI
2178 catch_interrupt (DWORD arg)
2180 switch (arg) {
2181 case CTRL_C_EVENT:
2182 case CTRL_BREAK_EVENT:
2183 interrupt = 1;
2184 return TRUE;
2185 default:
2186 /* No need to set interrupt as we are exiting anyway */
2187 return FALSE;
2190 #else /* not WIN32 */
2191 static RETSIGTYPE
2192 catch_interrupt (int arg)
2194 interrupt = 1;
2195 #ifdef OS2
2196 (void) signal (SIGINT, SIG_ACK);
2197 #else
2198 (void) signal (SIGINT, catch_interrupt);
2199 #endif /* not OS2 */
2201 #endif /* not WIN32 */
2203 #if defined(_MSC_VER)
2204 #define strtoull _strtoui64
2205 #endif
2207 static boolean start_time_set = false;
2208 static time_t start_time = 0;
2210 void init_start_time() {
2211 char *source_date_epoch;
2212 unsigned long long epoch;
2213 char *endptr;
2214 if (!start_time_set) {
2215 start_time_set = true;
2216 #ifndef onlyTeX
2217 source_date_epoch = getenv("SOURCE_DATE_EPOCH");
2218 if (source_date_epoch) {
2219 errno = 0;
2220 epoch = strtoull(source_date_epoch, &endptr, 10);
2221 if (epoch < 0 || *endptr != '\0' || errno != 0) {
2222 FATAL1 ("invalid epoch-seconds-timezone value for environment variable $SOURCE_DATE_EPOCH: %s",
2223 source_date_epoch);
2225 #if defined(_MSC_VER)
2226 if (epoch > 32535291599ULL)
2227 epoch = 32535291599ULL;
2228 #endif
2229 start_time = epoch;
2230 } else
2231 #endif /* not onlyTeX */
2233 start_time = time((time_t *) NULL);
2238 /* Besides getting the date and time here, we also set up the interrupt
2239 handler, for no particularly good reason. It's just that since the
2240 `fix_date_and_time' routine is called early on (section 1337 in TeX,
2241 ``Get the first line of input and prepare to start''), this is as
2242 good a place as any. */
2244 void
2245 get_date_and_time (integer *minutes, integer *day,
2246 integer *month, integer *year)
2248 struct tm *tmptr;
2249 #ifndef onlyTeX
2250 string sde_texprim = getenv ("FORCE_SOURCE_DATE");
2251 if (sde_texprim && STREQ (sde_texprim, "1")) {
2252 init_start_time ();
2253 tmptr = gmtime (&start_time);
2254 } else
2255 #endif /* not onlyTeX */
2257 /* whether the envvar was not set (usual case) or invalid,
2258 use current time. */
2259 time_t myclock = time ((time_t *) 0);
2260 tmptr = localtime (&myclock);
2262 #ifndef onlyTeX
2263 /* warn if they gave an invalid value, empty (null string) ok. */
2264 if (sde_texprim && strlen (sde_texprim) > 0
2265 && !STREQ (sde_texprim, "0")) {
2266 WARNING1 ("invalid value (expected 0 or 1) for environment variable $FORCE_SOURCE_DATE: %s",
2267 sde_texprim);
2269 #endif /* not onlyTeX */
2272 *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
2273 *day = tmptr->tm_mday;
2274 *month = tmptr->tm_mon + 1;
2275 *year = tmptr->tm_year + 1900;
2278 #ifdef SA_INTERRUPT
2279 /* Under SunOS 4.1.x, the default action after return from the
2280 signal handler is to restart the I/O if nothing has been
2281 transferred. The effect on TeX is that interrupts are ignored if
2282 we are waiting for input. The following tells the system to
2283 return EINTR from read() in this case. From ken@cs.toronto.edu. */
2285 struct sigaction a, oa;
2287 a.sa_handler = catch_interrupt;
2288 sigemptyset (&a.sa_mask);
2289 sigaddset (&a.sa_mask, SIGINT);
2290 a.sa_flags = SA_INTERRUPT;
2291 sigaction (SIGINT, &a, &oa);
2292 if (oa.sa_handler != SIG_DFL)
2293 sigaction (SIGINT, &oa, (struct sigaction *) 0);
2294 #else /* no SA_INTERRUPT */
2295 #ifdef WIN32
2296 SetConsoleCtrlHandler(catch_interrupt, TRUE);
2297 #else /* not WIN32 */
2298 RETSIGTYPE (*old_handler)(int);
2300 old_handler = signal (SIGINT, catch_interrupt);
2301 if (old_handler != SIG_DFL)
2302 signal (SIGINT, old_handler);
2303 #endif /* not WIN32 */
2304 #endif /* no SA_INTERRUPT */
2308 #if defined(pdfTeX) || defined(epTeX) || defined(eupTeX)
2310 Getting a high resolution time.
2312 void
2313 get_seconds_and_micros (integer *seconds, integer *micros)
2315 #if defined (HAVE_GETTIMEOFDAY)
2316 struct timeval tv;
2317 gettimeofday(&tv, NULL);
2318 *seconds = tv.tv_sec;
2319 *micros = tv.tv_usec;
2320 #elif defined (HAVE_FTIME)
2321 struct timeb tb;
2322 ftime(&tb);
2323 *seconds = tb.time;
2324 *micros = tb.millitm*1000;
2325 #else
2326 time_t myclock = time((time_t*)NULL);
2327 *seconds = myclock;
2328 *micros = 0;
2329 #endif
2331 #endif
2333 /* Read a line of input as efficiently as possible while still looking
2334 like Pascal. We set `last' to `first' and return `false' if we get
2335 to eof. Otherwise, we return `true' and set last = first +
2336 length(line except trailing whitespace). */
2338 #ifndef XeTeX /* for XeTeX, we have a replacement function in XeTeX_ext.c */
2339 boolean
2340 input_line (FILE *f)
2342 int i = EOF;
2344 /* Recognize either LF or CR as a line terminator. */
2345 #if IS_pTeX
2346 last = input_line2(f, (unsigned char *)buffer, first, bufsize, &i);
2347 #else
2348 #ifdef WIN32
2349 if (f != Poptr && fileno (f) != fileno (stdin)) {
2350 long position = ftell (f);
2352 if (position == 0L) { /* Detect and skip Byte order marks. */
2353 int k1, k2, k3, k4;
2354 k1 = getc (f);
2356 if (k1 != 0xff && k1 != 0xfe && k1 != 0xef)
2357 rewind (f);
2358 else {
2359 k2 = getc (f);
2361 if (k2 != 0xff && k2 != 0xfe && k2 != 0xbb)
2362 rewind (f);
2363 else if ((k1 == 0xff && k2 == 0xfe) || /* UTF-16(LE) */
2364 (k1 == 0xfe && k2 == 0xff)) /* UTF-16(BE) */
2366 else {
2367 k3 = getc (f);
2368 k4 = getc (f);
2369 if (k1 == 0xef && k2 == 0xbb && k3 == 0xbf &&
2370 k4 >= 0 && k4 <= 0x7e) /* UTF-8 */
2371 ungetc (k4, f);
2372 else
2373 rewind (f);
2378 #endif
2379 last = first;
2380 while (last < bufsize && (i = getc (f)) != EOF && i != '\n' && i != '\r')
2381 buffer[last++] = i;
2382 #endif
2384 if (i == EOF && errno != EINTR && last == first)
2385 return false;
2387 /* We didn't get the whole line because our buffer was too small. */
2388 if (i != EOF && i != '\n' && i != '\r') {
2389 fprintf (stderr, "! Unable to read an entire line---bufsize=%u.\n",
2390 (unsigned) bufsize);
2391 fputs ("Please increase buf_size in texmf.cnf.\n", stderr);
2392 uexit (1);
2395 buffer[last] = ' ';
2396 if (last >= maxbufstack)
2397 maxbufstack = last;
2399 /* If next char is LF of a CRLF, read it. */
2400 if (i == '\r') {
2401 while ((i = getc (f)) == EOF && errno == EINTR)
2403 if (i != '\n')
2404 ungetc (i, f);
2407 /* Trim trailing whitespace. */
2408 while (last > first && ISBLANK (buffer[last - 1]))
2409 --last;
2411 /* Don't bother using xord if we don't need to. */
2412 #if !defined(Aleph)
2413 for (i = first; i <= last; i++)
2414 buffer[i] = xord[buffer[i]];
2415 #endif
2417 #if IS_pTeX
2418 for (i = last+1; (i < last + 5 && i < bufsize) ; i++)
2419 buffer[i] = '\0';
2420 #endif
2422 return true;
2424 #endif /* !XeTeX */
2426 /* This string specifies what the `e' option does in response to an
2427 error message. */
2428 static const_string edit_value = EDITOR;
2430 /* This procedure originally due to sjc@s1-c. TeX & Metafont call it when
2431 the user types `e' in response to an error, invoking a text editor on
2432 the erroneous source file. FNSTART is how far into FILENAME the
2433 actual filename starts; FNLENGTH is how long the filename is. */
2435 void
2436 calledit (packedASCIIcode *filename,
2437 poolpointer fnstart,
2438 integer fnlength,
2439 integer linenumber)
2441 char *temp, *command, *fullcmd;
2442 char c;
2443 int sdone, ddone, i;
2445 #ifdef WIN32
2446 char *fp, *ffp, *env, editorname[256], buffer[256];
2447 int cnt = 0;
2448 int dontchange = 0;
2449 #endif
2451 sdone = ddone = 0;
2452 filename += fnstart;
2454 /* Close any open input files, since we're going to kill the job. */
2455 for (i = 1; i <= inopen; i++)
2456 #ifdef XeTeX
2457 xfclose (inputfile[i]->f, "inputfile");
2458 #else
2459 xfclose (inputfile[i], "inputfile");
2460 #endif
2462 /* Replace the default with the value of the appropriate environment
2463 variable or config file value, if it's set. */
2464 temp = kpse_var_value (edit_var);
2465 if (temp != NULL)
2466 edit_value = temp;
2468 /* Construct the command string. The `11' is the maximum length an
2469 integer might be. */
2470 command = xmalloc (strlen (edit_value) + fnlength + 11);
2472 /* So we can construct it as we go. */
2473 temp = command;
2475 #ifdef WIN32
2476 fp = editorname;
2477 if ((isalpha(*edit_value) && *(edit_value + 1) == ':'
2478 && IS_DIR_SEP (*(edit_value + 2)))
2479 || (*edit_value == '"' && isalpha(*(edit_value + 1))
2480 && *(edit_value + 2) == ':'
2481 && IS_DIR_SEP (*(edit_value + 3)))
2483 dontchange = 1;
2484 #endif
2486 while ((c = *edit_value++) != 0)
2488 if (c == '%')
2490 switch (c = *edit_value++)
2492 case 'd':
2493 if (ddone)
2494 FATAL ("call_edit: `%%d' appears twice in editor command");
2495 sprintf (temp, "%ld", (long int)linenumber);
2496 while (*temp != '\0')
2497 temp++;
2498 ddone = 1;
2499 break;
2501 case 's':
2502 if (sdone)
2503 FATAL ("call_edit: `%%s' appears twice in editor command");
2504 for (i =0; i < fnlength; i++)
2505 *temp++ = Xchr (filename[i]);
2506 sdone = 1;
2507 break;
2509 case '\0':
2510 *temp++ = '%';
2511 /* Back up to the null to force termination. */
2512 edit_value--;
2513 break;
2515 default:
2516 *temp++ = '%';
2517 *temp++ = c;
2518 break;
2521 else {
2522 #ifdef WIN32
2523 if (dontchange)
2524 *temp++ = c;
2525 else { if(Isspace(c) && cnt == 0) {
2526 cnt++;
2527 temp = command;
2528 *temp++ = c;
2529 *fp = '\0';
2530 } else if(!Isspace(c) && cnt == 0) {
2531 *fp++ = c;
2532 } else {
2533 *temp++ = c;
2536 #else
2537 *temp++ = c;
2538 #endif
2542 *temp = 0;
2544 #ifdef WIN32
2545 if (dontchange == 0) {
2546 if(editorname[0] == '.' ||
2547 editorname[0] == '/' ||
2548 editorname[0] == '\\') {
2549 fprintf(stderr, "%s is not allowed to execute.\n", editorname);
2550 uexit(1);
2552 env = (char *)getenv("PATH");
2553 if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
2554 if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
2555 fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
2556 uexit(1);
2559 fullcmd = (char *)xmalloc(strlen(buffer)+strlen(command)+5);
2560 strcpy(fullcmd, "\"");
2561 strcat(fullcmd, buffer);
2562 strcat(fullcmd, "\"");
2563 strcat(fullcmd, command);
2564 } else
2565 #endif
2566 fullcmd = command;
2568 /* Execute the command. */
2569 if (system (fullcmd) != 0)
2570 fprintf (stderr, "! Trouble executing `%s'.\n", command);
2572 /* Quit, since we found an error. */
2573 uexit (1);
2576 /* Read and write dump files. As distributed, these files are
2577 architecture dependent; specifically, BigEndian and LittleEndian
2578 architectures produce different files. These routines always output
2579 BigEndian files. This still does not guarantee them to be
2580 architecture-independent, because it is possible to make a format
2581 that dumps a glue ratio, i.e., a floating-point number. Fortunately,
2582 none of the standard formats do that. */
2584 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE) /* this fn */
2586 /* This macro is always invoked as a statement. It assumes a variable
2587 `temp'. */
2589 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp
2592 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
2593 opposite-endianness of whatever they are now. */
2595 static void
2596 swap_items (char *p, int nitems, int size)
2598 char temp;
2600 /* Since `size' does not change, we can write a while loop for each
2601 case, and avoid testing `size' for each time. */
2602 switch (size)
2604 /* 16-byte items happen on the DEC Alpha machine when we are not
2605 doing sharable memory dumps. */
2606 case 16:
2607 while (nitems--)
2609 SWAP (p[0], p[15]);
2610 SWAP (p[1], p[14]);
2611 SWAP (p[2], p[13]);
2612 SWAP (p[3], p[12]);
2613 SWAP (p[4], p[11]);
2614 SWAP (p[5], p[10]);
2615 SWAP (p[6], p[9]);
2616 SWAP (p[7], p[8]);
2617 p += size;
2619 break;
2621 case 8:
2622 while (nitems--)
2624 SWAP (p[0], p[7]);
2625 SWAP (p[1], p[6]);
2626 SWAP (p[2], p[5]);
2627 SWAP (p[3], p[4]);
2628 p += size;
2630 break;
2632 case 4:
2633 while (nitems--)
2635 SWAP (p[0], p[3]);
2636 SWAP (p[1], p[2]);
2637 p += size;
2639 break;
2641 case 2:
2642 while (nitems--)
2644 SWAP (p[0], p[1]);
2645 p += size;
2647 break;
2649 case 1:
2650 /* Nothing to do. */
2651 break;
2653 default:
2654 FATAL1 ("Can't swap a %d-byte item for (un)dumping", size);
2657 #endif /* not WORDS_BIGENDIAN and not NO_DUMP_SHARE */
2660 /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
2661 The pointer to the stuff to write is P, and we write to the file
2662 OUT_FILE. */
2664 void
2665 #ifdef XeTeX
2666 do_dump (char *p, int item_size, int nitems, gzFile out_file)
2667 #else
2668 do_dump (char *p, int item_size, int nitems, FILE *out_file)
2669 #endif
2671 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2672 swap_items (p, nitems, item_size);
2673 #endif
2675 #ifdef XeTeX
2676 if (gzwrite (out_file, p, item_size * nitems) != item_size * nitems)
2677 #else
2678 if (fwrite (p, item_size, nitems, out_file) != nitems)
2679 #endif
2681 fprintf (stderr, "! Could not write %d %d-byte item(s) to %s.\n",
2682 nitems, item_size, nameoffile+1);
2683 uexit (1);
2686 /* Have to restore the old contents of memory, since some of it might
2687 get used again. */
2688 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2689 swap_items (p, nitems, item_size);
2690 #endif
2694 /* Here is the dual of the writing routine. */
2696 void
2697 #ifdef XeTeX
2698 do_undump (char *p, int item_size, int nitems, gzFile in_file)
2699 #else
2700 do_undump (char *p, int item_size, int nitems, FILE *in_file)
2701 #endif
2703 #ifdef XeTeX
2704 if (gzread (in_file, p, item_size * nitems) != item_size * nitems)
2705 #else
2706 if (fread (p, item_size, nitems, in_file) != (size_t) nitems)
2707 #endif
2708 FATAL3 ("Could not undump %d %d-byte item(s) from %s",
2709 nitems, item_size, nameoffile+1);
2711 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2712 swap_items (p, nitems, item_size);
2713 #endif
2716 /* FIXME -- some (most?) of this can/should be moved to the Pascal/WEB side. */
2717 #if defined(TeX) || defined(MF)
2718 #if !defined(pdfTeX)
2719 static void
2720 checkpoolpointer (poolpointer poolptr, size_t len)
2722 if (poolptr + len >= poolsize) {
2723 fprintf (stderr, "\nstring pool overflow [%i bytes]\n",
2724 (int)poolsize); /* fixme */
2725 exit(1);
2729 #ifndef XeTeX /* XeTeX uses this from XeTeX_ext.c */
2730 static
2731 #endif
2733 maketexstring(const_string s)
2735 size_t len;
2736 #ifdef XeTeX
2737 UInt32 rval;
2738 const unsigned char *cp = (const unsigned char *)s;
2739 #endif
2740 #if defined(TeX)
2741 if (s == NULL || *s == 0)
2742 return getnullstr();
2743 #else
2744 assert (s != 0);
2745 #endif
2746 len = strlen(s);
2747 checkpoolpointer (poolptr, len); /* in the XeTeX case, this may be more than enough */
2748 #ifdef XeTeX
2749 while ((rval = *(cp++)) != 0) {
2750 UInt16 extraBytes = bytesFromUTF8[rval];
2751 switch (extraBytes) { /* note: code falls through cases! */
2752 case 5: rval <<= 6; if (*cp) rval += *(cp++);
2753 case 4: rval <<= 6; if (*cp) rval += *(cp++);
2754 case 3: rval <<= 6; if (*cp) rval += *(cp++);
2755 case 2: rval <<= 6; if (*cp) rval += *(cp++);
2756 case 1: rval <<= 6; if (*cp) rval += *(cp++);
2757 case 0: ;
2759 rval -= offsetsFromUTF8[extraBytes];
2760 if (rval > 0xffff) {
2761 rval -= 0x10000;
2762 strpool[poolptr++] = 0xd800 + rval / 0x0400;
2763 strpool[poolptr++] = 0xdc00 + rval % 0x0400;
2765 else
2766 strpool[poolptr++] = rval;
2768 #else /* ! XeTeX */
2769 while (len-- > 0)
2770 strpool[poolptr++] = *s++;
2771 #endif /* ! XeTeX */
2773 return makestring();
2775 #endif /* !pdfTeX */
2777 strnumber
2778 makefullnamestring(void)
2780 return maketexstring(fullnameoffile);
2783 /* Get the job name to be used, which may have been set from the
2784 command line. */
2785 strnumber
2786 getjobname(strnumber name)
2788 strnumber ret = name;
2789 if (c_job_name != NULL)
2790 ret = maketexstring(c_job_name);
2791 return ret;
2793 #endif
2795 #if defined(TeX)
2796 static int
2797 compare_paths (const_string p1, const_string p2)
2799 int ret;
2800 while (
2801 #ifdef MONOCASE_FILENAMES
2802 (((ret = (toupper(*p1) - toupper(*p2))) == 0) && (*p2 != 0))
2803 #else
2804 (((ret = (*p1 - *p2)) == 0) && (*p2 != 0))
2805 #endif
2806 || (IS_DIR_SEP(*p1) && IS_DIR_SEP(*p2))) {
2807 p1++, p2++;
2809 ret = (ret < 0 ? -1 : (ret > 0 ? 1 : 0));
2810 return ret;
2813 #ifdef XeTeX /* the string pool is UTF-16 but we want a UTF-8 string */
2815 string
2816 gettexstring (strnumber s)
2818 unsigned bytesToWrite = 0;
2819 poolpointer len, i, j;
2820 string name;
2821 if (strstart[s + 1 - 65536L] < strstart[s - 65536L])
2822 return NULL;
2823 len = strstart[s + 1 - 65536L] - strstart[s - 65536L];
2824 name = xmalloc(len * 3 + 1); /* max UTF16->UTF8 expansion
2825 (code units, not bytes) */
2826 for (i = 0, j = 0; i < len; i++) {
2827 unsigned c = strpool[i + strstart[s - 65536L]];
2828 if (c >= 0xD800 && c <= 0xDBFF) {
2829 unsigned lo = strpool[++i + strstart[s - 65536L]];
2830 if (lo >= 0xDC00 && lo <= 0xDFFF)
2831 c = (c - 0xD800) * 0x0400 + lo - 0xDC00;
2832 else
2833 c = 0xFFFD;
2835 if (c < 0x80)
2836 bytesToWrite = 1;
2837 else if (c < 0x800)
2838 bytesToWrite = 2;
2839 else if (c < 0x10000)
2840 bytesToWrite = 3;
2841 else if (c < 0x110000)
2842 bytesToWrite = 4;
2843 else {
2844 bytesToWrite = 3;
2845 c = 0xFFFD;
2848 j += bytesToWrite;
2849 switch (bytesToWrite) { /* note: everything falls through. */
2850 case 4: name[--j] = ((c | 0x80) & 0xBF); c >>= 6;
2851 case 3: name[--j] = ((c | 0x80) & 0xBF); c >>= 6;
2852 case 2: name[--j] = ((c | 0x80) & 0xBF); c >>= 6;
2853 case 1: name[--j] = (c | firstByteMark[bytesToWrite]);
2855 j += bytesToWrite;
2857 name[j] = 0;
2858 return name;
2861 #else
2863 string
2864 gettexstring (strnumber s)
2866 poolpointer len;
2867 string name;
2868 #if !defined(Aleph)
2869 len = strstart[s + 1] - strstart[s];
2870 #else
2871 len = strstartar[s + 1 - 65536L] - strstartar[s - 65536L];
2872 #endif
2873 name = (string)xmalloc (len + 1);
2874 #if !defined(Aleph)
2875 strncpy (name, (string)&strpool[strstart[s]], len);
2876 #else
2878 poolpointer i;
2879 /* Don't use strncpy. The strpool is not made up of chars. */
2880 for (i=0; i<len; i++) name[i] = strpool[i+strstartar[s - 65536L]];
2882 #endif
2883 name[len] = 0;
2884 return name;
2887 #endif /* not XeTeX */
2889 boolean
2890 isnewsource (strnumber srcfilename, int lineno)
2892 char *name = gettexstring(srcfilename);
2893 return (compare_paths(name, last_source_name) != 0 || lineno != last_lineno);
2896 void
2897 remembersourceinfo (strnumber srcfilename, int lineno)
2899 if (last_source_name)
2900 free(last_source_name);
2901 last_source_name = gettexstring(srcfilename);
2902 last_lineno = lineno;
2905 poolpointer
2906 makesrcspecial (strnumber srcfilename, int lineno)
2908 poolpointer oldpoolptr = poolptr;
2909 char *filename = gettexstring(srcfilename);
2910 /* FIXME: Magic number. */
2911 char buf[40];
2912 char *s = buf;
2914 /* Always put a space after the number, which makes things easier
2915 * to parse.
2917 sprintf (buf, "src:%d ", lineno);
2919 if (poolptr + strlen(buf) + strlen(filename) >= (size_t)poolsize) {
2920 fprintf (stderr, "\nstring pool overflow\n"); /* fixme */
2921 exit (1);
2923 s = buf;
2924 while (*s)
2925 strpool[poolptr++] = *s++;
2927 s = filename;
2928 while (*s)
2929 strpool[poolptr++] = *s++;
2931 return (oldpoolptr);
2934 /* pdfTeX routines also used for e-pTeX, e-upTeX, and XeTeX */
2935 #if defined (pdfTeX) || defined (epTeX) || defined (eupTeX) || defined(XeTeX)
2937 #include <kpathsea/c-stat.h>
2938 #include "md5.h"
2940 #define check_nprintf(size_get, size_want) \
2941 if ((unsigned)(size_get) >= (unsigned)(size_want)) \
2942 pdftex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__);
2943 # define check_buf(size, buf_size) \
2944 if ((unsigned)(size) > (unsigned)(buf_size)) \
2945 pdftex_fail("buffer overflow at file %s, line %d", __FILE__, __LINE__ )
2946 # define xfree(p) do { if (p != NULL) free(p); p = NULL; } while (0)
2947 # define MAX_CSTRING_LEN 1024 * 1024
2949 #if !defined (pdfTeX)
2950 # define PRINTF_BUF_SIZE 1024
2951 static char print_buf[PRINTF_BUF_SIZE];
2953 /* Helper for pdftex_fail. */
2954 static void safe_print(const char *str)
2956 const char *c;
2957 for (c = str; *c; ++c)
2958 print(*c);
2960 /* pdftex_fail may be called when a buffer overflow has happened/is
2961 happening, therefore may not call mktexstring. However, with the
2962 current implementation it appears that error messages are misleading,
2963 possibly because pool overflows are detected too late.
2965 The output format of this fuction must be the same as pdf_error in
2966 pdftex.web! */
2967 __attribute__ ((noreturn, format(printf, 1, 2)))
2968 void pdftex_fail(const char *fmt, ...)
2970 va_list args;
2971 va_start(args, fmt);
2972 println();
2973 safe_print("!error: ");
2974 vsnprintf(print_buf, PRINTF_BUF_SIZE, fmt, args);
2975 safe_print(print_buf);
2976 va_end(args);
2977 println();
2978 safe_print(" ==> Fatal error occurred, output file will be damaged!");
2979 println();
2980 if (kpathsea_debug) {
2981 safe_print("kpathsea_debug enabled, calling abort()...");
2982 println();
2983 abort();
2984 } else {
2985 exit(EXIT_FAILURE);
2988 #endif /* not pdfTeX */
2990 #if !defined(XeTeX)
2992 #define TIME_STR_SIZE 30
2993 char start_time_str[TIME_STR_SIZE];
2994 static char time_str[TIME_STR_SIZE];
2995 /* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */
2997 static void makepdftime(time_t t, char *time_str, boolean utc)
3000 struct tm lt, gmt;
3001 size_t size;
3002 int i, off, off_hours, off_mins;
3004 /* get the time */
3005 if (utc) {
3006 lt = *gmtime(&t);
3008 else {
3009 lt = *localtime(&t);
3011 size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", &lt);
3012 /* expected format: "YYYYmmddHHMMSS" */
3013 if (size == 0) {
3014 /* unexpected, contents of time_str is undefined */
3015 time_str[0] = '\0';
3016 return;
3019 /* correction for seconds: %S can be in range 00..61,
3020 the PDF reference expects 00..59,
3021 therefore we map "60" and "61" to "59" */
3022 if (time_str[14] == '6') {
3023 time_str[14] = '5';
3024 time_str[15] = '9';
3025 time_str[16] = '\0'; /* for safety */
3028 /* get the time zone offset */
3029 gmt = *gmtime(&t);
3031 /* this calculation method was found in exim's tod.c */
3032 off = 60 * (lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min;
3033 if (lt.tm_year != gmt.tm_year) {
3034 off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440;
3035 } else if (lt.tm_yday != gmt.tm_yday) {
3036 off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440;
3039 if (off == 0) {
3040 time_str[size++] = 'Z';
3041 time_str[size] = 0;
3042 } else {
3043 off_hours = off / 60;
3044 off_mins = abs(off - off_hours * 60);
3045 i = snprintf(&time_str[size], 9, "%+03d'%02d'", off_hours, off_mins);
3046 check_nprintf(i, 9);
3050 void initstarttime(void)
3052 if (!start_time_set) {
3053 init_start_time ();
3054 if (getenv ("SOURCE_DATE_EPOCH")) {
3055 makepdftime (start_time, start_time_str, /* utc= */true);
3056 } else {
3057 makepdftime (start_time, start_time_str, /* utc= */false);
3062 char *makecstring(integer s)
3064 static char *cstrbuf = NULL;
3065 char *p;
3066 static int allocsize;
3067 int allocgrow, i, l = strstart[s + 1] - strstart[s];
3068 check_buf(l + 1, MAX_CSTRING_LEN);
3069 if (cstrbuf == NULL) {
3070 allocsize = l + 1;
3071 cstrbuf = xmallocarray(char, allocsize);
3072 } else if (l + 1 > allocsize) {
3073 allocgrow = allocsize * 0.2;
3074 if (l + 1 - allocgrow > allocsize)
3075 allocsize = l + 1;
3076 else if (allocsize < MAX_CSTRING_LEN - allocgrow)
3077 allocsize += allocgrow;
3078 else
3079 allocsize = MAX_CSTRING_LEN;
3080 cstrbuf = xreallocarray(cstrbuf, char, allocsize);
3082 p = cstrbuf;
3083 for (i = 0; i < l; i++)
3084 *p++ = strpool[i + strstart[s]];
3085 *p = 0;
3086 return cstrbuf;
3089 /* makecfilename
3090 input/ouput same as makecstring:
3091 input: string number
3092 output: C string with quotes removed.
3093 That means, file names that are legal on some operation systems
3094 cannot any more be used since pdfTeX version 1.30.4.
3096 char *makecfilename(integer s)
3098 char *name = makecstring(s);
3099 char *p = name;
3100 char *q = name;
3102 while (*p) {
3103 if (*p != '"')
3104 *q++ = *p;
3105 p++;
3107 *q = '\0';
3108 return name;
3111 void getcreationdate(void)
3113 size_t len;
3114 initstarttime();
3115 /* put creation date on top of string pool and update poolptr */
3116 len = strlen(start_time_str);
3118 /* In e-pTeX, "init len => call initstarttime()" (as pdftexdir/utils.c)
3119 yields unintentional output. */
3121 if ((unsigned) (poolptr + len) >= (unsigned) (poolsize)) {
3122 poolptr = poolsize;
3123 /* error by str_toks that calls str_room(1) */
3124 return;
3127 memcpy(&strpool[poolptr], start_time_str, len);
3128 poolptr += len;
3131 void getfilemoddate(integer s)
3133 struct stat file_data;
3135 char *file_name = kpse_find_tex(makecfilename(s));
3136 if (file_name == NULL) {
3137 return; /* empty string */
3140 recorder_record_input(file_name);
3141 /* get file status */
3142 if (stat(file_name, &file_data) == 0) {
3143 size_t len;
3145 makepdftime(file_data.st_mtime, time_str, /* utc= */false);
3146 len = strlen(time_str);
3147 if ((unsigned) (poolptr + len) >= (unsigned) (poolsize)) {
3148 poolptr = poolsize;
3149 /* error by str_toks that calls str_room(1) */
3150 } else {
3151 memcpy(&strpool[poolptr], time_str, len);
3152 poolptr += len;
3155 /* else { errno contains error code } */
3157 xfree(file_name);
3160 void getfilesize(integer s)
3162 struct stat file_data;
3163 int i;
3165 char *file_name = kpse_find_tex(makecfilename(s));
3166 if (file_name == NULL) {
3167 return; /* empty string */
3170 recorder_record_input(file_name);
3171 /* get file status */
3172 if (stat(file_name, &file_data) == 0) {
3173 size_t len;
3174 char buf[20];
3176 /* st_size has type off_t */
3177 i = snprintf(buf, sizeof(buf),
3178 "%lu", (long unsigned int) file_data.st_size);
3179 check_nprintf(i, sizeof(buf));
3180 len = strlen(buf);
3181 if ((unsigned) (poolptr + len) >= (unsigned) (poolsize)) {
3182 poolptr = poolsize;
3183 /* error by str_toks that calls str_room(1) */
3184 } else {
3185 memcpy(&strpool[poolptr], buf, len);
3186 poolptr += len;
3189 /* else { errno contains error code } */
3191 xfree(file_name);
3194 void getfiledump(integer s, int offset, int length)
3196 FILE *f;
3197 int read, i;
3198 poolpointer data_ptr;
3199 poolpointer data_end;
3200 char *file_name;
3202 if (length == 0) {
3203 /* empty result string */
3204 return;
3207 if (poolptr + 2 * length + 1 >= poolsize) {
3208 /* no place for result */
3209 poolptr = poolsize;
3210 /* error by str_toks that calls str_room(1) */
3211 return;
3214 file_name = kpse_find_tex(makecfilename(s));
3215 if (file_name == NULL) {
3216 return; /* empty string */
3219 /* read file data */
3220 f = fopen(file_name, FOPEN_RBIN_MODE);
3221 if (f == NULL) {
3222 xfree(file_name);
3223 return;
3225 recorder_record_input(file_name);
3226 if (fseek(f, offset, SEEK_SET) != 0) {
3227 xfree(file_name);
3228 return;
3230 /* there is enough space in the string pool, the read
3231 data are put in the upper half of the result, thus
3232 the conversion to hex can be done without overwriting
3233 unconverted bytes. */
3234 data_ptr = poolptr + length;
3235 read = fread(&strpool[data_ptr], sizeof(char), length, f);
3236 fclose(f);
3238 /* convert to hex */
3239 data_end = data_ptr + read;
3240 for (; data_ptr < data_end; data_ptr++) {
3241 i = snprintf((char *) &strpool[poolptr], 3,
3242 "%.2X", (unsigned int) strpool[data_ptr]);
3243 check_nprintf(i, 3);
3244 poolptr += i;
3246 xfree(file_name);
3248 #endif /* not XeTeX */
3250 /* Converts any given string in into an allowed PDF string which is
3251 * hexadecimal encoded;
3252 * sizeof(out) should be at least lin*2+1.
3254 void convertStringToHexString(const char *in, char *out, int lin)
3256 int i, j, k;
3257 char buf[3];
3258 j = 0;
3259 for (i = 0; i < lin; i++) {
3260 k = snprintf(buf, sizeof(buf),
3261 "%02X", (unsigned int) (unsigned char) in[i]);
3262 check_nprintf(k, sizeof(buf));
3263 out[j++] = buf[0];
3264 out[j++] = buf[1];
3266 out[j] = '\0';
3269 #define DIGEST_SIZE 16
3270 #define FILE_BUF_SIZE 1024
3272 void getmd5sum(strnumber s, boolean file)
3274 md5_state_t state;
3275 md5_byte_t digest[DIGEST_SIZE];
3276 char outbuf[2 * DIGEST_SIZE + 1];
3277 int len = 2 * DIGEST_SIZE;
3278 #if defined(XeTeX)
3279 char *xname;
3280 int i;
3281 #endif
3283 if (file) {
3284 char file_buf[FILE_BUF_SIZE];
3285 int read = 0;
3286 FILE *f;
3287 char *file_name;
3289 #if defined(XeTeX)
3290 xname = gettexstring (s);
3291 file_name = kpse_find_tex (xname);
3292 xfree (xname);
3293 #else
3294 file_name = kpse_find_tex(makecfilename(s));
3295 #endif
3296 if (file_name == NULL) {
3297 return; /* empty string */
3299 /* in case of error the empty string is returned,
3300 no need for xfopen that aborts on error.
3302 f = fopen(file_name, FOPEN_RBIN_MODE);
3303 if (f == NULL) {
3304 xfree(file_name);
3305 return;
3307 recorder_record_input(file_name);
3308 md5_init(&state);
3309 while ((read = fread(&file_buf, sizeof(char), FILE_BUF_SIZE, f)) > 0) {
3310 md5_append(&state, (const md5_byte_t *) file_buf, read);
3312 md5_finish(&state, digest);
3313 fclose(f);
3315 xfree(file_name);
3316 } else {
3317 /* s contains the data */
3318 md5_init(&state);
3319 #if defined(XeTeX)
3320 xname = gettexstring (s);
3321 md5_append(&state,
3322 (md5_byte_t *) xname,
3323 strlen (xname));
3324 xfree (xname);
3325 #else
3326 md5_append(&state,
3327 (md5_byte_t *) &strpool[strstart[s]],
3328 strstart[s + 1] - strstart[s]);
3329 #endif
3330 md5_finish(&state, digest);
3333 if (poolptr + len >= poolsize) {
3334 /* error by str_toks that calls str_room(1) */
3335 return;
3337 convertStringToHexString((char *) digest, outbuf, DIGEST_SIZE);
3338 #if defined(XeTeX)
3339 for (i = 0; i < 2 * DIGEST_SIZE; i++)
3340 strpool[poolptr++] = (uint16_t)outbuf[i];
3341 #else
3342 memcpy(&strpool[poolptr], outbuf, len);
3343 poolptr += len;
3344 #endif
3347 #endif /* pdfTeX or e-pTeX or e-upTeX or XeTeX */
3348 #endif /* TeX */
3350 /* Metafont/MetaPost fraction routines. Replaced either by assembler or C.
3351 The assembler syntax doesn't work on Solaris/x86. */
3352 #ifndef TeX
3353 #if defined (__sun__) || defined (__cplusplus)
3354 #define NO_MF_ASM
3355 #endif
3356 /* The assembler code is not PIC safe on i?86 so use C code. */
3357 #if defined (__PIC__) && defined (__i386__)
3358 #define NO_MF_ASM
3359 #endif
3360 #if defined(WIN32) && !defined(NO_MF_ASM) && !defined(__MINGW32__)
3361 #include "lib/mfmpw32.c"
3362 #elif defined (__i386__) && defined (__GNUC__) && !defined (NO_MF_ASM)
3363 #include "lib/mfmpi386.asm"
3364 #else
3365 /* Replace fixed-point fraction routines from mf.web and mp.web with
3366 Hobby's floating-point C code. */
3368 /****************************************************************
3369 Copyright 1990 - 1995 by AT&T Bell Laboratories.
3371 Permission to use, copy, modify, and distribute this software
3372 and its documentation for any purpose and without fee is hereby
3373 granted, provided that the above copyright notice appear in all
3374 copies and that both that the copyright notice and this
3375 permission notice and warranty disclaimer appear in supporting
3376 documentation, and that the names of AT&T Bell Laboratories or
3377 any of its entities not be used in advertising or publicity
3378 pertaining to distribution of the software without specific,
3379 written prior permission.
3381 AT&T disclaims all warranties with regard to this software,
3382 including all implied warranties of merchantability and fitness.
3383 In no event shall AT&T be liable for any special, indirect or
3384 consequential damages or any damages whatsoever resulting from
3385 loss of use, data or profits, whether in an action of contract,
3386 negligence or other tortious action, arising out of or in
3387 connection with the use or performance of this software.
3388 ****************************************************************/
3390 /**********************************************************
3391 The following is by John Hobby
3392 **********************************************************/
3394 #ifndef FIXPT
3396 /* These replacements for takefraction, makefraction, takescaled, makescaled
3397 run about 3 to 11 times faster than the standard versions on modern machines
3398 that have fast hardware for double-precision floating point. They should
3399 produce approximately correct results on all machines and agree exactly
3400 with the standard versions on machines that satisfy the following conditions:
3401 1. Doubles must have at least 46 mantissa bits; i.e., numbers expressible
3402 as n*2^k with abs(n)<2^46 should be representable.
3403 2. The following should hold for addition, subtraction, and multiplcation but
3404 not necessarily for division:
3405 A. If the true answer is between two representable numbers, the computed
3406 answer must be one of them.
3407 B. When the true answer is representable, this must be the computed result.
3408 3. Dividing one double by another should always produce a relative error of
3409 at most one part in 2^46. (This is why the mantissa requirement is
3410 46 bits instead of 45 bits.)
3411 3. In the absence of overflow, double-to-integer conversion should truncate
3412 toward zero and do this in an exact fashion.
3413 4. Integer-to-double convesion should produce exact results.
3414 5. Dividing one power of two by another should yield an exact result.
3415 6. ASCII to double conversion should be exact for integer values.
3416 7. Integer arithmetic must be done in the two's-complement system.
3418 #define ELGORDO 0x7fffffff
3419 #define TWEXP31 2147483648.0
3420 #define TWEXP28 268435456.0
3421 #define TWEXP16 65536.0
3422 #define TWEXP_16 (1.0/65536.0)
3423 #define TWEXP_28 (1.0/268435456.0)
3425 integer
3426 ztakefraction (integer p, integer q) /* Approximate p*q/2^28 */
3427 { register double d;
3428 register integer i;
3429 d = (double)p * (double)q * TWEXP_28;
3430 if ((p^q) >= 0) {
3431 d += 0.5;
3432 if (d>=TWEXP31) {
3433 if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
3434 aritherror = true;
3435 return ELGORDO;
3437 i = (integer) d;
3438 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
3439 } else {
3440 d -= 0.5;
3441 if (d<= -TWEXP31) {
3442 if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
3443 aritherror = true;
3444 return -ELGORDO;
3446 i = (integer) d;
3447 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
3449 return i;
3452 integer
3453 ztakescaled (integer p, integer q) /* Approximate p*q/2^16 */
3454 { register double d;
3455 register integer i;
3456 d = (double)p * (double)q * TWEXP_16;
3457 if ((p^q) >= 0) {
3458 d += 0.5;
3459 if (d>=TWEXP31) {
3460 if (d!=TWEXP31 || (((p&077777)*(q&077777))&040000)==0)
3461 aritherror = true;
3462 return ELGORDO;
3464 i = (integer) d;
3465 if (d==i && (((p&077777)*(q&077777))&040000)!=0) --i;
3466 } else {
3467 d -= 0.5;
3468 if (d<= -TWEXP31) {
3469 if (d!= -TWEXP31 || ((-(p&077777)*(q&077777))&040000)==0)
3470 aritherror = true;
3471 return -ELGORDO;
3473 i = (integer) d;
3474 if (d==i && ((-(p&077777)*(q&077777))&040000)!=0) ++i;
3476 return i;
3479 /* Note that d cannot exactly equal TWEXP31 when the overflow test is made
3480 because the exact value of p/q cannot be strictly between (2^31-1)/2^28
3481 and 8/1. No pair of integers less than 2^31 has such a ratio.
3483 integer
3484 zmakefraction (integer p, integer q) /* Approximate 2^28*p/q */
3485 { register double d;
3486 register integer i;
3487 #ifdef DEBUG
3488 if (q==0) confusion(47);
3489 #endif /* DEBUG */
3490 d = TWEXP28 * (double)p /(double)q;
3491 if ((p^q) >= 0) {
3492 d += 0.5;
3493 if (d>=TWEXP31) {aritherror=true; return ELGORDO;}
3494 i = (integer) d;
3495 if (d==i && ( ((q>0 ? -q : q)&077777)
3496 * (((i&037777)<<1)-1) & 04000)!=0) --i;
3497 } else {
3498 d -= 0.5;
3499 if (d<= -TWEXP31) {aritherror=true; return -ELGORDO;}
3500 i = (integer) d;
3501 if (d==i && ( ((q>0 ? q : -q)&077777)
3502 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
3504 return i;
3507 /* Note that d cannot exactly equal TWEXP31 when the overflow test is made
3508 because the exact value of p/q cannot be strictly between (2^31-1)/2^16
3509 and 2^15/1. No pair of integers less than 2^31 has such a ratio.
3511 integer
3512 zmakescaled (integer p, integer q) /* Approximate 2^16*p/q */
3513 { register double d;
3514 register integer i;
3515 #ifdef DEBUG
3516 if (q==0) confusion(47);
3517 #endif /* DEBUG */
3518 d = TWEXP16 * (double)p /(double)q;
3519 if ((p^q) >= 0) {
3520 d += 0.5;
3521 if (d>=TWEXP31) {aritherror=true; return ELGORDO;}
3522 i = (integer) d;
3523 if (d==i && ( ((q>0 ? -q : q)&077777)
3524 * (((i&037777)<<1)-1) & 04000)!=0) --i;
3525 } else {
3526 d -= 0.5;
3527 if (d<= -TWEXP31) {aritherror=true; return -ELGORDO;}
3528 i = (integer) d;
3529 if (d==i && ( ((q>0 ? q : -q)&077777)
3530 * (((i&037777)<<1)+1) & 04000)!=0) ++i;
3532 return i;
3535 #endif /* not FIXPT */
3536 #endif /* not assembler */
3537 #endif /* not TeX, i.e., MF */
3539 #ifdef MF
3540 /* On-line display routines for Metafont. Here we use a dispatch table
3541 indexed by the MFTERM or TERM environment variable to select the
3542 graphics routines appropriate to the user's terminal. stdout must be
3543 connected to a terminal for us to do any graphics. */
3545 #ifdef MFNOWIN
3546 #undef AMIGAWIN
3547 #undef EPSFWIN
3548 #undef HP2627WIN
3549 #undef MFTALKWIN
3550 #undef NEXTWIN
3551 #undef REGISWIN
3552 #undef SUNWIN
3553 #undef TEKTRONIXWIN
3554 #undef UNITERMWIN
3555 #undef WIN32WIN
3556 #undef X11WIN
3557 #endif
3559 /* Prototypes for Metafont display routines: mf_XXX_initscreen,
3560 mf_XXX_updatescreen, mf_XXX_blankrectangle, and mf_XXX_paintrow. */
3561 #include <window/mfdisplay.h>
3563 /* This variable, `mfwsw', contains the dispatch tables for each
3564 terminal. We map the Pascal calls to the routines `init_screen',
3565 `update_screen', `blank_rectangle', and `paint_row' into the
3566 appropriate entry point for the specific terminal that MF is being
3567 run on. */
3569 struct mfwin_sw
3571 const char *mfwsw_type; /* Name of terminal a la TERMCAP. */
3572 int (*mfwsw_initscreen) (void);
3573 void (*mfwsw_updatescrn) (void);
3574 void (*mfwsw_blankrect) (screencol, screencol, screenrow, screenrow);
3575 void (*mfwsw_paintrow) (screenrow, pixelcolor, transspec, screencol);
3576 } mfwsw[] =
3578 #ifdef AMIGAWIN
3579 { "amiterm", mf_amiga_initscreen, mf_amiga_updatescreen,
3580 mf_amiga_blankrectangle, mf_amiga_paintrow },
3581 #endif
3582 #ifdef EPSFWIN
3583 { "epsf", mf_epsf_initscreen, mf_epsf_updatescreen,
3584 mf_epsf_blankrectangle, mf_epsf_paintrow },
3585 #endif
3586 #ifdef HP2627WIN
3587 { "hp2627", mf_hp2627_initscreen, mf_hp2627_updatescreen,
3588 mf_hp2627_blankrectangle, mf_hp2627_paintrow },
3589 #endif
3590 #ifdef MFTALKWIN
3591 { "mftalk", mf_mftalk_initscreen, mf_mftalk_updatescreen,
3592 mf_mftalk_blankrectangle, mf_mftalk_paintrow },
3593 #endif
3594 #ifdef NEXTWIN
3595 { "next", mf_next_initscreen, mf_next_updatescreen,
3596 mf_next_blankrectangle, mf_next_paintrow },
3597 #endif
3598 #ifdef REGISWIN
3599 { "regis", mf_regis_initscreen, mf_regis_updatescreen,
3600 mf_regis_blankrectangle, mf_regis_paintrow },
3601 #endif
3602 #ifdef SUNWIN
3603 { "sun", mf_sun_initscreen, mf_sun_updatescreen,
3604 mf_sun_blankrectangle, mf_sun_paintrow },
3605 #endif
3606 #ifdef TEKTRONIXWIN
3607 { "tek", mf_tektronix_initscreen, mf_tektronix_updatescreen,
3608 mf_tektronix_blankrectangle, mf_tektronix_paintrow },
3609 #endif
3610 #ifdef UNITERMWIN
3611 { "uniterm", mf_uniterm_initscreen, mf_uniterm_updatescreen,
3612 mf_uniterm_blankrectangle, mf_uniterm_paintrow },
3613 #endif
3614 #ifdef WIN32WIN
3615 { "win32term", mf_win32_initscreen, mf_win32_updatescreen,
3616 mf_win32_blankrectangle, mf_win32_paintrow },
3617 #endif
3618 #ifdef X11WIN
3619 { "xterm", mf_x11_initscreen, mf_x11_updatescreen,
3620 mf_x11_blankrectangle, mf_x11_paintrow },
3621 #endif
3623 /* Always support this. */
3624 { "trap", mf_trap_initscreen, mf_trap_updatescreen,
3625 mf_trap_blankrectangle, mf_trap_paintrow },
3627 /* Finally, we must have an entry with a terminal type of NULL. */
3628 { NULL, NULL, NULL, NULL, NULL }
3630 }; /* End of the array initialization. */
3633 /* This is a pointer to the mfwsw[] entry that we find. */
3634 static struct mfwin_sw *mfwp;
3637 /* The following are routines that just jump to the correct
3638 terminal-specific graphics code. If none of the routines in the
3639 dispatch table exist, or they fail, we produce trap-compatible
3640 output, i.e., the same words and punctuation that the unchanged
3641 mf.web would produce. */
3644 /* This returns true if we can do window operations, else false. */
3646 boolean
3647 initscreen (void)
3649 int retval;
3650 /* If MFTERM is set, use it. */
3651 const_string tty_type = kpse_var_value ("MFTERM");
3653 if (tty_type == NULL)
3655 #if defined (AMIGA)
3656 tty_type = "amiterm";
3657 #elif defined (WIN32)
3658 tty_type = "win32term";
3659 #elif defined (OS2) || defined (__DJGPP__) /* not AMIGA nor WIN32 */
3660 tty_type = "mftalk";
3661 #else /* not (OS2 or WIN32 or __DJGPP__ or AMIGA) */
3662 /* If DISPLAY is set, we are X11; otherwise, who knows. */
3663 boolean have_display = getenv ("DISPLAY") != NULL;
3664 tty_type = have_display ? "xterm" : getenv ("TERM");
3666 /* If we don't know what kind of terminal this is, or if Metafont
3667 isn't being run interactively, don't do any online output. */
3668 if (tty_type == NULL
3669 || (!STREQ (tty_type, "trap") && !isatty (fileno (stdout))))
3670 return 0;
3671 #endif /* not (OS2 or WIN32 or __DJGPP__ or AMIGA) */
3674 /* Test each of the terminals given in `mfwsw' against the terminal
3675 type, and take the first one that matches, or if the user is running
3676 under Emacs, the first one. */
3677 for (mfwp = mfwsw; mfwp->mfwsw_type != NULL; mfwp++) {
3678 if (!strncmp (mfwp->mfwsw_type, tty_type, strlen (mfwp->mfwsw_type))
3679 || STREQ (tty_type, "emacs")) {
3680 if (mfwp->mfwsw_initscreen) {
3681 retval = (*mfwp->mfwsw_initscreen) ();
3682 #ifdef WIN32
3683 Sleep(1000); /* Wait for opening a window */
3684 #endif
3685 return retval;
3687 else {
3688 fprintf (stderr, "mf: Couldn't initialize online display for `%s'.\n",
3689 tty_type);
3690 break;
3695 /* The current terminal type wasn't found in any of the entries, or
3696 initalization failed, so silently give up, assuming that the user
3697 isn't on a terminal that supports graphic output. */
3698 return 0;
3702 /* Make sure everything is visible. */
3704 void
3705 updatescreen (void)
3707 if (mfwp->mfwsw_updatescrn)
3708 (*mfwp->mfwsw_updatescrn) ();
3712 /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
3713 the background color. */
3715 void
3716 blankrectangle (screencol left, screencol right,
3717 screenrow top, screenrow bottom)
3719 if (mfwp->mfwsw_blankrect)
3720 (*mfwp->mfwsw_blankrect) (left, right, top, bottom);
3724 /* This paints ROW, starting with the color INIT_COLOR.
3725 TRANSITION_VECTOR then specifies the length of the run; then we
3726 switch colors. This goes on for VECTOR_SIZE transitions. */
3728 void
3729 paintrow (screenrow row, pixelcolor init_color,
3730 transspec transition_vector, screencol vector_size)
3732 if (mfwp->mfwsw_paintrow)
3733 (*mfwp->mfwsw_paintrow) (row, init_color, transition_vector, vector_size);
3735 #endif /* MF */