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
6 This file is public domain. */
8 /* This file is included from, e.g., texextra,c after
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
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>
22 #include <kpathsea/concatn.h>
25 #if defined (HAVE_SYS_TIME_H)
27 #elif defined (HAVE_SYS_TIMEB_H)
28 #include <sys/timeb.h>
30 #include <time.h> /* For `struct tm'. Moved here for Visual Studio 2005. */
36 #include <signal.h> /* Catch interrupts. */
38 #include <texmfmp-help.h>
40 /* {tex,mf}d.h defines TeX, MF, INI, and other such symbols.
41 Unfortunately there's no way to get the banner into this code, so
42 just repeat the text. */
43 /* We also define predicates, e.g., IS_eTeX for all e-TeX like engines, so
44 the rest of this file can remain unchanged when adding a new engine. */
48 #include <xetexdir/xetexextra.h>
51 #include <etexdir/etexextra.h>
52 #elif defined (pdfTeX)
54 #include <pdftexdir/pdftexextra.h>
55 #include <pdftexdir/ptexlib.h>
58 #include <alephdir/alephextra.h>
61 #include <ptexdir/ptexextra.h>
65 #include <eptexdir/eptexextra.h>
69 #include <uptexdir/uptexextra.h>
70 #elif defined (eupTeX)
74 #include <euptexdir/euptexextra.h>
76 #define BANNER "This is TeX, Version 3.14159265"
77 #define COPYRIGHT_HOLDER "D.E. Knuth"
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"
89 #define edit_var "TEXEDIT"
93 #include <mfluadir/mfluaextra.h>
94 #elif defined(MFLuaJIT)
95 #include <mfluajitdir/mfluajitextra.h>
97 #define BANNER "This is Metafont, Version 2.7182818"
98 #define COPYRIGHT_HOLDER "D.E. Knuth"
100 #define PROGRAM_HELP MFHELP
101 #define BUG_ADDRESS "tex-k@tug.org"
102 #define DUMP_VAR MFbasedefault
103 #define DUMP_LENGTH_VAR basedefaultlength
104 #define DUMP_OPTION "base"
106 #define DUMP_EXT ".bas"
108 #define DUMP_EXT ".base"
110 #define INPUT_FORMAT kpse_mf_format
111 #define INI_PROGRAM "inimf"
112 #define VIR_PROGRAM "virmf"
114 #define edit_var "MFEDIT"
117 #if !defined(IS_eTeX)
120 #if !defined(IS_pTeX)
123 #if !defined(IS_upTeX)
127 #if defined(__SyncTeX__)
129 SyncTeX file name should be full path in the case where
130 --output-directory option is given.
131 Borrowed from LuaTeX.
133 char *generic_synctex_get_current_name (void)
136 if (!fullnameoffile
) {
140 if (kpse_absolute_p(fullnameoffile
, false)) {
141 return xstrdup(fullnameoffile
);
144 ret
= concat3(pwdbuf
, DIR_SEP_STRING
, fullnameoffile
);
156 #if defined(TeX) || (defined(MF) && defined(WIN32))
160 return (c
== ' ' || c
== '\t');
162 #endif /* TeX || (MF && WIN32) */
168 If shellenabledp == 0, all shell escapes are forbidden.
169 If (shellenabledp == 1 && restrictedshell == 0), any command
170 is allowed for a shell escape.
171 If (shellenabledp == 1 && restrictedshell == 1), only commands
172 given in the configuration file as
173 shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun,...
174 (no spaces between commands) in texmf.cnf are allowed for a shell
175 escape in a restricted form: command name and arguments should be
176 separated by a white space. The first word should be a command
177 name. The quotation character for an argument with spaces,
178 including a pathname, should be ". ' should not be used.
180 Internally, all arguments are quoted by ' (Unix) or " (Windows)
181 before calling the system() function in order to forbid execution
182 of any embedded command.
184 If the --shell-escape option is given, we set
185 shellenabledp = 1 and restrictedshell = 0, i.e., any command is allowed.
186 If the --shell-restricted option is given, we set
187 shellenabledp = 1 and restrictedshell = 1, i.e., only given cmds allowed.
188 If the --no-shell-escape option is given, we set
189 shellenabledp = -1 (and restrictedshell is irrelevant).
190 If none of these option are given, there are three cases:
191 (1) In the case where
195 it becomes shellenabledp = 1 and restrictedshell = 0,
196 that is, any command is allowed.
197 (2) In the case where
199 it becomes shellenabledp = 1 and restrictedshell = 1,
200 that is, restricted shell escape is allowed.
201 (3) In all other cases, shellenabledp = 0, that is, shell
202 escape is forbidden. The value of restrictedshell is
203 irrelevant if shellenabledp == 0.
206 /* cmdlist is a list of allowed commands which are given like this:
207 shell_escape_commands = kpsewhich,ebb,extractbb,mpost,metafun
210 static char **cmdlist
= NULL
;
213 mk_shellcmdlist (char *v
)
222 /* analyze the variable shell_escape_commands = foo,bar,...
223 spaces before and after (,) are not allowed. */
225 while ((r
= strchr (q
, ',')) != 0) {
231 cmdlist
= xmalloc (n
* sizeof (char *));
234 while ((r
= strchr (q
, ',')) != 0) {
245 init_shell_escape (void)
247 if (shellenabledp
< 0) { /* --no-shell-escape on cmd line */
251 if (shellenabledp
== 0) { /* no shell options on cmd line, check cnf */
252 char *v1
= kpse_var_value ("shell_escape");
254 if (*v1
== 't' || *v1
== 'y' || *v1
== '1') {
256 } else if (*v1
== 'p') {
264 /* If shell escapes are restricted, get allowed cmds from cnf. */
265 if (shellenabledp
&& restrictedshell
== 1) {
266 char *v2
= kpse_var_value ("shell_escape_commands");
268 mk_shellcmdlist (v2
);
284 char_needs_quote (int c
)
286 /* special characters of cmd.exe */
288 return (c
== '&' || c
== '|' || c
== '%' || c
== '<' ||
289 c
== '>' || c
== ';' || c
== ',' || c
== '(' ||
296 -1 : invalid quotation of an argument
297 0 : command is not allowed
298 2 : restricted shell escape, CMD is allowed.
300 We set *SAFECMD to a safely-quoted version of *CMD; this is what
301 should get executed. And we set CMDNAME to its first word; this is
302 what is checked against the shell_escape_commands list. */
305 shell_cmd_is_allowed (const char *cmd
, char **safecmd
, char **cmdname
)
314 /* pre == 1 means that the previous character is a white space
315 pre == 0 means that the previous character is not a white space */
316 buf
= xmalloc (strlen (cmd
) + 1);
322 while (!Isspace(*d
) && *d
)
326 /* *cmdname is the first word of the command line. For example,
327 *cmdname == "kpsewhich" for
328 \write18{kpsewhich --progname=dvipdfm --format="other text files" config}
330 *cmdname
= xstrdup (c
);
333 /* Is *cmdname listed in a texmf.cnf vriable as
334 shell_escape_commands = foo,bar,... ? */
338 if (strcmp (*p
, *cmdname
) == 0) {
339 /* *cmdname is found in the list, so restricted shell escape
349 for (s
= cmd
; *s
; s
++) {
354 /* allocate enough memory (too much?) */
356 *safecmd
= xmalloc (2 * strlen (cmd
) + 3 + 2 * spaces
);
358 *safecmd
= xmalloc (strlen (cmd
) + 3 + 2 * spaces
);
361 /* make a safe command line *safecmd */
366 while (!Isspace (*s
) && *s
)
371 /* Quotation given by a user. " should always be used; we
372 transform it below. If ' is used, simply immediately
373 return a quotation error. */
379 /* All arguments are quoted as 'foo' (Unix) or "foo" (Windows)
380 before calling system(). Therefore closing QUOTE is necessary
381 if the previous character is not a white space.
383 --format="other text files" becomes
384 '--format=''other text files' (Unix)
385 "--format"="other text files" (Windows) */
400 /* output the quotation mark for the quoted argument */
405 /* Illegal use of ', or closing quotation mark is missing */
406 if (*s
== '\'' || *s
== '\0')
410 The following in WIN32 may not be necessary, because
411 all arguments are quoted.
414 if (char_needs_quote (*s
))
421 /* Closing quotation mark will be output afterwards, so
422 we do nothing here */
425 /* The character after the closing quotation mark
426 should be a white space or NULL */
427 if (!Isspace (*s
) && *s
)
430 /* Beginning of a usual argument */
431 } else if (pre
== 1 && !Isspace (*s
)) {
436 The following in WIN32 may not be necessary, because
437 all arguments are quoted.
440 if (char_needs_quote (*s
))
445 /* Ending of a usual argument */
447 } else if (pre
== 0 && Isspace (*s
)) {
449 /* Closing quotation mark */
453 /* Copy a character from cmd to *safecmd. */
456 The following in WIN32 may not be necessary, because
457 all arguments are quoted.
460 if (char_needs_quote (*s
))
467 /* End of the command line */
476 if (strlen (p
) > 2 && p
[1] == ':' && !IS_DIR_SEP (p
[2])) {
477 q
= xmalloc (strlen (p
) + 2);
485 } else if (!IS_DIR_SEP (p
[0]) && !(p
[1] == ':' && IS_DIR_SEP (p
[2]))) {
486 p
= kpse_var_value ("SELFAUTOLOC");
489 while (*r
&& !Isspace(*r
))
492 q
= concatn ("\"", p
, "/", *safecmd
, "\"", NULL
);
496 while (*r
&& Isspace(*r
))
499 q
= concatn ("\"", p
, "/", *safecmd
, "\" ", r
, NULL
);
501 q
= concatn ("\"", p
, "/", *safecmd
, "\"", NULL
);
515 /* We should only be called with shellenabledp == 1.
517 -1 if a quotation syntax error.
518 0 if CMD is not allowed; given shellenabledp==1, this is because
519 shell escapes are restricted and CMD is not allowed.
520 1 if shell escapes are not restricted, hence any command is allowed.
521 2 if shell escapes are restricted and CMD is allowed (possibly after
526 #define system fsyscp_system
529 #define popen fsyscp_popen
530 #endif /* ENABLE_PIPES */
534 runsystem (const char *cmd
)
537 char *safecmd
= NULL
;
538 char *cmdname
= NULL
;
541 if (shellenabledp
<= 0) {
545 /* If restrictedshell == 0, any command is allowed. */
546 if (restrictedshell
== 0)
549 allow
= shell_cmd_is_allowed (cmd
, &safecmd
, &cmdname
);
552 status
= system (cmd
);
554 status
= system (safecmd
);
556 /* Not really meaningful, but we have to manage the return value of system. */
558 fprintf(stderr
,"system returned with code %d\n", status
);
570 /* Like runsystem(), the runpopen() function is called only when
571 shellenabledp == 1. Unlike runsystem(), here we write errors to
572 stderr, since we have nowhere better to use; and of course we return
573 a file handle (or NULL) instead of a status indicator. */
576 runpopen (char *cmd
, const char *mode
)
579 char *safecmd
= NULL
;
580 char *cmdname
= NULL
;
586 for (pp
= cmd
; *pp
; pp
++) {
587 if (*pp
== '\'') *pp
= '"';
591 /* If restrictedshell == 0, any command is allowed. */
592 if (restrictedshell
== 0)
595 allow
= shell_cmd_is_allowed (cmd
, &safecmd
, &cmdname
);
598 f
= popen (cmd
, mode
);
600 f
= popen (safecmd
, mode
);
601 else if (allow
== -1)
602 fprintf (stderr
, "\nrunpopen quotation error in command line: %s\n",
605 fprintf (stderr
, "\nrunpopen command not allowed: %s\n", cmdname
);
613 #endif /* ENABLE_PIPES */
615 /* The main program, etc. */
618 #include "xetexdir/XeTeX_ext.h"
621 /* What we were invoked as and with. */
625 /* If the user overrides argv[0] with -progname. */
626 static const_string user_progname
;
628 /* The C version of the jobname, if given. */
629 static const_string c_job_name
;
631 /* The filename for dynamic character translation, or NULL. */
632 string translate_filename
;
633 string default_translate_filename
;
636 /* Needed for --src-specials option. */
637 static char *last_source_name
;
638 static int last_lineno
;
639 static boolean srcspecialsoption
= false;
640 static void parse_src_specials_option (const_string
);
643 /* Parsing a first %&-line in the input file. */
644 static void parse_first_line (const_string
);
646 /* Parse option flags. */
647 static void parse_options (int, string
*);
649 /* Try to figure out if we have been given a filename. */
650 static string
get_input_file_name (void);
652 /* Get a true/false value for a variable from texmf.cnf and the environment. */
654 texmf_yesno(const_string var
)
656 string value
= kpse_var_value (var
);
657 return value
&& (*value
== 't' || *value
== 'y' || *value
== '1');
661 const char *ptexbanner
= BANNER
;
665 /* forward declaration */
667 normalize_quotes (const_string name
, const_string mesg
);
669 int srcspecialsp
= 0;
671 /* Support of 8.3-name convention. If *buffer == NULL, nothing is done. */
672 static void change_to_long_name (char **buffer
)
678 memset (outbuf
, 0, 260);
679 strcpy (inbuf
, *buffer
);
680 if (GetLongPathName (inbuf
, outbuf
, 260)) {
681 *buffer
= (char *)realloc(*buffer
, strlen(outbuf
) + 1);
682 strcpy (*buffer
, outbuf
);
688 /* The entry point: set up for reading the command line, which will
689 happen in `topenin', then call the main body. */
692 maininit (int ac
, string
*av
)
694 string main_input_file
;
695 #if (IS_upTeX || defined(XeTeX)) && defined(WIN32)
698 /* Save to pass along to topenin. */
702 /* Must be initialized before options are parsed. */
703 interactionoption
= 4;
705 /* Have things to record as we go along. */
706 kpse_record_input
= recorder_record_input
;
707 kpse_record_output
= recorder_record_output
;
709 #if defined(__SyncTeX__)
710 /* 0 means "disable Synchronize TeXnology".
711 synctexoption is a *.web variable.
712 We initialize it to a weird value to catch the -synctex command line flag.
713 At runtime, if synctexoption is not INT_MAX, then it contains the
714 command line option provided; otherwise, no such option was given
716 # define SYNCTEX_NO_OPTION INT_MAX
717 synctexoption
= SYNCTEX_NO_OPTION
;
721 kpse_set_program_name (argv
[0], NULL
);
724 #if defined(XeTeX) && defined(WIN32)
725 kpse_set_program_name (argv
[0], NULL
);
727 #if (IS_upTeX || defined(XeTeX)) && defined(WIN32)
728 enc
= kpse_var_value("command_line_encoding");
729 get_command_line_args_utf8(enc
, &argc
, &argv
);
732 /* If the user says --help or --version, we need to notice early. And
733 since we want the --ini option, have to do it before getting into
734 the web (which would read the base file, etc.). */
735 #if (IS_upTeX || defined(XeTeX)) && defined(WIN32)
736 parse_options (argc
, argv
);
738 parse_options (ac
, av
);
742 /* In pTeX and friends, texmf.cnf is not recorded in the case of --recorder,
743 because parse_options() is executed after the start of kpathsea due to
744 special initializations. Therefore we record texmf.cnf here. */
745 if (recorder_enabled
) {
746 string p
= kpse_find_file ("texmf.cnf", kpse_cnf_format
, 0);
748 recorder_record_input (p
);
752 /* If -progname was not specified, default to the dump name. */
754 user_progname
= dump_name
;
756 /* Do this early so we can inspect kpse_invocation_name and
757 kpse_program_name below, and because we have to do this before
758 any path searching. */
759 #if IS_pTeX || (defined(XeTeX) && defined(WIN32))
761 kpse_reset_program_name (user_progname
);
763 kpse_set_program_name (argv
[0], user_progname
);
768 /* If the program name is "mflua-nowin", then reset the name as "mflua". */
769 if (strncasecmp (kpse_invocation_name
, "mflua-nowin", 11) == 0)
770 kpse_reset_program_name ("mflua");
771 #elif defined(MFLuaJIT)
772 /* If the program name is "mfluajit-nowin", then reset the name as "mfluajit". */
773 if (strncasecmp (kpse_invocation_name
, "mfluajit-nowin", 14) == 0)
774 kpse_reset_program_name ("mfluajit");
776 /* If the program name is "mf-nowin", then reset the name as "mf". */
777 if (strncasecmp (kpse_invocation_name
, "mf-nowin", 8) == 0)
778 kpse_reset_program_name ("mf");
782 /* FIXME: gather engine names in a single spot. */
783 xputenv ("engine", TEXMFENGINENAME
);
785 /* Were we given a simple filename? */
786 main_input_file
= get_input_file_name();
789 if (main_input_file
== NULL
) {
796 if (name
&& name
[0] != '-' && name
[0] != '&' && name
[0] != '\\') {
797 if (strlen (name
) > 2 && isalpha (name
[0]) && name
[1] == ':' &&
800 for (pp
= name
; *pp
; pp
++) {
803 else if (*pp
== '\\')
808 name
= normalize_quotes(argv
[argc
-1], "argument");
809 main_input_file
= kpse_find_file(argv
[argc
-1], INPUT_FORMAT
, false);
811 change_to_long_name (&main_input_file
);
813 name
= normalize_quotes(main_input_file
, "argument");
817 name
= normalize_quotes(argv
[argc
-1], "argument");
818 quoted
= (name
[0] == '"');
820 /* Overwrite last quote and skip first quote. */
821 name
[strlen(name
)-1] = '\0';
824 main_input_file
= kpse_find_file(name
, INPUT_FORMAT
, false);
826 change_to_long_name (&main_input_file
);
828 /* Undo modifications */
829 name
[strlen(name
)] = '"';
834 name
= normalize_quotes(main_input_file
, "argument");
842 /* Second chance to activate file:line:error style messages, this
843 time from texmf.cnf. */
844 if (filelineerrorstylep
< 0) {
845 filelineerrorstylep
= 0;
846 } else if (!filelineerrorstylep
) {
847 filelineerrorstylep
= texmf_yesno ("file_line_error_style");
850 /* If no dump default yet, and we're not doing anything special on
851 this run, we may want to look at the first line of the main input
852 file for a %&<dumpname> specifier. */
853 if (parsefirstlinep
< 0) {
855 } else if (!parsefirstlinep
) {
856 parsefirstlinep
= texmf_yesno ("parse_first_line");
858 if (parsefirstlinep
&& (!dump_name
|| !translate_filename
)) {
859 parse_first_line (main_input_file
);
861 /* Check whether there still is no translate_filename known. If so,
862 use the default_translate_filename. */
863 /* FIXME: deprecated. */
864 if (!translate_filename
) {
865 translate_filename
= default_translate_filename
;
867 /* If we're preloaded, I guess everything is set up. I don't really
868 know any more, it's been so long since anyone preloaded. */
869 if (readyalready
!= 314159) {
870 /* The `ini_version' variable is declared/used in the change files. */
871 boolean virversion
= false;
872 if (FILESTRCASEEQ (kpse_program_name
, INI_PROGRAM
)) {
874 } else if (FILESTRCASEEQ (kpse_program_name
, VIR_PROGRAM
)) {
877 } else if (FILESTRCASEEQ (kpse_program_name
, "initex")) {
879 } else if (FILESTRCASEEQ (kpse_program_name
, "virtex")) {
882 } else if (FILESTRCASEEQ (kpse_program_name
, "mltex")) {
889 /* If called as *vir{mf,tex,mpost} use `plain'. Otherwise, use the
890 name we were invoked under. */
891 dump_name
= (virversion
? "plain" : kpse_program_name
);
896 /* Sanity check: -mltex, -enc, -etex only work in combination with -ini. */
900 fprintf(stderr
, "-mltex only works with -ini\n");
902 #if !defined(XeTeX) && !IS_pTeX
904 fprintf(stderr
, "-enc only works with -ini\n");
910 fprintf(stderr
, "-etex only works with -ini\n");
916 /* If we've set up the fmt/base default in any of the various ways
917 above, also set its length. */
919 const_string with_ext
= NULL
;
920 unsigned name_len
= strlen (dump_name
);
921 unsigned ext_len
= strlen (DUMP_EXT
);
923 /* Provide extension if not there already. */
924 if (name_len
> ext_len
925 && FILESTRCASEEQ (dump_name
+ name_len
- ext_len
, DUMP_EXT
)) {
926 with_ext
= dump_name
;
928 with_ext
= concat (dump_name
, DUMP_EXT
);
930 DUMP_VAR
= concat (" ", with_ext
); /* adjust array for Pascal */
931 DUMP_LENGTH_VAR
= strlen (DUMP_VAR
+ 1);
933 /* For dump_name to be NULL is a bug. */
937 /* Additional initializations. No particular reason for doing them
938 here instead of first thing in the change file; less symbols to
939 propagate through Webc, that's all. */
941 kpse_set_program_enabled (kpse_mf_format
, MAKE_TEX_MF_BY_DEFAULT
,
943 kpse_set_program_enabled (kpse_base_format
, MAKE_TEX_FMT_BY_DEFAULT
,
948 kpse_set_program_enabled (kpse_ocp_format
, MAKE_OMEGA_OCP_BY_DEFAULT
,
950 kpse_set_program_enabled (kpse_ofm_format
, MAKE_OMEGA_OFM_BY_DEFAULT
,
952 kpse_set_program_enabled (kpse_tfm_format
, false, kpse_src_compile
);
954 kpse_set_program_enabled (kpse_tfm_format
, MAKE_TEX_TFM_BY_DEFAULT
,
957 kpse_set_program_enabled (kpse_tex_format
, MAKE_TEX_TEX_BY_DEFAULT
,
959 kpse_set_program_enabled (kpse_fmt_format
, MAKE_TEX_FMT_BY_DEFAULT
,
962 init_shell_escape ();
964 if (!outputcomment
) {
965 outputcomment
= kpse_var_value ("output_comment");
970 /* The entry point: set up for reading the command line, which will
971 happen in `topenin', then call the main body. */
975 DLLPROC (int ac
, string
*av
)
977 main (int ac
, string
*av
)
981 _wildcard (&ac
, &av
);
982 _response (&ac
, &av
);
986 av
[0] = kpse_program_basename (av
[0]);
988 setmode(fileno(stdin
), _O_BINARY
);
996 if ((strlen(av
[ac
-1]) > 2) &&
997 isalpha(av
[ac
-1][0]) &&
998 (av
[ac
-1][1] == ':') &&
999 (av
[ac
-1][2] == '\\')) {
1000 for (pp
=av
[ac
-1]+2; *pp
; pp
++) {
1012 /* Call the real main program. */
1015 return EXIT_SUCCESS
;
1018 /* This is supposed to ``open the terminal for input'', but what we
1019 really do is copy command line arguments into TeX's or Metafont's
1020 buffer, so they can handle them. If nothing is available, or we've
1021 been called already (and hence, argc==0), we return with
1030 static UFILE termin_file
;
1032 termin
= &termin_file
;
1034 termin
->savedChar
= -1;
1035 termin
->skipNextLF
= 0;
1036 termin
->encodingMode
= UTF8
;
1037 termin
->conversionData
= 0;
1038 inputfile
[0] = termin
;
1042 buffer
[first
] = 0; /* In case there are no arguments. */
1044 if (optind
< argc
) { /* We have command line arguments. */
1046 for (i
= optind
; i
< argc
; i
++) {
1048 unsigned char *ptr
= (unsigned char *)&(argv
[i
][0]);
1049 /* need to interpret UTF8 from the command line */
1051 while ((rval
= *(ptr
++)) != 0) {
1052 UInt16 extraBytes
= bytesFromUTF8
[rval
];
1053 switch (extraBytes
) { /* note: code falls through cases! */
1054 case 5: rval
<<= 6; if (*ptr
) rval
+= *(ptr
++);
1055 case 4: rval
<<= 6; if (*ptr
) rval
+= *(ptr
++);
1056 case 3: rval
<<= 6; if (*ptr
) rval
+= *(ptr
++);
1057 case 2: rval
<<= 6; if (*ptr
) rval
+= *(ptr
++);
1058 case 1: rval
<<= 6; if (*ptr
) rval
+= *(ptr
++);
1061 rval
-= offsetsFromUTF8
[extraBytes
];
1065 char *ptr
= &(argv
[i
][0]);
1066 /* Don't use strcat, since in Aleph the buffer elements aren't
1069 buffer
[k
++] = *(ptr
++);
1074 argc
= 0; /* Don't do this again. */
1078 /* Find the end of the buffer. */
1079 for (last
= first
; buffer
[last
]; ++last
)
1082 /* Make `last' be one past the last non-blank character in `buffer'. */
1083 /* ??? The test for '\r' should not be necessary. */
1084 for (--last
; last
>= first
1085 && ISBLANK (buffer
[last
]) && buffer
[last
] != '\r'; --last
)
1089 /* One more time, this time converting to TeX's internal character
1091 #if !defined(Aleph) && !defined(XeTeX)
1092 for (i
= first
; i
< last
; i
++)
1093 buffer
[i
] = xord
[buffer
[i
]];
1097 /* IPC for TeX. By Tom Rokicki for the NeXT; it makes TeX ship out the
1098 DVI file in a pipe to TeXView so that the output can be displayed
1099 incrementally. Shamim Mohamed adapted it for Web2c. */
1100 #if defined (TeX) && defined (IPC)
1104 #include <winsock2.h>
1106 #include <sys/socket.h>
1108 #ifndef O_NONBLOCK /* POSIX */
1109 #ifdef O_NDELAY /* BSD */
1110 #define O_NONBLOCK O_NDELAY
1111 #elif defined(O_FNDELAY) /* NeXT */
1112 #define O_NONBLOCK O_FNDELAY
1114 what the fcntl
? cannot implement IPC without equivalent
for O_NONBLOCK
.
1116 #endif /* no O_NONBLOCK */
1120 # define IPC_AF AF_INET
1121 # ifndef IPC_LOCAL_HOST
1122 # define IPC_LOCAL_HOST "127.0.0.1"
1123 # define FIXED_PORT (unsigned short)4242
1126 # define IPC_AF AF_UNIX
1127 # ifndef IPC_PIPE_NAME /* $HOME is prepended to this. */
1128 # define IPC_PIPE_NAME "/.TeXview_Pipe"
1131 #ifndef IPC_SERVER_CMD /* Command to run to start the server. */
1133 # define IPC_SERVER_CMD "texview.exe"
1135 # define IPC_SERVER_CMD "open `which TeXview`"
1141 int namelength
; /* length of auxiliary data */
1142 int eof
; /* new eof for dvi file */
1143 #if 0 /* see usage of struct msg below */
1144 char more_data
[0]; /* where the rest of the stuff goes */
1148 static struct sockaddr
*ipc_addr
;
1149 static int ipc_addr_len
;
1152 ipc_make_name (void)
1154 if (ipc_addr_len
== 0) {
1156 unsigned long remote_addr
= inet_addr(IPC_LOCAL_HOST
);
1157 if (remote_addr
!= INADDR_NONE
) {
1158 struct sockaddr_in
*ipc_sin_addr
= xmalloc (sizeof (struct sockaddr_in
));
1159 ipc_sin_addr
->sin_family
= AF_INET
;
1160 ipc_sin_addr
->sin_addr
.s_addr
= remote_addr
;
1161 ipc_sin_addr
->sin_port
= htons (FIXED_PORT
);
1162 ipc_addr
= ((struct sockaddr
*) ipc_sin_addr
);
1163 ipc_addr_len
= sizeof(struct sockaddr_in
);
1166 string s
= getenv ("HOME");
1169 ipc_addr
= xmalloc (strlen (s
) + 40);
1170 ipc_addr
->sa_family
= 0;
1171 ipc_name
= ipc_addr
->sa_data
;
1172 strcpy (ipc_name
, s
);
1173 strcat (ipc_name
, IPC_PIPE_NAME
);
1174 ipc_addr_len
= strlen (ipc_name
) + 3;
1178 return ipc_addr_len
;
1181 static int sock
= -1;
1184 # define CLOSE_SOCKET(s) closesocket (s); WSACleanup ()
1186 # define CLOSE_SOCKET(s) close (s)
1196 ipc_open_out (void) {
1198 struct WSAData wsaData
;
1200 unsigned long mode
= 1;
1203 fputs ("tex: Opening socket for IPC output ...\n", stderr
);
1210 if ((nCode
= WSAStartup(MAKEWORD(1, 1), &wsaData
)) != 0) {
1211 fprintf(stderr
,"WSAStartup() returned error code %d.\n", nCode
);
1216 if (ipc_make_name () <= 0)
1219 sock
= socket (IPC_AF
, SOCK_STREAM
, 0);
1222 fprintf(stderr
, "tex: Socket handle is %d\n", sock
);
1224 fprintf(stderr
, "tex: Socket is invalid.\n");
1228 if (connect (sock
, ipc_addr
, ipc_addr_len
) != 0 ||
1230 ioctlsocket (sock
, FIONBIO
, &mode
) < 0
1232 fcntl (sock
, F_SETFL
, O_NONBLOCK
) < 0
1235 CLOSE_SOCKET (sock
);
1238 fputs ("tex: IPC socket cannot be connected.\n", stderr
);
1239 fputs ("tex: Socket is closed.\n", stderr
);
1244 fputs ("tex: Successfully opened IPC socket.\n", stderr
);
1250 ipc_close_out (void)
1253 fputs ("tex: Closing output socket ...\n", stderr
);
1255 if (ipc_is_open ()) {
1256 CLOSE_SOCKET (sock
);
1262 ipc_snd (int n
, int is_eof
, char *data
)
1267 char more_data
[1024];
1270 if (!ipc_is_open ()) {
1275 fprintf(stderr
, "%d\t%d\n", ourmsg
.msg
.namelength
, ourmsg
.msg
.eof
);
1276 fputs ("tex: Sending message to socket ...\n", stderr
);
1278 ourmsg
.msg
.namelength
= n
;
1279 ourmsg
.msg
.eof
= is_eof
;
1281 strcpy (ourmsg
.more_data
, data
);
1283 n
+= sizeof (struct msg
);
1285 fprintf(stderr
, "%d\t%d\n", ourmsg
.msg
.namelength
, ourmsg
.msg
.eof
);
1286 fputs ("tex: Writing to socket...\n", stderr
);
1289 if (send (sock
, (char *)&ourmsg
, n
, 0) != n
) {
1291 if (write (sock
, &ourmsg
, n
) != n
) {
1296 fputs ("tex: IPC message sent.\n", stderr
);
1300 /* This routine notifies the server if there is an eof, or the filename
1301 if a new DVI file is starting. This is the routine called by TeX.
1302 Aleph defines str_start(#) as str_start_ar[# - too_big_char], with
1303 too_big_char = biggest_char + 1 = 65536 (omstr.ch). */
1306 ipcpage (int is_eof
)
1308 static boolean begun
= false;
1313 string name
; /* Just the filename. */
1314 string cwd
= xgetcwd ();
1318 len
= strstart
[outputfilename
+ 1] - strstart
[outputfilename
];
1320 len
= strstartar
[outputfilename
+ 1 - 65536L] -
1321 strstartar
[outputfilename
- 65536L];
1323 name
= xmalloc (len
+ 1);
1325 strncpy (name
, (string
)&strpool
[strstart
[outputfilename
]], len
);
1329 for (i
=0; i
<len
; i
++)
1330 name
[i
] = strpool
[i
+strstartar
[outputfilename
- 65536L]];
1335 /* Have to pass whole filename to the other end, since it may have
1336 been started up and running as a daemon, e.g., as with the NeXT
1338 p
= concat3 (cwd
, DIR_SEP_STRING
, name
);
1344 for (q
= p
; *q
; q
++) {
1347 else if (IS_KANJI(q
))
1355 ipc_snd (len
, is_eof
, p
);
1360 #endif /* TeX && IPC */
1362 #if defined (TeX) || defined (MF)
1363 /* TCX and Aleph&Co get along like sparks and gunpowder. */
1364 #if !defined(Aleph) && !defined(XeTeX)
1366 /* Return the next number following START, setting POST to the following
1367 character, as in strtol. Issue a warning and return -1 if no number
1371 tcx_get_num (int upb
,
1372 unsigned line_count
,
1376 int num
= strtol (start
, post
, 0);
1377 assert (post
&& *post
);
1378 if (*post
== start
) {
1379 /* Could not get a number. If blank line, fine. Else complain. */
1381 while (*p
&& ISSPACE (*p
))
1384 fprintf (stderr
, "%s:%d: Expected numeric constant, not `%s'.\n",
1385 translate_filename
, line_count
, start
);
1387 } else if (num
< 0 || num
> upb
) {
1388 fprintf (stderr
, "%s:%d: Destination charcode %d <0 or >%d.\n",
1389 translate_filename
, line_count
, num
, upb
);
1396 /* Update the xchr, xord, and xprn arrays for TeX, allowing a
1397 translation table specified at runtime via an external file.
1398 Look for the character translation file FNAME along the same path as
1399 tex.pool. If no suffix in FNAME, use .tcx (don't bother trying to
1400 support extension-less names for these files). */
1402 /* FIXME: A new format ought to be introduced for these files. */
1407 string orig_filename
;
1408 if (!find_suffix (translate_filename
)) {
1409 translate_filename
= concat (translate_filename
, ".tcx");
1411 orig_filename
= translate_filename
;
1413 = kpse_find_file (translate_filename
, kpse_web2c_format
, true);
1414 if (translate_filename
) {
1416 unsigned line_count
= 0;
1417 FILE *translate_file
= xfopen (translate_filename
, FOPEN_R_MODE
);
1418 while ((line
= read_line (translate_file
))) {
1421 string comment_loc
= strchr (line
, '%');
1427 first
= tcx_get_num (255, line_count
, line
, &start2
);
1433 second
= tcx_get_num (255, line_count
, start2
, &start3
);
1435 /* I suppose we could check for nonempty junk following the
1436 "printable" code, but let's not bother. */
1439 /* If they mention a second code, make that the internal number. */
1440 xord
[first
] = second
;
1441 xchr
[second
] = first
;
1443 printable
= tcx_get_num (1, line_count
, start3
, &extra
);
1444 /* Not-a-number, may be a comment. */
1445 if (printable
== -1)
1447 /* Don't allow the 7bit ASCII set to become unprintable. */
1448 if (32 <= second
&& second
<= 126)
1451 second
= first
; /* else make internal the same as external */
1452 /* If they mention a charcode, call it printable. */
1456 xprn
[second
] = printable
;
1460 xfclose(translate_file
, translate_filename
);
1462 WARNING1 ("Could not open char translation file `%s'", orig_filename
);
1465 #endif /* !Aleph && !XeTeX */
1466 #endif /* TeX || MF [character translation] */
1468 #ifdef XeTeX /* XeTeX handles this differently, and allows odd quotes within names */
1470 normalize_quotes (const_string name
, const_string mesg
)
1473 boolean must_quote
= false;
1474 int len
= strlen(name
);
1475 /* Leave room for quotes and NUL. */
1479 for (q
= name
; *q
; q
++) {
1486 else if (*q
== '\"' || *q
== '\'') {
1488 if (quote_char
== 0)
1489 quote_char
= '\"' + '\'' - *q
;
1490 len
+= 2; /* this could sometimes add length we don't need */
1493 ret
= xmalloc(len
+ 1);
1496 if (quote_char
== 0)
1500 for (q
= name
; *q
; q
++) {
1501 if (*q
== quote_char
) {
1503 quote_char
= '\"' + '\'' - quote_char
;
1508 if (quote_char
!= 0)
1514 /* Normalize quoting of filename -- that is, only quote if there is a space,
1515 and always use the quote-name-quote style. */
1517 normalize_quotes (const_string name
, const_string mesg
)
1519 boolean quoted
= false;
1520 boolean must_quote
= (strchr(name
, ' ') != NULL
);
1521 /* Leave room for quotes and NUL. */
1522 string ret
= xmalloc(strlen(name
)+3);
1528 for (q
= name
; *q
; q
++) {
1538 fprintf(stderr
, "! Unbalanced quotes in %s %s\n", mesg
, name
);
1545 /* Getting the input filename. */
1547 get_input_file_name (void)
1549 string input_file_name
= NULL
;
1551 if (argv
[optind
] && argv
[optind
][0] != '&' && argv
[optind
][0] != '\\') {
1552 /* Not &format, not \input, so assume simple filename. */
1559 if (strlen (argv
[optind
]) > 2 && isalpha (argv
[optind
][0]) &&
1560 argv
[optind
][1] == ':' && argv
[optind
][2] == '\\') {
1562 for (pp
= argv
[optind
]; *pp
; pp
++) {
1565 else if (IS_KANJI(pp
))
1571 name
= normalize_quotes(argv
[optind
], "argument");
1573 input_file_name
= kpse_find_file(argv
[optind
], INPUT_FORMAT
, false);
1576 change_to_long_name (&input_file_name
);
1579 quoted
= (name
[0] == '"');
1581 /* Overwrite last quote and skip first quote. */
1582 name
[strlen(name
)-1] = '\0';
1585 input_file_name
= kpse_find_file(name
, INPUT_FORMAT
, false);
1588 change_to_long_name (&input_file_name
);
1591 /* Undo modifications */
1592 name
[strlen(name
)] = '"';
1597 if (!srcspecialsp
) {
1598 if (input_file_name
)
1599 name
= normalize_quotes (input_file_name
, "argument");
1602 argv
[optind
] = name
;
1604 return input_file_name
;
1607 /* Reading the options. */
1609 /* Test whether getopt found an option ``A''.
1610 Assumes the option index is in the variable `option_index', and the
1611 option table in a variable `long_options'. */
1612 #define ARGUMENT_IS(a) STREQ (long_options[option_index].name, a)
1614 /* SunOS cc can't initialize automatic structs, so make this static. */
1615 static struct option long_options
[]
1616 = { { DUMP_OPTION
, 1, 0, 0 },
1618 /* FIXME: Obsolete -- for backward compatibility only. */
1619 { "efmt", 1, 0, 0 },
1621 { "help", 0, 0, 0 },
1622 { "ini", 0, &iniversion
, 1 },
1623 { "interaction", 1, 0, 0 },
1624 { "halt-on-error", 0, &haltonerrorp
, 1 },
1625 { "kpathsea-debug", 1, 0, 0 },
1626 { "progname", 1, 0, 0 },
1627 { "version", 0, 0, 0 },
1628 { "recorder", 0, &recorder_enabled
, 1 },
1631 { "ipc", 0, &ipcon
, 1 },
1632 { "ipc-start", 0, &ipcon
, 2 },
1635 { "mltex", 0, &mltexp
, 1 },
1636 #if !defined(XeTeX) && !IS_pTeX
1637 { "enc", 0, &enctexp
, 1 },
1641 { "etex", 0, &etexp
, 1 },
1643 { "output-comment", 1, 0, 0 },
1645 { "draftmode", 0, 0, 0 },
1646 { "output-format", 1, 0, 0 },
1648 { "shell-escape", 0, &shellenabledp
, 1 },
1649 { "no-shell-escape", 0, &shellenabledp
, -1 },
1650 { "enable-write18", 0, &shellenabledp
, 1 },
1651 { "disable-write18", 0, &shellenabledp
, -1 },
1652 { "shell-restricted", 0, 0, 0 },
1653 { "debug-format", 0, &debugformatfile
, 1 },
1654 { "src-specials", 2, 0, 0 },
1655 #if defined(__SyncTeX__)
1656 /* Synchronization: just like "interaction" above */
1657 { "synctex", 1, 0, 0 },
1660 #if defined (TeX) || defined (MF)
1661 { "file-line-error-style", 0, &filelineerrorstylep
, 1 },
1662 { "no-file-line-error-style", 0, &filelineerrorstylep
, -1 },
1663 /* Shorter option names for the above. */
1664 { "file-line-error", 0, &filelineerrorstylep
, 1 },
1665 { "no-file-line-error", 0, &filelineerrorstylep
, -1 },
1666 { "jobname", 1, 0, 0 },
1667 { "output-directory", 1, 0, 0 },
1668 { "parse-first-line", 0, &parsefirstlinep
, 1 },
1669 { "no-parse-first-line", 0, &parsefirstlinep
, -1 },
1671 { "translate-file", 1, 0, 0 },
1672 { "default-translate-file", 1, 0, 0 },
1673 { "8bit", 0, &eightbitp
, 1 },
1676 { "no-pdf", 0, &nopdfoutput
, 1 },
1677 { "output-driver", 1, 0, 0 },
1678 { "papersize", 1, 0, 0 },
1680 { "mktex", 1, 0, 0 },
1681 { "no-mktex", 1, 0, 0 },
1682 #endif /* TeX or MF */
1685 { "sjis-terminal", 0, &sjisterminal
, 1 },
1686 { "guess-input-enc", 0, &infile_enc_auto
, 1 },
1687 { "no-guess-input-enc", 0, &infile_enc_auto
, 0 },
1689 { "kanji", 1, 0, 0 },
1690 { "kanji-internal", 1, 0, 0 },
1691 #endif /* IS_pTeX */
1695 parse_options (int argc
, string
*argv
)
1697 int g
; /* `getopt' return code. */
1701 g
= getopt_long_only (argc
, argv
, "+", long_options
, &option_index
);
1703 if (g
== -1) /* End of arguments, exit the loop. */
1706 if (g
== '?') { /* Unknown option. */
1707 /* FIXME: usage (argv[0]); replaced by continue. */
1711 assert (g
== 0); /* We have no short option names. */
1713 if (ARGUMENT_IS ("kpathsea-debug")) {
1714 kpathsea_debug
|= atoi (optarg
);
1717 } else if (ARGUMENT_IS ("papersize")) {
1719 } else if (ARGUMENT_IS ("output-driver")) {
1720 outputdriver
= optarg
;
1723 } else if (ARGUMENT_IS ("progname")) {
1724 user_progname
= optarg
;
1726 } else if (ARGUMENT_IS ("jobname")) {
1728 c_job_name
= optarg
;
1730 c_job_name
= normalize_quotes (optarg
, "jobname");
1733 } else if (ARGUMENT_IS (DUMP_OPTION
)) {
1738 /* FIXME: Obsolete -- for backward compatibility only. */
1739 } else if (ARGUMENT_IS ("efmt")) {
1744 } else if (ARGUMENT_IS ("output-directory")) {
1745 output_directory
= optarg
;
1748 } else if (ARGUMENT_IS ("output-comment")) {
1749 unsigned len
= strlen (optarg
);
1751 outputcomment
= optarg
;
1753 WARNING2 ("Comment truncated to 255 characters from %d. (%s)",
1755 outputcomment
= xmalloc (256);
1756 strncpy (outputcomment
, optarg
, 255);
1757 outputcomment
[255] = 0;
1761 } else if (ARGUMENT_IS ("ipc-start")) {
1763 /* Try to start up the other end if it's not already. */
1764 if (!ipc_is_open ()) {
1766 if (_spawnlp (_P_NOWAIT
, IPC_SERVER_CMD
, IPC_SERVER_CMD
, NULL
) != -1) {
1768 if (system (IPC_SERVER_CMD
) == 0) {
1771 for (i
= 0; i
< 20 && !ipc_is_open (); i
++) {
1773 Sleep (100); /* 2000ms is too long for a simple w32 example */
1783 } else if (ARGUMENT_IS ("shell-restricted")) {
1785 restrictedshell
= 1;
1787 } else if (ARGUMENT_IS ("src-specials")) {
1788 last_source_name
= xstrdup("");
1789 /* Option `--src" without any value means `auto' mode. */
1790 if (optarg
== NULL
) {
1791 insertsrcspecialeverypar
= true;
1792 insertsrcspecialauto
= true;
1793 srcspecialsoption
= true;
1794 srcspecialsp
= true;
1796 parse_src_specials_option(optarg
);
1800 } else if (ARGUMENT_IS ("output-format")) {
1801 pdfoutputoption
= 1;
1802 if (strcmp(optarg
, "dvi") == 0) {
1804 } else if (strcmp(optarg
, "pdf") == 0) {
1807 WARNING1 ("Ignoring unknown value `%s' for --output-format", optarg
);
1808 pdfoutputoption
= 0;
1810 } else if (ARGUMENT_IS ("draftmode")) {
1811 pdfdraftmodeoption
= 1;
1812 pdfdraftmodevalue
= 1;
1814 #if defined (TeX) || defined (MF)
1816 } else if (ARGUMENT_IS ("translate-file")) {
1817 translate_filename
= optarg
;
1818 } else if (ARGUMENT_IS ("default-translate-file")) {
1819 default_translate_filename
= optarg
;
1821 } else if (ARGUMENT_IS ("mktex")) {
1822 kpse_maketex_option (optarg
, true);
1823 } else if (ARGUMENT_IS ("no-mktex")) {
1824 kpse_maketex_option (optarg
, false);
1825 #endif /* TeX or MF */
1826 } else if (ARGUMENT_IS ("interaction")) {
1827 /* These numbers match @d's in *.ch */
1828 if (STREQ (optarg
, "batchmode")) {
1829 interactionoption
= 0;
1830 } else if (STREQ (optarg
, "nonstopmode")) {
1831 interactionoption
= 1;
1832 } else if (STREQ (optarg
, "scrollmode")) {
1833 interactionoption
= 2;
1834 } else if (STREQ (optarg
, "errorstopmode")) {
1835 interactionoption
= 3;
1837 WARNING1 ("Ignoring unknown argument `%s' to --interaction", optarg
);
1840 } else if (ARGUMENT_IS ("kanji")) {
1841 if (!set_enc_string (optarg
, NULL
)) {
1842 WARNING1 ("Ignoring unknown argument `%s' to --kanji", optarg
);
1844 } else if (ARGUMENT_IS ("kanji-internal")) {
1845 if (!set_enc_string (NULL
, optarg
)) {
1846 WARNING1 ("Ignoring unknown argument `%s' to --kanji-internal", optarg
);
1850 } else if (ARGUMENT_IS ("help")) {
1851 usagehelp (PROGRAM_HELP
, BUG_ADDRESS
);
1853 #if defined(__SyncTeX__)
1854 } else if (ARGUMENT_IS ("synctex")) {
1855 /* Synchronize TeXnology: catching the command line option as a long */
1856 synctexoption
= (int) strtol(optarg
, NULL
, 0);
1859 } else if (ARGUMENT_IS ("version")) {
1861 #if defined (pdfTeX) || defined(XeTeX)
1862 initversionstring(&versions
);
1866 printversionandexit (BANNER
, COPYRIGHT_HOLDER
, AUTHOR
, versions
);
1868 } /* Else it was a flag; getopt has already done the assignment. */
1874 parse_src_specials_option (const_string opt_list
)
1876 char * toklist
= xstrdup(opt_list
);
1878 insertsrcspecialauto
= false;
1879 tok
= strtok (toklist
, ", ");
1881 if (strcmp (tok
, "everypar") == 0
1882 || strcmp (tok
, "par") == 0
1883 || strcmp (tok
, "auto") == 0) {
1884 insertsrcspecialauto
= true;
1885 insertsrcspecialeverypar
= true;
1886 } else if (strcmp (tok
, "everyparend") == 0
1887 || strcmp (tok
, "parend") == 0)
1888 insertsrcspecialeveryparend
= true;
1889 else if (strcmp (tok
, "everycr") == 0
1890 || strcmp (tok
, "cr") == 0)
1891 insertsrcspecialeverycr
= true;
1892 else if (strcmp (tok
, "everymath") == 0
1893 || strcmp (tok
, "math") == 0)
1894 insertsrcspecialeverymath
= true;
1895 else if (strcmp (tok
, "everyhbox") == 0
1896 || strcmp (tok
, "hbox") == 0)
1897 insertsrcspecialeveryhbox
= true;
1898 else if (strcmp (tok
, "everyvbox") == 0
1899 || strcmp (tok
, "vbox") == 0)
1900 insertsrcspecialeveryvbox
= true;
1901 else if (strcmp (tok
, "everydisplay") == 0
1902 || strcmp (tok
, "display") == 0)
1903 insertsrcspecialeverydisplay
= true;
1904 else if (strcmp (tok
, "none") == 0) {
1905 /* This one allows to reset an option that could appear in texmf.cnf */
1906 insertsrcspecialauto
= insertsrcspecialeverypar
=
1907 insertsrcspecialeveryparend
= insertsrcspecialeverycr
=
1908 insertsrcspecialeverymath
= insertsrcspecialeveryhbox
=
1909 insertsrcspecialeveryvbox
= insertsrcspecialeverydisplay
= false;
1911 WARNING1 ("Ignoring unknown argument `%s' to --src-specials", tok
);
1913 tok
= strtok(0, ", ");
1916 srcspecialsp
=insertsrcspecialauto
| insertsrcspecialeverypar
|
1917 insertsrcspecialeveryparend
| insertsrcspecialeverycr
|
1918 insertsrcspecialeverymath
| insertsrcspecialeveryhbox
|
1919 insertsrcspecialeveryvbox
| insertsrcspecialeverydisplay
;
1920 srcspecialsoption
= true;
1924 /* If the first thing on the command line (we use the globals `argv' and
1925 `optind') is a normal filename (i.e., does not start with `&' or
1926 `\'), and if we can open it, and if its first line is %&FORMAT, and
1927 FORMAT is a readable dump file, then set DUMP_VAR to FORMAT.
1928 Also call kpse_reset_program_name to ensure the correct paths for the
1931 parse_first_line (const_string filename
)
1933 FILE *f
= filename
? fopen (filename
, FOPEN_R_MODE
) : NULL
;
1935 string first_line
= read_line (f
);
1936 xfclose (f
, filename
);
1938 /* We deal with the general format "%&fmt --translate-file=tcx" */
1939 /* The idea of using this format came from Wlodzimierz Bzyl
1940 <matwb@monika.univ.gda.pl> */
1941 if (first_line
&& first_line
[0] == '%' && first_line
[1] == '&') {
1942 /* Parse the first line into at most three space-separated parts. */
1948 for (s
= first_line
+2; ISBLANK(*s
); ++s
)
1951 while (*s
&& npart
!= 3) {
1953 while (*s
&& *s
!= ' ') s
++;
1954 while (*s
== ' ') *s
++ = '\0';
1958 /* Look at what we've got. Very crude! */
1959 if (*parse
&& **parse
!= '-') {
1962 /* format already determined, do nothing. */
1964 string f_name
= concat (part
[0], DUMP_EXT
);
1965 string d_name
= kpse_find_file (f_name
, DUMP_FORMAT
, false);
1966 if (d_name
&& kpse_readable_file (d_name
)) {
1967 dump_name
= xstrdup (part
[0]);
1968 kpse_reset_program_name (dump_name
);
1969 /* Tell TeX/MF/MP we have a %&name line... */
1976 /* The tcx stuff, if any. Should we support the -translate-file
1977 form as well as --translate-file? */
1980 if (translate_filename
) {
1981 /* TCX file already set, do nothing. */
1982 } else if (STREQ (*parse
, "--translate-file")) {
1984 } else if (STREQ (*parse
, "-translate-file")) {
1986 } else if (STRNEQ (*parse
, "--translate-file=", 17)) {
1988 } else if (STRNEQ (*parse
, "-translate-file=", 16)) {
1991 /* Just set the name, no sanity checks here. */
1992 /* FIXME: remove trailing spaces. */
1994 translate_filename
= xstrdup(s
);
2007 /* The code that implements popen() needs an array for tracking
2008 possible pipe file pointers, because these need to be
2009 closed using pclose().
2014 #define NUM_PIPES 16
2016 static FILE *pipes
[NUM_PIPES
];
2019 open_in_or_pipe (FILE **f_ptr
, int filefmt
, const_string fopen_mode
)
2021 string fname
= NULL
;
2022 int i
; /* iterator */
2024 /* opening a read pipe is straightforward, only have to
2025 skip past the pipe symbol in the file name. filename
2026 quoting is assumed to happen elsewhere (it does :-)) */
2028 if (shellenabledp
&& *(nameoffile
+1) == '|') {
2029 /* the user requested a pipe */
2031 fname
= xmalloc(strlen((const_string
)(nameoffile
+1))+1);
2032 strcpy(fname
,(const_string
)(nameoffile
+1));
2033 recorder_record_input (fname
+ 1);
2034 *f_ptr
= runpopen(fname
+1,"r");
2036 for (i
=0; i
<NUM_PIPES
; i
++) {
2037 if (pipes
[i
]==NULL
) {
2043 setvbuf (*f_ptr
,NULL
,_IONBF
,0);
2048 return *f_ptr
!= NULL
;
2051 return open_input(f_ptr
,filefmt
,fopen_mode
) ;
2056 u_open_in_or_pipe(unicodefile
* f
, integer filefmt
, const_string fopen_mode
, integer mode
, integer encodingData
)
2058 string fname
= NULL
;
2059 int i
; /* iterator */
2061 /* opening a read pipe is straightforward, only have to
2062 skip past the pipe symbol in the file name. filename
2063 quoting is assumed to happen elsewhere (it does :-)) */
2065 if (shellenabledp
&& *(nameoffile
+1) == '|') {
2066 /* the user requested a pipe */
2067 *f
= malloc(sizeof(UFILE
));
2068 (*f
)->encodingMode
= (mode
== AUTO
) ? UTF8
: mode
;
2069 (*f
)->conversionData
= 0;
2070 (*f
)->savedChar
= -1;
2071 (*f
)->skipNextLF
= 0;
2073 fname
= xmalloc(strlen((const_string
)(nameoffile
+1))+1);
2074 strcpy(fname
,(const_string
)(nameoffile
+1));
2075 recorder_record_input (fname
+ 1);
2076 (*f
)->f
= runpopen(fname
+1,"r");
2078 for (i
=0; i
<NUM_PIPES
; i
++) {
2079 if (pipes
[i
]==NULL
) {
2085 setvbuf ((*f
)->f
,NULL
,_IONBF
,0);
2090 return (*f
)->f
!= NULL
;
2093 return u_open_in(f
, filefmt
, fopen_mode
, mode
, encodingData
);
2098 open_out_or_pipe (FILE **f_ptr
, const_string fopen_mode
)
2101 int i
; /* iterator */
2103 /* opening a write pipe takes a little bit more work, because TeX
2104 will perhaps have appended ".tex". To avoid user confusion as
2105 much as possible, this extension is stripped only when the command
2106 is a bare word. Some small string trickery is needed to make
2107 sure the correct number of bytes is free()-d afterwards */
2109 if (shellenabledp
&& *(nameoffile
+1) == '|') {
2110 /* the user requested a pipe */
2111 fname
= xmalloc(strlen((const_string
)(nameoffile
+1))+1);
2112 strcpy(fname
,(const_string
)(nameoffile
+1));
2113 if (strchr (fname
,' ')==NULL
&& strchr(fname
,'>')==NULL
) {
2114 /* mp and mf currently do not use this code, but it
2115 is better to be prepared */
2116 if (STREQ((fname
+strlen(fname
)-4),".tex"))
2117 *(fname
+strlen(fname
)-4) = 0;
2118 *f_ptr
= runpopen(fname
+1,"w");
2119 *(fname
+strlen(fname
)) = '.';
2121 *f_ptr
= runpopen(fname
+1,"w");
2123 recorder_record_output (fname
+ 1);
2126 for (i
=0; i
<NUM_PIPES
; i
++) {
2127 if (pipes
[i
]==NULL
) {
2134 setvbuf(*f_ptr
,NULL
,_IONBF
,0);
2136 return *f_ptr
!= NULL
;
2139 return open_output(f_ptr
,fopen_mode
);
2144 close_file_or_pipe (FILE *f
)
2146 int i
; /* iterator */
2148 if (shellenabledp
) {
2149 /* if this file was a pipe, pclose() it and return */
2150 for (i
=0; i
<NUM_PIPES
; i
++) {
2151 if (pipes
[i
] == f
) {
2165 #endif /* ENABLE_PIPES */
2167 /* All our interrupt handler has to do is set TeX's or Metafont's global
2168 variable `interrupt'; then they will do everything needed. */
2170 /* Win32 doesn't set SIGINT ... */
2172 catch_interrupt (DWORD arg
)
2176 case CTRL_BREAK_EVENT
:
2180 /* No need to set interrupt as we are exiting anyway */
2184 #else /* not WIN32 */
2186 catch_interrupt (int arg
)
2190 (void) signal (SIGINT
, SIG_ACK
);
2192 (void) signal (SIGINT
, catch_interrupt
);
2193 #endif /* not OS2 */
2195 #endif /* not WIN32 */
2197 /* Besides getting the date and time here, we also set up the interrupt
2198 handler, for no particularly good reason. It's just that since the
2199 `fix_date_and_time' routine is called early on (section 1337 in TeX,
2200 ``Get the first line of input and prepare to start''), this is as
2201 good a place as any. */
2204 get_date_and_time (integer
*minutes
, integer
*day
,
2205 integer
*month
, integer
*year
)
2207 time_t myclock
= time ((time_t *) 0);
2208 struct tm
*tmptr
= localtime (&myclock
);
2210 *minutes
= tmptr
->tm_hour
* 60 + tmptr
->tm_min
;
2211 *day
= tmptr
->tm_mday
;
2212 *month
= tmptr
->tm_mon
+ 1;
2213 *year
= tmptr
->tm_year
+ 1900;
2217 /* Under SunOS 4.1.x, the default action after return from the
2218 signal handler is to restart the I/O if nothing has been
2219 transferred. The effect on TeX is that interrupts are ignored if
2220 we are waiting for input. The following tells the system to
2221 return EINTR from read() in this case. From ken@cs.toronto.edu. */
2223 struct sigaction a
, oa
;
2225 a
.sa_handler
= catch_interrupt
;
2226 sigemptyset (&a
.sa_mask
);
2227 sigaddset (&a
.sa_mask
, SIGINT
);
2228 a
.sa_flags
= SA_INTERRUPT
;
2229 sigaction (SIGINT
, &a
, &oa
);
2230 if (oa
.sa_handler
!= SIG_DFL
)
2231 sigaction (SIGINT
, &oa
, (struct sigaction
*) 0);
2232 #else /* no SA_INTERRUPT */
2234 SetConsoleCtrlHandler(catch_interrupt
, TRUE
);
2235 #else /* not WIN32 */
2236 RETSIGTYPE (*old_handler
)(int);
2238 old_handler
= signal (SIGINT
, catch_interrupt
);
2239 if (old_handler
!= SIG_DFL
)
2240 signal (SIGINT
, old_handler
);
2241 #endif /* not WIN32 */
2242 #endif /* no SA_INTERRUPT */
2248 Getting a high resolution time.
2251 get_seconds_and_micros (integer
*seconds
, integer
*micros
)
2253 #if defined (HAVE_GETTIMEOFDAY)
2255 gettimeofday(&tv
, NULL
);
2256 *seconds
= tv
.tv_sec
;
2257 *micros
= tv
.tv_usec
;
2258 #elif defined (HAVE_FTIME)
2262 *micros
= tb
.millitm
*1000;
2264 time_t myclock
= time((time_t*)NULL
);
2271 /* Read a line of input as efficiently as possible while still looking
2272 like Pascal. We set `last' to `first' and return `false' if we get
2273 to eof. Otherwise, we return `true' and set last = first +
2274 length(line except trailing whitespace). */
2276 #ifndef XeTeX /* for XeTeX, we have a replacement function in XeTeX_ext.c */
2278 input_line (FILE *f
)
2282 /* Recognize either LF or CR as a line terminator. */
2284 last
= input_line2(f
, (unsigned char *)buffer
, first
, bufsize
, &i
);
2287 if (f
!= Poptr
&& fileno (f
) != fileno (stdin
)) {
2288 long position
= ftell (f
);
2290 if (position
== 0L) { /* Detect and skip Byte order marks. */
2294 if (k1
!= 0xff && k1
!= 0xfe && k1
!= 0xef)
2299 if (k2
!= 0xff && k2
!= 0xfe && k2
!= 0xbb)
2301 else if ((k1
== 0xff && k2
== 0xfe) || /* UTF-16(LE) */
2302 (k1
== 0xfe && k2
== 0xff)) /* UTF-16(BE) */
2307 if (k1
== 0xef && k2
== 0xbb && k3
== 0xbf &&
2308 k4
>= 0 && k4
<= 0x7e) /* UTF-8 */
2318 while (last
< bufsize
&& (i
= getc (f
)) != EOF
&& i
!= '\n' && i
!= '\r')
2322 if (i
== EOF
&& errno
!= EINTR
&& last
== first
)
2325 /* We didn't get the whole line because our buffer was too small. */
2326 if (i
!= EOF
&& i
!= '\n' && i
!= '\r') {
2327 fprintf (stderr
, "! Unable to read an entire line---bufsize=%u.\n",
2328 (unsigned) bufsize
);
2329 fputs ("Please increase buf_size in texmf.cnf.\n", stderr
);
2334 if (last
>= maxbufstack
)
2337 /* If next char is LF of a CRLF, read it. */
2339 while ((i
= getc (f
)) == EOF
&& errno
== EINTR
)
2345 /* Trim trailing whitespace. */
2346 while (last
> first
&& ISBLANK (buffer
[last
- 1]))
2349 /* Don't bother using xord if we don't need to. */
2351 for (i
= first
; i
<= last
; i
++)
2352 buffer
[i
] = xord
[buffer
[i
]];
2356 for (i
= last
+1; (i
< last
+ 5 && i
< bufsize
) ; i
++)
2364 /* This string specifies what the `e' option does in response to an
2366 static const_string edit_value
= EDITOR
;
2368 /* This procedure originally due to sjc@s1-c. TeX & Metafont call it when
2369 the user types `e' in response to an error, invoking a text editor on
2370 the erroneous source file. FNSTART is how far into FILENAME the
2371 actual filename starts; FNLENGTH is how long the filename is. */
2374 calledit (packedASCIIcode
*filename
,
2375 poolpointer fnstart
,
2379 char *temp
, *command
, *fullcmd
;
2381 int sdone
, ddone
, i
;
2384 char *fp
, *ffp
, *env
, editorname
[256], buffer
[256];
2390 filename
+= fnstart
;
2392 /* Close any open input files, since we're going to kill the job. */
2393 for (i
= 1; i
<= inopen
; i
++)
2395 xfclose (inputfile
[i
]->f
, "inputfile");
2397 xfclose (inputfile
[i
], "inputfile");
2400 /* Replace the default with the value of the appropriate environment
2401 variable or config file value, if it's set. */
2402 temp
= kpse_var_value (edit_var
);
2406 /* Construct the command string. The `11' is the maximum length an
2407 integer might be. */
2408 command
= xmalloc (strlen (edit_value
) + fnlength
+ 11);
2410 /* So we can construct it as we go. */
2415 if ((isalpha(*edit_value
) && *(edit_value
+ 1) == ':'
2416 && IS_DIR_SEP (*(edit_value
+ 2)))
2417 || (*edit_value
== '"' && isalpha(*(edit_value
+ 1))
2418 && *(edit_value
+ 2) == ':'
2419 && IS_DIR_SEP (*(edit_value
+ 3)))
2424 while ((c
= *edit_value
++) != 0)
2428 switch (c
= *edit_value
++)
2432 FATAL ("call_edit: `%%d' appears twice in editor command");
2433 sprintf (temp
, "%ld", (long int)linenumber
);
2434 while (*temp
!= '\0')
2441 FATAL ("call_edit: `%%s' appears twice in editor command");
2442 for (i
=0; i
< fnlength
; i
++)
2443 *temp
++ = Xchr (filename
[i
]);
2449 /* Back up to the null to force termination. */
2463 else { if(Isspace(c
) && cnt
== 0) {
2468 } else if(!Isspace(c
) && cnt
== 0) {
2483 if (dontchange
== 0) {
2484 if(editorname
[0] == '.' ||
2485 editorname
[0] == '/' ||
2486 editorname
[0] == '\\') {
2487 fprintf(stderr
, "%s is not allowed to execute.\n", editorname
);
2490 env
= (char *)getenv("PATH");
2491 if(SearchPath(env
, editorname
, ".exe", 256, buffer
, &ffp
)==0) {
2492 if(SearchPath(env
, editorname
, ".bat", 256, buffer
, &ffp
)==0) {
2493 fprintf(stderr
, "I cannot find %s in the PATH.\n", editorname
);
2497 fullcmd
= (char *)xmalloc(strlen(buffer
)+strlen(command
)+5);
2498 strcpy(fullcmd
, "\"");
2499 strcat(fullcmd
, buffer
);
2500 strcat(fullcmd
, "\"");
2501 strcat(fullcmd
, command
);
2506 /* Execute the command. */
2507 if (system (fullcmd
) != 0)
2508 fprintf (stderr
, "! Trouble executing `%s'.\n", command
);
2510 /* Quit, since we found an error. */
2514 /* Read and write dump files. As distributed, these files are
2515 architecture dependent; specifically, BigEndian and LittleEndian
2516 architectures produce different files. These routines always output
2517 BigEndian files. This still does not guarantee them to be
2518 architecture-independent, because it is possible to make a format
2519 that dumps a glue ratio, i.e., a floating-point number. Fortunately,
2520 none of the standard formats do that. */
2522 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE) /* this fn */
2524 /* This macro is always invoked as a statement. It assumes a variable
2527 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp
2530 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
2531 opposite-endianness of whatever they are now. */
2534 swap_items (char *p
, int nitems
, int size
)
2538 /* Since `size' does not change, we can write a while loop for each
2539 case, and avoid testing `size' for each time. */
2542 /* 16-byte items happen on the DEC Alpha machine when we are not
2543 doing sharable memory dumps. */
2588 /* Nothing to do. */
2592 FATAL1 ("Can't swap a %d-byte item for (un)dumping", size
);
2595 #endif /* not WORDS_BIGENDIAN and not NO_DUMP_SHARE */
2598 /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
2599 The pointer to the stuff to write is P, and we write to the file
2604 do_dump (char *p
, int item_size
, int nitems
, gzFile out_file
)
2606 do_dump (char *p
, int item_size
, int nitems
, FILE *out_file
)
2609 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2610 swap_items (p
, nitems
, item_size
);
2614 if (gzwrite (out_file
, p
, item_size
* nitems
) != item_size
* nitems
)
2616 if (fwrite (p
, item_size
, nitems
, out_file
) != nitems
)
2619 fprintf (stderr
, "! Could not write %d %d-byte item(s) to %s.\n",
2620 nitems
, item_size
, nameoffile
+1);
2624 /* Have to restore the old contents of memory, since some of it might
2626 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2627 swap_items (p
, nitems
, item_size
);
2632 /* Here is the dual of the writing routine. */
2636 do_undump (char *p
, int item_size
, int nitems
, gzFile in_file
)
2638 do_undump (char *p
, int item_size
, int nitems
, FILE *in_file
)
2642 if (gzread (in_file
, p
, item_size
* nitems
) != item_size
* nitems
)
2644 if (fread (p
, item_size
, nitems
, in_file
) != (size_t) nitems
)
2646 FATAL3 ("Could not undump %d %d-byte item(s) from %s",
2647 nitems
, item_size
, nameoffile
+1);
2649 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2650 swap_items (p
, nitems
, item_size
);
2654 /* FIXME -- some (most?) of this can/should be moved to the Pascal/WEB side. */
2655 #if defined(TeX) || defined(MF)
2656 #if !defined(pdfTeX)
2658 checkpoolpointer (poolpointer poolptr
, size_t len
)
2660 if (poolptr
+ len
>= poolsize
) {
2661 fprintf (stderr
, "\nstring pool overflow [%i bytes]\n",
2662 (int)poolsize
); /* fixme */
2667 #ifndef XeTeX /* XeTeX uses this from XeTeX_ext.c */
2671 maketexstring(const_string s
)
2676 const unsigned char *cp
= (const unsigned char *)s
;
2679 if (s
== NULL
|| *s
== 0)
2680 return getnullstr();
2685 checkpoolpointer (poolptr
, len
); /* in the XeTeX case, this may be more than enough */
2687 while ((rval
= *(cp
++)) != 0) {
2688 UInt16 extraBytes
= bytesFromUTF8
[rval
];
2689 switch (extraBytes
) { /* note: code falls through cases! */
2690 case 5: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2691 case 4: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2692 case 3: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2693 case 2: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2694 case 1: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2697 rval
-= offsetsFromUTF8
[extraBytes
];
2698 if (rval
> 0xffff) {
2700 strpool
[poolptr
++] = 0xd800 + rval
/ 0x0400;
2701 strpool
[poolptr
++] = 0xdc00 + rval
% 0x0400;
2704 strpool
[poolptr
++] = rval
;
2708 strpool
[poolptr
++] = *s
++;
2709 #endif /* ! XeTeX */
2711 return makestring();
2713 #endif /* !pdfTeX */
2716 makefullnamestring(void)
2718 return maketexstring(fullnameoffile
);
2721 /* Get the job name to be used, which may have been set from the
2724 getjobname(strnumber name
)
2726 strnumber ret
= name
;
2727 if (c_job_name
!= NULL
)
2728 ret
= maketexstring(c_job_name
);
2735 compare_paths (const_string p1
, const_string p2
)
2739 #ifdef MONOCASE_FILENAMES
2740 (((ret
= (toupper(*p1
) - toupper(*p2
))) == 0) && (*p2
!= 0))
2742 (((ret
= (*p1
- *p2
)) == 0) && (*p2
!= 0))
2744 || (IS_DIR_SEP(*p1
) && IS_DIR_SEP(*p2
))) {
2747 ret
= (ret
< 0 ? -1 : (ret
> 0 ? 1 : 0));
2751 #ifdef XeTeX /* the string pool is UTF-16 but we want a UTF-8 string */
2754 gettexstring (strnumber s
)
2756 unsigned bytesToWrite
= 0;
2757 poolpointer len
, i
, j
;
2759 len
= strstart
[s
+ 1 - 65536L] - strstart
[s
- 65536L];
2760 name
= xmalloc(len
* 3 + 1); /* max UTF16->UTF8 expansion
2761 (code units, not bytes) */
2762 for (i
= 0, j
= 0; i
< len
; i
++) {
2763 unsigned c
= strpool
[i
+ strstart
[s
- 65536L]];
2764 if (c
>= 0xD800 && c
<= 0xDBFF) {
2765 unsigned lo
= strpool
[++i
+ strstart
[s
- 65536L]];
2766 if (lo
>= 0xDC00 && lo
<= 0xDFFF)
2767 c
= (c
- 0xD800) * 0x0400 + lo
- 0xDC00;
2775 else if (c
< 0x10000)
2777 else if (c
< 0x110000)
2785 switch (bytesToWrite
) { /* note: everything falls through. */
2786 case 4: name
[--j
] = ((c
| 0x80) & 0xBF); c
>>= 6;
2787 case 3: name
[--j
] = ((c
| 0x80) & 0xBF); c
>>= 6;
2788 case 2: name
[--j
] = ((c
| 0x80) & 0xBF); c
>>= 6;
2789 case 1: name
[--j
] = (c
| firstByteMark
[bytesToWrite
]);
2800 gettexstring (strnumber s
)
2805 len
= strstart
[s
+ 1] - strstart
[s
];
2807 len
= strstartar
[s
+ 1 - 65536L] - strstartar
[s
- 65536L];
2809 name
= (string
)xmalloc (len
+ 1);
2811 strncpy (name
, (string
)&strpool
[strstart
[s
]], len
);
2815 /* Don't use strncpy. The strpool is not made up of chars. */
2816 for (i
=0; i
<len
; i
++) name
[i
] = strpool
[i
+strstartar
[s
- 65536L]];
2823 #endif /* not XeTeX */
2826 isnewsource (strnumber srcfilename
, int lineno
)
2828 char *name
= gettexstring(srcfilename
);
2829 return (compare_paths(name
, last_source_name
) != 0 || lineno
!= last_lineno
);
2833 remembersourceinfo (strnumber srcfilename
, int lineno
)
2835 if (last_source_name
)
2836 free(last_source_name
);
2837 last_source_name
= gettexstring(srcfilename
);
2838 last_lineno
= lineno
;
2842 makesrcspecial (strnumber srcfilename
, int lineno
)
2844 poolpointer oldpoolptr
= poolptr
;
2845 char *filename
= gettexstring(srcfilename
);
2846 /* FIXME: Magic number. */
2850 /* Always put a space after the number, which makes things easier
2853 sprintf (buf
, "src:%d ", lineno
);
2855 if (poolptr
+ strlen(buf
) + strlen(filename
) >= (size_t)poolsize
) {
2856 fprintf (stderr
, "\nstring pool overflow\n"); /* fixme */
2861 strpool
[poolptr
++] = *s
++;
2865 strpool
[poolptr
++] = *s
++;
2867 return (oldpoolptr
);
2870 /* pdfTeX routines also used for e-pTeX, e-upTeX, and XeTeX */
2871 #if defined (pdfTeX) || defined (epTeX) || defined (eupTeX) || defined(XeTeX)
2873 #include <kpathsea/c-stat.h>
2876 #define check_nprintf(size_get, size_want) \
2877 if ((unsigned)(size_get) >= (unsigned)(size_want)) \
2878 pdftex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__);
2879 # define check_buf(size, buf_size) \
2880 if ((unsigned)(size) > (unsigned)(buf_size)) \
2881 pdftex_fail("buffer overflow at file %s, line %d", __FILE__, __LINE__ )
2882 # define xfree(p) do { if (p != NULL) free(p); p = NULL; } while (0)
2883 # define MAX_CSTRING_LEN 1024 * 1024
2885 #if !defined (pdfTeX)
2886 # define PRINTF_BUF_SIZE 1024
2887 static char print_buf
[PRINTF_BUF_SIZE
];
2889 /* Helper for pdftex_fail. */
2890 static void safe_print(const char *str
)
2893 for (c
= str
; *c
; ++c
)
2896 /* pdftex_fail may be called when a buffer overflow has happened/is
2897 happening, therefore may not call mktexstring. However, with the
2898 current implementation it appears that error messages are misleading,
2899 possibly because pool overflows are detected too late.
2901 The output format of this fuction must be the same as pdf_error in
2903 __attribute__ ((noreturn
, format(printf
, 1, 2)))
2904 void pdftex_fail(const char *fmt
, ...)
2907 va_start(args
, fmt
);
2909 safe_print("!error: ");
2910 vsnprintf(print_buf
, PRINTF_BUF_SIZE
, fmt
, args
);
2911 safe_print(print_buf
);
2914 safe_print(" ==> Fatal error occurred, output file will be damaged!");
2916 if (kpathsea_debug
) {
2917 safe_print("kpathsea_debug enabled, calling abort()...");
2924 #endif /* not pdfTeX */
2927 static boolean start_time_set
= false;
2928 static time_t start_time
= 0;
2929 #define TIME_STR_SIZE 30
2930 char start_time_str
[TIME_STR_SIZE
];
2931 static char time_str
[TIME_STR_SIZE
];
2932 /* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */
2934 static void makepdftime(time_t t
, char *time_str
, boolean utc
)
2939 int i
, off
, off_hours
, off_mins
;
2946 lt
= *localtime(&t
);
2948 size
= strftime(time_str
, TIME_STR_SIZE
, "D:%Y%m%d%H%M%S", <
);
2949 /* expected format: "YYYYmmddHHMMSS" */
2951 /* unexpected, contents of time_str is undefined */
2956 /* correction for seconds: %S can be in range 00..61,
2957 the PDF reference expects 00..59,
2958 therefore we map "60" and "61" to "59" */
2959 if (time_str
[14] == '6') {
2962 time_str
[16] = '\0'; /* for safety */
2965 /* get the time zone offset */
2968 /* this calculation method was found in exim's tod.c */
2969 off
= 60 * (lt
.tm_hour
- gmt
.tm_hour
) + lt
.tm_min
- gmt
.tm_min
;
2970 if (lt
.tm_year
!= gmt
.tm_year
) {
2971 off
+= (lt
.tm_year
> gmt
.tm_year
) ? 1440 : -1440;
2972 } else if (lt
.tm_yday
!= gmt
.tm_yday
) {
2973 off
+= (lt
.tm_yday
> gmt
.tm_yday
) ? 1440 : -1440;
2977 time_str
[size
++] = 'Z';
2980 off_hours
= off
/ 60;
2981 off_mins
= abs(off
- off_hours
* 60);
2982 i
= snprintf(&time_str
[size
], 9, "%+03d'%02d'", off_hours
, off_mins
);
2983 check_nprintf(i
, 9);
2987 #if defined(_MSC_VER)
2988 #define strtoll _strtoi64
2991 void initstarttime(void)
2993 char *source_date_epoch
;
2996 if (!start_time_set
) {
2997 start_time_set
= true;
2998 source_date_epoch
= getenv("SOURCE_DATE_EPOCH");
2999 if (source_date_epoch
) {
3001 epoch
= strtoll(source_date_epoch
, &endptr
, 10);
3002 if (epoch
< 0 || *endptr
!= '\0' || errno
!= 0) {
3003 FATAL1 ("invalid value for environment variable $SOURCE_DATE_EPOCH: %s",
3007 makepdftime(start_time
, start_time_str
, /* utc= */true);
3010 start_time
= time((time_t *) NULL
);
3011 makepdftime(start_time
, start_time_str
, /* utc= */false);
3016 char *makecstring(integer s
)
3018 static char *cstrbuf
= NULL
;
3020 static int allocsize
;
3021 int allocgrow
, i
, l
= strstart
[s
+ 1] - strstart
[s
];
3022 check_buf(l
+ 1, MAX_CSTRING_LEN
);
3023 if (cstrbuf
== NULL
) {
3025 cstrbuf
= xmallocarray(char, allocsize
);
3026 } else if (l
+ 1 > allocsize
) {
3027 allocgrow
= allocsize
* 0.2;
3028 if (l
+ 1 - allocgrow
> allocsize
)
3030 else if (allocsize
< MAX_CSTRING_LEN
- allocgrow
)
3031 allocsize
+= allocgrow
;
3033 allocsize
= MAX_CSTRING_LEN
;
3034 cstrbuf
= xreallocarray(cstrbuf
, char, allocsize
);
3037 for (i
= 0; i
< l
; i
++)
3038 *p
++ = strpool
[i
+ strstart
[s
]];
3044 input/ouput same as makecstring:
3045 input: string number
3046 output: C string with quotes removed.
3047 That means, file names that are legal on some operation systems
3048 cannot any more be used since pdfTeX version 1.30.4.
3050 char *makecfilename(integer s
)
3052 char *name
= makecstring(s
);
3065 void getcreationdate(void)
3069 /* put creation date on top of string pool and update poolptr */
3070 len
= strlen(start_time_str
);
3072 /* In e-pTeX, "init len => call initstarttime()" (as pdftexdir/utils.c)
3073 yields unintentional output. */
3075 if ((unsigned) (poolptr
+ len
) >= (unsigned) (poolsize
)) {
3077 /* error by str_toks that calls str_room(1) */
3081 memcpy(&strpool
[poolptr
], start_time_str
, len
);
3085 void getfilemoddate(integer s
)
3087 struct stat file_data
;
3089 char *file_name
= kpse_find_tex(makecfilename(s
));
3090 if (file_name
== NULL
) {
3091 return; /* empty string */
3094 recorder_record_input(file_name
);
3095 /* get file status */
3096 if (stat(file_name
, &file_data
) == 0) {
3099 makepdftime(file_data
.st_mtime
, time_str
, /* utc= */false);
3100 len
= strlen(time_str
);
3101 if ((unsigned) (poolptr
+ len
) >= (unsigned) (poolsize
)) {
3103 /* error by str_toks that calls str_room(1) */
3105 memcpy(&strpool
[poolptr
], time_str
, len
);
3109 /* else { errno contains error code } */
3114 void getfilesize(integer s
)
3116 struct stat file_data
;
3119 char *file_name
= kpse_find_tex(makecfilename(s
));
3120 if (file_name
== NULL
) {
3121 return; /* empty string */
3124 recorder_record_input(file_name
);
3125 /* get file status */
3126 if (stat(file_name
, &file_data
) == 0) {
3130 /* st_size has type off_t */
3131 i
= snprintf(buf
, sizeof(buf
),
3132 "%lu", (long unsigned int) file_data
.st_size
);
3133 check_nprintf(i
, sizeof(buf
));
3135 if ((unsigned) (poolptr
+ len
) >= (unsigned) (poolsize
)) {
3137 /* error by str_toks that calls str_room(1) */
3139 memcpy(&strpool
[poolptr
], buf
, len
);
3143 /* else { errno contains error code } */
3148 void getfiledump(integer s
, int offset
, int length
)
3152 poolpointer data_ptr
;
3153 poolpointer data_end
;
3157 /* empty result string */
3161 if (poolptr
+ 2 * length
+ 1 >= poolsize
) {
3162 /* no place for result */
3164 /* error by str_toks that calls str_room(1) */
3168 file_name
= kpse_find_tex(makecfilename(s
));
3169 if (file_name
== NULL
) {
3170 return; /* empty string */
3173 /* read file data */
3174 f
= fopen(file_name
, FOPEN_RBIN_MODE
);
3179 recorder_record_input(file_name
);
3180 if (fseek(f
, offset
, SEEK_SET
) != 0) {
3184 /* there is enough space in the string pool, the read
3185 data are put in the upper half of the result, thus
3186 the conversion to hex can be done without overwriting
3187 unconverted bytes. */
3188 data_ptr
= poolptr
+ length
;
3189 read
= fread(&strpool
[data_ptr
], sizeof(char), length
, f
);
3192 /* convert to hex */
3193 data_end
= data_ptr
+ read
;
3194 for (; data_ptr
< data_end
; data_ptr
++) {
3195 i
= snprintf((char *) &strpool
[poolptr
], 3,
3196 "%.2X", (unsigned int) strpool
[data_ptr
]);
3197 check_nprintf(i
, 3);
3202 #endif /* not XeTeX */
3204 /* Converts any given string in into an allowed PDF string which is
3205 * hexadecimal encoded;
3206 * sizeof(out) should be at least lin*2+1.
3208 void convertStringToHexString(const char *in
, char *out
, int lin
)
3213 for (i
= 0; i
< lin
; i
++) {
3214 k
= snprintf(buf
, sizeof(buf
),
3215 "%02X", (unsigned int) (unsigned char) in
[i
]);
3216 check_nprintf(k
, sizeof(buf
));
3223 #define DIGEST_SIZE 16
3224 #define FILE_BUF_SIZE 1024
3226 void getmd5sum(strnumber s
, boolean file
)
3229 md5_byte_t digest
[DIGEST_SIZE
];
3230 char outbuf
[2 * DIGEST_SIZE
+ 1];
3231 int len
= 2 * DIGEST_SIZE
;
3238 char file_buf
[FILE_BUF_SIZE
];
3244 xname
= gettexstring (s
);
3245 file_name
= kpse_find_tex (xname
);
3248 file_name
= kpse_find_tex(makecfilename(s
));
3250 if (file_name
== NULL
) {
3251 return; /* empty string */
3253 /* in case of error the empty string is returned,
3254 no need for xfopen that aborts on error.
3256 f
= fopen(file_name
, FOPEN_RBIN_MODE
);
3261 recorder_record_input(file_name
);
3263 while ((read
= fread(&file_buf
, sizeof(char), FILE_BUF_SIZE
, f
)) > 0) {
3264 md5_append(&state
, (const md5_byte_t
*) file_buf
, read
);
3266 md5_finish(&state
, digest
);
3271 /* s contains the data */
3274 xname
= gettexstring (s
);
3276 (md5_byte_t
*) xname
,
3281 (md5_byte_t
*) &strpool
[strstart
[s
]],
3282 strstart
[s
+ 1] - strstart
[s
]);
3284 md5_finish(&state
, digest
);
3287 if (poolptr
+ len
>= poolsize
) {
3288 /* error by str_toks that calls str_room(1) */
3291 convertStringToHexString((char *) digest
, outbuf
, DIGEST_SIZE
);
3293 for (i
= 0; i
< 2 * DIGEST_SIZE
; i
++)
3294 strpool
[poolptr
++] = (uint16_t)outbuf
[i
];
3296 memcpy(&strpool
[poolptr
], outbuf
, len
);
3301 #endif /* pdfTeX or e-pTeX or e-upTeX or XeTeX */
3304 /* Metafont/MetaPost fraction routines. Replaced either by assembler or C.
3305 The assembler syntax doesn't work on Solaris/x86. */
3307 #if defined (__sun__) || defined (__cplusplus)
3310 /* The assembler code is not PIC safe on i?86 so use C code. */
3311 #if defined (__PIC__) && defined (__i386__)
3314 #if defined(WIN32) && !defined(NO_MF_ASM) && !defined(__MINGW32__)
3315 #include "lib/mfmpw32.c"
3316 #elif defined (__i386__) && defined (__GNUC__) && !defined (NO_MF_ASM)
3317 #include "lib/mfmpi386.asm"
3319 /* Replace fixed-point fraction routines from mf.web and mp.web with
3320 Hobby's floating-point C code. */
3322 /****************************************************************
3323 Copyright 1990 - 1995 by AT&T Bell Laboratories.
3325 Permission to use, copy, modify, and distribute this software
3326 and its documentation for any purpose and without fee is hereby
3327 granted, provided that the above copyright notice appear in all
3328 copies and that both that the copyright notice and this
3329 permission notice and warranty disclaimer appear in supporting
3330 documentation, and that the names of AT&T Bell Laboratories or
3331 any of its entities not be used in advertising or publicity
3332 pertaining to distribution of the software without specific,
3333 written prior permission.
3335 AT&T disclaims all warranties with regard to this software,
3336 including all implied warranties of merchantability and fitness.
3337 In no event shall AT&T be liable for any special, indirect or
3338 consequential damages or any damages whatsoever resulting from
3339 loss of use, data or profits, whether in an action of contract,
3340 negligence or other tortious action, arising out of or in
3341 connection with the use or performance of this software.
3342 ****************************************************************/
3344 /**********************************************************
3345 The following is by John Hobby
3346 **********************************************************/
3350 /* These replacements for takefraction, makefraction, takescaled, makescaled
3351 run about 3 to 11 times faster than the standard versions on modern machines
3352 that have fast hardware for double-precision floating point. They should
3353 produce approximately correct results on all machines and agree exactly
3354 with the standard versions on machines that satisfy the following conditions:
3355 1. Doubles must have at least 46 mantissa bits; i.e., numbers expressible
3356 as n*2^k with abs(n)<2^46 should be representable.
3357 2. The following should hold for addition, subtraction, and multiplcation but
3358 not necessarily for division:
3359 A. If the true answer is between two representable numbers, the computed
3360 answer must be one of them.
3361 B. When the true answer is representable, this must be the computed result.
3362 3. Dividing one double by another should always produce a relative error of
3363 at most one part in 2^46. (This is why the mantissa requirement is
3364 46 bits instead of 45 bits.)
3365 3. In the absence of overflow, double-to-integer conversion should truncate
3366 toward zero and do this in an exact fashion.
3367 4. Integer-to-double convesion should produce exact results.
3368 5. Dividing one power of two by another should yield an exact result.
3369 6. ASCII to double conversion should be exact for integer values.
3370 7. Integer arithmetic must be done in the two's-complement system.
3372 #define ELGORDO 0x7fffffff
3373 #define TWEXP31 2147483648.0
3374 #define TWEXP28 268435456.0
3375 #define TWEXP16 65536.0
3376 #define TWEXP_16 (1.0/65536.0)
3377 #define TWEXP_28 (1.0/268435456.0)
3380 ztakefraction (integer p
, integer q
) /* Approximate p*q/2^28 */
3381 { register double d
;
3383 d
= (double)p
* (double)q
* TWEXP_28
;
3387 if (d
!=TWEXP31
|| (((p
&077777)*(q
&077777))&040000)==0)
3392 if (d
==i
&& (((p
&077777)*(q
&077777))&040000)!=0) --i
;
3396 if (d
!= -TWEXP31
|| ((-(p
&077777)*(q
&077777))&040000)==0)
3401 if (d
==i
&& ((-(p
&077777)*(q
&077777))&040000)!=0) ++i
;
3407 ztakescaled (integer p
, integer q
) /* Approximate p*q/2^16 */
3408 { register double d
;
3410 d
= (double)p
* (double)q
* TWEXP_16
;
3414 if (d
!=TWEXP31
|| (((p
&077777)*(q
&077777))&040000)==0)
3419 if (d
==i
&& (((p
&077777)*(q
&077777))&040000)!=0) --i
;
3423 if (d
!= -TWEXP31
|| ((-(p
&077777)*(q
&077777))&040000)==0)
3428 if (d
==i
&& ((-(p
&077777)*(q
&077777))&040000)!=0) ++i
;
3433 /* Note that d cannot exactly equal TWEXP31 when the overflow test is made
3434 because the exact value of p/q cannot be strictly between (2^31-1)/2^28
3435 and 8/1. No pair of integers less than 2^31 has such a ratio.
3438 zmakefraction (integer p
, integer q
) /* Approximate 2^28*p/q */
3439 { register double d
;
3442 if (q
==0) confusion(47);
3444 d
= TWEXP28
* (double)p
/(double)q
;
3447 if (d
>=TWEXP31
) {aritherror
=true; return ELGORDO
;}
3449 if (d
==i
&& ( ((q
>0 ? -q
: q
)&077777)
3450 * (((i
&037777)<<1)-1) & 04000)!=0) --i
;
3453 if (d
<= -TWEXP31
) {aritherror
=true; return -ELGORDO
;}
3455 if (d
==i
&& ( ((q
>0 ? q
: -q
)&077777)
3456 * (((i
&037777)<<1)+1) & 04000)!=0) ++i
;
3461 /* Note that d cannot exactly equal TWEXP31 when the overflow test is made
3462 because the exact value of p/q cannot be strictly between (2^31-1)/2^16
3463 and 2^15/1. No pair of integers less than 2^31 has such a ratio.
3466 zmakescaled (integer p
, integer q
) /* Approximate 2^16*p/q */
3467 { register double d
;
3470 if (q
==0) confusion(47);
3472 d
= TWEXP16
* (double)p
/(double)q
;
3475 if (d
>=TWEXP31
) {aritherror
=true; return ELGORDO
;}
3477 if (d
==i
&& ( ((q
>0 ? -q
: q
)&077777)
3478 * (((i
&037777)<<1)-1) & 04000)!=0) --i
;
3481 if (d
<= -TWEXP31
) {aritherror
=true; return -ELGORDO
;}
3483 if (d
==i
&& ( ((q
>0 ? q
: -q
)&077777)
3484 * (((i
&037777)<<1)+1) & 04000)!=0) ++i
;
3489 #endif /* not FIXPT */
3490 #endif /* not assembler */
3491 #endif /* not TeX, i.e., MF */
3494 /* On-line display routines for Metafont. Here we use a dispatch table
3495 indexed by the MFTERM or TERM environment variable to select the
3496 graphics routines appropriate to the user's terminal. stdout must be
3497 connected to a terminal for us to do any graphics. */
3513 /* Prototypes for Metafont display routines: mf_XXX_initscreen,
3514 mf_XXX_updatescreen, mf_XXX_blankrectangle, and mf_XXX_paintrow. */
3515 #include <window/mfdisplay.h>
3517 /* This variable, `mfwsw', contains the dispatch tables for each
3518 terminal. We map the Pascal calls to the routines `init_screen',
3519 `update_screen', `blank_rectangle', and `paint_row' into the
3520 appropriate entry point for the specific terminal that MF is being
3525 const char *mfwsw_type
; /* Name of terminal a la TERMCAP. */
3526 int (*mfwsw_initscreen
) (void);
3527 void (*mfwsw_updatescrn
) (void);
3528 void (*mfwsw_blankrect
) (screencol
, screencol
, screenrow
, screenrow
);
3529 void (*mfwsw_paintrow
) (screenrow
, pixelcolor
, transspec
, screencol
);
3533 { "amiterm", mf_amiga_initscreen
, mf_amiga_updatescreen
,
3534 mf_amiga_blankrectangle
, mf_amiga_paintrow
},
3537 { "epsf", mf_epsf_initscreen
, mf_epsf_updatescreen
,
3538 mf_epsf_blankrectangle
, mf_epsf_paintrow
},
3541 { "hp2627", mf_hp2627_initscreen
, mf_hp2627_updatescreen
,
3542 mf_hp2627_blankrectangle
, mf_hp2627_paintrow
},
3545 { "mftalk", mf_mftalk_initscreen
, mf_mftalk_updatescreen
,
3546 mf_mftalk_blankrectangle
, mf_mftalk_paintrow
},
3549 { "next", mf_next_initscreen
, mf_next_updatescreen
,
3550 mf_next_blankrectangle
, mf_next_paintrow
},
3553 { "regis", mf_regis_initscreen
, mf_regis_updatescreen
,
3554 mf_regis_blankrectangle
, mf_regis_paintrow
},
3557 { "sun", mf_sun_initscreen
, mf_sun_updatescreen
,
3558 mf_sun_blankrectangle
, mf_sun_paintrow
},
3561 { "tek", mf_tektronix_initscreen
, mf_tektronix_updatescreen
,
3562 mf_tektronix_blankrectangle
, mf_tektronix_paintrow
},
3565 { "uniterm", mf_uniterm_initscreen
, mf_uniterm_updatescreen
,
3566 mf_uniterm_blankrectangle
, mf_uniterm_paintrow
},
3569 { "win32term", mf_win32_initscreen
, mf_win32_updatescreen
,
3570 mf_win32_blankrectangle
, mf_win32_paintrow
},
3573 { "xterm", mf_x11_initscreen
, mf_x11_updatescreen
,
3574 mf_x11_blankrectangle
, mf_x11_paintrow
},
3577 /* Always support this. */
3578 { "trap", mf_trap_initscreen
, mf_trap_updatescreen
,
3579 mf_trap_blankrectangle
, mf_trap_paintrow
},
3581 /* Finally, we must have an entry with a terminal type of NULL. */
3582 { NULL
, NULL
, NULL
, NULL
, NULL
}
3584 }; /* End of the array initialization. */
3587 /* This is a pointer to the mfwsw[] entry that we find. */
3588 static struct mfwin_sw
*mfwp
;
3591 /* The following are routines that just jump to the correct
3592 terminal-specific graphics code. If none of the routines in the
3593 dispatch table exist, or they fail, we produce trap-compatible
3594 output, i.e., the same words and punctuation that the unchanged
3595 mf.web would produce. */
3598 /* This returns true if we can do window operations, else false. */
3604 /* If MFTERM is set, use it. */
3605 const_string tty_type
= kpse_var_value ("MFTERM");
3607 if (tty_type
== NULL
)
3610 tty_type
= "amiterm";
3611 #elif defined (WIN32)
3612 tty_type
= "win32term";
3613 #elif defined (OS2) || defined (__DJGPP__) /* not AMIGA nor WIN32 */
3614 tty_type
= "mftalk";
3615 #else /* not (OS2 or WIN32 or __DJGPP__ or AMIGA) */
3616 /* If DISPLAY is set, we are X11; otherwise, who knows. */
3617 boolean have_display
= getenv ("DISPLAY") != NULL
;
3618 tty_type
= have_display
? "xterm" : getenv ("TERM");
3620 /* If we don't know what kind of terminal this is, or if Metafont
3621 isn't being run interactively, don't do any online output. */
3622 if (tty_type
== NULL
3623 || (!STREQ (tty_type
, "trap") && !isatty (fileno (stdout
))))
3625 #endif /* not (OS2 or WIN32 or __DJGPP__ or AMIGA) */
3628 /* Test each of the terminals given in `mfwsw' against the terminal
3629 type, and take the first one that matches, or if the user is running
3630 under Emacs, the first one. */
3631 for (mfwp
= mfwsw
; mfwp
->mfwsw_type
!= NULL
; mfwp
++) {
3632 if (!strncmp (mfwp
->mfwsw_type
, tty_type
, strlen (mfwp
->mfwsw_type
))
3633 || STREQ (tty_type
, "emacs")) {
3634 if (mfwp
->mfwsw_initscreen
) {
3635 retval
= (*mfwp
->mfwsw_initscreen
) ();
3637 Sleep(1000); /* Wait for opening a window */
3642 fprintf (stderr
, "mf: Couldn't initialize online display for `%s'.\n",
3649 /* The current terminal type wasn't found in any of the entries, or
3650 initalization failed, so silently give up, assuming that the user
3651 isn't on a terminal that supports graphic output. */
3656 /* Make sure everything is visible. */
3661 if (mfwp
->mfwsw_updatescrn
)
3662 (*mfwp
->mfwsw_updatescrn
) ();
3666 /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
3667 the background color. */
3670 blankrectangle (screencol left
, screencol right
,
3671 screenrow top
, screenrow bottom
)
3673 if (mfwp
->mfwsw_blankrect
)
3674 (*mfwp
->mfwsw_blankrect
) (left
, right
, top
, bottom
);
3678 /* This paints ROW, starting with the color INIT_COLOR.
3679 TRANSITION_VECTOR then specifies the length of the run; then we
3680 switch colors. This goes on for VECTOR_SIZE transitions. */
3683 paintrow (screenrow row
, pixelcolor init_color
,
3684 transspec transition_vector
, screencol vector_size
)
3686 if (mfwp
->mfwsw_paintrow
)
3687 (*mfwp
->mfwsw_paintrow
) (row
, init_color
, transition_vector
, vector_size
);