1 /* Copyright 1992 Karl Berry
2 Copyright 2007 TeX Users Group
3 Copyright 2014 Clerk Ma
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 #pragma warning(disable:4115) // kill rpcasync.h complaint
27 #define MYLIBAPI __declspec(dllexport)
32 #pragma warning(disable:4996)
33 #pragma warning(disable:4131) // old style declarator
34 #pragma warning(disable:4135) // conversion between different integral types
35 #pragma warning(disable:4127) // conditional expression is constant
39 #define EXTERN /* Instantiate data in `texd.h' or `mfd.h' here ! */
43 /* Hand-coded routines for TeX or Metafont in C. This code was (mostly)
44 written by Tim Morgan, drawing from other Unix ports of TeX. */
46 /* Either `texd.h' or `mfd.h' will include `../common/texmf.h'. */
48 /* Note: INITEX definition in makefile only affects included *.h files */
51 // int __cdecl read (int, void *, unsigned int);
54 /* Instantiate data in `texd.h' or `mfd.h' here. */
57 #define dump_default_var TEX_format_default
58 #define dump_default " plain.fmt"
59 #define dump_format " %s.fmt"
60 #define dump_ext_length 4
61 #define dump_default_length format_default_length
62 #define virgin_program "virtex"
63 #define main_program texbody
64 #define edit_value tex_edit_value
65 #define edit_var "UFYFEJU" /* shrouded 93/Nov/20 */
68 #include <ctype.h> // needed for isascii and isalpha
70 #define ISSPACE(c) (isascii (c) && isspace(c))
72 // #include "c-ctype.h"
73 // #include "c-pathch.h"
75 /* For `struct tm'. */
77 #include <time.h> // needed for time, struct tm etc.
79 extern struct tm * localtime();
81 /* Catch interrupts. */
82 #include <signal.h> // needed for signal, SIGINT, SIG_IGN, SIG_ERR etc.
84 /* following may be found in local.c --- used for key replacement */
86 extern char * replacement[]; /* pointers to replacement strings */
88 /* extern char *buffercopy; */ /* pointer to allocated copy of buffer */
90 // extern char *grabenv(char *); /* in local.c - bkph */
92 /* extern void try_and_open(char *); */ /* inb local.c */
94 #ifdef FUNNY_CORE_DUMP
95 void funny_core_dump (void);
98 /* ridderbusch.pad@nixdorf.com says this is necessary. */
103 /* The main program, etc. */
105 /* What we were invoked as and with. */
106 static char *program_name = NULL;
107 int gargc; /* number of args - set to zero after initialization */
108 char **gargv; /* char *gargv[] -- bkph ? */
110 /* The entry point: set up for reading the command line, which will
111 happen in `t_open_in', then call the main body. */
114 int init(int, char **); /* in local.c */
118 char * set_program_name (char *comm)
121 if ((s = strrchr (comm, '\\')) != NULL)
123 else if ((s = strrchr (comm, '/')) != NULL)
125 else if ((s = strrchr (comm, ':')) != NULL)
129 /* program_name = s; */
135 jmp_buf jumpbuffer; // for non-local jumps
137 int main (int ac, char *av[])
141 char custom_default[PATH_MAX];
143 gargc = ac; /* make available globally */
144 gargv = av; /* make available globally */
146 program_name = set_program_name(av[0]); /* rewritten 1994/Mar/1 - bkph */
148 program_name = strrchr (av[0], PATH_SEP);
149 if (program_name == NULL)
150 program_name = av[0];
156 if (init(gargc, gargv)) /* in local.c */
157 return -1; // failure
160 dump_default_var = dump_default;
161 /* dump_default_length = strlen (dump_default + 1); */
162 dump_default_length = strlen (dump_default_var + 1); /* 93/Nov/20 */
164 /* The following doesn't make sense on DOS since we can't core dump */
167 if (ready_already != 314159)
170 program_name = set_program_name(av[0]); /* rewritten 1994/Mar/1 - bkph */
172 program_name = strrchr (av[0], PATH_SEP);
174 if (program_name == NULL)
175 program_name = av[0];
179 /* TeX or Metafont adds the space at the end of the name. */
180 if (strcmp (program_name, virgin_program) != 0)
182 (void) sprintf (custom_default, dump_format, program_name);
183 dump_default_var = custom_default;
184 dump_default_length = strlen (program_name) + dump_ext_length;
189 // call main_program = texbody in itex.c
190 // now creates jump buffer for non-local goto's 99/Nov/7
194 ret = setjmp(jumpbuffer);
197 { // get here when setting up jumpbuffer
198 flag = main_program(); // texbody in itex.c
201 sprintf(log_line, "EXITING at %s %d %d %d\n", "MAIN", flag, ret, jump_used);
202 show_line(log_line, 0);
206 { // get here from non-local jump via jumpbuffer - if any
209 sprintf(log_line, "EXITING at %s %d %d %d\n", "JUMPOUT", flag, ret, jump_used);
210 show_line(log_line, 0);
214 if (endit(flag) != 0)
215 flag = 1; /* do final clean up in local.c */
221 else exit (flag); // avoid circularity!
225 /* This is supposed to ``open the terminal for input'', but what we
226 really do is copy command line arguments into TeX's or Metafont's
227 buffer, so they can handle them. If nothing is available, or we've
228 been called already (and hence, gargc==0), we return with
230 /* texk/web2c/lib/texmfmp.c */
231 void t_open_in (void)
235 buffer[first] = 0; /* In case there are no arguments. */
238 /* command line arguments? 94/Apr/10 */
239 if (gargc > optind && optind > 0)
241 for (i = optind; i < gargc; i++) /* 94/Apr/10 */
243 /* We do have command line arguments. */
246 for (i = 1; i < gargc; i++)
249 /* the following won't happen if pseudo_space is set ... */
250 if (allow_quoted_names && strchr(gargv[i], ' ') != NULL)
252 (void) strcat ((char *) &buffer[first], "\"");
253 (void) strcat ((char *) &buffer[first], gargv[i]);
254 (void) strcat ((char *) &buffer[first], "\"");
257 (void) strcat ((char *) &buffer[first], gargv[i]);
258 (void) strcat ((char *) &buffer[first], " ");
260 gargc = 0; /* Don't do this again. */
263 /* Find the end of the buffer. */
264 for (last = first; buffer[last]; ++last) ;
266 /* Make `last' be one past the last non-blank non-formfeed character
268 for (--last; last >= first
269 && ISSPACE (buffer[last]) && buffer[last] != '\f'; --last);
272 /* do we want to check line for non-ASCII at this point ? */
274 /* One more time, this time converting to TeX's internal character
275 representation. */ /* for command line input in this case */
276 /* #ifdef NONASCII */
279 for (i = first; i < last; i++)
280 buffer[i] = xord[buffer[i]];
285 /* All our interrupt handler has to do is set TeX's or Metafont's global
286 variable `interrupt'; then they will do everything needed. */
289 /* catch_interrupt () */
290 catch_interrupt (int err)
291 { /* NOTE: err is unreferenced - bkph */
292 (void) signal (SIGINT, SIG_IGN); /* turn off interrupts for now */
293 /* interrupt = 1; */ /* make sure interrupt declared volatile */
294 // if (interrupt++ >= 3) uexit(1); /* emergency exit -- bkph */
295 if (interrupt++ >= 3) exit(1); /* emergency exit -- bkph */
296 (void) signal (SIGINT, catch_interrupt); /* turn them back on again */
299 /* Besides getting the date and time here, we also set up the interrupt
300 handler, for no particularly good reason. It's just that since the
301 `fix_date_and_time' routine is called early on (section 1337 in TeX,
302 ``Get the first line of input and prepare to start''), this is as
303 good a place as any. */
305 void get_date_and_time (integer *minutes, integer *pday, integer *pmonth, integer *pyear)
311 /* time_t clock = time ((long *) 0); */
312 /* clock = time (NULL); */
313 (void) time (&clock); /* - seconds since 1970 */
315 sprintf(log_line, "The time is %u\n", clock); /* debugging */
316 show_line(log_line, 0);
319 show_line("Time not available!\n", 1);
320 /* clock = 0; *//* 901621283 1998 July 28 06:21:00 */
322 tmptr = localtime (&clock);
323 /* MS C runtime library has trouble for clock >= 2^31 !!! */
324 if (tmptr == NULL) { /* debugging 95/Dec/30*/
325 sprintf(log_line, "Cannot convert time (%0ld)!\n", clock);
326 show_line(log_line, 1);
327 *pyear=2038; *pmonth=1; *pday=18; *minutes=22 * 60 + 14;
329 *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
330 *pday = tmptr->tm_mday;
331 *pmonth = tmptr->tm_mon + 1;
332 *pyear = tmptr->tm_year + 1900;
334 sprintf(log_line, "%d-%d-%d %d:%d\n",
335 tmptr->tm_year + 1900, tmptr->tm_mon + 1, tmptr->tm_mday,
336 tmptr->tm_hour, tmptr->tm_min);
337 show_line(log_line, 0);
343 if (!no_interrupts) {
344 if (signal(SIGINT, catch_interrupt) == SIG_ERR) {
345 show_line(" CTRL-C handler not installed\n", 0);
347 uexit(1); /* do we care when run as DLL ? */
352 RETSIGTYPE (*old_handler)();
354 if ((old_handler = signal (SIGINT, catch_interrupt)) != SIG_DFL)
355 (void) signal (SIGINT, old_handler);
360 /* I/O for TeX and Metafont. */ /* give file name ? */
362 void complain_line (FILE *output)
365 #ifdef ALLOCATEBUFFER
366 sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", current_buf_size);
368 sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", buf_size);
370 if (output == stderr) show_line(log_line, 1);
371 else if (output == stdout) show_line(log_line, 0);
372 else fputs(log_line, output); // never
373 show_line(" (File may have a line termination problem.)", 0);
376 void show_bad_line (FILE *output, int first, int last)
380 for (i = first; i <= last; i++) {
382 if ((show_in_hex && ch > 127)) {
383 c = ch >> 4; d = ch & 15;
384 if (c > 9) c = c + 'a' - 10;
386 if (d > 9) d = d + 'a' - 10;
388 // putc('^', output); putc('^', output);
389 *s++ = '^'; *s++ = '^';
390 // putc (c, output); putc (d, output);
391 *s++ = (char) c; *s++ = (char) d;
394 // putc('^', output); putc('^', output);
395 *s++ = '^'; *s++ = '^';
396 // putc (ch + 64, output);
397 *s++ = (char) (ch+64);
399 else if (ch == 127) {
400 // putc('^', output); putc('^', output);
401 *s++ = '^'; *s++ = '^';
402 // putc (ch - 64, output);
403 *s++ = (char) (ch-64);
410 // putc(' ', output); /* putc('\n', output); */
413 if (output == stderr) show_line(log_line, 1);
414 else if (output == stdout) show_line(log_line, 0);
415 else fputs(log_line, output); // log_file
418 // split off for convenience and use in ConsoleInput
420 bool input_line_finish (void) {
424 /* if last line in file does not end with \n - never happens ? */
425 /* if (i == EOF && buffer[last] != '\n') buffer[last++] = '\n'; */
427 buffer[last] = ' '; /* space terminate */
428 if (last >= max_buf_stack) max_buf_stack = last; /* remember longest line */
430 /* Trim trailing whitespace. */
431 /* #define isblank(c) ((c) == ' ' || (c) == '\t') */
432 /* What about \n ? Can't get in here ?- bkph */
433 /* What about control-Z that gets read in binary mode ? - bkph */
435 /* while (last > first && buffer[last - 1] <= ' ') --last; */
436 while (last > first) {
437 i = buffer[last - 1];
438 if (i == ' ' || i == '\t') --last;
439 /* else if (trimeof && i == 26) --last; */ /* 93/Nov/24 */
442 /* if (trimeof != 0 && i == EOF && last == first)
443 return false; */ /* EOF and line empty */
445 // while (last > first
446 // && isblank (buffer[last - 1]) && buffer[last - 1] != '\r')
450 /* following added to check source file integrity ASCII 32 - 127 */
451 /* allow space, tab, new-page - also allow return, newline ? */
452 if (restrict_to_ascii) {
454 for (i = first; i <= last; i++) {
456 /* if (ch > 127 || (ch < ' ' && ch != '\t' && ch != '\f')) */
457 /* 1 -- 8, 11, 14 -- 31 are not good ASCII characters */
458 if (ch > 126 || (ch < ' ' && ch != '\t' && ch != '\f'
459 && ch != '\r' && ch != '\n')) {
460 sprintf(log_line, "\n! non ASCII char (%d) in line: ", ch);
461 show_line(log_line, 1);
463 fprintf(log_file, "\n! non ASCII char (%d) in line: ", ch);
464 /* buffer[i]= 127; */ /* not defined - invalid char */
470 show_bad_line(errout, first, last);
471 if (log_opened) show_bad_line(log_file, first, last);
474 /* Don't bother using xord if we don't need to. */ /* for input line */
475 /* #ifdef NONASCII */ /* has been turned into command line flag - bkph */
477 for (i = first; i <= last; i++)
478 buffer[i] = xord[buffer[i]];
484 /* Read a line of input into buffer as efficiently as possible (ha ha)
485 while still looking like Pascal.
486 We set `last' to `first' and return `false' if we get to eof.
487 Otherwise, we return `true' and set last = first +
488 length(line except trailing whitespace). */
490 bool input_line (FILE *f)
492 // int ch, flag; /* for restrict_to_ascii case 94/Jan/21 */
493 char *u; /* 1994/July/3 for key_replace */
496 /* and here is the long way of doing this */
498 /* following is new version with tab expansion and key replacement */
499 /* may want to expand out separately for speed 1994/July/3 */
500 /* different versions depending on return_flag / tabexpand / key_replace */
501 /* while (last < buf_size && (i = getc (f)) != EOF) */
502 #ifdef ALLOCATEBUFFER
505 while (last < buf_size)
509 if (i < ' ') { /* isolate the more expensive tests */
510 if (i == EOF || i == '\n' || (i == '\r' && return_flag)) break;
511 else if (i == '\t' && tab_step != 0) { // deal with tab
513 buffer[last++] = (ASCII_code) ' ';
514 #ifdef ALLOCATEBUFFER
515 if (last >= current_buf_size) {
516 buffer = realloc_buffer(increment_buf_size);
517 if (last >= current_buf_size) break;
520 #ifdef ALLOCATEBUFFER
521 while ((last - first) % tab_step != 0)
523 while (last < buf_size && (last - first) % tab_step != 0)
527 buffer[last++] = (ASCII_code) ' ';
528 #ifdef ALLOCATEBUFFER
529 if (last >= current_buf_size) {
530 buffer = realloc_buffer(increment_buf_size);
531 if (last >= current_buf_size) break;
538 if (key_replace && (u = replacement[i]) != NULL) {
539 #ifdef ALLOCATEBUFFER
542 while (last < buf_size && *u != '\0')
545 buffer[last++] = (ASCII_code) *u++;
546 #ifdef ALLOCATEBUFFER
547 if (last >= current_buf_size) {
548 buffer = realloc_buffer(increment_buf_size);
549 if (last >= current_buf_size) break;
554 else { /* normal case */
555 buffer[last++] = (ASCII_code) i;
556 #ifdef ALLOCATEBUFFER
557 if (last >= current_buf_size) {
558 buffer = realloc_buffer(increment_buf_size);
559 if (last >= current_buf_size) break;
563 } // end of for(;;) or while loop
565 // can break out of above on EOF '\n' or '\r
566 // sprintf(log_line, "BREAK on %d at %ld\n", i, ftell(f));
567 // show_line(log_line, 0); // debugging only
569 if (return_flag) { /* let return terminate line as well as newline */
570 if (i == '\r') { /* see whether return followed by newline */
571 i = getc (f); /* in which case throw away the newline */
576 /* else buffer[last-1] = (ASCII_code) i; */
580 // sprintf(log_line, "first %d last %d\n", first, last);
581 // show_line(log_line, 0); // debugging only
582 // strncpy(log_line, &buffer[first], last - first + 1);
583 // log_line[last-first] = '\n';
584 // log_line[last-first+1] = '\0';
585 // show_line(log_line, 0); // debugging only
587 // Turn Ctrl-Z at end of file into newline 2000 June 22
588 // if (i == EOF && trimeof != 0 && buffer[last-1] == 26) last--; /* ^Z */
589 if (i == EOF && trimeof && buffer[last-1] == 26) {
590 // buffer[last-1] = 10; /* ^J */
591 // buffer[last] = '\0';
593 // sprintf(log_line, "CTRL-Z first %d last %d\n", first, last);
594 // show_line(log_line, 0); // debugging only
596 if (i == EOF && last == first)
597 return false; /* EOF and line empty - true end of file */
599 /* Didn't get the whole line because buffer was too small? */
600 /* This shouldn't happen anymore 99/Jan/23 */
601 if (i != EOF && i != '\n' && i != '\r') {
602 complain_line(errout);
603 if (log_opened) complain_line(log_file); /* ? 93/Nov/20 */
604 /* This may no longer be needed ... now that we grow it */
605 if (truncate_long_lines) { /* 98/Feb/3 */
606 while (i != EOF && i != '\n' && i != '\r') {
607 i = getc (f); // discard rest of line
609 last--; /* just in case */
611 else uexit(1); /* line too long */
613 return input_line_finish();
614 } /* end of input_line */
617 /* This string specifies what the `e' option does in response to an
620 static char *edit_value = EDITOR;
622 void unshroud_string (char *real_var, char *var, int n) {
627 /* while ((c = *t++) != '\0' && n-- > 0) *s++ = (char) (c - 1); */
628 while ((c = *t++) != '\0' && --n > 0) *s++ = (char) (c - 1);
629 if (n >= 0) *s = (char) c;
630 else *s = '\0'; /* terminate it anyway */
633 char *get_env_shroud (char *var) {
637 unshroud_string (real_var, var, sizeof(real_var));
638 /* real_value = getenv(real_var); */ /* 1994/Mar/1 */
639 real_value = grabenv(real_var); /* 1994/Mar/1 */
641 sprintf(log_line, "\nset %s=", real_var);
642 show_line(log_line, 0);
643 if (real_value != NULL) {
644 show_line(real_value, 0);
648 /* return get_env_shroud (real_var); */ /* serious bug ! since 93/Nov/20 */
649 /* return getenv (real_var); */ /* fixed 93/Dec/28 */
650 return real_value; /* 94/Mar/1 */
653 /* This procedure is due to sjc@s1-c. TeX (or Metafont) calls it when
654 the user types `e' in response to an error, invoking a text editor on
655 the erroneous source file. FNSTART is how far into STRINGPOOL the
656 actual filename starts; FNLENGTH is how long the filename is.
658 See ../site.h for how to set the default, and how to override it. */
660 /* called from close_files_and_terminate in tex9.c */
662 void call_edit (ASCII_code *stringpool, pool_pointer fnstart,
663 integer fnlength, integer linenumber) {
664 char *command, *s, *t, *u;
666 int sdone, ddone, ldone;
668 unsigned int commandlen;
669 ASCII_code *texfilename;
670 ASCII_code *log_file_name;
671 pool_pointer lgstart; /* 1994/Jan/94 */
672 integer lglength; /* 1994/Jan/94 */
674 if (log_opened) { /* 1994/Aug/10 */
675 lgstart = str_start[texmf_log_name];
676 lglength = length(texmf_log_name);
677 log_file_name = stringpool + lgstart;
678 } else { /* 1994/Aug/10 */
680 log_file_name = (unsigned char *) "";
683 sdone = ddone = ldone = 0;
684 /* filename += fnstart; */
685 texfilename = stringpool + fnstart;
687 /* Close any open input files, since we're going to kill the job. */
688 /* and since the editor will need access to them... */
689 for (i = 1; i <= in_open; i++) (void) fclose (input_file[i]);
691 n = fcloseall(); /* paranoia 1994/Aug/10 */
692 if (n > 0 && verbose_flag) {
693 sprintf(log_line, "Closed %d streams\n", n);
694 show_line(log_line, 0);
697 /* Replace the default with the value of the appropriate environment
698 variable, if it's set. */
699 /* s = getenv (edit_var); */ /* 93/Nov/20 */
700 s = get_env_shroud (edit_var);
701 if (s != NULL) edit_value = s; /* OK, replace wired in default */
703 /* Construct the command string. */
704 /* The `11' is the maximum length a 32 bit integer might be, plus one for null. */
705 /* Plus 2 for quotes if needed 99/May/31 */
706 /* command = (string) xmalloc (strlen (edit_value) + fnlength + 11); */
707 commandlen = strlen (edit_value) + fnlength + lglength + 10 + 1 + 2;
708 command = (string) xmalloc (commandlen);
709 /* make more space for log_file_name 1994/Jan/26 */
710 /* So we can construct it as we go. */
713 /* should we manipulate edit_value first ? Add quotes if space in exe name ? */
714 /* remove quotes around [...] string for WinEdt ? */
717 while ((c = *u++) != 0) {
718 if (c == '%') { /* handle special codes */
724 "! bad command syntax (%c).\n", 'd');
725 show_line(log_line, 1);
728 "! `%%d' cannot appear twice in editor command.\n");
729 show_line(log_line, 1);
733 (void) sprintf (s, "%d", linenumber);
734 while (*s != '\0') s++;
735 ddone = 1; /* indicate already used %d */
742 "! bad command syntax (%c).\n", 's');
743 show_line(log_line, 1);
746 "! `%%s' cannot appear twice in editor command.\n");
747 show_line(log_line, 1);
751 t = (char *) texfilename;
754 /* following modified to allow non ASCII - bkph */ /* for file names */
756 /* for (i = 0; i < fnlength; i++) *s++ = xchr [filename[i]]; */
757 for (i = 0; i < n; i++) *s++ = xchr [*t++];
759 /* for (i = 0; i < fnlength; i++) *s++ = (char) filename[i]; */
760 for (i = 0; i < n; i++) *s++ = (char) *t++;
761 sdone = 1; /* indicate already used %s */
764 case 'l': /* 1994/Jan/28 */
768 "! bad command syntax (%c).\n", 'l');
769 show_line(log_line, 1);
772 "! `%%l' cannot appear twice in editor command.\n");
773 show_line(log_line, 1);
777 t = (char *) log_file_name;
778 n = lglength; /* 1994/Jan/28 */
780 /* following modified to allow non ASCII - bkph */ /* for file names */
782 /* for (i = 0; i < fnlength; i++) *s++ = xchr [filename[i]]; */
783 for (i = 0; i < n; i++) *s++ = xchr [*t++];
785 /* for (i = 0; i < fnlength; i++) *s++ = (char) filename[i]; */
786 for (i = 0; i < n; i++) *s++ = (char) *t++;
787 ldone = 1; /* indicate already used %l */
790 case '\0': /* '%' at end of line */
792 u--; /* Back up to the null to force termination. */
795 default: /* something other than 's', 'd', 'l' follows */
801 else *s++ = c; /* ordinary character pass it through */
804 *s = 0; /* terminate the command string */
805 if (strlen(command) + 1 >= commandlen) { /* should not happen! */
807 "Command too long (%d > %d)\n", strlen(command) + 1, commandlen);
808 show_line(log_line, 1);
812 /* You must explicitly flush (using fflush or _flushall) or close any stream before calling system. */
814 /* Try and execute the command. */
815 /* There may be problem here with long names and spaces ??? */
816 /* Use _exec or _spawn instead ??? */
818 if (system (command) != 0) {
819 // fprintf (errout, "\n");
823 "! Error in call: %s\n", command); /* shroud ? */
824 show_line(log_line, 1);
825 /* errno seems to be 0 typically, so perror says "no error" */
827 if (errno != 0) perrormod("! DOS says"); /* 94/Aug/10 - bkph */
829 sprintf(log_line, " (TEXEDIT=%s)\n", edit_value);
830 show_line(log_line, 0);
831 show_line(" (Editor specified may be missing or path may be wrong)\n", 0);
832 show_line(" (or there may be missing -- or extraneous -- quotation signs)\n", 0);
834 uexit(1); /* Quit, since we found an error. */
838 /* Read and write format (for TeX) or base (for Metafont) files. In
839 tex.web, these files are architecture dependent; specifically,
840 BigEndian and LittleEndian architectures produce different files.
841 These routines always output BigEndian files. This still does not
842 make the dump files architecture-independent, because it is possible
843 to make a format file that dumps a glue ratio, i.e., a floating-point
844 number. Fortunately, none of the standard formats do that. */
846 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP) /* this fn */
848 /* We don't REALLY care what `endian' the machine is after all ! */
849 /* But we do care about speed - so check exe file for following - bkph */
852 // char swapmarkerstring="ERROR: SWAPPING - NOT BigEndian AND NOT NoFmtBaseSwap";
855 /* This macro is always invoked as a statement. It assumes a variable
858 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp;
861 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
862 opposite-endianness of whatever they are now. */
864 static int swap_items (char *p, int nitems, int size) {
867 /* Since `size' does not change, we can write a while loop for each
868 case, and avoid testing `size' for each time. */
905 sprintf(log_line, "! I can't (un)dump a %d byte item.\n", size);
906 show_line(log_line, 1);
911 #endif /* not WORDS_BIGENDIAN and not NO_FMTBASE_SWAP */
913 /* Hmm, this could benefit from some on the fly compression - bkph */
914 /* and complementary decompression on input - bkph */
916 /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
917 The pointer to the stuff to write is P, and we write to the file
920 int do_dump (char *p, int item_size, int nitems, FILE *out_file)
922 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
923 swap_items (p, nitems, item_size);
925 /* if (fwrite (p, item_size, nitems, out_file) != nitems) */ /* bkph */
926 if ((int) fwrite (p, item_size, nitems, out_file) != nitems){
928 sprintf(log_line, "! Could not write %d %d-byte item%s.\n",
929 nitems, item_size, (nitems > 1) ? "s" : "");
930 show_line(log_line, 1);
934 /* Have to restore the old contents of memory, since some of it might
936 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
937 swap_items (p, nitems, item_size);
942 /* Hmm, this could benefit from some on the fly decompression - bkph */
944 /* Here is the dual of the writing routine. */
945 int do_undump (char *p, int item_size, int nitems, FILE *in_file)
947 /* if (fread(p, item_size, nitems, in_file) != nitems) */ /* bkph */
948 /* try and speed this up a bit using read() ? bkph 93/Nov/26 */
949 /* doubt whether it makes any real difference ... so forget it ! */
951 unsigned int nbytes = item_size * nitems;
952 if ((unsigned int) read(fileno (in_file), p, nbytes) != nbytes) {
954 sprintf(log_line, "! Could not read %d %d-byte item%s.\n",
955 nitems, item_size, (nitems > 1) ? "s" : "");
956 show_line(log_line, 1);
960 if ((int) fread((void *) p, item_size, nitems, in_file) != nitems) {
962 sprintf(log_line, "! Could not read %d %d-byte item%s.\n",
963 nitems, item_size, (nitems > 1) ? "s" : "");
964 show_line(log_line, 1);
969 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
970 swap_items (p, nitems, item_size);
976 #ifdef FUNNY_CORE_DUMP
977 /* This procedure is due to chris@mimsy.umd.edu. It makes a core dump
978 without any sort of error status (abort(2) does return an error status,
979 so we don't want to use that). It is used only when making a preloaded
980 TeX from virtex, and is triggered by a magic file name requested as
981 input (see `open_input', above). */
983 void funny_core_dump () {
987 switch (pid = vfork ())
989 case -1: /* failed */
991 exit (-1); /* NOTREACHED */
994 (void) signal (SIGQUIT, SIG_DFL);
995 (void) kill (getpid (), SIGQUIT);
996 (void) write (2, "how did we get here?\n", 21);
997 exit (1); /* NOTREACHED */
999 default: /* parent */
1000 while ((w = wait (&status)) != pid && w != -1)
1002 if (status.w_coredump)
1004 (void) write (2, "attempt to dump core failed\n", 28);
1008 #endif /* FUNNY_CORE_DUMP */
1011 /* On-line display routines for Metafont. Here we use a dispatch table
1012 indexed by the MFTERM or TERM environment variable to select the
1013 graphics routines appropriate to the user's terminal. stdout must be
1014 connected to a terminal for us to do any graphics. */
1016 /* We don't want any other window routines screwing us up if we're
1017 trying to do the trap test. We could have written another device for
1018 the trap test, but the terminal type conditionals in initscreen argue
1021 #if defined (TRAP) || defined (INI)
1032 extern mf_pm_initscreen (), mf_pm_updatescreen();
1033 extern mf_pm_blankrectangle (), mf_pm_paintrow();
1038 extern mf_hp2627_initscreen (), mf_hp2627_updatescreen();
1039 extern mf_hp2627_blankrectangle (), mf_hp2627_paintrow();
1043 extern mf_sun_initscreen (), mf_sun_updatescreen();
1044 extern mf_sun_blankrectangle (), mf_sun_paintrow();
1048 extern mf_tektronix_initscreen (), mf_tektronix_updatescreen();
1049 extern mf_tektronix_blankrectangle (), mf_tektronix_paintrow();
1053 extern mf_uniterm_initscreen (), mf_uniterm_updatescreen();
1054 extern mf_uniterm_blankrectangle(), mf_uniterm_paintrow();
1058 extern mf_x10_initscreen (), mf_x10_updatescreen();
1059 extern mf_x10_blankrectangle (), mf_x10_paintrow();
1063 extern mf_x11_initscreen (), mf_x11_updatescreen();
1064 extern mf_x11_blankrectangle (), mf_x11_paintrow();
1068 /* `mfwsw' contains the dispatch tables for each terminal. We map the
1069 Pascal calls to the routines `init_screen', `update_screen',
1070 `blank_rectangle', and `paint_row' into the appropriate entry point
1071 for the specific terminal that MF is being run on. */
1075 char *mfwsw_type; /* Name of terminal a la TERMCAP. */
1076 int (*mfwsw_initscreen)();
1077 int (*mfwsw_updatescrn)();
1078 int (*mfwsw_blankrect)();
1079 int (*mfwsw_paintrow)();
1082 /* Now we have the initializer for all the devices we support. */
1086 { "hp2627", mf_hp2627_initscreen, mf_hp2627_updatescreen,
1087 mf_hp2627_blankrectangle, mf_hp2627_paintrow },
1091 { "sun", mf_sun_initscreen, mf_sun_updatescreen,
1092 mf_sun_blankrectangle, mf_sun_paintrow },
1096 { "tek", mf_tektronix_initscreen, mf_tektronix_updatescreen,
1097 mf_tektronix_blankrectangle, mf_tektronix_paintrow },
1101 { "uniterm", mf_uniterm_initscreen, mf_uniterm_updatescreen,
1102 mf_uniterm_blankrectangle, mf_uniterm_paintrow },
1106 { "xterm", mf_x10_initscreen, mf_x10_updatescreen,
1107 mf_x10_blankrectangle, mf_x10_paintrow },
1111 { "xterm", mf_x11_initscreen, mf_x11_updatescreen,
1112 mf_x11_blankrectangle, mf_x11_paintrow },
1116 { "PM", mf_pm_initscreen, mf_pm_updatescreen,
1117 mf_pm_blankrectangle, mf_pm_paintrow },
1120 /* Finally, we must have an entry with a terminal type of NULL. */
1121 { NULL, NULL, NULL, NULL, NULL }
1123 }; /* End of the array initialization. */
1126 /* This is a pointer to the mfwsw[] entry that we find. */
1127 static struct mfwin_sw *mfwp;
1129 /* The following are routines that just jump to the correct
1130 terminal-specific graphics code. If none of the routines in the
1131 dispatch table exist, or they fail, we produce trap-compatible
1132 output, i.e., the same words and punctuation that the unchanged
1133 mf.web would produce. */
1136 /* This returns true if we can do window operations, else false. */
1142 /* If MFTERM is set, use it. */
1143 char *ttytype = getenv ("MFTERM"); /* not for TeX */
1145 if (ttytype == NULL)
1146 { /* If DISPLAY is set, we are X11; otherwise, who knows. */
1147 bool have_display = getenv ("DISPLAY") != NULL;
1148 ttytype = have_display ? "xterm" : getenv ("TERM");
1151 /* If we don't know kind of terminal this is, or if Metafont isn't
1152 being run interactively, don't do any online output. */
1153 if (ttytype == NULL || !isatty (fileno (stdout)))
1156 /* Test each of the terminals given in `mfwsw' against the terminal
1157 type, and take the first one that matches, or if the user is running
1158 under Emacs, the first one. */
1159 for (mfwp = mfwsw; mfwp->mfwsw_type != NULL; mfwp++)
1160 if (!strncmp (mfwp->mfwsw_type, ttytype, strlen (mfwp->mfwsw_type))
1161 || !strcmp (ttytype, "emacs"))
1162 if (mfwp->mfwsw_initscreen)
1163 return ((*mfwp->mfwsw_initscreen) ());
1168 "! Couldn't initialize the online display for a `%s'.\n",
1170 show_line(log_line, 1);
1174 /* The current terminal type wasn't found in any of the entries, so
1175 silently give up, assuming that the user isn't on a terminal that
1176 supports graphic output. */
1184 /* Make sure everything is visible. */
1190 if (mfwp->mfwsw_updatescrn)
1191 ((*mfwp->mfwsw_updatescrn) ());
1194 show_line("Updatescreen called\n", 0);
1197 fprintf (log_file, "Calling UPDATESCREEN\n");
1202 /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
1203 the background color. */
1206 blankrectangle (left, right, top, bottom)
1207 screencol left, right;
1208 screenrow top, bottom;
1211 if (mfwp->mfwsw_blankrect)
1212 ((*mfwp->mfwsw_blankrect) (left, right, top, bottom));
1215 sprintf(log_line, "Blankrectangle l=%d r=%d t=%d b=%d\n",
1216 left, right, top, bottom);
1217 show_line(log_line, 0);
1220 fprintf (log_file, "\nCalling BLANKRECTANGLE(%d,%d,%d,%d)\n", left,
1221 right, top, bottom);
1225 /* This paints ROW, starting with the color INIT_COLOR.
1226 TRANSITION_VECTOR then specifies the length of the run; then we
1227 switch colors. This goes on for VECTOR_SIZE transitions. */
1230 paintrow (row, init_color, transition_vector, vector_size)
1232 pixelcolor init_color;
1233 transspec transition_vector;
1234 screencol vector_size;
1237 if (mfwp->mfwsw_paintrow)
1238 ((*mfwp->mfwsw_paintrow) (row, init_color,
1239 transition_vector, vector_size));
1242 sprintf(log_line, "Paintrow r=%d c=%d v=");
1243 show_line(log_line, 0);
1244 while (vector_size-- > 0) {
1245 // printf ("%d ", transition_vector++);
1246 sprintf(log_line, "%d ", transition_vector++);
1247 show_line(log_line, 0);
1254 fprintf(log_file, "Calling PAINTROW(%d,%d;", row, init_color);
1255 for (k = 0; k <= vector_size; k++)
1257 fprintf(log_file, "%d", transition_vector[k]);
1258 if (k != vector_size)
1259 fprintf(log_file, ",");
1261 fprintf(log_file, ")\n");
1264 #endif /* not TeX */
1266 /* int tab_step; tab_step = 8; `-H=8' */