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 */
117 char *set_program_name(char *comm)
120 if ((s = strrchr (comm, '\\')) != NULL) s++;
121 else if ((s = strrchr (comm, '/')) != NULL) s++;
122 else if ((s = strrchr (comm, ':')) != NULL) s++;
124 /* program_name = s; */
130 jmp_buf jumpbuffer; // for non-local jumps
132 int main (int ac, char *av[])
136 char custom_default[PATH_MAX];
138 gargc = ac; /* make available globally */
139 gargv = av; /* make available globally */
141 program_name = set_program_name(av[0]); /* rewritten 1994/Mar/1 - bkph */
143 program_name = strrchr (av[0], PATH_SEP);
144 if (program_name == NULL) program_name = av[0];
149 if (init(gargc, gargv)) /* in local.c */
150 return -1; // failure
153 dump_default_var = dump_default;
154 /* dump_default_length = strlen (dump_default + 1); */
155 dump_default_length = strlen (dump_default_var + 1); /* 93/Nov/20 */
157 /* The following doesn't make sense on DOS since we can't core dump */
160 if (ready_already != 314159) {
162 program_name = set_program_name(av[0]); /* rewritten 1994/Mar/1 - bkph */
164 program_name = strrchr (av[0], PATH_SEP);
165 if (program_name == NULL) program_name = av[0];
168 if (strcmp (program_name, virgin_program) != 0) {
169 /* TeX or Metafont adds the space at the end of the name. */
170 (void) sprintf (custom_default, dump_format, program_name);
171 dump_default_var = custom_default;
172 dump_default_length = strlen (program_name) + dump_ext_length;
177 // call main_program = texbody in itex.c
178 // now creates jump buffer for non-local goto's 99/Nov/7
181 ret = setjmp(jumpbuffer);
182 if (ret == 0) { // get here when setting up jumpbuffer
183 flag = main_program(); // texbody in itex.c
185 sprintf(log_line, "EXITING at %s %d %d %d\n", "MAIN", flag, ret, jump_used);
186 show_line(log_line, 0);
188 } else { // get here from non-local jump via jumpbuffer - if any
190 sprintf(log_line, "EXITING at %s %d %d %d\n", "JUMPOUT", flag, ret, jump_used);
191 show_line(log_line, 0);
195 // ABORTCHECKZERO; // after storefmtfiles e.g.
197 if (endit(flag) != 0) flag = 1; /* do final clean up in local.c */
198 if (flag == 0) return 0;
202 else exit (flag); // avoid circularity!
206 /* This is supposed to ``open the terminal for input'', but what we
207 really do is copy command line arguments into TeX's or Metafont's
208 buffer, so they can handle them. If nothing is available, or we've
209 been called already (and hence, gargc==0), we return with
212 void t_open_in (void)
217 /* if (trace_flag) show_line("Entering t_open_in (texmf)\n", 0); */
219 buffer[first] = 0; /* So the first `strcat' will work. */
221 /* We just string the command line arguments together with spaces */
223 /* if (gargc > optind) { */ /* command line stuff after arguments ? */
224 if (gargc > optind && optind > 0) { /* command line arguments? 94/Apr/10 */
225 /* for (i = 1; i < gargc; i++) */
226 for (i = optind; i < gargc; i++) /* 94/Apr/10 */
228 if (gargc > 1) { /* We do have command line arguments. */
229 for (i = 1; i < gargc; i++)
232 /* the following won't happen if pseudo_space is set ... */
233 if (allow_quoted_names && strchr(gargv[i], ' ') != NULL) {
234 (void) strcat ((char *) &buffer[first], "\"");
235 (void) strcat ((char *) &buffer[first], gargv[i]);
236 (void) strcat ((char *) &buffer[first], "\"");
238 else (void) strcat ((char *) &buffer[first], gargv[i]);
239 (void) strcat ((char *) &buffer[first], " ");
241 gargc = 0; /* Don't do this again. */
244 /* Find the end of the buffer. */
245 for (last = first; buffer[last]; ++last) ;
247 /* Make `last' be one past the last non-blank non-formfeed character
249 for (--last; last >= first
250 && ISSPACE (buffer[last]) && buffer[last] != '\f'; --last) ;
253 /* do we want to check line for non-ASCII at this point ? */
255 /* One more time, this time converting to TeX's internal character
256 representation. */ /* for command line input in this case */
257 /* #ifdef NONASCII */
259 for (i = first; i < last; i++)
260 buffer[i] = xord[buffer[i]];
265 /* All our interrupt handler has to do is set TeX's or Metafont's global
266 variable `interrupt'; then they will do everything needed. */
269 /* catch_interrupt () */
270 catch_interrupt (int err)
271 { /* NOTE: err is unreferenced - bkph */
272 (void) signal (SIGINT, SIG_IGN); /* turn off interrupts for now */
273 /* interrupt = 1; */ /* make sure interrupt declared volatile */
274 // if (interrupt++ >= 3) uexit(1); /* emergency exit -- bkph */
275 if (interrupt++ >= 3) exit(1); /* emergency exit -- bkph */
276 (void) signal (SIGINT, catch_interrupt); /* turn them back on again */
279 /* Besides getting the date and time here, we also set up the interrupt
280 handler, for no particularly good reason. It's just that since the
281 `fix_date_and_time' routine is called early on (section 1337 in TeX,
282 ``Get the first line of input and prepare to start''), this is as
283 good a place as any. */
285 void get_date_and_time (integer *minutes, integer *pday, integer *pmonth, integer *pyear)
291 /* time_t clock = time ((long *) 0); */
292 /* clock = time (NULL); */
293 (void) time (&clock); /* - seconds since 1970 */
295 sprintf(log_line, "The time is %u\n", clock); /* debugging */
296 show_line(log_line, 0);
299 show_line("Time not available!\n", 1);
300 /* clock = 0; *//* 901621283 1998 July 28 06:21:00 */
302 tmptr = localtime (&clock);
303 /* MS C runtime library has trouble for clock >= 2^31 !!! */
304 if (tmptr == NULL) { /* debugging 95/Dec/30*/
305 sprintf(log_line, "Cannot convert time (%0ld)!\n", clock);
306 show_line(log_line, 1);
307 *pyear=2038; *pmonth=1; *pday=18; *minutes=22 * 60 + 14;
310 *minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
311 *pday = tmptr->tm_mday;
312 *pmonth = tmptr->tm_mon + 1;
313 *pyear = tmptr->tm_year + 1900;
315 sprintf(log_line, "%d-%d-%d %d:%d\n",
316 tmptr->tm_year + 1900, tmptr->tm_mon + 1, tmptr->tm_mday,
317 tmptr->tm_hour, tmptr->tm_min);
318 show_line(log_line, 0);
324 if (!no_interrupts) {
325 if (signal(SIGINT, catch_interrupt)== SIG_ERR) {
326 show_line(" CTRL-C handler not installed\n", 0);
328 uexit(1); /* do we care when run as DLL ? */
333 RETSIGTYPE (*old_handler)();
335 if ((old_handler = signal (SIGINT, catch_interrupt)) != SIG_DFL)
336 (void) signal (SIGINT, old_handler);
341 /* I/O for TeX and Metafont. */ /* give file name ? */
343 void complain_line (FILE *output)
346 #ifdef ALLOCATEBUFFER
347 sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", current_buf_size);
349 sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", buf_size);
351 if (output == stderr) show_line(log_line, 1);
352 else if (output == stdout) show_line(log_line, 0);
353 else fputs(log_line, output); // never
354 show_line(" (File may have a line termination problem.)", 0);
357 void show_bad_line (FILE *output, int first, int last)
361 for (i = first; i <= last; i++) {
363 if ((show_in_hex && ch > 127)) {
364 c = ch >> 4; d = ch & 15;
365 if (c > 9) c = c + 'a' - 10;
367 if (d > 9) d = d + 'a' - 10;
369 // putc('^', output); putc('^', output);
370 *s++ = '^'; *s++ = '^';
371 // putc (c, output); putc (d, output);
372 *s++ = (char) c; *s++ = (char) d;
375 // putc('^', output); putc('^', output);
376 *s++ = '^'; *s++ = '^';
377 // putc (ch + 64, output);
378 *s++ = (char) (ch+64);
380 else if (ch == 127) {
381 // putc('^', output); putc('^', output);
382 *s++ = '^'; *s++ = '^';
383 // putc (ch - 64, output);
384 *s++ = (char) (ch-64);
391 // putc(' ', output); /* putc('\n', output); */
394 if (output == stderr) show_line(log_line, 1);
395 else if (output == stdout) show_line(log_line, 0);
396 else fputs(log_line, output); // log_file
399 // split off for convenience and use in ConsoleInput
401 bool input_line_finish (void) {
405 /* if last line in file does not end with \n - never happens ? */
406 /* if (i == EOF && buffer[last] != '\n') buffer[last++] = '\n'; */
408 buffer[last] = ' '; /* space terminate */
409 if (last >= max_buf_stack) max_buf_stack = last; /* remember longest line */
411 /* Trim trailing whitespace. */
412 /* #define isblank(c) ((c) == ' ' || (c) == '\t') */
413 /* What about \n ? Can't get in here ?- bkph */
414 /* What about control-Z that gets read in binary mode ? - bkph */
416 /* while (last > first && buffer[last - 1] <= ' ') --last; */
417 while (last > first) {
418 i = buffer[last - 1];
419 if (i == ' ' || i == '\t') --last;
420 /* else if (trimeof && i == 26) --last; */ /* 93/Nov/24 */
423 /* if (trimeof != 0 && i == EOF && last == first)
424 return false; */ /* EOF and line empty */
426 // while (last > first
427 // && isblank (buffer[last - 1]) && buffer[last - 1] != '\r')
431 /* following added to check source file integrity ASCII 32 - 127 */
432 /* allow space, tab, new-page - also allow return, newline ? */
433 if (restrict_to_ascii) {
435 for (i = first; i <= last; i++) {
437 /* if (ch > 127 || (ch < ' ' && ch != '\t' && ch != '\f')) */
438 /* 1 -- 8, 11, 14 -- 31 are not good ASCII characters */
439 if (ch > 126 || (ch < ' ' && ch != '\t' && ch != '\f'
440 && ch != '\r' && ch != '\n')) {
441 sprintf(log_line, "\n! non ASCII char (%d) in line: ", ch);
442 show_line(log_line, 1);
444 fprintf(log_file, "\n! non ASCII char (%d) in line: ", ch);
445 /* buffer[i]= 127; */ /* not defined - invalid char */
451 show_bad_line(errout, first, last);
452 if (log_opened) show_bad_line(log_file, first, last);
455 /* Don't bother using xord if we don't need to. */ /* for input line */
456 /* #ifdef NONASCII */ /* has been turned into command line flag - bkph */
458 for (i = first; i <= last; i++)
459 buffer[i] = xord[buffer[i]];
465 /* Read a line of input into buffer as efficiently as possible (ha ha)
466 while still looking like Pascal.
467 We set `last' to `first' and return `false' if we get to eof.
468 Otherwise, we return `true' and set last = first +
469 length(line except trailing whitespace). */
471 bool input_line (FILE *f)
473 // int ch, flag; /* for restrict_to_ascii case 94/Jan/21 */
474 char *u; /* 1994/July/3 for key_replace */
477 /* and here is the long way of doing this */
479 /* following is new version with tab expansion and key replacement */
480 /* may want to expand out separately for speed 1994/July/3 */
481 /* different versions depending on return_flag / tabexpand / key_replace */
482 /* while (last < buf_size && (i = getc (f)) != EOF) */
483 #ifdef ALLOCATEBUFFER
486 while (last < buf_size)
490 if (i < ' ') { /* isolate the more expensive tests */
491 if (i == EOF || i == '\n' || (i == '\r' && return_flag)) break;
492 else if (i == '\t' && tab_step != 0) { // deal with tab
494 buffer[last++] = (ASCII_code) ' ';
495 #ifdef ALLOCATEBUFFER
496 if (last >= current_buf_size) {
497 buffer = realloc_buffer(increment_buf_size);
498 if (last >= current_buf_size) break;
501 #ifdef ALLOCATEBUFFER
502 while ((last - first) % tab_step != 0)
504 while (last < buf_size && (last - first) % tab_step != 0)
508 buffer[last++] = (ASCII_code) ' ';
509 #ifdef ALLOCATEBUFFER
510 if (last >= current_buf_size) {
511 buffer = realloc_buffer(increment_buf_size);
512 if (last >= current_buf_size) break;
519 if (key_replace && (u = replacement[i]) != NULL) {
520 #ifdef ALLOCATEBUFFER
523 while (last < buf_size && *u != '\0')
526 buffer[last++] = (ASCII_code) *u++;
527 #ifdef ALLOCATEBUFFER
528 if (last >= current_buf_size) {
529 buffer = realloc_buffer(increment_buf_size);
530 if (last >= current_buf_size) break;
535 else { /* normal case */
536 buffer[last++] = (ASCII_code) i;
537 #ifdef ALLOCATEBUFFER
538 if (last >= current_buf_size) {
539 buffer = realloc_buffer(increment_buf_size);
540 if (last >= current_buf_size) break;
544 } // end of for(;;) or while loop
546 // can break out of above on EOF '\n' or '\r
547 // sprintf(log_line, "BREAK on %d at %ld\n", i, ftell(f));
548 // show_line(log_line, 0); // debugging only
550 if (return_flag) { /* let return terminate line as well as newline */
551 if (i == '\r') { /* see whether return followed by newline */
552 i = getc (f); /* in which case throw away the newline */
557 /* else buffer[last-1] = (ASCII_code) i; */
561 // sprintf(log_line, "first %d last %d\n", first, last);
562 // show_line(log_line, 0); // debugging only
563 // strncpy(log_line, &buffer[first], last - first + 1);
564 // log_line[last-first] = '\n';
565 // log_line[last-first+1] = '\0';
566 // show_line(log_line, 0); // debugging only
568 // Turn Ctrl-Z at end of file into newline 2000 June 22
569 // if (i == EOF && trimeof != 0 && buffer[last-1] == 26) last--; /* ^Z */
570 if (i == EOF && trimeof && buffer[last-1] == 26) {
571 // buffer[last-1] = 10; /* ^J */
572 // buffer[last] = '\0';
574 // sprintf(log_line, "CTRL-Z first %d last %d\n", first, last);
575 // show_line(log_line, 0); // debugging only
577 if (i == EOF && last == first)
578 return false; /* EOF and line empty - true end of file */
580 /* Didn't get the whole line because buffer was too small? */
581 /* This shouldn't happen anymore 99/Jan/23 */
582 if (i != EOF && i != '\n' && i != '\r') {
583 complain_line(errout);
584 if (log_opened) complain_line(log_file); /* ? 93/Nov/20 */
585 /* This may no longer be needed ... now that we grow it */
586 if (truncate_long_lines) { /* 98/Feb/3 */
587 while (i != EOF && i != '\n' && i != '\r') {
588 i = getc (f); // discard rest of line
590 last--; /* just in case */
592 else uexit(1); /* line too long */
594 return input_line_finish();
595 } /* end of input_line */
598 /* This string specifies what the `e' option does in response to an
601 static char *edit_value = EDITOR;
603 void unshroud_string (char *real_var, char *var, int n) {
608 /* while ((c = *t++) != '\0' && n-- > 0) *s++ = (char) (c - 1); */
609 while ((c = *t++) != '\0' && --n > 0) *s++ = (char) (c - 1);
610 if (n >= 0) *s = (char) c;
611 else *s = '\0'; /* terminate it anyway */
614 char *get_env_shroud (char *var) {
618 unshroud_string (real_var, var, sizeof(real_var));
619 /* real_value = getenv(real_var); */ /* 1994/Mar/1 */
620 real_value = grabenv(real_var); /* 1994/Mar/1 */
622 sprintf(log_line, "\nset %s=", real_var);
623 show_line(log_line, 0);
624 if (real_value != NULL) {
625 show_line(real_value, 0);
629 /* return get_env_shroud (real_var); */ /* serious bug ! since 93/Nov/20 */
630 /* return getenv (real_var); */ /* fixed 93/Dec/28 */
631 return real_value; /* 94/Mar/1 */
634 /* This procedure is due to sjc@s1-c. TeX (or Metafont) calls it when
635 the user types `e' in response to an error, invoking a text editor on
636 the erroneous source file. FNSTART is how far into STRINGPOOL the
637 actual filename starts; FNLENGTH is how long the filename is.
639 See ../site.h for how to set the default, and how to override it. */
641 /* called from close_files_and_terminate in tex9.c */
643 void call_edit (ASCII_code *stringpool, pool_pointer fnstart,
644 integer fnlength, integer linenumber) {
645 char *command, *s, *t, *u;
647 int sdone, ddone, ldone;
649 unsigned int commandlen;
650 ASCII_code *texfilename;
651 ASCII_code *log_file_name;
652 pool_pointer lgstart; /* 1994/Jan/94 */
653 integer lglength; /* 1994/Jan/94 */
655 if (log_opened) { /* 1994/Aug/10 */
656 lgstart = str_start[texmf_log_name];
657 lglength = str_start[texmf_log_name + 1]- str_start[texmf_log_name];
658 log_file_name = stringpool + lgstart;
660 else { /* 1994/Aug/10 */
662 log_file_name = (unsigned char *) "";
665 sdone = ddone = ldone = 0;
666 /* filename += fnstart; */
667 texfilename = stringpool + fnstart;
669 /* Close any open input files, since we're going to kill the job. */
670 /* and since the editor will need access to them... */
671 for (i = 1; i <= in_open; i++) (void) fclose (input_file[i]);
673 n = fcloseall(); /* paranoia 1994/Aug/10 */
674 if (n > 0 && verbose_flag) {
675 sprintf(log_line, "Closed %d streams\n", n);
676 show_line(log_line, 0);
679 /* Replace the default with the value of the appropriate environment
680 variable, if it's set. */
681 /* s = getenv (edit_var); */ /* 93/Nov/20 */
682 s = get_env_shroud (edit_var);
683 if (s != NULL) edit_value = s; /* OK, replace wired in default */
685 /* Construct the command string. */
686 /* The `11' is the maximum length a 32 bit integer might be, plus one for null. */
687 /* Plus 2 for quotes if needed 99/May/31 */
688 /* command = (string) xmalloc (strlen (edit_value) + fnlength + 11); */
689 commandlen = strlen (edit_value) + fnlength + lglength + 10 + 1 + 2;
690 command = (string) xmalloc (commandlen);
691 /* make more space for log_file_name 1994/Jan/26 */
692 /* So we can construct it as we go. */
695 /* should we manipulate edit_value first ? Add quotes if space in exe name ? */
696 /* remove quotes around [...] string for WinEdt ? */
699 while ((c = *u++) != 0) {
700 if (c == '%') { /* handle special codes */
706 "! bad command syntax (%c).\n", 'd');
707 show_line(log_line, 1);
710 "! `%%d' cannot appear twice in editor command.\n");
711 show_line(log_line, 1);
715 (void) sprintf (s, "%d", linenumber);
716 while (*s != '\0') s++;
717 ddone = 1; /* indicate already used %d */
724 "! bad command syntax (%c).\n", 's');
725 show_line(log_line, 1);
728 "! `%%s' cannot appear twice in editor command.\n");
729 show_line(log_line, 1);
733 t = (char *) texfilename;
736 /* following modified to allow non ASCII - bkph */ /* for file names */
738 /* for (i = 0; i < fnlength; i++) *s++ = xchr [filename[i]]; */
739 for (i = 0; i < n; i++) *s++ = xchr [*t++];
741 /* for (i = 0; i < fnlength; i++) *s++ = (char) filename[i]; */
742 for (i = 0; i < n; i++) *s++ = (char) *t++;
743 sdone = 1; /* indicate already used %s */
746 case 'l': /* 1994/Jan/28 */
750 "! bad command syntax (%c).\n", 'l');
751 show_line(log_line, 1);
754 "! `%%l' cannot appear twice in editor command.\n");
755 show_line(log_line, 1);
759 t = (char *) log_file_name;
760 n = lglength; /* 1994/Jan/28 */
762 /* following modified to allow non ASCII - bkph */ /* for file names */
764 /* for (i = 0; i < fnlength; i++) *s++ = xchr [filename[i]]; */
765 for (i = 0; i < n; i++) *s++ = xchr [*t++];
767 /* for (i = 0; i < fnlength; i++) *s++ = (char) filename[i]; */
768 for (i = 0; i < n; i++) *s++ = (char) *t++;
769 ldone = 1; /* indicate already used %l */
772 case '\0': /* '%' at end of line */
774 u--; /* Back up to the null to force termination. */
777 default: /* something other than 's', 'd', 'l' follows */
783 else *s++ = c; /* ordinary character pass it through */
786 *s = 0; /* terminate the command string */
787 if (strlen(command) + 1 >= commandlen) { /* should not happen! */
789 "Command too long (%d > %d)\n", strlen(command) + 1, commandlen);
790 show_line(log_line, 1);
794 /* You must explicitly flush (using fflush or _flushall) or close any stream before calling system. */
796 /* Try and execute the command. */
797 /* There may be problem here with long names and spaces ??? */
798 /* Use _exec or _spawn instead ??? */
800 if (system (command) != 0) {
801 // fprintf (errout, "\n");
805 "! Error in call: %s\n", command); /* shroud ? */
806 show_line(log_line, 1);
807 /* errno seems to be 0 typically, so perror says "no error" */
809 if (errno != 0) perrormod("! DOS says"); /* 94/Aug/10 - bkph */
811 sprintf(log_line, " (TEXEDIT=%s)\n", edit_value);
812 show_line(log_line, 0);
813 show_line(" (Editor specified may be missing or path may be wrong)\n", 0);
814 show_line(" (or there may be missing -- or extraneous -- quotation signs)\n", 0);
816 uexit(1); /* Quit, since we found an error. */
820 /* Read and write format (for TeX) or base (for Metafont) files. In
821 tex.web, these files are architecture dependent; specifically,
822 BigEndian and LittleEndian architectures produce different files.
823 These routines always output BigEndian files. This still does not
824 make the dump files architecture-independent, because it is possible
825 to make a format file that dumps a glue ratio, i.e., a floating-point
826 number. Fortunately, none of the standard formats do that. */
828 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP) /* this fn */
830 /* We don't REALLY care what `endian' the machine is after all ! */
831 /* But we do care about speed - so check exe file for following - bkph */
834 // char swapmarkerstring="ERROR: SWAPPING - NOT BigEndian AND NOT NoFmtBaseSwap";
837 /* This macro is always invoked as a statement. It assumes a variable
840 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp;
843 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
844 opposite-endianness of whatever they are now. */
846 static int swap_items (char *p, int nitems, int size) {
849 /* Since `size' does not change, we can write a while loop for each
850 case, and avoid testing `size' for each time. */
887 sprintf(log_line, "! I can't (un)dump a %d byte item.\n", size);
888 show_line(log_line, 1);
893 #endif /* not WORDS_BIGENDIAN and not NO_FMTBASE_SWAP */
895 /* Hmm, this could benefit from some on the fly compression - bkph */
896 /* and complementary decompression on input - bkph */
898 /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
899 The pointer to the stuff to write is P, and we write to the file
902 int do_dump (char *p, int item_size, int nitems, FILE *out_file)
904 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
905 swap_items (p, nitems, item_size);
907 /* if (fwrite (p, item_size, nitems, out_file) != nitems) */ /* bkph */
908 if ((int) fwrite (p, item_size, nitems, out_file) != nitems){
910 sprintf(log_line, "! Could not write %d %d-byte item%s.\n",
911 nitems, item_size, (nitems > 1) ? "s" : "");
912 show_line(log_line, 1);
916 /* Have to restore the old contents of memory, since some of it might
918 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
919 swap_items (p, nitems, item_size);
924 /* Hmm, this could benefit from some on the fly decompression - bkph */
926 /* Here is the dual of the writing routine. */
927 int do_undump (char *p, int item_size, int nitems, FILE *in_file)
929 /* if (fread(p, item_size, nitems, in_file) != nitems) */ /* bkph */
930 /* try and speed this up a bit using read() ? bkph 93/Nov/26 */
931 /* doubt whether it makes any real difference ... so forget it ! */
933 unsigned int nbytes = item_size * nitems;
934 if ((unsigned int) read(fileno (in_file), p, nbytes) != nbytes) {
936 sprintf(log_line, "! Could not read %d %d-byte item%s.\n",
937 nitems, item_size, (nitems > 1) ? "s" : "");
938 show_line(log_line, 1);
942 if ((int) fread((void *) p, item_size, nitems, in_file) != nitems) {
944 sprintf(log_line, "! Could not read %d %d-byte item%s.\n",
945 nitems, item_size, (nitems > 1) ? "s" : "");
946 show_line(log_line, 1);
951 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
952 swap_items (p, nitems, item_size);
958 #ifdef FUNNY_CORE_DUMP
959 /* This procedure is due to chris@mimsy.umd.edu. It makes a core dump
960 without any sort of error status (abort(2) does return an error status,
961 so we don't want to use that). It is used only when making a preloaded
962 TeX from virtex, and is triggered by a magic file name requested as
963 input (see `open_input', above). */
965 void funny_core_dump () {
969 switch (pid = vfork ())
971 case -1: /* failed */
973 exit (-1); /* NOTREACHED */
976 (void) signal (SIGQUIT, SIG_DFL);
977 (void) kill (getpid (), SIGQUIT);
978 (void) write (2, "how did we get here?\n", 21);
979 exit (1); /* NOTREACHED */
981 default: /* parent */
982 while ((w = wait (&status)) != pid && w != -1)
984 if (status.w_coredump)
986 (void) write (2, "attempt to dump core failed\n", 28);
990 #endif /* FUNNY_CORE_DUMP */
993 /* On-line display routines for Metafont. Here we use a dispatch table
994 indexed by the MFTERM or TERM environment variable to select the
995 graphics routines appropriate to the user's terminal. stdout must be
996 connected to a terminal for us to do any graphics. */
998 /* We don't want any other window routines screwing us up if we're
999 trying to do the trap test. We could have written another device for
1000 the trap test, but the terminal type conditionals in initscreen argue
1003 #if defined (TRAP) || defined (INI)
1014 extern mf_pm_initscreen (), mf_pm_updatescreen();
1015 extern mf_pm_blankrectangle (), mf_pm_paintrow();
1020 extern mf_hp2627_initscreen (), mf_hp2627_updatescreen();
1021 extern mf_hp2627_blankrectangle (), mf_hp2627_paintrow();
1025 extern mf_sun_initscreen (), mf_sun_updatescreen();
1026 extern mf_sun_blankrectangle (), mf_sun_paintrow();
1030 extern mf_tektronix_initscreen (), mf_tektronix_updatescreen();
1031 extern mf_tektronix_blankrectangle (), mf_tektronix_paintrow();
1035 extern mf_uniterm_initscreen (), mf_uniterm_updatescreen();
1036 extern mf_uniterm_blankrectangle(), mf_uniterm_paintrow();
1040 extern mf_x10_initscreen (), mf_x10_updatescreen();
1041 extern mf_x10_blankrectangle (), mf_x10_paintrow();
1045 extern mf_x11_initscreen (), mf_x11_updatescreen();
1046 extern mf_x11_blankrectangle (), mf_x11_paintrow();
1050 /* `mfwsw' contains the dispatch tables for each terminal. We map the
1051 Pascal calls to the routines `init_screen', `update_screen',
1052 `blank_rectangle', and `paint_row' into the appropriate entry point
1053 for the specific terminal that MF is being run on. */
1057 char *mfwsw_type; /* Name of terminal a la TERMCAP. */
1058 int (*mfwsw_initscreen)();
1059 int (*mfwsw_updatescrn)();
1060 int (*mfwsw_blankrect)();
1061 int (*mfwsw_paintrow)();
1064 /* Now we have the initializer for all the devices we support. */
1068 { "hp2627", mf_hp2627_initscreen, mf_hp2627_updatescreen,
1069 mf_hp2627_blankrectangle, mf_hp2627_paintrow },
1073 { "sun", mf_sun_initscreen, mf_sun_updatescreen,
1074 mf_sun_blankrectangle, mf_sun_paintrow },
1078 { "tek", mf_tektronix_initscreen, mf_tektronix_updatescreen,
1079 mf_tektronix_blankrectangle, mf_tektronix_paintrow },
1083 { "uniterm", mf_uniterm_initscreen, mf_uniterm_updatescreen,
1084 mf_uniterm_blankrectangle, mf_uniterm_paintrow },
1088 { "xterm", mf_x10_initscreen, mf_x10_updatescreen,
1089 mf_x10_blankrectangle, mf_x10_paintrow },
1093 { "xterm", mf_x11_initscreen, mf_x11_updatescreen,
1094 mf_x11_blankrectangle, mf_x11_paintrow },
1098 { "PM", mf_pm_initscreen, mf_pm_updatescreen,
1099 mf_pm_blankrectangle, mf_pm_paintrow },
1102 /* Finally, we must have an entry with a terminal type of NULL. */
1103 { NULL, NULL, NULL, NULL, NULL }
1105 }; /* End of the array initialization. */
1108 /* This is a pointer to the mfwsw[] entry that we find. */
1109 static struct mfwin_sw *mfwp;
1111 /* The following are routines that just jump to the correct
1112 terminal-specific graphics code. If none of the routines in the
1113 dispatch table exist, or they fail, we produce trap-compatible
1114 output, i.e., the same words and punctuation that the unchanged
1115 mf.web would produce. */
1118 /* This returns true if we can do window operations, else false. */
1124 /* If MFTERM is set, use it. */
1125 char *ttytype = getenv ("MFTERM"); /* not for TeX */
1127 if (ttytype == NULL)
1128 { /* If DISPLAY is set, we are X11; otherwise, who knows. */
1129 bool have_display = getenv ("DISPLAY") != NULL;
1130 ttytype = have_display ? "xterm" : getenv ("TERM");
1133 /* If we don't know kind of terminal this is, or if Metafont isn't
1134 being run interactively, don't do any online output. */
1135 if (ttytype == NULL || !isatty (fileno (stdout)))
1138 /* Test each of the terminals given in `mfwsw' against the terminal
1139 type, and take the first one that matches, or if the user is running
1140 under Emacs, the first one. */
1141 for (mfwp = mfwsw; mfwp->mfwsw_type != NULL; mfwp++)
1142 if (!strncmp (mfwp->mfwsw_type, ttytype, strlen (mfwp->mfwsw_type))
1143 || !strcmp (ttytype, "emacs"))
1144 if (mfwp->mfwsw_initscreen)
1145 return ((*mfwp->mfwsw_initscreen) ());
1150 "! Couldn't initialize the online display for a `%s'.\n",
1152 show_line(log_line, 1);
1156 /* The current terminal type wasn't found in any of the entries, so
1157 silently give up, assuming that the user isn't on a terminal that
1158 supports graphic output. */
1166 /* Make sure everything is visible. */
1172 if (mfwp->mfwsw_updatescrn)
1173 ((*mfwp->mfwsw_updatescrn) ());
1176 show_line("Updatescreen called\n", 0);
1179 fprintf (log_file, "Calling UPDATESCREEN\n");
1184 /* This sets the rectangle bounded by ([left,right], [top,bottom]) to
1185 the background color. */
1188 blankrectangle (left, right, top, bottom)
1189 screencol left, right;
1190 screenrow top, bottom;
1193 if (mfwp->mfwsw_blankrect)
1194 ((*mfwp->mfwsw_blankrect) (left, right, top, bottom));
1197 sprintf(log_line, "Blankrectangle l=%d r=%d t=%d b=%d\n",
1198 left, right, top, bottom);
1199 show_line(log_line, 0);
1202 fprintf (log_file, "\nCalling BLANKRECTANGLE(%d,%d,%d,%d)\n", left,
1203 right, top, bottom);
1207 /* This paints ROW, starting with the color INIT_COLOR.
1208 TRANSITION_VECTOR then specifies the length of the run; then we
1209 switch colors. This goes on for VECTOR_SIZE transitions. */
1212 paintrow (row, init_color, transition_vector, vector_size)
1214 pixelcolor init_color;
1215 transspec transition_vector;
1216 screencol vector_size;
1219 if (mfwp->mfwsw_paintrow)
1220 ((*mfwp->mfwsw_paintrow) (row, init_color,
1221 transition_vector, vector_size));
1224 sprintf(log_line, "Paintrow r=%d c=%d v=");
1225 show_line(log_line, 0);
1226 while (vector_size-- > 0) {
1227 // printf ("%d ", transition_vector++);
1228 sprintf(log_line, "%d ", transition_vector++);
1229 show_line(log_line, 0);
1236 fprintf(log_file, "Calling PAINTROW(%d,%d;", row, init_color);
1237 for (k = 0; k <= vector_size; k++)
1239 fprintf(log_file, "%d", transition_vector[k]);
1240 if (k != vector_size)
1241 fprintf(log_file, ",");
1243 fprintf(log_file, ")\n");
1246 #endif /* not TeX */
1248 /* int tab_step; tab_step = 8; `-H=8' */