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));
2034 free(fullnameoffile
);
2035 fullnameoffile
= xstrdup(fname
);
2036 recorder_record_input (fname
+ 1);
2037 *f_ptr
= runpopen(fname
+1,"r");
2039 for (i
=0; i
<NUM_PIPES
; i
++) {
2040 if (pipes
[i
]==NULL
) {
2046 setvbuf (*f_ptr
,NULL
,_IONBF
,0);
2051 return *f_ptr
!= NULL
;
2054 return open_input(f_ptr
,filefmt
,fopen_mode
) ;
2059 u_open_in_or_pipe(unicodefile
* f
, integer filefmt
, const_string fopen_mode
, integer mode
, integer encodingData
)
2061 string fname
= NULL
;
2062 int i
; /* iterator */
2064 /* opening a read pipe is straightforward, only have to
2065 skip past the pipe symbol in the file name. filename
2066 quoting is assumed to happen elsewhere (it does :-)) */
2068 if (shellenabledp
&& *(nameoffile
+1) == '|') {
2069 /* the user requested a pipe */
2070 *f
= malloc(sizeof(UFILE
));
2071 (*f
)->encodingMode
= (mode
== AUTO
) ? UTF8
: mode
;
2072 (*f
)->conversionData
= 0;
2073 (*f
)->savedChar
= -1;
2074 (*f
)->skipNextLF
= 0;
2076 fname
= xmalloc(strlen((const_string
)(nameoffile
+1))+1);
2077 strcpy(fname
,(const_string
)(nameoffile
+1));
2079 free(fullnameoffile
);
2080 fullnameoffile
= xstrdup(fname
);
2081 recorder_record_input (fname
+ 1);
2082 (*f
)->f
= runpopen(fname
+1,"r");
2084 for (i
=0; i
<NUM_PIPES
; i
++) {
2085 if (pipes
[i
]==NULL
) {
2091 setvbuf ((*f
)->f
,NULL
,_IONBF
,0);
2096 return (*f
)->f
!= NULL
;
2099 return u_open_in(f
, filefmt
, fopen_mode
, mode
, encodingData
);
2104 open_out_or_pipe (FILE **f_ptr
, const_string fopen_mode
)
2107 int i
; /* iterator */
2109 /* opening a write pipe takes a little bit more work, because TeX
2110 will perhaps have appended ".tex". To avoid user confusion as
2111 much as possible, this extension is stripped only when the command
2112 is a bare word. Some small string trickery is needed to make
2113 sure the correct number of bytes is free()-d afterwards */
2115 if (shellenabledp
&& *(nameoffile
+1) == '|') {
2116 /* the user requested a pipe */
2117 fname
= xmalloc(strlen((const_string
)(nameoffile
+1))+1);
2118 strcpy(fname
,(const_string
)(nameoffile
+1));
2119 if (strchr (fname
,' ')==NULL
&& strchr(fname
,'>')==NULL
) {
2120 /* mp and mf currently do not use this code, but it
2121 is better to be prepared */
2122 if (STREQ((fname
+strlen(fname
)-4),".tex"))
2123 *(fname
+strlen(fname
)-4) = 0;
2124 *f_ptr
= runpopen(fname
+1,"w");
2125 *(fname
+strlen(fname
)) = '.';
2127 *f_ptr
= runpopen(fname
+1,"w");
2129 recorder_record_output (fname
+ 1);
2132 for (i
=0; i
<NUM_PIPES
; i
++) {
2133 if (pipes
[i
]==NULL
) {
2140 setvbuf(*f_ptr
,NULL
,_IONBF
,0);
2142 return *f_ptr
!= NULL
;
2145 return open_output(f_ptr
,fopen_mode
);
2150 close_file_or_pipe (FILE *f
)
2152 int i
; /* iterator */
2154 if (shellenabledp
) {
2155 /* if this file was a pipe, pclose() it and return */
2156 for (i
=0; i
<NUM_PIPES
; i
++) {
2157 if (pipes
[i
] == f
) {
2171 #endif /* ENABLE_PIPES */
2173 /* All our interrupt handler has to do is set TeX's or Metafont's global
2174 variable `interrupt'; then they will do everything needed. */
2176 /* Win32 doesn't set SIGINT ... */
2178 catch_interrupt (DWORD arg
)
2182 case CTRL_BREAK_EVENT
:
2186 /* No need to set interrupt as we are exiting anyway */
2190 #else /* not WIN32 */
2192 catch_interrupt (int arg
)
2196 (void) signal (SIGINT
, SIG_ACK
);
2198 (void) signal (SIGINT
, catch_interrupt
);
2199 #endif /* not OS2 */
2201 #endif /* not WIN32 */
2203 #if defined(_MSC_VER)
2204 #define strtoull _strtoui64
2207 static boolean start_time_set
= false;
2208 static time_t start_time
= 0;
2210 void init_start_time() {
2211 char *source_date_epoch
;
2212 unsigned long long epoch
;
2214 if (!start_time_set
) {
2215 start_time_set
= true;
2217 source_date_epoch
= getenv("SOURCE_DATE_EPOCH");
2218 if (source_date_epoch
) {
2220 epoch
= strtoull(source_date_epoch
, &endptr
, 10);
2221 if (epoch
< 0 || *endptr
!= '\0' || errno
!= 0) {
2222 FATAL1 ("invalid epoch-seconds-timezone value for environment variable $SOURCE_DATE_EPOCH: %s",
2225 #if defined(_MSC_VER)
2226 if (epoch
> 32535291599ULL)
2227 epoch
= 32535291599ULL;
2231 #endif /* not onlyTeX */
2233 start_time
= time((time_t *) NULL
);
2238 /* Besides getting the date and time here, we also set up the interrupt
2239 handler, for no particularly good reason. It's just that since the
2240 `fix_date_and_time' routine is called early on (section 1337 in TeX,
2241 ``Get the first line of input and prepare to start''), this is as
2242 good a place as any. */
2245 get_date_and_time (integer
*minutes
, integer
*day
,
2246 integer
*month
, integer
*year
)
2250 string sde_texprim
= getenv ("FORCE_SOURCE_DATE");
2251 if (sde_texprim
&& STREQ (sde_texprim
, "1")) {
2253 tmptr
= gmtime (&start_time
);
2255 #endif /* not onlyTeX */
2257 /* whether the envvar was not set (usual case) or invalid,
2258 use current time. */
2259 time_t myclock
= time ((time_t *) 0);
2260 tmptr
= localtime (&myclock
);
2263 /* warn if they gave an invalid value, empty (null string) ok. */
2264 if (sde_texprim
&& strlen (sde_texprim
) > 0
2265 && !STREQ (sde_texprim
, "0")) {
2266 WARNING1 ("invalid value (expected 0 or 1) for environment variable $FORCE_SOURCE_DATE: %s",
2269 #endif /* not onlyTeX */
2272 *minutes
= tmptr
->tm_hour
* 60 + tmptr
->tm_min
;
2273 *day
= tmptr
->tm_mday
;
2274 *month
= tmptr
->tm_mon
+ 1;
2275 *year
= tmptr
->tm_year
+ 1900;
2279 /* Under SunOS 4.1.x, the default action after return from the
2280 signal handler is to restart the I/O if nothing has been
2281 transferred. The effect on TeX is that interrupts are ignored if
2282 we are waiting for input. The following tells the system to
2283 return EINTR from read() in this case. From ken@cs.toronto.edu. */
2285 struct sigaction a
, oa
;
2287 a
.sa_handler
= catch_interrupt
;
2288 sigemptyset (&a
.sa_mask
);
2289 sigaddset (&a
.sa_mask
, SIGINT
);
2290 a
.sa_flags
= SA_INTERRUPT
;
2291 sigaction (SIGINT
, &a
, &oa
);
2292 if (oa
.sa_handler
!= SIG_DFL
)
2293 sigaction (SIGINT
, &oa
, (struct sigaction
*) 0);
2294 #else /* no SA_INTERRUPT */
2296 SetConsoleCtrlHandler(catch_interrupt
, TRUE
);
2297 #else /* not WIN32 */
2298 RETSIGTYPE (*old_handler
)(int);
2300 old_handler
= signal (SIGINT
, catch_interrupt
);
2301 if (old_handler
!= SIG_DFL
)
2302 signal (SIGINT
, old_handler
);
2303 #endif /* not WIN32 */
2304 #endif /* no SA_INTERRUPT */
2308 #if defined(pdfTeX) || defined(epTeX) || defined(eupTeX)
2310 Getting a high resolution time.
2313 get_seconds_and_micros (integer
*seconds
, integer
*micros
)
2315 #if defined (HAVE_GETTIMEOFDAY)
2317 gettimeofday(&tv
, NULL
);
2318 *seconds
= tv
.tv_sec
;
2319 *micros
= tv
.tv_usec
;
2320 #elif defined (HAVE_FTIME)
2324 *micros
= tb
.millitm
*1000;
2326 time_t myclock
= time((time_t*)NULL
);
2333 /* Read a line of input as efficiently as possible while still looking
2334 like Pascal. We set `last' to `first' and return `false' if we get
2335 to eof. Otherwise, we return `true' and set last = first +
2336 length(line except trailing whitespace). */
2338 #ifndef XeTeX /* for XeTeX, we have a replacement function in XeTeX_ext.c */
2340 input_line (FILE *f
)
2344 /* Recognize either LF or CR as a line terminator. */
2346 last
= input_line2(f
, (unsigned char *)buffer
, first
, bufsize
, &i
);
2349 if (f
!= Poptr
&& fileno (f
) != fileno (stdin
)) {
2350 long position
= ftell (f
);
2352 if (position
== 0L) { /* Detect and skip Byte order marks. */
2356 if (k1
!= 0xff && k1
!= 0xfe && k1
!= 0xef)
2361 if (k2
!= 0xff && k2
!= 0xfe && k2
!= 0xbb)
2363 else if ((k1
== 0xff && k2
== 0xfe) || /* UTF-16(LE) */
2364 (k1
== 0xfe && k2
== 0xff)) /* UTF-16(BE) */
2369 if (k1
== 0xef && k2
== 0xbb && k3
== 0xbf &&
2370 k4
>= 0 && k4
<= 0x7e) /* UTF-8 */
2380 while (last
< bufsize
&& (i
= getc (f
)) != EOF
&& i
!= '\n' && i
!= '\r')
2384 if (i
== EOF
&& errno
!= EINTR
&& last
== first
)
2387 /* We didn't get the whole line because our buffer was too small. */
2388 if (i
!= EOF
&& i
!= '\n' && i
!= '\r') {
2389 fprintf (stderr
, "! Unable to read an entire line---bufsize=%u.\n",
2390 (unsigned) bufsize
);
2391 fputs ("Please increase buf_size in texmf.cnf.\n", stderr
);
2396 if (last
>= maxbufstack
)
2399 /* If next char is LF of a CRLF, read it. */
2401 while ((i
= getc (f
)) == EOF
&& errno
== EINTR
)
2407 /* Trim trailing whitespace. */
2408 while (last
> first
&& ISBLANK (buffer
[last
- 1]))
2411 /* Don't bother using xord if we don't need to. */
2413 for (i
= first
; i
<= last
; i
++)
2414 buffer
[i
] = xord
[buffer
[i
]];
2418 for (i
= last
+1; (i
< last
+ 5 && i
< bufsize
) ; i
++)
2426 /* This string specifies what the `e' option does in response to an
2428 static const_string edit_value
= EDITOR
;
2430 /* This procedure originally due to sjc@s1-c. TeX & Metafont call it when
2431 the user types `e' in response to an error, invoking a text editor on
2432 the erroneous source file. FNSTART is how far into FILENAME the
2433 actual filename starts; FNLENGTH is how long the filename is. */
2436 calledit (packedASCIIcode
*filename
,
2437 poolpointer fnstart
,
2441 char *temp
, *command
, *fullcmd
;
2443 int sdone
, ddone
, i
;
2446 char *fp
, *ffp
, *env
, editorname
[256], buffer
[256];
2452 filename
+= fnstart
;
2454 /* Close any open input files, since we're going to kill the job. */
2455 for (i
= 1; i
<= inopen
; i
++)
2457 xfclose (inputfile
[i
]->f
, "inputfile");
2459 xfclose (inputfile
[i
], "inputfile");
2462 /* Replace the default with the value of the appropriate environment
2463 variable or config file value, if it's set. */
2464 temp
= kpse_var_value (edit_var
);
2468 /* Construct the command string. The `11' is the maximum length an
2469 integer might be. */
2470 command
= xmalloc (strlen (edit_value
) + fnlength
+ 11);
2472 /* So we can construct it as we go. */
2477 if ((isalpha(*edit_value
) && *(edit_value
+ 1) == ':'
2478 && IS_DIR_SEP (*(edit_value
+ 2)))
2479 || (*edit_value
== '"' && isalpha(*(edit_value
+ 1))
2480 && *(edit_value
+ 2) == ':'
2481 && IS_DIR_SEP (*(edit_value
+ 3)))
2486 while ((c
= *edit_value
++) != 0)
2490 switch (c
= *edit_value
++)
2494 FATAL ("call_edit: `%%d' appears twice in editor command");
2495 sprintf (temp
, "%ld", (long int)linenumber
);
2496 while (*temp
!= '\0')
2503 FATAL ("call_edit: `%%s' appears twice in editor command");
2504 for (i
=0; i
< fnlength
; i
++)
2505 *temp
++ = Xchr (filename
[i
]);
2511 /* Back up to the null to force termination. */
2525 else { if(Isspace(c
) && cnt
== 0) {
2530 } else if(!Isspace(c
) && cnt
== 0) {
2545 if (dontchange
== 0) {
2546 if(editorname
[0] == '.' ||
2547 editorname
[0] == '/' ||
2548 editorname
[0] == '\\') {
2549 fprintf(stderr
, "%s is not allowed to execute.\n", editorname
);
2552 env
= (char *)getenv("PATH");
2553 if(SearchPath(env
, editorname
, ".exe", 256, buffer
, &ffp
)==0) {
2554 if(SearchPath(env
, editorname
, ".bat", 256, buffer
, &ffp
)==0) {
2555 fprintf(stderr
, "I cannot find %s in the PATH.\n", editorname
);
2559 fullcmd
= (char *)xmalloc(strlen(buffer
)+strlen(command
)+5);
2560 strcpy(fullcmd
, "\"");
2561 strcat(fullcmd
, buffer
);
2562 strcat(fullcmd
, "\"");
2563 strcat(fullcmd
, command
);
2568 /* Execute the command. */
2569 if (system (fullcmd
) != 0)
2570 fprintf (stderr
, "! Trouble executing `%s'.\n", command
);
2572 /* Quit, since we found an error. */
2576 /* Read and write dump files. As distributed, these files are
2577 architecture dependent; specifically, BigEndian and LittleEndian
2578 architectures produce different files. These routines always output
2579 BigEndian files. This still does not guarantee them to be
2580 architecture-independent, because it is possible to make a format
2581 that dumps a glue ratio, i.e., a floating-point number. Fortunately,
2582 none of the standard formats do that. */
2584 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE) /* this fn */
2586 /* This macro is always invoked as a statement. It assumes a variable
2589 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp
2592 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
2593 opposite-endianness of whatever they are now. */
2596 swap_items (char *p
, int nitems
, int size
)
2600 /* Since `size' does not change, we can write a while loop for each
2601 case, and avoid testing `size' for each time. */
2604 /* 16-byte items happen on the DEC Alpha machine when we are not
2605 doing sharable memory dumps. */
2650 /* Nothing to do. */
2654 FATAL1 ("Can't swap a %d-byte item for (un)dumping", size
);
2657 #endif /* not WORDS_BIGENDIAN and not NO_DUMP_SHARE */
2660 /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
2661 The pointer to the stuff to write is P, and we write to the file
2666 do_dump (char *p
, int item_size
, int nitems
, gzFile out_file
)
2668 do_dump (char *p
, int item_size
, int nitems
, FILE *out_file
)
2671 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2672 swap_items (p
, nitems
, item_size
);
2676 if (gzwrite (out_file
, p
, item_size
* nitems
) != item_size
* nitems
)
2678 if (fwrite (p
, item_size
, nitems
, out_file
) != nitems
)
2681 fprintf (stderr
, "! Could not write %d %d-byte item(s) to %s.\n",
2682 nitems
, item_size
, nameoffile
+1);
2686 /* Have to restore the old contents of memory, since some of it might
2688 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2689 swap_items (p
, nitems
, item_size
);
2694 /* Here is the dual of the writing routine. */
2698 do_undump (char *p
, int item_size
, int nitems
, gzFile in_file
)
2700 do_undump (char *p
, int item_size
, int nitems
, FILE *in_file
)
2704 if (gzread (in_file
, p
, item_size
* nitems
) != item_size
* nitems
)
2706 if (fread (p
, item_size
, nitems
, in_file
) != (size_t) nitems
)
2708 FATAL3 ("Could not undump %d %d-byte item(s) from %s",
2709 nitems
, item_size
, nameoffile
+1);
2711 #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE)
2712 swap_items (p
, nitems
, item_size
);
2716 /* FIXME -- some (most?) of this can/should be moved to the Pascal/WEB side. */
2717 #if defined(TeX) || defined(MF)
2718 #if !defined(pdfTeX)
2720 checkpoolpointer (poolpointer poolptr
, size_t len
)
2722 if (poolptr
+ len
>= poolsize
) {
2723 fprintf (stderr
, "\nstring pool overflow [%i bytes]\n",
2724 (int)poolsize
); /* fixme */
2729 #ifndef XeTeX /* XeTeX uses this from XeTeX_ext.c */
2733 maketexstring(const_string s
)
2738 const unsigned char *cp
= (const unsigned char *)s
;
2741 if (s
== NULL
|| *s
== 0)
2742 return getnullstr();
2747 checkpoolpointer (poolptr
, len
); /* in the XeTeX case, this may be more than enough */
2749 while ((rval
= *(cp
++)) != 0) {
2750 UInt16 extraBytes
= bytesFromUTF8
[rval
];
2751 switch (extraBytes
) { /* note: code falls through cases! */
2752 case 5: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2753 case 4: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2754 case 3: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2755 case 2: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2756 case 1: rval
<<= 6; if (*cp
) rval
+= *(cp
++);
2759 rval
-= offsetsFromUTF8
[extraBytes
];
2760 if (rval
> 0xffff) {
2762 strpool
[poolptr
++] = 0xd800 + rval
/ 0x0400;
2763 strpool
[poolptr
++] = 0xdc00 + rval
% 0x0400;
2766 strpool
[poolptr
++] = rval
;
2770 strpool
[poolptr
++] = *s
++;
2771 #endif /* ! XeTeX */
2773 return makestring();
2775 #endif /* !pdfTeX */
2778 makefullnamestring(void)
2780 return maketexstring(fullnameoffile
);
2783 /* Get the job name to be used, which may have been set from the
2786 getjobname(strnumber name
)
2788 strnumber ret
= name
;
2789 if (c_job_name
!= NULL
)
2790 ret
= maketexstring(c_job_name
);
2797 compare_paths (const_string p1
, const_string p2
)
2801 #ifdef MONOCASE_FILENAMES
2802 (((ret
= (toupper(*p1
) - toupper(*p2
))) == 0) && (*p2
!= 0))
2804 (((ret
= (*p1
- *p2
)) == 0) && (*p2
!= 0))
2806 || (IS_DIR_SEP(*p1
) && IS_DIR_SEP(*p2
))) {
2809 ret
= (ret
< 0 ? -1 : (ret
> 0 ? 1 : 0));
2813 #ifdef XeTeX /* the string pool is UTF-16 but we want a UTF-8 string */
2816 gettexstring (strnumber s
)
2818 unsigned bytesToWrite
= 0;
2819 poolpointer len
, i
, j
;
2821 if (strstart
[s
+ 1 - 65536L] < strstart
[s
- 65536L])
2823 len
= strstart
[s
+ 1 - 65536L] - strstart
[s
- 65536L];
2824 name
= xmalloc(len
* 3 + 1); /* max UTF16->UTF8 expansion
2825 (code units, not bytes) */
2826 for (i
= 0, j
= 0; i
< len
; i
++) {
2827 unsigned c
= strpool
[i
+ strstart
[s
- 65536L]];
2828 if (c
>= 0xD800 && c
<= 0xDBFF) {
2829 unsigned lo
= strpool
[++i
+ strstart
[s
- 65536L]];
2830 if (lo
>= 0xDC00 && lo
<= 0xDFFF)
2831 c
= (c
- 0xD800) * 0x0400 + lo
- 0xDC00;
2839 else if (c
< 0x10000)
2841 else if (c
< 0x110000)
2849 switch (bytesToWrite
) { /* note: everything falls through. */
2850 case 4: name
[--j
] = ((c
| 0x80) & 0xBF); c
>>= 6;
2851 case 3: name
[--j
] = ((c
| 0x80) & 0xBF); c
>>= 6;
2852 case 2: name
[--j
] = ((c
| 0x80) & 0xBF); c
>>= 6;
2853 case 1: name
[--j
] = (c
| firstByteMark
[bytesToWrite
]);
2864 gettexstring (strnumber s
)
2869 len
= strstart
[s
+ 1] - strstart
[s
];
2871 len
= strstartar
[s
+ 1 - 65536L] - strstartar
[s
- 65536L];
2873 name
= (string
)xmalloc (len
+ 1);
2875 strncpy (name
, (string
)&strpool
[strstart
[s
]], len
);
2879 /* Don't use strncpy. The strpool is not made up of chars. */
2880 for (i
=0; i
<len
; i
++) name
[i
] = strpool
[i
+strstartar
[s
- 65536L]];
2887 #endif /* not XeTeX */
2890 isnewsource (strnumber srcfilename
, int lineno
)
2892 char *name
= gettexstring(srcfilename
);
2893 return (compare_paths(name
, last_source_name
) != 0 || lineno
!= last_lineno
);
2897 remembersourceinfo (strnumber srcfilename
, int lineno
)
2899 if (last_source_name
)
2900 free(last_source_name
);
2901 last_source_name
= gettexstring(srcfilename
);
2902 last_lineno
= lineno
;
2906 makesrcspecial (strnumber srcfilename
, int lineno
)
2908 poolpointer oldpoolptr
= poolptr
;
2909 char *filename
= gettexstring(srcfilename
);
2910 /* FIXME: Magic number. */
2914 /* Always put a space after the number, which makes things easier
2917 sprintf (buf
, "src:%d ", lineno
);
2919 if (poolptr
+ strlen(buf
) + strlen(filename
) >= (size_t)poolsize
) {
2920 fprintf (stderr
, "\nstring pool overflow\n"); /* fixme */
2925 strpool
[poolptr
++] = *s
++;
2929 strpool
[poolptr
++] = *s
++;
2931 return (oldpoolptr
);
2934 /* pdfTeX routines also used for e-pTeX, e-upTeX, and XeTeX */
2935 #if defined (pdfTeX) || defined (epTeX) || defined (eupTeX) || defined(XeTeX)
2937 #include <kpathsea/c-stat.h>
2940 #define check_nprintf(size_get, size_want) \
2941 if ((unsigned)(size_get) >= (unsigned)(size_want)) \
2942 pdftex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__);
2943 # define check_buf(size, buf_size) \
2944 if ((unsigned)(size) > (unsigned)(buf_size)) \
2945 pdftex_fail("buffer overflow at file %s, line %d", __FILE__, __LINE__ )
2946 # define xfree(p) do { if (p != NULL) free(p); p = NULL; } while (0)
2947 # define MAX_CSTRING_LEN 1024 * 1024
2949 #if !defined (pdfTeX)
2950 # define PRINTF_BUF_SIZE 1024
2951 static char print_buf
[PRINTF_BUF_SIZE
];
2953 /* Helper for pdftex_fail. */
2954 static void safe_print(const char *str
)
2957 for (c
= str
; *c
; ++c
)
2960 /* pdftex_fail may be called when a buffer overflow has happened/is
2961 happening, therefore may not call mktexstring. However, with the
2962 current implementation it appears that error messages are misleading,
2963 possibly because pool overflows are detected too late.
2965 The output format of this fuction must be the same as pdf_error in
2967 __attribute__ ((noreturn
, format(printf
, 1, 2)))
2968 void pdftex_fail(const char *fmt
, ...)
2971 va_start(args
, fmt
);
2973 safe_print("!error: ");
2974 vsnprintf(print_buf
, PRINTF_BUF_SIZE
, fmt
, args
);
2975 safe_print(print_buf
);
2978 safe_print(" ==> Fatal error occurred, output file will be damaged!");
2980 if (kpathsea_debug
) {
2981 safe_print("kpathsea_debug enabled, calling abort()...");
2988 #endif /* not pdfTeX */
2992 #define TIME_STR_SIZE 30
2993 char start_time_str
[TIME_STR_SIZE
];
2994 static char time_str
[TIME_STR_SIZE
];
2995 /* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */
2997 static void makepdftime(time_t t
, char *time_str
, boolean utc
)
3002 int i
, off
, off_hours
, off_mins
;
3009 lt
= *localtime(&t
);
3011 size
= strftime(time_str
, TIME_STR_SIZE
, "D:%Y%m%d%H%M%S", <
);
3012 /* expected format: "YYYYmmddHHMMSS" */
3014 /* unexpected, contents of time_str is undefined */
3019 /* correction for seconds: %S can be in range 00..61,
3020 the PDF reference expects 00..59,
3021 therefore we map "60" and "61" to "59" */
3022 if (time_str
[14] == '6') {
3025 time_str
[16] = '\0'; /* for safety */
3028 /* get the time zone offset */
3031 /* this calculation method was found in exim's tod.c */
3032 off
= 60 * (lt
.tm_hour
- gmt
.tm_hour
) + lt
.tm_min
- gmt
.tm_min
;
3033 if (lt
.tm_year
!= gmt
.tm_year
) {
3034 off
+= (lt
.tm_year
> gmt
.tm_year
) ? 1440 : -1440;
3035 } else if (lt
.tm_yday
!= gmt
.tm_yday
) {
3036 off
+= (lt
.tm_yday
> gmt
.tm_yday
) ? 1440 : -1440;
3040 time_str
[size
++] = 'Z';
3043 off_hours
= off
/ 60;
3044 off_mins
= abs(off
- off_hours
* 60);
3045 i
= snprintf(&time_str
[size
], 9, "%+03d'%02d'", off_hours
, off_mins
);
3046 check_nprintf(i
, 9);
3050 void initstarttime(void)
3052 if (!start_time_set
) {
3054 if (getenv ("SOURCE_DATE_EPOCH")) {
3055 makepdftime (start_time
, start_time_str
, /* utc= */true);
3057 makepdftime (start_time
, start_time_str
, /* utc= */false);
3062 char *makecstring(integer s
)
3064 static char *cstrbuf
= NULL
;
3066 static int allocsize
;
3067 int allocgrow
, i
, l
= strstart
[s
+ 1] - strstart
[s
];
3068 check_buf(l
+ 1, MAX_CSTRING_LEN
);
3069 if (cstrbuf
== NULL
) {
3071 cstrbuf
= xmallocarray(char, allocsize
);
3072 } else if (l
+ 1 > allocsize
) {
3073 allocgrow
= allocsize
* 0.2;
3074 if (l
+ 1 - allocgrow
> allocsize
)
3076 else if (allocsize
< MAX_CSTRING_LEN
- allocgrow
)
3077 allocsize
+= allocgrow
;
3079 allocsize
= MAX_CSTRING_LEN
;
3080 cstrbuf
= xreallocarray(cstrbuf
, char, allocsize
);
3083 for (i
= 0; i
< l
; i
++)
3084 *p
++ = strpool
[i
+ strstart
[s
]];
3090 input/ouput same as makecstring:
3091 input: string number
3092 output: C string with quotes removed.
3093 That means, file names that are legal on some operation systems
3094 cannot any more be used since pdfTeX version 1.30.4.
3096 char *makecfilename(integer s
)
3098 char *name
= makecstring(s
);
3111 void getcreationdate(void)
3115 /* put creation date on top of string pool and update poolptr */
3116 len
= strlen(start_time_str
);
3118 /* In e-pTeX, "init len => call initstarttime()" (as pdftexdir/utils.c)
3119 yields unintentional output. */
3121 if ((unsigned) (poolptr
+ len
) >= (unsigned) (poolsize
)) {
3123 /* error by str_toks that calls str_room(1) */
3127 memcpy(&strpool
[poolptr
], start_time_str
, len
);
3131 void getfilemoddate(integer s
)
3133 struct stat file_data
;
3135 char *file_name
= kpse_find_tex(makecfilename(s
));
3136 if (file_name
== NULL
) {
3137 return; /* empty string */
3140 recorder_record_input(file_name
);
3141 /* get file status */
3142 if (stat(file_name
, &file_data
) == 0) {
3145 makepdftime(file_data
.st_mtime
, time_str
, /* utc= */false);
3146 len
= strlen(time_str
);
3147 if ((unsigned) (poolptr
+ len
) >= (unsigned) (poolsize
)) {
3149 /* error by str_toks that calls str_room(1) */
3151 memcpy(&strpool
[poolptr
], time_str
, len
);
3155 /* else { errno contains error code } */
3160 void getfilesize(integer s
)
3162 struct stat file_data
;
3165 char *file_name
= kpse_find_tex(makecfilename(s
));
3166 if (file_name
== NULL
) {
3167 return; /* empty string */
3170 recorder_record_input(file_name
);
3171 /* get file status */
3172 if (stat(file_name
, &file_data
) == 0) {
3176 /* st_size has type off_t */
3177 i
= snprintf(buf
, sizeof(buf
),
3178 "%lu", (long unsigned int) file_data
.st_size
);
3179 check_nprintf(i
, sizeof(buf
));
3181 if ((unsigned) (poolptr
+ len
) >= (unsigned) (poolsize
)) {
3183 /* error by str_toks that calls str_room(1) */
3185 memcpy(&strpool
[poolptr
], buf
, len
);
3189 /* else { errno contains error code } */
3194 void getfiledump(integer s
, int offset
, int length
)
3198 poolpointer data_ptr
;
3199 poolpointer data_end
;
3203 /* empty result string */
3207 if (poolptr
+ 2 * length
+ 1 >= poolsize
) {
3208 /* no place for result */
3210 /* error by str_toks that calls str_room(1) */
3214 file_name
= kpse_find_tex(makecfilename(s
));
3215 if (file_name
== NULL
) {
3216 return; /* empty string */
3219 /* read file data */
3220 f
= fopen(file_name
, FOPEN_RBIN_MODE
);
3225 recorder_record_input(file_name
);
3226 if (fseek(f
, offset
, SEEK_SET
) != 0) {
3230 /* there is enough space in the string pool, the read
3231 data are put in the upper half of the result, thus
3232 the conversion to hex can be done without overwriting
3233 unconverted bytes. */
3234 data_ptr
= poolptr
+ length
;
3235 read
= fread(&strpool
[data_ptr
], sizeof(char), length
, f
);
3238 /* convert to hex */
3239 data_end
= data_ptr
+ read
;
3240 for (; data_ptr
< data_end
; data_ptr
++) {
3241 i
= snprintf((char *) &strpool
[poolptr
], 3,
3242 "%.2X", (unsigned int) strpool
[data_ptr
]);
3243 check_nprintf(i
, 3);
3248 #endif /* not XeTeX */
3250 /* Converts any given string in into an allowed PDF string which is
3251 * hexadecimal encoded;
3252 * sizeof(out) should be at least lin*2+1.
3254 void convertStringToHexString(const char *in
, char *out
, int lin
)
3259 for (i
= 0; i
< lin
; i
++) {
3260 k
= snprintf(buf
, sizeof(buf
),
3261 "%02X", (unsigned int) (unsigned char) in
[i
]);
3262 check_nprintf(k
, sizeof(buf
));
3269 #define DIGEST_SIZE 16
3270 #define FILE_BUF_SIZE 1024
3272 void getmd5sum(strnumber s
, boolean file
)
3275 md5_byte_t digest
[DIGEST_SIZE
];
3276 char outbuf
[2 * DIGEST_SIZE
+ 1];
3277 int len
= 2 * DIGEST_SIZE
;
3284 char file_buf
[FILE_BUF_SIZE
];
3290 xname
= gettexstring (s
);
3291 file_name
= kpse_find_tex (xname
);
3294 file_name
= kpse_find_tex(makecfilename(s
));
3296 if (file_name
== NULL
) {
3297 return; /* empty string */
3299 /* in case of error the empty string is returned,
3300 no need for xfopen that aborts on error.
3302 f
= fopen(file_name
, FOPEN_RBIN_MODE
);
3307 recorder_record_input(file_name
);
3309 while ((read
= fread(&file_buf
, sizeof(char), FILE_BUF_SIZE
, f
)) > 0) {
3310 md5_append(&state
, (const md5_byte_t
*) file_buf
, read
);
3312 md5_finish(&state
, digest
);
3317 /* s contains the data */
3320 xname
= gettexstring (s
);
3322 (md5_byte_t
*) xname
,
3327 (md5_byte_t
*) &strpool
[strstart
[s
]],
3328 strstart
[s
+ 1] - strstart
[s
]);
3330 md5_finish(&state
, digest
);
3333 if (poolptr
+ len
>= poolsize
) {
3334 /* error by str_toks that calls str_room(1) */
3337 convertStringToHexString((char *) digest
, outbuf
, DIGEST_SIZE
);
3339 for (i
= 0; i
< 2 * DIGEST_SIZE
; i
++)
3340 strpool
[poolptr
++] = (uint16_t)outbuf
[i
];
3342 memcpy(&strpool
[poolptr
], outbuf
, len
);
3347 #endif /* pdfTeX or e-pTeX or e-upTeX or XeTeX */
3350 /* Metafont/MetaPost fraction routines. Replaced either by assembler or C.
3351 The assembler syntax doesn't work on Solaris/x86. */
3353 #if defined (__sun__) || defined (__cplusplus)
3356 /* The assembler code is not PIC safe on i?86 so use C code. */
3357 #if defined (__PIC__) && defined (__i386__)
3360 #if defined(WIN32) && !defined(NO_MF_ASM) && !defined(__MINGW32__)
3361 #include "lib/mfmpw32.c"
3362 #elif defined (__i386__) && defined (__GNUC__) && !defined (NO_MF_ASM)
3363 #include "lib/mfmpi386.asm"
3365 /* Replace fixed-point fraction routines from mf.web and mp.web with
3366 Hobby's floating-point C code. */
3368 /****************************************************************
3369 Copyright 1990 - 1995 by AT&T Bell Laboratories.
3371 Permission to use, copy, modify, and distribute this software
3372 and its documentation for any purpose and without fee is hereby
3373 granted, provided that the above copyright notice appear in all
3374 copies and that both that the copyright notice and this
3375 permission notice and warranty disclaimer appear in supporting
3376 documentation, and that the names of AT&T Bell Laboratories or
3377 any of its entities not be used in advertising or publicity
3378 pertaining to distribution of the software without specific,
3379 written prior permission.
3381 AT&T disclaims all warranties with regard to this software,
3382 including all implied warranties of merchantability and fitness.
3383 In no event shall AT&T be liable for any special, indirect or
3384 consequential damages or any damages whatsoever resulting from
3385 loss of use, data or profits, whether in an action of contract,
3386 negligence or other tortious action, arising out of or in
3387 connection with the use or performance of this software.
3388 ****************************************************************/
3390 /**********************************************************
3391 The following is by John Hobby
3392 **********************************************************/
3396 /* These replacements for takefraction, makefraction, takescaled, makescaled
3397 run about 3 to 11 times faster than the standard versions on modern machines
3398 that have fast hardware for double-precision floating point. They should
3399 produce approximately correct results on all machines and agree exactly
3400 with the standard versions on machines that satisfy the following conditions:
3401 1. Doubles must have at least 46 mantissa bits; i.e., numbers expressible
3402 as n*2^k with abs(n)<2^46 should be representable.
3403 2. The following should hold for addition, subtraction, and multiplcation but
3404 not necessarily for division:
3405 A. If the true answer is between two representable numbers, the computed
3406 answer must be one of them.
3407 B. When the true answer is representable, this must be the computed result.
3408 3. Dividing one double by another should always produce a relative error of
3409 at most one part in 2^46. (This is why the mantissa requirement is
3410 46 bits instead of 45 bits.)
3411 3. In the absence of overflow, double-to-integer conversion should truncate
3412 toward zero and do this in an exact fashion.
3413 4. Integer-to-double convesion should produce exact results.
3414 5. Dividing one power of two by another should yield an exact result.
3415 6. ASCII to double conversion should be exact for integer values.
3416 7. Integer arithmetic must be done in the two's-complement system.
3418 #define ELGORDO 0x7fffffff
3419 #define TWEXP31 2147483648.0
3420 #define TWEXP28 268435456.0
3421 #define TWEXP16 65536.0
3422 #define TWEXP_16 (1.0/65536.0)
3423 #define TWEXP_28 (1.0/268435456.0)
3426 ztakefraction (integer p
, integer q
) /* Approximate p*q/2^28 */
3427 { register double d
;
3429 d
= (double)p
* (double)q
* TWEXP_28
;
3433 if (d
!=TWEXP31
|| (((p
&077777)*(q
&077777))&040000)==0)
3438 if (d
==i
&& (((p
&077777)*(q
&077777))&040000)!=0) --i
;
3442 if (d
!= -TWEXP31
|| ((-(p
&077777)*(q
&077777))&040000)==0)
3447 if (d
==i
&& ((-(p
&077777)*(q
&077777))&040000)!=0) ++i
;
3453 ztakescaled (integer p
, integer q
) /* Approximate p*q/2^16 */
3454 { register double d
;
3456 d
= (double)p
* (double)q
* TWEXP_16
;
3460 if (d
!=TWEXP31
|| (((p
&077777)*(q
&077777))&040000)==0)
3465 if (d
==i
&& (((p
&077777)*(q
&077777))&040000)!=0) --i
;
3469 if (d
!= -TWEXP31
|| ((-(p
&077777)*(q
&077777))&040000)==0)
3474 if (d
==i
&& ((-(p
&077777)*(q
&077777))&040000)!=0) ++i
;
3479 /* Note that d cannot exactly equal TWEXP31 when the overflow test is made
3480 because the exact value of p/q cannot be strictly between (2^31-1)/2^28
3481 and 8/1. No pair of integers less than 2^31 has such a ratio.
3484 zmakefraction (integer p
, integer q
) /* Approximate 2^28*p/q */
3485 { register double d
;
3488 if (q
==0) confusion(47);
3490 d
= TWEXP28
* (double)p
/(double)q
;
3493 if (d
>=TWEXP31
) {aritherror
=true; return ELGORDO
;}
3495 if (d
==i
&& ( ((q
>0 ? -q
: q
)&077777)
3496 * (((i
&037777)<<1)-1) & 04000)!=0) --i
;
3499 if (d
<= -TWEXP31
) {aritherror
=true; return -ELGORDO
;}
3501 if (d
==i
&& ( ((q
>0 ? q
: -q
)&077777)
3502 * (((i
&037777)<<1)+1) & 04000)!=0) ++i
;
3507 /* Note that d cannot exactly equal TWEXP31 when the overflow test is made
3508 because the exact value of p/q cannot be strictly between (2^31-1)/2^16
3509 and 2^15/1. No pair of integers less than 2^31 has such a ratio.
3512 zmakescaled (integer p
, integer q
) /* Approximate 2^16*p/q */
3513 { register double d
;
3516 if (q
==0) confusion(47);
3518 d
= TWEXP16
* (double)p
/(double)q
;
3521 if (d
>=TWEXP31
) {aritherror
=true; return ELGORDO
;}
3523 if (d
==i
&& ( ((q
>0 ? -q
: q
)&077777)
3524 * (((i
&037777)<<1)-1) & 04000)!=0) --i
;
3527 if (d
<= -TWEXP31
) {aritherror
=true; return -ELGORDO
;}
3529 if (d
==i
&& ( ((q
>0 ? q
: -q
)&077777)
3530 * (((i
&037777)<<1)+1) & 04000)!=0) ++i
;
3535 #endif /* not FIXPT */
3536 #endif /* not assembler */
3537 #endif /* not TeX, i.e., MF */
3540 /* On-line display routines for Metafont. Here we use a dispatch table
3541 indexed by the MFTERM or TERM environment variable to select the
3542 graphics routines appropriate to the user's terminal. stdout must be
3543 connected to a terminal for us to do any graphics. */
3559 /* Prototypes for Metafont display routines: mf_XXX_initscreen,
3560 mf_XXX_updatescreen, mf_XXX_blankrectangle, and mf_XXX_paintrow. */
3561 #include <window/mfdisplay.h>
3563 /* This variable, `mfwsw', contains the dispatch tables for each
3564 terminal. We map the Pascal calls to the routines `init_screen',
3565 `update_screen', `blank_rectangle', and `paint_row' into the
3566 appropriate entry point for the specific terminal that MF is being
3571 const char *mfwsw_type
; /* Name of terminal a la TERMCAP. */
3572 int (*mfwsw_initscreen
) (void);
3573 void (*mfwsw_updatescrn
) (void);
3574 void (*mfwsw_blankrect
) (screencol
, screencol
, screenrow
, screenrow
);
3575 void (*mfwsw_paintrow
) (screenrow
, pixelcolor
, transspec
, screencol
);
3579 { "amiterm", mf_amiga_initscreen
, mf_amiga_updatescreen
,
3580 mf_amiga_blankrectangle
, mf_amiga_paintrow
},
3583 { "epsf", mf_epsf_initscreen
, mf_epsf_updatescreen
,
3584 mf_epsf_blankrectangle
, mf_epsf_paintrow
},
3587 { "hp2627", mf_hp2627_initscreen
, mf_hp2627_updatescreen
,
3588 mf_hp2627_blankrectangle
, mf_hp2627_paintrow
},
3591 { "mftalk", mf_mftalk_initscreen
, mf_mftalk_updatescreen
,
3592 mf_mftalk_blankrectangle
, mf_mftalk_paintrow
},
3595 { "next", mf_next_initscreen
, mf_next_updatescreen
,
3596 mf_next_blankrectangle
, mf_next_paintrow
},
3599 { "regis", mf_regis_initscreen
, mf_regis_updatescreen
,
3600 mf_regis_blankrectangle
, mf_regis_paintrow
},
3603 { "sun", mf_sun_initscreen
, mf_sun_updatescreen
,
3604 mf_sun_blankrectangle
, mf_sun_paintrow
},
3607 { "tek", mf_tektronix_initscreen
, mf_tektronix_updatescreen
,
3608 mf_tektronix_blankrectangle
, mf_tektronix_paintrow
},
3611 { "uniterm", mf_uniterm_initscreen
, mf_uniterm_updatescreen
,
3612 mf_uniterm_blankrectangle
, mf_uniterm_paintrow
},
3615 { "win32term", mf_win32_initscreen
, mf_win32_updatescreen
,
3616 mf_win32_blankrectangle
, mf_win32_paintrow
},
3619 { "xterm", mf_x11_initscreen
, mf_x11_updatescreen
,
3620 mf_x11_blankrectangle
, mf_x11_paintrow
},
3623 /* Always support this. */
3624 { "trap", mf_trap_initscreen
, mf_trap_updatescreen
,
3625 mf_trap_blankrectangle
, mf_trap_paintrow
},
3627 /* Finally, we must have an entry with a terminal type of NULL. */
3628 { NULL
, NULL
, NULL
, NULL
, NULL
}
3630 }; /* End of the array initialization. */
3633 /* This is a pointer to the mfwsw[] entry that we find. */
3634 static struct mfwin_sw
*mfwp
;
3637 /* The following are routines that just jump to the correct
3638 terminal-specific graphics code. If none of the routines in the
3639 dispatch table exist, or they fail, we produce trap-compatible
3640 output, i.e., the same words and punctuation that the unchanged
3641 mf.web would produce. */
3644 /* This returns true if we can do window operations, else false. */
3650 /* If MFTERM is set, use it. */
3651 const_string tty_type
= kpse_var_value ("MFTERM");
3653 if (tty_type
== NULL
)
3656 tty_type
= "amiterm";
3657 #elif defined (WIN32)
3658 tty_type
= "win32term";
3659 #elif defined (OS2) || defined (__DJGPP__) /* not AMIGA nor WIN32 */
3660 tty_type
= "mftalk";
3661 #else /* not (OS2 or WIN32 or __DJGPP__ or AMIGA) */
3662 /* If DISPLAY is set, we are X11; otherwise, who knows. */
3663 boolean have_display
= getenv ("DISPLAY") != NULL
;
3664 tty_type
= have_display
? "xterm" : getenv ("TERM");
3666 /* If we don't know what kind of terminal this is, or if Metafont
3667 isn't being run interactively, don't do any online output. */
3668 if (tty_type
== NULL
3669 || (!STREQ (tty_type
, "trap") && !isatty (fileno (stdout
))))
3671 #endif /* not (OS2 or WIN32 or __DJGPP__ or AMIGA) */
3674 /* Test each of the terminals given in `mfwsw' against the terminal
3675 type, and take the first one that matches, or if the user is running
3676 under Emacs, the first one. */
3677 for (mfwp
= mfwsw
; mfwp
->mfwsw_type
!= NULL
; mfwp
++) {
3678 if (!strncmp (mfwp
->mfwsw_type
, tty_type
, strlen (mfwp
->mfwsw_type
))
3679 || STREQ (tty_type
, "emacs")) {
3680 if (mfwp
->mfwsw_initscreen
) {
3681 retval
= (*mfwp
->mfwsw_initscreen
) ();
3683 Sleep(1000); /* Wait for opening a window */
3688 fprintf (stderr
, "mf: Couldn't initialize online display for `%s'.\n",
3695 /* The current terminal type wasn't found in any of the entries, or
3696 initalization failed, so silently give up, assuming that the user
3697 isn't on a terminal that supports graphic output. */
3702 /* Make sure everything is visible. */
3707 if (mfwp
->mfwsw_updatescrn
)
3708 (*mfwp
->mfwsw_updatescrn
) ();
3712 /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
3713 the background color. */
3716 blankrectangle (screencol left
, screencol right
,
3717 screenrow top
, screenrow bottom
)
3719 if (mfwp
->mfwsw_blankrect
)
3720 (*mfwp
->mfwsw_blankrect
) (left
, right
, top
, bottom
);
3724 /* This paints ROW, starting with the color INIT_COLOR.
3725 TRANSITION_VECTOR then specifies the length of the run; then we
3726 switch colors. This goes on for VECTOR_SIZE transitions. */
3729 paintrow (screenrow row
, pixelcolor init_color
,
3730 transspec transition_vector
, screencol vector_size
)
3732 if (mfwp
->mfwsw_paintrow
)
3733 (*mfwp
->mfwsw_paintrow
) (row
, init_color
, transition_vector
, vector_size
);