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