OSDN Git Service

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