OSDN Git Service

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