OSDN Git Service

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