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