OSDN Git Service

code clean of dvipsone.
[putex/putex.git] / src / texsourc / yandytex.c
1 /* Copyright 1992 Karl Berry
2    Copyright 2007 TeX Users Group
3    Copyright 2014 Clerk Ma
4
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.
9
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.
14
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
18    02110-1301 USA.  */
19
20 #define EXTERN
21
22 #include "texd.h"
23
24
25 #define dump_default_var    TEX_format_default
26 #define dump_default        " plain.fmt"
27 #define dump_ext_length     4
28 #define dump_default_length format_default_length
29 #define main_program        texbody
30 #define edit_value          tex_edit_value
31 #define edit_var            "UFYFEJU" /* shrouded 93/Nov/20 */
32
33
34 extern char * replacement[];    /* pointers to replacement strings */
35
36 #ifdef FUNNY_CORE_DUMP
37   void funny_core_dump (void);
38 #endif
39
40 /* The main program, etc.  */
41
42 /* What we were invoked as and with.  */
43 static char *program_name = NULL;
44 int    gargc;   /* number of args - set to zero after initialization */
45 char **gargv;   /* char *gargv[] -- bkph ? */
46
47 /* The entry point: set up for reading the command line, which will
48    happen in `t_open_in', then call the main body.  */
49
50 int main_init(int, char **);     /* in local.c */
51
52 int jump_used = 0;
53
54 jmp_buf jumpbuffer;   // for non-local jumps
55
56 int main (int ac, char *av[])
57 {
58   int flag = 0, ret = 0;
59
60 #ifndef INI
61   char custom_default[PATH_MAX];
62 #endif
63
64 #ifdef WIN32
65   _setmaxstdio(2048);
66 #endif
67
68   gargc = ac;
69   gargv = av;
70
71   if (main_init(gargc, gargv))
72     return -1; // failure
73
74   dump_default_var = dump_default;
75   dump_default_length = strlen(dump_default_var + 1);
76
77   jump_used = 0;
78
79   ret = setjmp(jumpbuffer);
80
81   if (ret == 0)
82   {
83     flag = main_program();
84
85     if (trace_flag)
86     {
87       sprintf(log_line, "EXITING at %s %d %d %d\n", "MAIN", flag, ret, jump_used);
88       show_line(log_line, 0);
89     }
90   }
91   else
92   {
93     if (trace_flag)
94     {
95       sprintf(log_line, "EXITING at %s %d %d %d\n", "JUMPOUT", flag, ret, jump_used);
96       show_line(log_line, 0);
97     }
98   }
99
100   if (endit(flag) != 0)
101     flag = 1; /* do final clean up in local.c */
102
103   if (flag == 0)
104     return 0;
105
106 #ifdef _WINDOWS
107   return flag;
108 #else
109   else exit (flag);   // avoid circularity!
110 #endif
111 }
112
113 /* texk/web2c/lib/texmfmp.c */
114 void t_open_in (void)
115 {
116   int i;
117
118   buffer[first] = 0;  /* In case there are no arguments.  */
119
120 #ifdef MSDOS
121 /* command line arguments? 94/Apr/10 */
122   if (gargc > optind && optind > 0)
123   {
124     for (i = optind; i < gargc; i++)
125 #else
126   if (gargc > 1)
127   {
128     for (i = 1; i < gargc; i++)
129 #endif
130     {
131       if (allow_quoted_names && strchr(gargv[i], ' ') != NULL)
132       {
133         (void) strcat ((char *) &buffer[first], "\"");
134         (void) strcat ((char *) &buffer[first], gargv[i]);
135         (void) strcat ((char *) &buffer[first], "\"");
136       }
137       else
138         (void) strcat ((char *) &buffer[first], gargv[i]);
139
140       (void) strcat ((char *) &buffer[first], " ");
141     }
142     
143     gargc = 0;
144   }
145
146   /* Find the end of the buffer.  */
147   for (last = first; buffer[last]; ++last) ;
148
149   for (--last; last >= first
150       && ISBLANK (buffer[last]) && buffer[last] != '\r'; --last)
151       ;
152   last++;
153
154 /* One more time, this time converting to TeX's internal character
155    representation.  */ /* for command line input in this case */
156   if (non_ascii)
157   {
158     for (i = first; i < last; i++)
159       buffer[i] = xord[buffer[i]];
160   }
161 }
162
163 /* All our interrupt handler has to do is set TeX's or Metafont's global
164    variable `interrupt'; then they will do everything needed.  */
165
166 static void catch_interrupt (int err)
167 {
168   (void) signal (SIGINT, SIG_IGN);
169
170   if (interrupt++ >= 3)
171     exit(1);
172
173   (void) signal (SIGINT, catch_interrupt);
174 }
175
176 /* Besides getting the date and time here, we also set up the interrupt
177    handler, for no particularly good reason.  It's just that since the
178    `fix_date_and_time' routine is called early on (section 1337 in TeX,
179    ``Get the first line of input and prepare to start''), this is as
180    good a place as any.  */
181
182 void get_date_and_time (integer *sys_minutes,
183                         integer *sys_day,
184                         integer *sys_month,
185                         integer *sys_year)
186 {
187   time_t clock;
188   struct tm *tmptr;
189
190   (void) time (&clock);  /* - seconds since 1970 */ 
191
192   if (trace_flag)
193   {
194     sprintf(log_line, "The time is %u\n", clock);
195     show_line(log_line, 0);   
196   }
197
198   if (clock < 0)
199   {
200     show_line("Time not available!\n", 1);
201   }
202
203   tmptr = localtime (&clock);
204 /*  MS C runtime library has trouble for clock >= 2^31 !!! */
205   if (tmptr == NULL)           /* debugging 95/Dec/30*/
206   {
207     sprintf(log_line, "Cannot convert time (%0ld)!\n", clock);
208     show_line(log_line, 1);
209     *sys_year    = 2038;
210     *sys_month   = 1;
211     *sys_day     = 18;
212     *sys_minutes = 22 * 60 + 14;
213   }
214   else
215   {
216     *sys_minutes = tmptr->tm_hour * 60 + tmptr->tm_min;
217     *sys_day     = tmptr->tm_mday;
218     *sys_month   = tmptr->tm_mon + 1;
219     *sys_year    = tmptr->tm_year + 1900;
220
221     if (trace_flag)
222     {
223       sprintf(log_line, "%d-%d-%d %d:%d\n",
224         tmptr->tm_year + 1900,
225         tmptr->tm_mon + 1,
226         tmptr->tm_mday,
227         tmptr->tm_hour,
228         tmptr->tm_min);
229       show_line(log_line, 0);
230     }
231   }
232
233   {
234 #ifdef MSDOS
235     if (!no_interrupts)
236     {
237       if (signal(SIGINT, catch_interrupt) == SIG_ERR)
238       {
239         show_line(" CTRL-C handler not installed\n", 0);
240 #ifndef _WINDOWS
241         uexit(1);  /* do we care when run as DLL ? */
242 #endif
243       }
244     }
245 #else
246     void (*old_handler)();
247
248     if ((old_handler = signal (SIGINT, catch_interrupt)) != SIG_DFL)
249       (void) signal (SIGINT, old_handler);
250 #endif
251   }
252 }
253
254 /* I/O for TeX and Metafont.  */ /* give file name ? */
255
256 void complain_line (FILE *output)
257 {
258   show_line("\n", 0);
259
260 #ifdef ALLOCATEBUFFER
261   sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", current_buf_size);
262 #else
263   sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", buf_size);
264 #endif
265
266   if (output == stderr)
267     show_line(log_line, 1);
268   else
269     if (output == stdout)
270       show_line(log_line, 0);
271     else
272       fputs(log_line, output); // never
273
274   show_line("  (File may have a line termination problem.)", 0);
275 }
276
277 void show_bad_line (FILE *output, int first, int last)
278 {
279   int i, c, d, ch;
280   char *s = log_line;
281
282   for (i = first; i <= last; i++)
283   {
284     ch = buffer[i];
285
286     if ((show_in_hex && ch > 127))
287     {
288       c = ch >> 4;
289       d = ch & 15; 
290       if (c > 9)
291         c = c + 'a' - 10;
292       else
293         c = c + '0';
294       if (d > 9)
295         d = d + 'a' - 10;
296       else
297         d = d + '0';
298 /* putc('^', output); putc('^', output); */
299       *s++ = '^';
300       *s++ = '^';
301 /* putc (c, output); putc (d, output); */
302       *s++ = (char) c;
303       *s++ = (char) d;
304     }
305     else
306       if (ch < 32)
307       {
308 /* putc('^', output); putc('^', output); */
309         *s++ = '^';
310         *s++ = '^';
311 /* putc (ch + 64, output); */
312         *s++ = (char) (ch + 64);
313       }
314       else
315         if (ch == 127)
316         {
317 /* putc('^', output); putc('^', output); */
318           *s++ = '^';
319           *s++ = '^';
320 /* putc (ch - 64, output); */
321           *s++ = (char) (ch - 64);
322         }
323         else
324         {
325 /* putc(ch, output); */
326           *s++ = (char) ch;
327         }
328   }
329 //  putc(' ', output);    /*  putc('\n', output); */
330   *s++ = ' ';
331   *s++ = '\0';
332   if (output == stderr)
333     show_line(log_line, 1);
334   else
335     if (output == stdout)
336       show_line(log_line, 0);
337     else
338       fputs(log_line, output);   // log_file
339 }
340
341 // split off for convenience and use in ConsoleInput
342 bool input_line_finish (void)
343 {
344   int i = '\0';
345   int ch, flag;
346   
347 /*  if last line in file does not end with \n - never happens ? */
348 /*  if (i == EOF && buffer[last] != '\n') buffer[last++] = '\n'; */
349
350   buffer[last] = ' ';           /* space terminate */
351   if (last >= max_buf_stack)
352     max_buf_stack = last; /* remember longest line */
353
354 /* Trim trailing whitespace.  */ 
355 /* #define isblank(c) ((c) == ' ' || (c) == '\t') */
356 /* What about \n ?  Can't get in here ?- bkph */
357 /* What about control-Z that gets read in binary mode ? - bkph */
358 // #ifdef MYDEBUG
359 /*  while (last > first && buffer[last - 1] <= ' ')  --last; */
360   while (last > first) {
361     i = buffer[last - 1];
362     if (i == ' ' || i == '\t')
363       --last;
364 /*    else if (trimeof && i == 26) --last;   */   /* 93/Nov/24 */
365     else
366       break;
367   }
368 /*  if (trimeof != 0 && i == EOF && last == first)  
369       return false; */              /* EOF and line empty */
370 // #else
371 //   while (last > first
372 //         && isblank (buffer[last - 1]) && buffer[last - 1] != '\r')
373 //    --last;
374 // #endif
375
376 /* following added to check source file integrity ASCII 32 - 127 */
377 /* allow space, tab, new-page - also allow return, newline ? */
378   if (restrict_to_ascii)
379   {
380     flag = 0;
381     for (i = first; i <= last; i++)
382     {
383       ch = buffer[i];
384 /*      if (ch > 127 || (ch < ' ' && ch != '\t' && ch != '\f')) */
385 /*      1 -- 8, 11, 14 -- 31 are not good ASCII characters */
386       if (ch > 126 ||  (ch < ' ' && ch != '\t' && ch != '\f' && ch != '\r' && ch != '\n'))
387       {
388         sprintf(log_line, "\n! non ASCII char (%d) in line: ", ch);
389         show_line(log_line, 1);
390         if (log_opened)
391           fprintf(log_file, "\n! non ASCII char (%d) in line: ", ch);
392 /*        buffer[i]= 127; */ /* not defined - invalid char */
393         flag = 1;
394         break;
395       }
396     }
397     if (flag)
398     {
399       show_bad_line(errout, first, last);
400       if (log_opened)
401         show_bad_line(log_file, first, last);
402     }
403   }
404 /* Don't bother using xord if we don't need to. */ /* for input line */
405 /* #ifdef NONASCII */ /* has been turned into command line flag - bkph */
406   if (non_ascii)
407   {
408     for (i = first; i <= last; i++)
409       buffer[i] = xord[buffer[i]];
410   }
411 /* #endif */
412   return true;
413 }
414
415 /* Read a line of input into buffer as efficiently as possible (ha ha)
416    while still looking like Pascal.
417    We set `last' to `first' and return `false' if we get to eof.
418    Otherwise, we return `true' and set last = first +
419    length(line except trailing whitespace).  */
420
421 bool input_line (FILE *f)
422 {
423 //  int ch, flag;         /* for restrict_to_ascii case 94/Jan/21 */
424   char *u;            /* 1994/July/3 for key_replace */
425   int i = '\0';
426
427 /*  and here is the long way of doing this */
428   last = first;
429 /*  following is new version with tab expansion and key replacement */
430 /*  may want to expand out separately for speed 1994/July/3 */
431 /*  different versions depending on return_flag / tabexpand / key_replace */
432 /*  while (last < buf_size && (i = getc (f)) != EOF)  */
433 #ifdef ALLOCATEBUFFER
434   for ( ; ; ) 
435 #else
436   while (last < buf_size) 
437 #endif
438   {
439     i = getc (f);
440
441     if (i < ' ')    /* isolate the more expensive tests */
442     {
443       if (i == EOF || i == '\n' || (i == '\r' && return_flag))
444         break;
445       else if (i == '\t' && tab_step != 0)  // deal with tab
446       {
447         buffer[last++] = (ASCII_code) ' ';
448
449 #ifdef ALLOCATEBUFFER
450         if (last >= current_buf_size)
451         {
452           buffer = realloc_buffer(increment_buf_size);  
453
454           if (last >= current_buf_size)
455             break;
456         }
457 #endif
458
459 #ifdef ALLOCATEBUFFER
460         while ((last - first) % tab_step != 0) 
461 #else
462         while (last < buf_size && (last - first) % tab_step != 0)
463 #endif
464         {
465
466           buffer[last++] = (ASCII_code) ' ';
467
468 #ifdef ALLOCATEBUFFER
469           if (last >= current_buf_size)
470           {
471             buffer = realloc_buffer(increment_buf_size);  
472             if (last >= current_buf_size)
473               break;
474           }
475 #endif
476         }
477         continue;
478       }
479     }
480     if (key_replace && (u = replacement[i]) != NULL)
481     {
482 #ifdef ALLOCATEBUFFER
483       while (*u != '\0') 
484 #else
485       while (last < buf_size && *u != '\0')  
486 #endif
487       {
488         buffer[last++] = (ASCII_code) *u++;
489 #ifdef ALLOCATEBUFFER
490         if (last >= current_buf_size)
491         {
492           buffer = realloc_buffer(increment_buf_size);
493
494           if (last >= current_buf_size)
495             break;
496         }
497 #endif
498       }
499     }
500     else       /* normal case */
501     {
502       buffer[last++] = (ASCII_code) i;
503 #ifdef ALLOCATEBUFFER
504       if (last >= current_buf_size)
505       {
506         buffer = realloc_buffer(increment_buf_size);
507
508         if (last >= current_buf_size)
509           break;
510       }
511 #endif
512     }
513   }   // end of for(;;) or while loop
514
515 //  can break out of above on EOF '\n' or '\r
516 //  sprintf(log_line, "BREAK on %d at %ld\n", i, ftell(f));
517 //  show_line(log_line, 0); // debugging only
518
519   if (return_flag)    /* let return terminate line as well as newline */
520   {
521     if (i == '\r')      /* see whether return followed by newline */
522     {
523       i = getc (f);       /* in which case throw away the newline */
524       if (i != '\n')
525       {
526         ungetc (i, f);
527         i = '\r';
528       }
529 /*      else  buffer[last-1] = (ASCII_code) i; */
530     }
531   }
532
533 //  sprintf(log_line, "first %d last %d\n", first, last);
534 //  show_line(log_line, 0);   // debugging only
535 //  strncpy(log_line, &buffer[first], last - first + 1);
536 //  log_line[last-first] = '\n';
537 //  log_line[last-first+1] = '\0';
538 //  show_line(log_line, 0);   // debugging only
539
540 //  Turn Ctrl-Z at end of file into newline 2000 June 22
541 //  if (i == EOF && trimeof != 0 && buffer[last-1] == 26) last--; /* ^Z */
542   if (i == EOF && trimeof && buffer[last-1] == 26)
543   {
544 //    buffer[last-1] = 10;  /* ^J */
545 //    buffer[last] = '\0';
546     last--;
547 //    sprintf(log_line, "CTRL-Z first %d last %d\n", first, last);
548 //    show_line(log_line, 0); // debugging only
549   }
550   if (i == EOF && last == first)
551     return false;   /* EOF and line empty - true end of file */
552
553 /*  Didn't get the whole line because buffer was too small?  */
554 /*  This shouldn't happen anymore 99/Jan/23 */
555   if (i != EOF && i != '\n' && i != '\r')
556   {
557     complain_line(errout);
558     if (log_opened)
559       complain_line(log_file);  /* ? 93/Nov/20 */
560 /*    This may no longer be needed ... now that we grow it */
561     if (truncate_long_lines)        /* 98/Feb/3 */
562     {
563       while (i != EOF && i != '\n' && i != '\r')  {
564         i = getc (f);     // discard rest of line
565       }
566       last--;       /* just in case */
567     }
568     else
569       uexit(1);      /* line too long */
570   }
571   return input_line_finish();
572 } /* end of input_line */
573
574 \f
575 /* This string specifies what the `e' option does in response to an
576    error message.  */ 
577
578 static char *edit_value = "c:\\yandy\\WinEdt\\WinEdt.exe [Open('%s');SelLine(%d,7)]";
579
580 void unshroud_string (char *real_var, char *var, int n)
581 {
582   int c;
583   char *s=real_var;
584   char *t=var;
585   
586 /*  while ((c = *t++) != '\0' && n-- > 0) *s++ = (char) (c - 1); */
587   while ((c = *t++) != '\0' && --n > 0)
588     *s++ = (char) (c - 1);
589   if (n >= 0)
590     *s = (char) c;
591   else
592     *s = '\0';       /* terminate it anyway */
593 } /* 93/Nov/20 */
594
595 char *get_env_shroud (char *var)
596 {
597   char real_var[32];
598   char *real_value;
599
600   unshroud_string (real_var, var, sizeof(real_var));
601 /*  real_value = getenv(real_var); */     /* 1994/Mar/1 */
602   real_value = grabenv(real_var);       /* 1994/Mar/1 */
603
604   if (trace_flag)
605   {
606     sprintf(log_line, "\nset %s=", real_var);
607     show_line(log_line, 0);
608     if (real_value != NULL)
609     {
610       show_line(real_value, 0);
611     }
612     show_line("\n", 0);
613   }
614 /*  return get_env_shroud (real_var); */  /* serious bug ! since 93/Nov/20 */
615 /*  return getenv (real_var); */    /* fixed 93/Dec/28 */
616   return real_value;          /* 94/Mar/1 */
617 }   /* 93/Nov/20 */
618
619 /* This procedure is due to sjc@s1-c.  TeX (or Metafont) calls it when
620    the user types `e' in response to an error, invoking a text editor on
621    the erroneous source file.  FNSTART is how far into STRINGPOOL the
622    actual filename starts; FNLENGTH is how long the filename is.
623    
624    See ../site.h for how to set the default, and how to override it.  */
625
626 /* called from close_files_and_terminate in  tex9.c */
627
628 void call_edit (ASCII_code *stringpool, pool_pointer fnstart, integer fnlength, integer linenumber)
629 {
630   char *command, *s, *t, *u;
631   char c;
632   int sdone, ddone, ldone;
633   int i, n;
634   unsigned int commandlen;
635   ASCII_code *texfilename;
636   ASCII_code *log_file_name;
637   pool_pointer lgstart;         /* 1994/Jan/94 */
638   integer lglength;           /* 1994/Jan/94 */
639
640   if (log_opened)           /* 1994/Aug/10 */
641   {
642     lgstart = str_start[texmf_log_name];
643     lglength = length(texmf_log_name);
644     log_file_name = stringpool + lgstart;
645   }
646   else                /* 1994/Aug/10 */
647   {
648     lglength = 0;
649     log_file_name = (unsigned char *) "";
650   }
651
652   sdone = ddone = ldone = 0;
653 /*  filename += fnstart; */
654   texfilename = stringpool + fnstart;
655
656 /*  Close any open input files, since we're going to kill the job.  */
657 /*  and since the editor will need access to them... */
658   for (i = 1; i <= in_open; i++)
659     (void) fclose (input_file[i]);
660
661   n = fcloseall();            /* paranoia 1994/Aug/10 */
662
663   if (n > 0 && verbose_flag)
664   {
665     sprintf(log_line, "Closed %d streams\n", n);
666     show_line(log_line, 0);
667   }
668
669 /*  Replace the default with the value of the appropriate environment
670     variable, if it's set.  */
671 /*  s = getenv (edit_var);   */   /* 93/Nov/20 */
672   s = get_env_shroud (edit_var);  
673   if (s != NULL)
674     edit_value = s;  /* OK, replace wired in default */
675
676 /*  Construct the command string.  */
677 /*  The `11' is the maximum length a 32 bit integer might be, plus one for null.  */
678 /*  Plus 2 for quotes if needed 99/May/31 */
679 /*  command = (string) xmalloc (strlen (edit_value) + fnlength + 11); */
680   commandlen = strlen (edit_value) + fnlength + lglength + 10 + 1 + 2;
681   command = (string) xmalloc (commandlen); 
682 /*  make more space for log_file_name 1994/Jan/26 */
683 /*  So we can construct it as we go.  */
684   s = command;
685
686 /*  should we manipulate edit_value first ? Add quotes if space in exe name ? */
687 /*  remove quotes around [...] string for WinEdt ? */
688
689   u = edit_value;
690   while ((c = *u++) != 0) {
691     if (c == '%') {         /* handle special codes */
692       switch (c = *u++)
693       {
694         case 'd':
695           if (ddone)
696           {
697 #ifdef MSDOS
698             sprintf(log_line, "! bad command syntax (%c).\n", 'd');
699             show_line(log_line, 1);
700 #else
701             sprintf(log_line, "! `%%d' cannot appear twice in editor command.\n");
702             show_line(log_line, 1);
703 #endif
704             uexit(1); 
705           }
706           (void) sprintf (s, "%d", linenumber);
707           while (*s != '\0')
708             s++;
709           ddone = 1;      /* indicate already used %d */
710           break;
711
712         case 's':
713           if (sdone)
714           {
715 #ifdef MSDOS
716             sprintf(log_line, "! bad command syntax (%c).\n", 's'); 
717             show_line(log_line, 1);
718 #else
719             sprintf(log_line, "! `%%s' cannot appear twice in editor command.\n");
720             show_line(log_line, 1);
721 #endif
722             uexit(1); 
723           }
724           t = (char *) texfilename;
725           n = fnlength;
726
727 /* following modified to allow non ASCII - bkph */ /* for file names */
728           if (non_ascii)
729 /*        for (i = 0; i < fnlength; i++)  *s++ = xchr [filename[i]]; */
730             for (i = 0; i < n; i++)
731               *s++ = xchr [*t++];
732           else
733 /*        for (i = 0; i < fnlength; i++)  *s++ = (char) filename[i]; */
734             for (i = 0; i < n; i++)
735               *s++ = (char) *t++;
736           sdone = 1;      /* indicate already used %s */
737           break;
738
739         case 'l':           /* 1994/Jan/28 */
740           if (ldone)
741           {
742 #ifdef MSDOS
743             sprintf(log_line, "! bad command syntax (%c).\n", 'l'); 
744             show_line(log_line, 1);
745 #else
746             sprintf(log_line, "! `%%l' cannot appear twice in editor command.\n");
747             show_line(log_line, 1);
748 #endif
749             uexit(1); 
750           }
751           t = (char *) log_file_name;
752           n = lglength;       /* 1994/Jan/28 */
753
754 /* following modified to allow non ASCII - bkph */ /* for file names */
755           if (non_ascii)
756 /*      for (i = 0; i < fnlength; i++)  *s++ = xchr [filename[i]]; */
757             for (i = 0; i < n; i++)
758               *s++ = xchr [*t++];
759           else
760 /*      for (i = 0; i < fnlength; i++)  *s++ = (char) filename[i]; */
761             for (i = 0; i < n; i++)
762               *s++ = (char) *t++;
763           ldone = 1;      /* indicate already used %l */
764           break;
765
766         case '\0':      /*  '%'  at end of line */
767           *s++ = '%'; 
768           u--;  /* Back up to the null to force termination.  */
769           break;
770
771         default:      /* something other than 's', 'd', 'l' follows */
772           *s++ = '%';
773           *s++ = c;
774           break;
775       }
776     }
777     else *s++ = c;      /* ordinary character pass it through */
778   }
779
780   *s = 0;         /* terminate the command string */
781
782   if (strlen(command) + 1 >= commandlen) /* should not happen! */
783   {
784     sprintf(log_line, "Command too long (%d > %d)\n", strlen(command) + 1, commandlen);
785     show_line(log_line, 1);
786     uexit(1);
787   }
788
789   //flushall();
790   fflush(NULL);
791 /*  Try and execute the command.  */
792 /*  There may be problem here with long names and spaces ??? */
793 /*  Use _exec or _spawn instead ??? */
794
795   if (system (command) != 0)
796   {
797     show_line("\n", 0);
798     sprintf(log_line, "! Error in call: %s\n", command); /* shroud ? */
799     show_line(log_line, 1);
800 /*    errno seems to be 0 typically, so perror says "no error" */
801 #ifdef MSDOS
802     if (errno != 0)
803       perrormod("! DOS says");      /* 94/Aug/10 - bkph */
804 #endif
805     sprintf(log_line, "  (TEXEDIT=%s)\n", edit_value);
806     show_line(log_line, 0);
807     show_line("  (Editor specified may be missing or path may be wrong)\n", 0);
808     show_line("  (or there may be missing -- or extraneous -- quotation signs)\n", 0);
809   }
810   uexit(1);       /*  Quit, since we found an error.  */
811 }
812
813 \f
814 /* Read and write format (for TeX) or base (for Metafont) files.  In
815    tex.web, these files are architecture dependent; specifically,
816    BigEndian and LittleEndian architectures produce different files.
817    These routines always output BigEndian files.  This still does not
818    make the dump files architecture-independent, because it is possible
819    to make a format file that dumps a glue ratio, i.e., a floating-point
820    number.  Fortunately, none of the standard formats do that.  */
821
822 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP) /* this fn */
823
824 /* We don't REALLY care what `endian' the machine is after all ! */
825 /* But we do care about speed - so check exe file for following - bkph */
826
827 // #ifdef MYDEBUG
828 // char swapmarkerstring="ERROR: SWAPPING - NOT BigEndian AND NOT NoFmtBaseSwap";
829 // #endif
830
831 /* This macro is always invoked as a statement.  It assumes a variable
832    `temp'.  */
833    
834 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp;
835
836
837 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
838    opposite-endianness of whatever they are now.  */
839
840 static int swap_items (char *p, int nitems, int size)
841 {
842   char temp;
843
844   /* Since `size' does not change, we can write a while loop for each
845      case, and avoid testing `size' for each time.  */
846   switch (size)
847   {
848     case 8:
849       while (nitems--)
850       {
851         SWAP (p[0], p[7]);
852         SWAP (p[1], p[6]);
853         SWAP (p[2], p[5]);
854         SWAP (p[3], p[4]);
855         p += size;
856       }
857       break;
858
859     case 4:
860       while (nitems--)
861       {
862         SWAP (p[0], p[3]);
863         SWAP (p[1], p[2]);
864         p += size;
865       }
866       break;
867
868     case 2:
869       while (nitems--)
870       {
871         SWAP (p[0], p[1]);
872         p += size;
873       }
874       break;
875
876     case 1:
877     /* Nothing to do.  */
878       break;
879
880     default:
881       show_line("\n", 0);
882       sprintf(log_line, "! I can't (un)dump a %d byte item.\n", size);
883       show_line(log_line, 1);
884       uexit(1);
885   }
886   return 0;
887 }
888 #endif /* not WORDS_BIGENDIAN and not NO_FMTBASE_SWAP */
889
890 /* Hmm, this could benefit from some on the fly compression - bkph */
891 /* and complementary decompression on input - bkph */
892
893 /* Here we write NITEMS items, each item being ITEM_SIZE bytes long.
894    The pointer to the stuff to write is P, and we write to the file
895    OUT_FILE.  */
896
897 int do_dump (char *p, int item_size, int nitems, FILE *out_file)
898 {
899 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
900   swap_items (p, nitems, item_size);
901 #endif
902
903   if ((int) fwrite (p, item_size, nitems, out_file) != nitems)
904   {
905     show_line("\n", 0);
906     sprintf(log_line, "! Could not write %d %d-byte item%s.\n",
907                nitems, item_size, (nitems > 1) ? "s" : "");
908     show_line(log_line, 1);
909     uexit(1);
910   }
911
912 /* Have to restore the old contents of memory, since some of it might get used again.  */
913 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
914   swap_items (p, nitems, item_size);
915 #endif
916
917   return 0;
918 }
919
920 /* Hmm, this could benefit from some on the fly decompression - bkph */
921
922 /* Here is the dual of the writing routine.  */
923 int do_undump (char *p, int item_size, int nitems, FILE *in_file)
924 {
925   if ((int) fread((void *) p, item_size, nitems, in_file) != nitems)
926   {
927     show_line("\n", 0);
928     sprintf(log_line, "! Could not read %d %d-byte item%s.\n",
929                nitems, item_size, (nitems > 1) ? "s" : "");
930     show_line(log_line, 1);
931     uexit(1);
932   }
933
934 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
935   swap_items (p, nitems, item_size);
936 #endif
937   return 0;
938 }
939
940 \f
941 #ifdef FUNNY_CORE_DUMP
942 /* This procedure is due to chris@mimsy.umd.edu.  It makes a core dump
943    without any sort of error status (abort(2) does return an error status,
944    so we don't want to use that).  It is used only when making a preloaded
945    TeX from virtex, and is triggered by a magic file name requested as
946    input (see `open_input', above).  */
947
948 void funny_core_dump ()
949 {
950   int pid, w;
951   union wait status;
952
953   switch (pid = vfork ())
954   {
955     case -1:    /* failed */
956       perrormod ("vfork");
957       exit (-1);      /* NOTREACHED */
958
959     case 0:             /* child */
960        (void) signal (SIGQUIT, SIG_DFL);
961        (void) kill (getpid (), SIGQUIT);
962        (void) write (2, "how did we get here?\n", 21);
963        exit (1);       /* NOTREACHED */
964
965     default:    /* parent */
966       while ((w = wait (&status)) != pid && w != -1)
967         ;
968       if (status.w_coredump)
969         exit (0);
970       (void) write (2, "attempt to dump core failed\n", 28);
971       exit (1);
972   }
973 }
974 #endif /* FUNNY_CORE_DUMP */