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
24 #define dump_default_var TEX_format_default
25 #define dump_default " plain.fmt"
26 #define dump_ext_length 4
27 #define dump_default_length format_default_length
28 #define edit_value tex_edit_value
30 extern char * replacement[];
31 static char * program_name = NULL;
32 int gargc; /* number of args - set to zero after initialization */
35 /* The entry point: set up for reading the command line, which will
36 happen in `t_open_in', then call the main body. */
42 int main (int ac, char *av[])
44 int flag = 0, ret = 0;
53 if (main_init(gargc, gargv))
56 dump_default_var = dump_default;
57 dump_default_length = strlen(dump_default_var + 1);
61 ret = setjmp(jumpbuffer);
65 flag = main_program();
69 sprintf(log_line, "EXITING at %s: flag = %d, ret = %d, jump_used = %d\n", "main", flag, ret, jump_used);
70 show_line(log_line, 0);
77 sprintf(log_line, "EXITING at %s: flag = %d, ret = %d, jump_used = %d\n", "jump_out", flag, ret, jump_used);
78 show_line(log_line, 0);
83 flag = 1; /* do final clean up in local.c */
91 /* texk/web2c/lib/texmfmp.c */
96 buffer[first] = 0; /* In case there are no arguments. */
99 if (gargc > optind && optind > 0)
101 for (i = optind; i < gargc; i++)
105 for (i = 1; i < gargc; i++)
108 if (allow_quoted_names && strchr(gargv[i], ' ') != NULL)
110 (void) strcat ((char *) &buffer[first], "\"");
111 (void) strcat ((char *) &buffer[first], gargv[i]);
112 (void) strcat ((char *) &buffer[first], "\"");
115 (void) strcat ((char *) &buffer[first], gargv[i]);
117 (void) strcat ((char *) &buffer[first], " ");
123 /* Find the end of the buffer. */
124 for (last = first; buffer[last]; ++last)
127 for (--last; last >= first && ISBLANK (buffer[last]) && buffer[last] != '\r'; --last)
132 /* One more time, this time converting to TeX's internal character
133 representation. */ /* for command line input in this case */
136 for (i = first; i < last; i++)
137 buffer[i] = xord[buffer[i]];
141 /* All our interrupt handler has to do is set TeX's or Metafont's global
142 variable `interrupt'; then they will do everything needed. */
144 static void catch_interrupt (int err)
146 (void) signal (SIGINT, SIG_IGN);
148 if (interrupt++ >= 3)
151 (void) signal (SIGINT, catch_interrupt);
154 /* Besides getting the date and time here, we also set up the interrupt
155 handler, for no particularly good reason. It's just that since the
156 `fix_date_and_time' routine is called early on (section 1337 in TeX,
157 ``Get the first line of input and prepare to start''), this is as
158 good a place as any. */
160 void get_date_and_time (integer *sys_minutes,
168 (void) time (&clock); /* - seconds since 1970 */
172 sprintf(log_line, "The time is %u\n", clock);
173 show_line(log_line, 0);
177 puts("Time not available!\n");
179 tmptr = localtime (&clock);
183 sprintf(log_line, "Cannot convert time (%0ld)!\n", clock);
184 show_line(log_line, 1);
188 *sys_minutes = 22 * 60 + 14;
192 *sys_minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
193 *sys_day = tmptr->tm_mday;
194 *sys_month = tmptr->tm_mon + 1;
195 *sys_year = tmptr->tm_year + 1900;
199 sprintf(log_line, "%d-%d-%d %d:%d\n",
200 tmptr->tm_year + 1900,
205 show_line(log_line, 0);
213 if (signal(SIGINT, catch_interrupt) == SIG_ERR)
215 puts(" CTRL-C handler not installed\n");
217 uexit(EXIT_FAILURE); /* do we care when run as DLL ? */
222 void (*old_handler)();
224 if ((old_handler = signal (SIGINT, catch_interrupt)) != SIG_DFL)
225 (void) signal (SIGINT, old_handler);
230 /* I/O for TeX and Metafont. */
231 void complain_line (FILE *output)
235 #ifdef ALLOCATEBUFFER
236 sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", current_buf_size);
238 sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", buf_size);
241 if (output == stderr)
242 show_line(log_line, 1);
243 else if (output == stdout)
244 show_line(log_line, 0);
246 fputs(log_line, output); // never
248 puts(" (File may have a line termination problem.)");
251 void show_bad_line (FILE *output, int first, int last)
256 for (i = first; i <= last; i++)
260 if ((show_in_hex && ch > 127))
272 /* putc('^', output); putc('^', output); */
275 /* putc (c, output); putc (d, output); */
282 /* putc('^', output); putc('^', output); */
285 /* putc (ch + 64, output); */
286 *s++ = (char) (ch + 64);
291 /* putc('^', output); putc('^', output); */
294 /* putc (ch - 64, output); */
295 *s++ = (char) (ch - 64);
299 /* putc(ch, output); */
303 // putc(' ', output); /* putc('\n', output); */
306 if (output == stderr)
307 show_line(log_line, 1);
309 if (output == stdout)
310 show_line(log_line, 0);
312 fputs(log_line, output); // log_file
315 // split off for convenience and use in ConsoleInput
316 boolean input_line_finish (void)
321 /* if last line in file does not end with \n - never happens ? */
322 /* if (i == EOF && buffer[last] != '\n') buffer[last++] = '\n'; */
324 buffer[last] = ' '; /* space terminate */
325 if (last >= max_buf_stack)
326 max_buf_stack = last; /* remember longest line */
328 /* Trim trailing whitespace. */
329 /* #define isblank(c) ((c) == ' ' || (c) == '\t') */
330 /* What about \n ? Can't get in here ?- bkph */
331 /* What about control-Z that gets read in binary mode ? - bkph */
333 /* while (last > first && buffer[last - 1] <= ' ') --last; */
336 i = buffer[last - 1];
338 if (i == ' ' || i == '\t')
340 /* else if (trimeof && i == 26) --last; */ /* 93/Nov/24 */
344 /* if (trimeof != 0 && i == EOF && last == first)
345 return false; */ /* EOF and line empty */
347 // while (last > first
348 // && isblank (buffer[last - 1]) && buffer[last - 1] != '\r')
352 /* following added to check source file integrity ASCII 32 - 127 */
353 /* allow space, tab, new-page - also allow return, newline ? */
354 if (restrict_to_ascii)
357 for (i = first; i <= last; i++)
360 /* if (ch > 127 || (ch < ' ' && ch != '\t' && ch != '\f')) */
361 /* 1 -- 8, 11, 14 -- 31 are not good ASCII characters */
362 if (ch > 126 || (ch < ' ' && ch != '\t' && ch != '\f' && ch != '\r' && ch != '\n'))
364 sprintf(log_line, "\n! non ASCII char (%d) in line: ", ch);
365 show_line(log_line, 1);
367 fprintf(log_file, "\n! non ASCII char (%d) in line: ", ch);
368 /* buffer[i]= 127; */ /* not defined - invalid char */
375 show_bad_line(errout, first, last);
377 show_bad_line(log_file, first, last);
380 /* Don't bother using xord if we don't need to. */ /* for input line */
381 /* #ifdef NONASCII */ /* has been turned into command line flag - bkph */
384 for (i = first; i <= last; i++)
385 buffer[i] = xord[buffer[i]];
391 /* Read a line of input into buffer as efficiently as possible (ha ha)
392 while still looking like Pascal.
393 We set `last' to `first' and return `false' if we get to eof.
394 Otherwise, we return `true' and set last = first +
395 length(line except trailing whitespace). */
398 boolean input_line (FILE *f)
400 // int ch, flag; /* for restrict_to_ascii case 94/Jan/21 */
401 char *u; /* 1994/July/3 for key_replace */
404 /* and here is the long way of doing this */
406 /* following is new version with tab expansion and key replacement */
407 /* may want to expand out separately for speed 1994/July/3 */
408 /* different versions depending on return_flag / tabexpand / key_replace */
409 /* while (last < buf_size && (i = getc (f)) != EOF) */
410 #ifdef ALLOCATEBUFFER
413 while (last < buf_size)
420 if (i == EOF || i == '\n' || (i == '\r' && return_flag))
422 else if (i == '\t' && tab_step != 0)
424 buffer[last++] = (ASCII_code) ' ';
426 #ifdef ALLOCATEBUFFER
427 if (last >= current_buf_size)
429 buffer = realloc_buffer(increment_buf_size);
431 if (last >= current_buf_size)
436 #ifdef ALLOCATEBUFFER
437 while ((last - first) % tab_step != 0)
439 while (last < buf_size && (last - first) % tab_step != 0)
443 buffer[last++] = (ASCII_code) ' ';
445 #ifdef ALLOCATEBUFFER
446 if (last >= current_buf_size)
448 buffer = realloc_buffer(increment_buf_size);
450 if (last >= current_buf_size)
460 if (key_replace && (u = replacement[i]) != NULL)
462 #ifdef ALLOCATEBUFFER
465 while (last < buf_size && *u != '\0')
468 buffer[last++] = (ASCII_code) *u++;
469 #ifdef ALLOCATEBUFFER
470 if (last >= current_buf_size)
472 buffer = realloc_buffer(increment_buf_size);
474 if (last >= current_buf_size)
480 else /* normal case */
482 buffer[last++] = (ASCII_code) i;
484 #ifdef ALLOCATEBUFFER
485 if (last >= current_buf_size)
487 buffer = realloc_buffer(increment_buf_size);
489 if (last >= current_buf_size)
496 if (return_flag) /* let return terminate line as well as newline */
498 if (i == '\r') /* see whether return followed by newline */
500 i = getc (f); /* in which case throw away the newline */
507 /* else buffer[last-1] = (ASCII_code) i; */
511 // Turn Ctrl-Z at end of file into newline 2000 June 22
512 if (i == EOF && trimeof && buffer[last - 1] == 26)
517 if (i == EOF && last == first)
520 /* Didn't get the whole line because buffer was too small? */
521 /* This shouldn't happen anymore 99/Jan/23 */
522 if (i != EOF && i != '\n' && i != '\r')
524 complain_line(errout);
527 complain_line(log_file);
529 /* This may no longer be needed ... now that we grow it */
530 if (truncate_long_lines)
532 while (i != EOF && i != '\n' && i != '\r')
534 i = getc (f); // discard rest of line
537 last--; /* just in case */
540 uexit(EXIT_FAILURE); /* line too long */
543 return input_line_finish();
546 /* This string specifies what the `e' option does in response to an
549 static char *edit_value = "c:\\yandy\\WinEdt\\WinEdt.exe [Open('%s');SelLine(%d,7)]";
551 /* This procedure is due to sjc@s1-c. TeX (or Metafont) calls it when
552 the user types `e' in response to an error, invoking a text editor on
553 the erroneous source file. FNSTART is how far into STRINGPOOL the
554 actual filename starts; FNLENGTH is how long the filename is.
556 See ../site.h for how to set the default, and how to override it. */
558 /* called from close_files_and_terminate in tex9.c */
560 void call_edit (ASCII_code *stringpool, pool_pointer fnstart, integer fnlength, integer linenumber)
562 char *command, *s, *t, *u;
564 int sdone, ddone, ldone;
566 unsigned int commandlen;
567 ASCII_code *texfilename;
568 ASCII_code *log_file_name;
569 pool_pointer lgstart;
574 lgstart = str_start[texmf_log_name];
575 lglength = length(texmf_log_name);
576 log_file_name = stringpool + lgstart;
581 log_file_name = (unsigned char *) "";
584 sdone = ddone = ldone = 0;
585 texfilename = stringpool + fnstart;
587 for (i = 1; i <= in_open; i++)
588 (void) fclose (input_file[i]);
592 if (n > 0 && verbose_flag)
594 sprintf(log_line, "Closed %d streams\n", n);
595 show_line(log_line, 0);
598 s = kpse_var_value(edit_value);
603 commandlen = strlen (edit_value) + fnlength + lglength + 10 + 1 + 2;
604 command = (string) xmalloc (commandlen);
610 while ((c = *u++) != 0)
620 sprintf(log_line, "! bad command syntax (%c).\n", 'd');
621 show_line(log_line, 1);
623 sprintf(log_line, "! `%%d' cannot appear twice in editor command.\n");
624 show_line(log_line, 1);
629 (void) sprintf (s, "%d", linenumber);
641 sprintf(log_line, "! bad command syntax (%c).\n", 's');
642 show_line(log_line, 1);
644 sprintf(log_line, "! `%%s' cannot appear twice in editor command.\n");
645 show_line(log_line, 1);
650 t = (char *) texfilename;
654 for (i = 0; i < n; i++)
657 for (i = 0; i < n; i++)
667 sprintf(log_line, "! bad command syntax (%c).\n", 'l');
668 show_line(log_line, 1);
670 sprintf(log_line, "! `%%l' cannot appear twice in editor command.\n");
671 show_line(log_line, 1);
676 t = (char *) log_file_name;
680 for (i = 0; i < n; i++)
683 for (i = 0; i < n; i++)
704 *s = 0; /* terminate the command string */
706 if (strlen(command) + 1 >= commandlen)
708 sprintf(log_line, "Command too long (%d > %d)\n", strlen(command) + 1, commandlen);
709 show_line(log_line, 1);
716 if (system (command) != 0)
719 sprintf(log_line, "! Error in call: %s\n", command);
720 show_line(log_line, 1);
724 perrormod("! DOS says");
727 sprintf(log_line, " (TEXEDIT=%s)\n", edit_value);
728 show_line(log_line, 0);
729 puts(" (Editor specified may be missing or path may be wrong)\n");
730 puts(" (or there may be missing -- or extraneous -- quotation signs)\n");
736 /* Read and write format (for TeX) or base (for Metafont) files. In
737 tex.web, these files are architecture dependent; specifically,
738 BigEndian and LittleEndian architectures produce different files.
739 These routines always output BigEndian files. This still does not
740 make the dump files architecture-independent, because it is possible
741 to make a format file that dumps a glue ratio, i.e., a floating-point
742 number. Fortunately, none of the standard formats do that. */
744 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP) /* this fn */
746 /* We don't REALLY care what `endian' the machine is after all ! */
747 /* But we do care about speed - so check exe file for following - bkph */
750 // char swapmarkerstring="ERROR: SWAPPING - NOT BigEndian AND NOT NoFmtBaseSwap";
753 /* This macro is always invoked as a statement. It assumes a variable
756 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp;
759 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
760 opposite-endianness of whatever they are now. */
762 static int swap_items (char *p, int nitems, int size)
766 /* Since `size' does not change, we can write a while loop for each
767 case, and avoid testing `size' for each time. */
804 sprintf(log_line, "! I can't (un)dump a %d byte item.\n", size);
805 show_line(log_line, 1);
810 #endif /* not WORDS_BIGENDIAN and not NO_FMTBASE_SWAP */
812 /* Hmm, this could benefit from some on the fly compression - bkph */
813 /* and complementary decompression on input - bkph */
815 /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
816 The pointer to the stuff to write is P, and we write to the file
819 int do_dump (char *p, int item_size, int nitems, FILE *out_file)
821 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
822 swap_items (p, nitems, item_size);
826 if (gzwrite(gz_fmt_file, p, (item_size * nitems)) != (item_size * nitems))
828 if ((int) fwrite (p, item_size, nitems, out_file) != nitems)
832 sprintf(log_line, "! Could not write %d %d-byte item%s.\n",
833 nitems, item_size, (nitems > 1) ? "s" : "");
834 show_line(log_line, 1);
838 /* Have to restore the old contents of memory, since some of it might get used again. */
839 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
840 swap_items (p, nitems, item_size);
846 /* Hmm, this could benefit from some on the fly decompression - bkph */
848 /* Here is the dual of the writing routine. */
849 int do_undump (char *p, int item_size, int nitems, FILE *in_file)
852 if (gzread(gz_fmt_file, (void *) p, (unsigned int) (item_size * nitems)) <= 0)
854 if ((int) fread((void *) p, item_size, nitems, in_file) != nitems)
858 sprintf(log_line, "! Could not read %d %d-byte item%s.\n",
859 nitems, item_size, (nitems > 1) ? "s" : "");
860 show_line(log_line, 1);
864 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
865 swap_items (p, nitems, item_size);
871 #ifdef FUNNY_CORE_DUMP
872 /* This procedure is due to chris@mimsy.umd.edu. It makes a core dump
873 without any sort of error status (abort(2) does return an error status,
874 so we don't want to use that). It is used only when making a preloaded
875 TeX from virtex, and is triggered by a magic file name requested as
876 input (see `open_input', above). */
878 void funny_core_dump (void)
883 switch (pid = vfork ())
890 (void) signal (SIGQUIT, SIG_DFL);
891 (void) kill (getpid (), SIGQUIT);
892 (void) write (2, "how did we get here?\n", 21);
896 while ((w = wait (&status)) != pid && w != -1)
899 if (status.w_coredump)
902 (void) write (2, "attempt to dump core failed\n", 28);
906 #endif /* FUNNY_CORE_DUMP */