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