OSDN Git Service

font manager: libavl.
[putex/putex.git] / src / texsourc / local.c
1 /* Copyright 2007 TeX Users Group
2    Copyright 2014 Clerk Ma   
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17    02110-1301 USA.  */
18
19 #ifdef _WINDOWS
20   #define NOCOMM
21   #define NOSOUND
22   #define NODRIVERS
23   #define STRICT
24   #pragma warning(disable:4115) // kill rpcasync.h complaint
25   #include <windows.h>
26   #define MYLIBAPI __declspec(dllexport)
27 #endif
28
29 #pragma warning(disable:4996)
30 #pragma warning(disable:4131) // old style declarator
31 #pragma warning(disable:4135) // conversion between different integral types 
32 #pragma warning(disable:4127) // conditional expression is constant
33
34 #include <kpathsea/config.h>
35 #include <kpathsea/c-ctype.h>
36 #include <kpathsea/line.h>
37 #include <kpathsea/readable.h>
38 #include <kpathsea/variable.h>
39 #include <kpathsea/absolute.h>
40
41 #include <setjmp.h>
42
43 #define EXTERN extern
44
45 #include "texd.h"
46
47 /* Most Y & Y changes are localized here -- init() */
48
49 #define USEOUREALLOC      /* 96/Jan/20 */
50
51 #define USEMEMSET       /* 98/Jan/23 */
52
53 #ifdef USEOUREALLOC
54   #define REALLOC ourrealloc
55 #else
56   #define REALLOC realloc
57 #endif
58
59 #include <time.h>
60 #include <malloc.h> /* _msize, _expand, HEAPOK et.c */
61 #include <direct.h> /* for _getcwd() */
62
63 #pragma warning(disable:4032) // different type when promoted
64 #ifndef _WINDOWS
65   #include <conio.h>            /* for _getch() */
66 #endif
67 #pragma warning(default:4032) // different type when promoted
68
69 int wantcopyrght = 1;
70
71 char *compiletime  =  __TIME__;
72 char *compiledate  =  __DATE__;
73 char *www          = "http://www.tug.org/yandy";
74 char *rights       = "All Rights Reserved.";
75 char *copyright    = "\nCopyright (C) 1993--2000 Y&Y, Inc.\n"
76                      "Copyright (C) 2007 TeX Users Group.\n"
77                      "Copyright (C) 2014 Clerk Ma.\n\n"
78                      "This program is free software; you can redistribute it and/or modify\n"
79                      "it under the terms of the GNU General Public License as published by\n"
80                      "the Free Software Foundation; either version 2 of the License, or\n"
81                      "(at your option) any later version.\n\n  ";
82 char *yandyversion = "2.2.3";
83 char *application  = "Y&Y TeX"; /* 96/Jan/17 */
84 char *tex_version  = "This is TeX, Version 3.14159265";
85
86 clock_t start_time, main_time, finish_time;
87
88 char * dvi_directory = "";
89 char * log_directory = "";
90 char * aux_directory = "";
91 char * fmt_directory = "";
92 char * pdf_directory = "";
93
94 char * texpath = "";   /* path to executable - used if env vars not set */
95
96 char log_line[MAXLINE];  // used also in tex9.c
97
98 int mem_spec_flag     = 0;    /* non-zero if `-m=...' was used */ 
99 int format_spec       = 0;    /* non-zero if a format specified on command line */
100 int closed_already    = 0;    /* make sure we don't try this more than once */
101 bool reorder_arg_flag = true; /* put command line flags/arguments first */
102
103 /* Mapping from Windows ANSI to DOS code page 850 96/Jan/20 */
104 /* Used in tex0.c with wintodos[c-128]                      */
105
106 unsigned char wintodos[128] =
107 {
108     0,   0,   0, 159,   0,   0,   0,   0,
109    94,   0,   0,   0,   0,   0,   0,   0,
110     0,  96,  39,   0,   0,   7,   0,   0,
111   126,   0,   0,   0,   0,   0,   0,   0,
112    32, 173, 189, 156, 207, 190, 221,  21,
113     0, 184, 166, 174, 170,  45, 169,   0,
114   248, 241, 253, 252,   0, 230,  20, 250,
115     0, 251, 167, 175, 172, 171, 243, 168,
116   183, 181, 182, 199, 142, 143, 146, 128,
117   212, 144, 210, 211, 222, 214, 215, 216,
118   209, 165, 227, 224, 226, 229, 153, 158,
119   157, 235, 233, 234, 154, 237, 232, 225,
120   133, 160, 131, 198, 132, 134, 145, 135,
121   138, 130, 136, 137, 141, 161, 140, 139,
122   208, 164, 149, 162, 147, 228, 148, 246,
123   155, 151, 163, 150, 129, 236, 231, 152
124 };  
125
126 void show_usage (void)
127 {
128   char * s = log_line;
129
130   sprintf (s, "\n"
131       " yandytex [-?ivnwdrzpK] [-m=ini_mem] [-e=hyph_size] [-h=trie_size]\n"
132       "          [-x=xchr_file] [-k=key_file] [-o=dvi_dir] [-l=log_dir] [-a=aux_dir]\n"
133       "          [+format_file] [tex_file]\n\n"
134       "    -?    show this usage summary\n"
135       "    -i    start up as iniTeX (create format file)\n"
136       "    -v    be verbose (show implementation version number)\n"
137       "    -n    do not allow `non ASCII' characters in input files (complain instead)\n"
138       "    -w    do not show `non ASCII' characters in hexadecimal (show as is)\n"
139       "    -d    do not allow DOS style file names - i.e. do not convert \\ to /\n"
140       "    -r    do not allow Mac style termination - i.e. do not convert \\r to \\n\n"
141       "    -p    allow use of \\patterns after loading format (iniTeX only)\n"
142       "    -K    disable all extensions to basic TeX\n"
143       "    -m    initial main memory size in kilo words (iniTeX only)\n"
144       "    -e    hyphenation exception dictionary size (iniTeX only)\n"
145       "    -h    hyphenation pattern trie size (iniTeX only)\n"
146       "    -x    use `non ASCII' character mapping (xchr[]) defined in file\n"
147       "    -k    use `key replacement' defined in file\n"
148       "    -o    write DVI file in specified directory (default current directory)\n"
149       "    -l    write LOG file in specified directory (default current directory)\n"
150       "    -a    write AUX file in specified directory (default current directory)\n");
151   show_line(log_line, 1);
152
153 #ifndef _WINDOWS
154   uexit(1);     // has this been setup yet ???
155 #endif
156 }
157
158 /* -z    do not discard control-Z at end of input file (treat as character)\n\ */
159
160 /* -c    prepend current directory (.) to TFM directory list\n\ */
161 /* -b    check that files with read access are not actually directories\n\ */
162
163 /* \t-d\tallow DOS style file names - i.e. convert \\ to / \n\ */
164 /* \t\t(applies to file name and format file name, if present)\n\ */
165 /* \t-r\tallow Mac style line termination - i.e. convert \\r to \\n \n\ */
166
167 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
168
169 // Sep 27 1990 => 1990 Sep 27
170 // 012456789      0123456789
171 void scivilize (char * date)
172 {
173   int k;
174   char pyear[6];
175
176   strcpy (pyear, date + 7);
177
178   for (k = 5; k >= 0; k--)
179     date[k + 5] = date[k];
180
181   for (k = 0; k < 4; k++)
182     date[k] = pyear[k];
183
184   date[4] = ' ';
185
186   if (date[9] == ' ')
187     date[9] = '0'; /* replace space by '0' */
188
189   return;
190 }
191
192 // Thu Sep 27 06:26:35 1990 => 1990 Sep 27 06:26:35
193 void lcivilize (char * date)
194 {
195   int k;
196   char pyear[6];
197
198   strcpy (pyear, date + 20);
199
200   for (k = 18; k >= 0; k--)
201     date[k+1] = date[k];
202
203   date[20] = '\0';
204
205   for (k = 0; k < 4; k++)
206     date[k] = pyear[k];
207
208   date[4] = ' ';
209
210   return;
211 }
212
213 // now writes result into given buffer
214 void stamp_it (char *s)
215 {
216   char date[11 + 1];
217
218   strcpy(date, compiledate);
219   scivilize(date);
220   sprintf(s, "%s %s ", application, yandyversion);
221   s += strlen(s);
222   sprintf(s, "(compiled time: %s %s)", date, compiletime);
223   s += strlen(s);
224 }
225
226 void stampcopy (char *s)
227 {
228   if (wantcopyrght)
229   {
230     sprintf(s, "%s %s", copyright, www);
231   }
232 }
233
234 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
235
236 #define MAXCHRS 256
237 #define NOTDEF  127
238
239 void read_xchr_sub (FILE * xchr_input)
240 {
241   char buffer[PATH_MAX];
242   int k, from, to, count = 0;
243   char *s;
244
245 #ifdef USEMEMSET
246   memset (xchr, NOTDEF, MAXCHRS);           /* mark unused */
247 #else
248   for (k = 0; k < MAXCHRS; k++)
249     xchr[k] = -1; /* mark unused */
250 #endif
251
252 #ifdef USEMEMSET
253   memset (xord, NOTDEF, MAXCHRS);           /* mark unused */
254 #else
255   for (k = 0; k < MAXCHRS; k++)
256     xord[k] = -1;  /* mark unused */
257 #endif
258
259 #ifdef ALLOCATEBUFFER
260   while (fgets(buffer, current_buf_size, xchr_input) != NULL)
261 #else
262   while (fgets(buffer, sizeof(buffer), xchr_input) != NULL)
263 #endif
264   {
265     if (*buffer == '%' || *buffer == ';' || *buffer == '\n')
266       continue;
267
268     from = (int) strtol (buffer, &s, 0);
269     to = (int) strtol (s, NULL, 0);
270
271     if (from >= 0 && from < MAXCHRS && to >= 0 && to < MAXCHRS)
272     {
273       if (xchr[from]== (unsigned char) NOTDEF)
274       {
275         xchr[from]= (unsigned char) to;
276       }
277       else
278       {
279         sprintf(log_line, "NOTE: %s collision: %d => %d, %d\n", "xchr", from, xchr[from], to);
280         show_line(log_line, 0);
281       }
282
283       if (xord[to]== NOTDEF)
284       {
285         xord[to]= (unsigned char) from;
286       }
287       else
288       {
289         sprintf(log_line, "NOTE: %s collision: %d => %d, %d\n", "xord", to, xord[to], from);
290         show_line(log_line, 0);
291       }
292       count++;
293     }
294   }
295
296 /*  now fill in the gaps */ /* not clear this is a good idea ... */
297   for (k = 0; k < MAXCHRS; k++)
298   {
299     if (xchr[k]== NOTDEF)   /* if it has not been filled */
300     {
301       if (xord[k]== NOTDEF) /* see whether used already */
302       {
303         xchr[k]= (unsigned char) k; /* no, so make identity */
304         xord[k]= (unsigned char) k; /* no, so make identity */
305       }
306     }
307   }
308
309   xchr[NOTDEF]= NOTDEF;         /* fixed point of mapping */
310
311   if (trace_flag)
312   {
313     sprintf(log_line, "Read %d xchr[] pairs:\n", count);
314     show_line(log_line, 0);
315
316     for (k = 0; k < MAXCHRS; k++)
317     {
318       if (xchr[k]!= NOTDEF)
319       {
320         sprintf(log_line, "%d => %d\n", k, xchr[k]);
321         show_line(log_line, 0);
322       }
323     }
324   }
325 }
326
327 char *replacement[MAXCHRS];     /* pointers to replacement strings */
328
329 void read_repl_sub (FILE * repl_input)
330 {
331   int k, n, m, chrs;
332   char buffer[PATH_MAX];
333   char charname[128];
334   int charnum[10];
335   char *s, *t;
336   
337 #ifdef USEMEMSET
338   memset(replacement, 0, MAXCHRS * sizeof(replacement[ 0]));
339 #else
340   for (k = 0; k < MAXCHRS; k++)
341     replacement[k] = NULL;
342 #endif
343
344   while (fgets(buffer, PATH_MAX, repl_input) != NULL) {
345     if (*buffer == '%' || *buffer == ';' || *buffer == '\n')
346       continue;
347
348     if ((m = sscanf (buffer, "%d%n %s", &chrs, &n, &charname)) == 0)
349       continue;
350     else if (m == 2) {
351       if (*charname == '"') {   /* deal with quoted string "..." */
352         s = buffer + n;
353         t = charname;
354         while (*s != '"' && *s != '\0') s++;  /* step up to " */
355         if (*s++ == '\0') continue;       /* sanity check */
356         while (*s != '\0') {  
357           if (*s == '"') {
358             s++;            /* is it "" perhaps ? */
359             if (*s != '"') break;   /* no, end of string */
360           }
361           *t++ = *s++;          /* copy over */
362         }
363         *t = '\0';              /* and terminate */
364       }
365       if (chrs >= 0 && chrs < MAXCHRS)
366         replacement[chrs] = xstrdup(charname);
367     }
368 /*    presently the following can never get triggered */
369 /*    which is good, because it is perhaps not right ... */
370     else if ((m = sscanf (buffer, "%d %d %d %d %d %d %d %d %d %d %d",
371       &chrs, charnum, charnum+1, charnum+2, charnum+3, charnum+4,
372         charnum+5, charnum+6, charnum+7, charnum+8, charnum+9)) > 1) {
373 /*      for (k = 0; k < n-1; k++) charname[k] = (char) charnum; */
374       for (k = 0; k < n-1; k++) charname[k] = (char) charnum[k];
375       charname[m] = '\0';
376       if (chrs >= 0 && chrs < MAXCHRS)
377         replacement[chrs] = xstrdup(charname);      
378     }
379     else {
380       sprintf(log_line, "ERROR: don't understand %s", buffer);
381       show_line(log_line, 1);
382     }
383   }
384   if (trace_flag) {                  /* debugging output */
385     show_line("Key replacement table\n", 0);
386     for (k = 0; k < MAXCHRS; k++) {
387       if (replacement[k] != NULL) {
388         sprintf(log_line, "%d\t%s\n", k, replacement[k]);
389         show_line(log_line, 0);
390       }
391     }
392   }
393 }
394
395 /* Following used both to read xchr[] file and key replacement file */
396 /* the flag is 0 for -x=... and the flag is 1 for -k=... */
397 int read_xchr_file (char *filename, int flag, char *argv[])
398 {
399   FILE *pinput;
400   char infile[PATH_MAX];
401   char *s;
402
403   if (filename == NULL)
404     return -1;
405
406   if (trace_flag)
407   {
408     sprintf(log_line, "Reading xchr/repl %s\n", filename);
409     show_line(log_line, 0);
410   }
411
412 /*  first try using file as specified */
413   strcpy(infile, filename);
414
415   if (trace_flag)
416   {
417     sprintf(log_line, "Trying %s\n", infile);
418     show_line(log_line, 0);
419   }
420
421   if (share_flag == 0)
422     pinput = fopen (infile, "r");
423   else
424     pinput = _fsopen (infile, "r", share_flag);    /* 94/July/12 */
425
426   if (pinput == NULL)
427   {
428     if (strrchr(infile, '.') == NULL)
429     {
430       if (flag == 0)
431         strcat(infile, ".map");
432       else
433         strcat(infile, ".key");
434
435       if (trace_flag)
436       {
437         sprintf(log_line, "Trying %s\n", infile);
438         show_line(log_line, 0);
439       }
440
441       if (share_flag == 0)
442         pinput = fopen (infile, "r");
443       else
444         pinput = _fsopen (infile, "r", share_flag);  /* 94/July/12 */
445     }
446   }
447
448   if (pinput == NULL)
449   {
450     strcpy (infile, argv[0]);     /* try TeX program path */
451
452     if ((s = strrchr (infile, '\\')) != NULL) *(s+1) = '\0';
453     else if ((s = strrchr (infile, '/')) != NULL) *(s+1) = '\0';
454     else if ((s = strrchr (infile, ':')) != NULL) *(s+1) = '\0';
455
456     strcat (infile, filename);
457
458     if (trace_flag)
459     {
460       sprintf(log_line, "Trying %s\n", infile);
461       show_line(log_line, 0);
462     }
463
464     if (share_flag == 0)
465       pinput = fopen (infile, "r");
466     else
467       pinput = _fsopen (infile, "r", share_flag);    /* 94/July/12 */
468
469     if (pinput == NULL)
470     {
471       if (strchr(infile, '.') == NULL)
472       {
473         if (flag == 0)
474           strcat(infile, ".map");
475         else
476           strcat(infile, ".key");
477
478         if (trace_flag)
479         {
480           sprintf(log_line, "Trying %s\n", infile);
481           show_line(log_line, 0);
482         }
483
484         if (share_flag == 0)
485           pinput = fopen (infile, "r");
486         else
487           pinput = _fsopen (infile, "r", share_flag); /* 94/July/12 */
488       }
489     }
490   }
491
492   if (pinput == NULL)   /* 97/July/31 */
493   {
494     strcpy (infile, argv[0]);     /* try TeX program path */
495
496     if ((s = strrchr (infile, '\\')) != NULL) *(s+1) = '\0';
497     else if ((s = strrchr (infile, '/')) != NULL) *(s+1) = '\0';
498     else if ((s = strrchr (infile, ':')) != NULL) *(s+1) = '\0';
499
500     strcat (infile, "keyboard\\");
501     strcat (infile, filename);
502
503     if (trace_flag)
504     {
505       sprintf(log_line, "Trying %s\n", infile);
506       show_line(log_line, 0);
507     }
508
509     if (share_flag == 0)
510       pinput = fopen (infile, "r");
511     else
512       pinput = _fsopen (infile, "r", share_flag);
513
514     if (pinput == NULL)
515     {
516       if (strchr(infile, '.') == NULL)
517       {
518         if (flag == 0)
519           strcat(infile, ".map");
520         else
521           strcat(infile, ".key");
522
523         if (trace_flag)
524         {
525           sprintf(log_line, "Trying %s\n", infile);
526           show_line(log_line, 0);
527         }
528
529         if (share_flag == 0)
530           pinput = fopen (infile, "r");
531         else
532           pinput = _fsopen (infile, "r", share_flag);
533       }
534     }
535   }
536 /*  Note: can't look in TeX source file dir, since that is not known yet */
537   if (pinput == NULL)
538   {
539     sprintf(log_line, "ERROR: Sorry, cannot find %s file %s",
540         flag ? " xchr[]" : "key mapping", filename);
541     show_line(log_line, 1);
542     perrormod (filename);
543     return 0;         // failed
544   }
545
546   if (flag == 0)
547     read_xchr_sub (pinput);
548   else
549     read_repl_sub (pinput);
550
551   (void) fclose (pinput);
552   return 1;
553 }
554
555 /* need to also set `key_replace' here based on command line */
556 /* need to also allocate `buffercopy' here and free at end */
557 /* need to call `readreplace' in appropriate place */
558
559 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
560
561 /* Following may be useful if link without floating point emulation */
562
563 #ifdef DEBUG
564 void testfloating (void)
565 {
566   double dx = 1.0;
567   double dxold = 0.0;
568   int k = 0;
569
570   while (1.0 + dx != 1.0)
571   {
572     dxold = dx;
573     dx = dx / 2.0;
574     k++;
575   }
576   sprintf(log_line, "Floating test: dx = %lg (k = %d)\n", dxold, k - 1);
577   show_line(log_line, 0);
578 }
579 #endif
580
581 #define MAXSPLITS 3
582
583 /* ad hoc default minimum growth in memory realloc is 62% */
584 /* golden ratio (1 + \sqrt{5}) / 2 = 1.618033989... */
585 int percent_grow    = 62; /* default minimum growth in memory realloc is 62% */
586 int total_allocated = 0;  /* total memory allocated so far */
587 int ini_max_address = 0;  /* maximum address when starting */
588 int max_address     = 0;  /* maximum address seen in allocated memory */
589
590
591 void show_maximums (FILE *output)
592 {
593   sprintf(log_line, "Max allocated %d --- max address %d\n", total_allocated, max_address);
594 //  if (output != NULL) fputs(log_line, output); // log file
595 //  else if (flag == 0) show_line(log_line, 0); // informative
596 //  else if (flag == 1) show_line(log_line, 1); // error
597   if (output == stderr)
598     show_line(log_line, 1);
599   else if (output == stdout)
600     show_line(log_line, 0);
601   else
602     fputs(log_line, output);
603 }
604
605 /* our own version of realloc --- avoid supposed MicroSoft version bug */
606 /* also tries _expand first, which can avoid address growth ... */
607
608 #ifdef USEOUREALLOC 
609 void *ourrealloc (void *old, size_t new_size)
610 {
611   void * mnew;
612   size_t old_size, overlap;
613
614 /*  round up to nearest multiple of four bytes *//* avoid unlikely alignment */
615   if ((new_size % 4) != 0)
616     new_size = ((new_size / 4) + 1) * 4;
617
618   if (old == NULL)
619     return malloc (new_size);  /* no old block - use malloc */
620
621   old_size = _msize (old);
622
623   if (old_size >= new_size && old_size < new_size + 4)
624     return old;
625
626   mnew = _expand (old, new_size);      /* first try and expand in place */
627
628   if (mnew != NULL)
629   {
630     if (trace_flag)
631     {
632       sprintf(log_line, "EXPANDED! %d (%d) == %d (%d)\n",
633           mnew, new_size, old, old_size);
634       show_line(log_line, 0);
635     }
636     return mnew;
637   }
638 /*  *********************************************************************** */
639 /*  do this if you want to call the real realloc next -  */
640   mnew = realloc (old, new_size);
641
642   if (mnew != NULL)
643     return mnew;
644 /*  we are screwed typically if we ever drop through here - no more space */
645 /*  *********************************************************************** */
646   mnew = malloc (new_size);          /* otherwise find new space */
647
648   if (mnew == NULL)
649     return mnew;        /* if unable to allocate */
650
651   if (old_size < new_size)
652     overlap = old_size;
653   else
654     overlap = new_size;
655
656   memcpy (mnew, old, overlap);         /* copy old data to new area */
657   free(old);                  /* free the old area */
658   return mnew;
659 }
660 #endif
661
662 void memory_error (char *s, int n)
663 {
664   if (log_opened)
665   {
666     fprintf(log_file, "\n! Unable to allocate %d bytes for %s\n", n, s);
667     show_maximums(log_file);
668   }
669
670   sprintf(log_line, "\n! Unable to allocate %d bytes for %s\n", n, s);
671   show_line(log_line, 1);
672   show_maximums(stderr);
673
674 /*  exit (1); */      /* 94/Jan/22 */
675 /*  return to let TeX do its thing (such as complain about runaway) */
676 /*  don't set abort_flag here */
677 }
678
679 void trace_memory (char *s, int n)
680 {
681   sprintf(log_line, "Allocating %d bytes for %s\n", n, s);
682   show_line(log_line, 0);
683 }
684
685 void update_statistics (int address, int size, int oldsize)
686 {
687   if (address + size > max_address)
688     max_address = address + size;
689
690   total_allocated =  total_allocated + size - oldsize;
691 }
692
693 void probe_memory (void)
694 {
695   char *s;
696
697   s = (char *) malloc (4); /* get current top address */
698   free(s);
699   update_statistics ((int) s, 0, 0); /* show where we are */
700 }
701
702 void probe_show (void)
703 {
704   probe_memory();
705   show_maximums(stdout);
706 }
707
708 size_t roundup (size_t n)
709 {
710   if ((n % 4) == 0)
711     return n;
712   else
713     return ((n / 4) + 1) * 4;
714 }
715
716 #ifdef ALLOCATETRIES
717 /* using allocating hyphenation trie slows things down maybe 1%              */
718 /* but saves typically (270k - 55k) = 215k of memory                         */
719 /* NOTE: it's safe to allocate based on the trie_max read from fmt file      */
720 /* since hyphenation trie cannot be extended (after iniTeX)                  */
721 /* for iniTeX, however, we need to allocate the full trie_size ahead of time */
722 /*                                                                           */
723 /* NOTE: we don't ever reallocate these                                      */
724 /* returns -1 if it fails                                                    */
725
726 int allocate_tries (int trie_max)
727 {
728   int n, nl, no, nc;
729 /*  if (trie_max > trie_size) {
730     sprintf(log_line, "ERROR: invalid trie size (%d > %d)\n",
731       trie_max, trie_size);
732       show_line(log_line, 1);
733     exit (1);
734   } */ /* ??? removed 1993/dec/17 */
735   if (trie_max > 1000000)
736     trie_max = 1000000; /* some sort of sanity limit */
737 /*  important + 1 because original was halfword trie_trl[trie_size + 1] etc. */
738   nl = (trie_max + 1) * sizeof(halfword);    /* trie_trl[trie_size + 1] */
739   no = (trie_max + 1) * sizeof(halfword);    /* trie_tro[trie_size + 1] */
740   nc = (trie_max + 1) * sizeof(quarterword); /* trie_trc[trie_size + 1] */
741   n = nl + no + nc;
742
743   if (trace_flag)
744     trace_memory("hyphen trie", n);
745
746   trie_trl = (halfword *)    malloc (roundup(nl));
747   trie_tro = (halfword *)    malloc (roundup(no));
748   trie_trc = (quarterword *) malloc (roundup(nc));
749
750   if (trie_trl == NULL || trie_tro == NULL || trie_trc == NULL)
751   {
752     memory_error("hyphen trie", n);
753     return -1;
754   }
755
756   if (trace_flag)
757   {
758     sprintf(log_line, "Addresses trie_trl %d trie_tro %d trie_trc %d\n", trie_trl, trie_tro, trie_trc);
759     show_line(log_line, 0);
760   }
761
762   update_statistics ((int) trie_trl, nl, 0);
763   update_statistics ((int) trie_tro, no, 0);
764   update_statistics ((int) trie_trc, nc, 0);
765 /*  sprintf(log_line, "trie_size %d trie_max %d\n", trie_size, trie_max); */ /* debug */
766   trie_size = trie_max;           /* BUG FIX 98/Jan/5 */
767
768   if (trace_flag)
769     probe_show();     /* 94/Mar/25 */
770   return 0;               // success
771 }
772 #endif
773
774 #ifdef ALLOCATEHYPHEN
775 bool prime (int);       /* test function later in this file */
776
777 int current_prime = 0;         /* remember in case reallocated later */
778
779 /* we don't return an address here, since TWO memory regions allocated */
780 /* plus, we don't really reallocate, we FLUSH the old information totally */
781 /* returns -1 if it fails */
782
783 int realloc_hyphen (int hyphen_prime)
784 {
785   int n, nw, nl;
786
787   if (!prime(hyphen_prime))
788   {
789     sprintf(log_line, "ERROR: non-prime hyphen exception number (%d)\n", hyphen_prime);
790     show_line(log_line, 1);
791     return -1;
792   }
793 /*  need not/cannot preserve old contents when hyphen prime is changed */
794 /*  if (hyph_list != NULL) free(hyph_list); */
795 /*  if (hyph_word != NULL) free(hyph_word); */
796 /*  important + 1 since str_number hyph_word[hyphen_prime + 1]  in original etc. */
797   nw = (hyphen_prime + 1) * sizeof(str_number);
798   nl = (hyphen_prime + 1) * sizeof(halfword);
799   n = nw + nl;
800
801   if (trace_flag)
802     trace_memory("hyphen exception", n);
803
804 /*  initially hyph_word will be NULL so this acts like malloc */
805 /*  hyph_word = (str_number *) malloc (nw); */
806   hyph_word = (str_number *) REALLOC (hyph_word, nw);  /* 94/Mar/24 */
807 /*  initially hyph_list will be NULL so this acts like malloc */
808 /*  hyph_list = (halfword *) malloc (nl); */
809   hyph_list = (halfword *) REALLOC (hyph_list, nl);   /* 94/Mar/24 */
810
811   if (hyph_word == NULL || hyph_list == NULL)
812   {
813     memory_error("hyphen exception", n);
814     return -1;
815   }
816
817   if (trace_flag)
818   {
819     sprintf(log_line, "Addresses hyph_word %d hyph_list %d\n", hyph_word, hyph_list);
820     show_line(log_line, 0);
821   }
822 /*  cannot preserve old contents when hyphen prime is changed */
823 #ifdef USEMEMSET
824   memset(hyph_word, 0, (hyphen_prime + 1) * sizeof (hyph_word[0]));
825 #else
826   for (k = 0; k <= hyphen_prime; k++) hyph_word[k]= 0;
827 #endif
828
829 #ifdef USEMEMSET
830   memset(hyph_list, 0, (hyphen_prime + 1) * sizeof (hyph_list[0]));
831 #else
832   for (k = 0; k <= hyphen_prime; k++) hyph_list[k]= 0;
833 #endif
834   hyph_count = 0;   /* or use reset_hyphen() in itex.c */
835
836   if (current_prime != 0)
837   {
838     update_statistics ((int) hyph_word, nw, (current_prime + 1) * sizeof(str_number));
839     update_statistics ((int) hyph_list, nl, (current_prime + 1) * sizeof(halfword));
840   }
841   else
842   {
843     update_statistics ((int) hyph_word, nw, 0);
844     update_statistics ((int) hyph_list, nl, 0);
845   }
846   current_prime = hyphen_prime;
847
848   if (trace_flag)
849     probe_show();     /* 94/Mar/25 */
850
851   return 0;               // success
852 }
853 #endif
854
855 int current_mem_size = 0;   /* current total words in main mem allocated -1 */
856
857 /* this gets called from itex.c when it figures out what mem_top is */
858 /* or gets called from here when in ini_TeX mode */ /* and nowhere else */
859 /* initial allocation only, may get expanded later */
860 /* NOTE: we DON't use ALLOCATEHIGH & ALLOCATELOW anymore */
861 /* returns NULL if it fails */
862
863 #ifdef ALLOCATEMAIN   
864 /* initial main memory alloc - mem_top */
865 memory_word *allocate_main_memory (int size)
866 {
867   int n;
868
869 /*  Using -i *and* pre-loading format */ /* in this case get called twice */
870 /*  Get rid of initial blank memory again or use realloc ... */
871 /*  Could we avoid this by detecting presence of & before allocating ? */
872 /*  Also, if its already large enough, maybe we can avoid this ? */
873 /*  don't bother if current_mem_size == mem_max - mem_start ? */
874   if (mainmemory != NULL)
875   {
876     if (trace_flag)
877       show_line("Reallocating initial memory allocation\n", 1);
878   }
879
880   mem_top = mem_bot + size;
881
882 #ifdef ALLOCATEHIGH         /* NOT USED ANYMORE */
883   if (mem_extra_high != 0 && !is_initex)
884     mem_max = mem_top + mem_extra_high;
885 #endif
886
887   mem_max = mem_top;
888
889 #ifdef ALLOCATELOW          /* NOT USED ANYMORE */
890   if (mem_extra_low != 0 && !is_initex)
891     mem_start = mem_bot - mem_extra_low;  /* increase main memory */
892 #endif
893
894   mem_start = 0;     /* bottom of memory allocated by system */
895 /*  mem_min = mem_start; */ /* bottom of area made available to TeX */
896   mem_min = 0;       /* bottom of area made available to TeX */
897   n = (mem_max - mem_start + 1) * sizeof (memory_word); /* 256k * 8 = 2000 k */
898
899   if (trace_flag)
900     trace_memory("main memory", n);
901
902 /*  mainmemory = (memory_word *) malloc (n); */  /* 94/March/24 */
903 /*  normally mainmemory == NULL here so acts like malloc ... */
904   mainmemory = (memory_word *) REALLOC (mainmemory, n);
905
906   if (mainmemory == NULL)
907   {
908     memory_error("initial main memory", n);
909 //    exit (1);             /* serious error */
910     return NULL;
911   }
912
913   if (trace_flag)
914   {
915     sprintf(log_line, "Address main memory == %d\n", mainmemory);
916     show_line(log_line, 0);
917   }
918
919   zzzaa = mainmemory;
920
921   if (mem_start != 0 && !is_initex)
922     zzzaa = mainmemory - mem_start;
923
924   if (trace_flag)
925   {
926     sprintf(log_line, "Offset address main memory == %d\n", zzzaa);
927     show_line(log_line, 0);
928   }
929
930   update_statistics ((int) mainmemory, n,
931     (current_mem_size + 1) * sizeof (memory_word));
932 /*  current_mem_size = (mem_max - mem_start + 1); */
933   current_mem_size = mem_max - mem_start;   /* total number of words - 1 */
934
935   if (trace_flag)
936     probe_show();     /* 94/Mar/25 */
937
938   return zzzaa;             /* same as zmem, mem 94/Jan/24 */
939 }
940 #endif  /* end of ALLOCATEMAIN */
941
942 #ifdef ALLOCATEMAIN
943 /* int firstallocation = 1; */
944
945 /* increase main memory allocation at low end and high end */
946 /* called only from tex0.c *//* called with one of losize or hisize == 0 */
947 /* returns NULL if it fails */
948
949 memory_word *realloc_main (int losize, int hisize)
950 {  
951   int k, minsize;
952   int newsize = 0;        /* to quieten compiler */
953   int n = 0;          /* to quieten compiler */
954   memory_word * newmemory = NULL; /* to quieten compiler */
955
956 /*  if (losize == 0 && hisize > 0) runawayflag = 1;
957   else runawayflag = 0; */ /* 94/Jan/22 */
958
959   if (trace_flag)
960   {
961     sprintf(log_line, "WARNING: Entering realloc_main lo %d hi %d\n", losize, hisize);
962     show_line(log_line, 0);
963   }
964
965   if (is_initex)
966   {
967     show_line("ERROR: Cannot extent main memory in iniTeX\n", 1);
968
969     if (! knuth_flag)
970       show_line("Please use `-m=...' on command line\n", 0);
971 //    abort_flag++;  // ???
972     return NULL;
973   }
974
975   if (trace_flag)
976   {
977     sprintf(log_line, "Old Address %s == %d\n", "main memory", mainmemory);
978     show_line(log_line, 0);
979   }
980
981   if (current_mem_size + 1 == max_mem_size) /* if we REALLY run up to limit ! */
982   {
983     memory_error("main memory", (max_mem_size + 1) * sizeof(memory_word));
984 //    abort_flag++;  // ???
985     return NULL;
986   }
987 /*  first allocation should expand *both* lo and hi */
988   if (hisize == 0 && mem_end == mem_max)
989     hisize = losize;
990
991   if (losize == 0 && mem_start == mem_min)
992     losize = hisize;
993
994 /*  try and prevent excessive frequent reallocations */
995 /*  while avoiding over allocation by too much */
996   minsize = current_mem_size / 100 * percent_grow;
997
998   if (losize + hisize < minsize)
999   {
1000     if (losize > 0 && hisize > 0)
1001     {
1002       losize = minsize / 2;
1003       hisize = minsize / 2;
1004     }
1005     else if (losize > 0)
1006       losize = minsize;
1007     else if (hisize > 0)
1008       hisize = minsize;
1009   }
1010
1011   if (losize > 0 && losize < mem_top / 2)
1012     losize = mem_top / 2;
1013
1014   if (hisize > 0 && hisize < mem_top / 2)
1015     hisize = mem_top / 2;
1016
1017   for (k = 0; k < MAXSPLITS; k++)
1018   {
1019     newsize = current_mem_size + losize + hisize;
1020
1021     if (newsize >= max_mem_size) /* bump against limit - ha ha ha */
1022     {
1023       while (newsize >= max_mem_size) {
1024         losize = losize / 2; hisize = hisize / 2;
1025         newsize = current_mem_size + losize + hisize;
1026       }
1027     }
1028
1029     n = (newsize + 1) * sizeof (memory_word);
1030
1031     if (trace_flag)
1032       trace_memory("main memory", n);
1033
1034     newmemory = (memory_word *) REALLOC (mainmemory, n);
1035
1036     if (newmemory != NULL)
1037       break; /* did we get it ? */
1038
1039     if (current_mem_size == 0)
1040       break; /* in case we ever use for initial */
1041
1042     losize = losize / 2; hisize = hisize / 2;
1043   }
1044
1045   if (newmemory == NULL)
1046   {
1047     memory_error("main memory", n);
1048     return zzzaa;           /* try and continue with TeX !!! */
1049   }
1050
1051   if (trace_flag)
1052   {
1053     sprintf(log_line, "New Address %s == %d\n", "main memory", newmemory);
1054     show_line(log_line, 0);
1055   }
1056
1057   if (losize > 0)
1058   {
1059 /*  shift everything upward to make space for new low area */
1060     if (trace_flag)
1061     {
1062       sprintf(log_line, "memmove %d %d %d \n", newmemory + losize,
1063           newmemory, (current_mem_size + 1) * sizeof(memory_word));
1064       show_line(log_line, 0);
1065     }
1066     memmove (newmemory + losize, newmemory,
1067       (current_mem_size + 1) * sizeof(memory_word));
1068 /*  could reduce words moved by (mem_max - mem_end) */
1069   }
1070   mainmemory = newmemory;       /* remember for free later */
1071
1072   if (losize > 0)
1073     mem_start = mem_start - losize; /* update lower limit */
1074
1075   if (hisize > 0)
1076     mem_max = mem_max + hisize;   /* update upper limit */
1077
1078   update_statistics ((int) mainmemory, n,
1079     (current_mem_size + 1) * sizeof (memory_word));
1080   current_mem_size = newsize;
1081
1082   if (current_mem_size != mem_max - mem_start)
1083   {
1084     show_line("ERROR: Impossible Memory Error\n", 1);
1085   }
1086
1087   if (mem_start != 0)
1088     zzzaa = mainmemory - mem_start; /* ??? sign ??? */
1089   else
1090     zzzaa = mainmemory;
1091
1092   if (trace_flag)
1093     probe_show();     /* 94/Mar/25 */
1094
1095   return zzzaa;
1096 }
1097 #endif
1098
1099 #ifdef ALLOCATEFONT
1100 /* font_mem_size = 10000L ==> font_info array 100k * 8 = 800 kilobytes */
1101
1102 int current_font_mem_size = 0;
1103
1104 /* fmemoryword can be either halfword or memory_word */
1105 fmemoryword * realloc_font_info (int size)
1106 {
1107   fmemoryword *newfontinfo = NULL;
1108   int k, minsize;
1109   int newsize = 0;  /* to quieten compiler */
1110   int n = 0;        /* to quieten compiler */
1111
1112   if (trace_flag)
1113   {
1114     sprintf(log_line, "Old Address %s == %d\n",  "font_info", font_info);
1115     show_line(log_line, 0);
1116   }
1117 /*  during initial allocation, font_info == NULL - realloc acts like malloc */
1118 /*  during initial allocation current_font_mem_size == 0 */
1119   if (current_font_mem_size == font_mem_size)  /* if we REALLY run up to limit */
1120   {
1121 /*    memory_error("font", (font_mem_size + 1) * sizeof(memory_word)); */
1122     return font_info;    /* pass it back to TeX 99/Fabe/4 */
1123   }
1124 /*  try and prevent excessive frequent reallocations */
1125 /*  while avoiding over allocation by too much */
1126 /*  minsize = current_font_mem_size / 2; */
1127   minsize = current_font_mem_size / 100 * percent_grow;
1128
1129   if (size < minsize)
1130     size = minsize;
1131
1132   if (size < initial_font_mem_size)
1133     size = initial_font_mem_size;
1134
1135   for (k=0; k < MAXSPLITS; k++)
1136   {
1137     newsize = current_font_mem_size + size;
1138
1139     if (newsize > font_mem_size)
1140       newsize = font_mem_size; /* bump against limit */
1141
1142 /*    important + 1 since fmemoryword font_info[font_mem_size + 1]  original */
1143     n = (newsize + 1) * sizeof (fmemoryword);
1144
1145     if (trace_flag)
1146       trace_memory("font_info", n);
1147
1148     newfontinfo = (fmemoryword *) REALLOC (font_info, n);
1149
1150     if (newfontinfo != NULL)
1151       break;   /* did we get it ? */
1152
1153     if (current_font_mem_size == 0)
1154       break; /* initial allocation must work */
1155
1156     size = size / 2;
1157   }
1158
1159   if (newfontinfo == NULL)
1160   {
1161     memory_error("font", n);
1162     return font_info;        /* try and continue !!! */
1163   }
1164
1165   font_info = newfontinfo;
1166
1167   if (trace_flag)
1168   {
1169     sprintf(log_line, "New Address %s == %d\n", "font_info", font_info);
1170     show_line(log_line, 0);
1171   }
1172
1173   update_statistics ((int) font_info, n, current_font_mem_size * sizeof(fmemoryword));
1174   current_font_mem_size = newsize;
1175
1176   if (trace_flag)
1177     probe_show();     /* 94/Mar/25 */
1178   return font_info;
1179 }
1180 #endif
1181
1182 #ifdef ALLOCATESTRING
1183 int current_pool_size = 0;
1184
1185 packed_ASCII_code * realloc_str_pool (int size)
1186 {
1187   int k, minsize;
1188   int newsize = 0;
1189   int n = 0;
1190   packed_ASCII_code *newstrpool = NULL;
1191
1192   if (trace_flag)
1193   {
1194     sprintf(log_line, "Old Address %s == %d\n", "string pool", str_pool);
1195     show_line(log_line, 0);
1196   }
1197
1198   if (current_pool_size == pool_size)
1199   {
1200 /*    memory_error ("string pool", (pool_size + 1) * sizeof(packed_ASCII_code)); */
1201 /*    exit (1); */
1202     return str_pool;   /* pass it back to TeX 99/Fabe/4 */
1203   }
1204 /*  minsize =  current_pool_size / 2; */
1205   minsize =  current_pool_size / 100 * percent_grow;
1206   if (size < minsize) size = minsize;
1207   if (size < initial_pool_size) size = initial_pool_size;
1208
1209   for (k = 0; k < MAXSPLITS; k++) {
1210     newsize = current_pool_size + size;
1211     if (newsize > pool_size) newsize = pool_size;
1212 /* important + 1 since  packed_ASCII_code str_pool[pool_size + 1]; in original */
1213     n = (newsize + 1) * sizeof (packed_ASCII_code);
1214     if (trace_flag) trace_memory("str_pool", n);
1215     newstrpool = (packed_ASCII_code *) REALLOC (str_pool, n); /* 95/Sep/24 */
1216     if (newstrpool != NULL) break;    /* did we get it ? */
1217     if (current_pool_size == 0) break;  /* initial allocation must work */
1218     size = size / 2;          /* else can retry smaller */
1219   }
1220
1221   if (newstrpool == NULL)
1222   {
1223     memory_error("string pool", n);
1224     return str_pool;           /* try and continue !!! */
1225   }
1226
1227   str_pool = newstrpool;
1228   update_statistics ((int) str_pool, n, current_pool_size);
1229   current_pool_size = newsize;
1230
1231   if (trace_flag)
1232   {
1233     sprintf(log_line, "New Address %s == %d\n", "string pool", str_pool);
1234     show_line(log_line, 0);
1235   }
1236   
1237   if (trace_flag)
1238     probe_show();     /* 94/Mar/25 */
1239
1240   return str_pool;
1241 }
1242 #endif
1243
1244 #ifdef ALLOCATESTRING
1245 int current_max_strings = 0;
1246
1247 pool_pointer *realloc_str_start (int size)
1248 {
1249   int k, minsize;
1250   int n=0;
1251   int newsize=0;
1252   pool_pointer *newstrstart=NULL;
1253
1254   if (trace_flag)
1255   {
1256     sprintf(log_line, "Old Address %s == %d\n", "string start", str_start);
1257     show_line(log_line, 0);
1258   }
1259
1260   if (current_max_strings == max_strings)
1261   {
1262 /*    memory_error ("string pointer", (max_strings + 1) * sizeof(pool_pointer)); */
1263 /*    exit (1); */
1264     return str_start;    /* pass it back to TeX 99/Fabe/4 */
1265   }
1266 /*  minsize = current_max_strings / 2; */
1267   minsize = current_max_strings / 100 * percent_grow;
1268   if (size < minsize) size = minsize;
1269   if (size < initial_max_strings) size = initial_max_strings;
1270
1271   for (k = 0; k < MAXSPLITS; k++)
1272   {
1273     newsize = current_max_strings + size;
1274     if (newsize > max_strings) newsize = max_strings;
1275 /*    important + 1 since str_start[maxstring + 1] originally */
1276     n = (newsize + 1) * sizeof (pool_pointer);
1277     if (trace_flag) trace_memory("str_start", n);
1278     newstrstart = (pool_pointer *) REALLOC (str_start, n);
1279     if (newstrstart != NULL) break;   /* did we get it ? */
1280     if (current_max_strings == 0) break;  /* initial allocation must work */
1281     size = size / 2;          /* otherwise can try smaller */
1282   }
1283
1284   if (newstrstart == NULL) {
1285     memory_error("string pointer", n);
1286     return str_start;          /* try and continue */
1287   }
1288   str_start = newstrstart;
1289   update_statistics((int) str_start, n, current_max_strings * sizeof (pool_pointer));
1290   current_max_strings = newsize;
1291   if (trace_flag) {
1292     sprintf(log_line, "New Address %s == %d\n", "string start", str_start);
1293     show_line(log_line, 0);
1294   }
1295   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1296   return str_start;
1297 }
1298 #endif
1299
1300 #ifdef ALLOCATEINI
1301
1302 /* returns -1 if it fails */
1303 /* size == trie_size */
1304 int allocate_ini (int size)
1305 {
1306   int n, nl, no, nc, nr, nh, nt;
1307     nh = nr = nl = (size + 1) *  sizeof(trie_pointer);
1308     no = (size + 1) *  sizeof(trie_op_code);
1309     nc = (size + 1) *  sizeof(packed_ASCII_code);
1310 /*    nt = (size + 1) *  sizeof(bool); */
1311     nt = (size + 1) *  sizeof(char);
1312     n = nl + no + nc + nr + nh + nt;
1313 /*    n = (size + 1) * (sizeof(packed_ASCII_code) + sizeof(trie_op_code) +
1314       3 *  sizeof(trie_pointer) + sizeof (char)); */
1315     if (trace_flag) trace_memory ("iniTeX hyphen trie", n);
1316     trie_l = (trie_pointer *) malloc (roundup(nl));
1317     trie_o = (trie_op_code *) malloc (roundup(no));
1318     trie_c = (packed_ASCII_code *) malloc (roundup(nc));
1319     trie_r = (trie_pointer *) malloc (roundup(nr));
1320     trie_hash = (trie_pointer *) malloc (roundup(nh));
1321 /*    trie_taken = (bool *) malloc (nt); */
1322     trie_taken = (char *) malloc (roundup(nt));
1323     if (trie_c == NULL || trie_o == NULL || trie_l == NULL || trie_r == NULL ||
1324       trie_hash == NULL || trie_taken == NULL) {
1325       memory_error("iniTeX hyphen trie", n);
1326 //      exit (1);           /* serious error */     
1327       return -1;
1328     }
1329     if (trace_flag) {
1330       sprintf(log_line, "Addresses trie_l %d trie_o %d trie_c %d\n", 
1331           trie_l, trie_o, trie_c);
1332       show_line(log_line, 0);
1333       sprintf(log_line, "Addresses trie_r %d trie_hash %d trie_taken %d\n", 
1334           trie_r, trie_hash, trie_taken);
1335       show_line(log_line, 0);
1336     }
1337     update_statistics ((int) trie_l, nl, 0);
1338     update_statistics ((int) trie_o, no, 0);
1339     update_statistics ((int) trie_c, nc, 0);
1340     update_statistics ((int) trie_r, nr, 0);
1341     update_statistics ((int) trie_hash, nh, 0);
1342     update_statistics ((int) trie_taken, nt, 0);
1343 /*    trie_size = size; */ /* ??? */
1344     if (trace_flag)  probe_show();     /* 94/Mar/25 */
1345     return 0;               // success
1346 }
1347 #endif
1348
1349 #ifdef ALLOCATESAVESTACK
1350 int current_save_size = 0;
1351
1352 memory_word *realloc_save_stack (int size)
1353 {
1354   int k, minsize;
1355   int n=0, newsize=0;
1356   memory_word *newsave_stack=NULL;
1357
1358   if (trace_flag)
1359   {
1360     sprintf(log_line, "Old Address %s == %d\n", "save stack", save_stack);
1361     show_line(log_line, 0);
1362   }
1363
1364   if (current_save_size == save_size)  /* arbitrary limit */
1365   {
1366 /*    memory_error ("save stack", (save_size + 1) * sizeof(memory_word)); */
1367 /*    exit (1); */
1368     return save_stack;       /* let TeX handle the error */
1369   }
1370
1371   minsize =  current_save_size / 100 * percent_grow;
1372
1373   if (size < minsize)
1374     size = minsize;
1375
1376   if (size < initial_save_size)
1377     size = initial_save_size;
1378
1379   for (k = 0; k < MAXSPLITS; k++)
1380   {
1381     newsize = current_save_size + size;
1382     if (newsize > save_size) newsize = save_size;
1383     n = (newsize + 1) * sizeof (memory_word); /* save_stack[save_size + 1] */
1384     if (trace_flag) trace_memory("save_stack", n);
1385     newsave_stack = (memory_word *) REALLOC (save_stack, n);
1386     if (newsave_stack != NULL) break;    /* did we get it ? */
1387     if (current_save_size == 0) break;  /* initial allocation must work */
1388     size = size / 2;          /* else can retry smaller */
1389   }
1390
1391   if (newsave_stack == NULL)
1392   {
1393     memory_error("save stack", n);
1394     return save_stack;           /* try and continue !!! */
1395   }
1396
1397   save_stack = newsave_stack;
1398   update_statistics ((int) save_stack, n, current_save_size);
1399   current_save_size = newsize;
1400
1401   if (trace_flag)
1402   {
1403     sprintf(log_line, "Current%s %d\n", "save_size", current_save_size);
1404     show_line(log_line, 0);
1405     sprintf(log_line, "New Address %s == %d\n", "save stack", save_stack);
1406     show_line(log_line, 0);
1407   }
1408
1409   if (trace_flag) probe_show();      /* 94/Mar/25 */
1410   return save_stack;
1411 }
1412 #endif
1413
1414 #ifdef ALLOCATEINPUTSTACK
1415 int current_stack_size = 0;       /* input stack size */
1416
1417 in_state_record *realloc_input_stack (int size)
1418 {
1419   int k, minsize;
1420   int n=0, newsize=0;
1421   in_state_record *newinputstack=NULL;
1422
1423   if (trace_flag) {
1424     sprintf(log_line, "Old Address %s == %d\n",  "input stack", input_stack);
1425     show_line(log_line, 0);
1426   }
1427   if (current_stack_size == stack_size) {  /* arbitrary limit */
1428 /*    memory_error ("input stack", (stack_size + 1) * sizeof(in_state_record)); */
1429 /*    exit (1); */
1430     return input_stack;
1431   }
1432   minsize =  current_stack_size / 100 * percent_grow;
1433   if (size < minsize) size = minsize;
1434   if (size < initial_stack_size) size = initial_stack_size;
1435
1436   for (k = 0; k < MAXSPLITS; k++) {
1437     newsize = current_stack_size + size;
1438     if (newsize > stack_size) newsize = stack_size;
1439     n = (newsize + 1) * sizeof (in_state_record); /* input_stack[stack_size + 1] */
1440     if (trace_flag) trace_memory("input_stack", n);
1441     newinputstack = (in_state_record *) REALLOC (input_stack, n);
1442     if (newinputstack != NULL) break;   /* did we get it ? */
1443     if (current_stack_size == 0) break; /* initial allocation must work */
1444     size = size / 2;          /* else can retry smaller */
1445   }
1446
1447   if (newinputstack == NULL) {
1448     memory_error("input stack", n);
1449     return input_stack;            /* try and continue !!! */
1450   }
1451   input_stack = newinputstack;
1452   update_statistics ((int) input_stack, n, current_stack_size);
1453   current_stack_size = newsize;
1454   if (trace_flag) {
1455     sprintf(log_line, "Current%s %d\n", "stack_size", current_stack_size);
1456     show_line(log_line, 0);
1457     sprintf(log_line, "New Address %s == %d\n", "input stack", input_stack);
1458     show_line(log_line, 0);
1459   }
1460   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1461   return input_stack;
1462 }
1463 #endif
1464
1465 #ifdef ALLOCATENESTSTACK
1466 int current_nest_size = 0;        /* current nest size */
1467
1468 list_state_record *realloc_nest_stack (int size)
1469 {
1470   int k, minsize;
1471   int n=0, newsize=0;
1472   list_state_record *newnest=NULL;
1473
1474   if (trace_flag) {
1475     sprintf(log_line, "Old Address %s == %d\n",  "nest stack", nest);
1476     show_line(log_line, 0);
1477   }
1478   if (current_nest_size == nest_size) {  /* arbitrary limit */
1479 /*    memory_error ("nest stack", (nest_size + 1) * sizeof(list_state_record)); */
1480 /*    exit (1); */
1481     return nest;        /* let TeX handle the error */
1482   }
1483   minsize =  current_nest_size / 100 * percent_grow;
1484   if (size < minsize) size = minsize;
1485   if (size < initial_nest_size) size = initial_nest_size;
1486
1487   for (k = 0; k < MAXSPLITS; k++) {
1488     newsize = current_nest_size + size;
1489     if (newsize > nest_size) newsize = nest_size;
1490     n = (newsize + 1) * sizeof (list_state_record); /* nest[nest_size + 1] */
1491     if (trace_flag) trace_memory("nest stack", n);
1492     newnest = (list_state_record *) REALLOC (nest, n);
1493     if (newnest != NULL) break;   /* did we get it ? */
1494     if (current_nest_size == 0) break;  /* initial allocation must work */
1495     size = size / 2;          /* else can retry smaller */
1496   }
1497
1498   if (newnest == NULL) {
1499     memory_error("nest stack", n);
1500     return nest;            /* try and continue !!! */
1501   }
1502   nest = newnest;
1503   update_statistics ((int) nest, n, current_nest_size);
1504   current_nest_size = newsize;
1505   if (trace_flag) {
1506     sprintf(log_line, "Current%s %d\n", "nest_size", current_nest_size);
1507     show_line(log_line, 0);
1508     sprintf(log_line, "New Address %s == %d\n", "nest stack", nest);
1509     show_line(log_line, 0);
1510   }
1511   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1512   return nest;
1513 }
1514 #endif
1515
1516 #ifdef ALLOCATEPARAMSTACK
1517 int current_param_size=0;       /* current param size */
1518
1519 halfword *realloc_param_stack (int size)
1520 {
1521   int k, minsize;
1522   int n=0, newsize=0;
1523   halfword *newparam=NULL;
1524
1525   if (trace_flag) {
1526     sprintf(log_line, "Old Address %s == %d\n",  "param stack", param_stack);
1527     show_line(log_line, 0);
1528   }
1529   if (current_param_size == param_size) {  /* arbitrary limit */
1530 /*    memory_error ("param stack", (param_size + 1) * sizeof(halfword)); */
1531 /*    exit (1); */
1532     return param_stack;        /* let TeX handle the error */
1533   }
1534   minsize =  current_param_size / 100 * percent_grow;
1535   if (size < minsize) size = minsize;
1536   if (size < initial_param_size) size = initial_param_size;
1537
1538   for (k = 0; k < MAXSPLITS; k++) {
1539     newsize = current_param_size + size;
1540     if (newsize > param_size) newsize = param_size;
1541     n = (newsize + 1) * sizeof (halfword); /* param_stack[param_size + 1] */
1542     if (trace_flag) trace_memory("param stack", n);
1543     newparam = (halfword *) REALLOC (param_stack, n); 
1544     if (newparam != NULL) break;    /* did we get it ? */
1545     if (current_param_size == 0) break; /* initial allocation must work */
1546     size = size / 2;          /* else can retry smaller */
1547   }
1548
1549   if (newparam == NULL) {
1550     memory_error("param stack", n);
1551     return param_stack;            /* try and continue !!! */
1552   }
1553   param_stack = newparam;
1554   update_statistics ((int) param_stack, n, current_param_size);
1555   current_param_size = newsize;
1556   if (trace_flag) {
1557     sprintf(log_line, "Current%s %d\n", "param_size", current_param_size);
1558     show_line(log_line, 0);
1559     sprintf(log_line, "New Address %s == %d\n", "param stack", param_stack);
1560     show_line(log_line, 0);
1561   }
1562   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1563   return param_stack;
1564 }
1565 #endif
1566
1567 #ifdef ALLOCATEBUFFER
1568 int current_buf_size = 0;
1569
1570 ASCII_code *realloc_buffer (int size)
1571 {
1572   int k, minsize;
1573   int n=0, newsize=0;
1574   ASCII_code *newbuffer=NULL;
1575
1576   if (trace_flag) {
1577     sprintf(log_line, "Old Address %s == %d\n", "buffer", buffer);
1578     show_line(log_line, 0);
1579   }
1580   if (current_buf_size == buf_size) {  /* arbitrary limit */
1581 /*    memory_error ("buffer", buf_size); */
1582 /*    exit (1); */
1583     return buffer;    /* pass it back to TeX 99/Fabe/4 */
1584   }
1585   minsize =  current_buf_size / 100 * percent_grow;
1586   if (size < minsize) size = minsize;
1587   if (size < initial_buf_size) size = initial_buf_size;
1588
1589   for (k = 0; k < MAXSPLITS; k++) {
1590     newsize = current_buf_size + size;
1591     if (newsize > buf_size) newsize = buf_size;
1592     n = (newsize + 1) * sizeof(ASCII_code);  /* buffer[buf_size + 1] */
1593     if (trace_flag) trace_memory("buffer", n);
1594     newbuffer = (ASCII_code *) REALLOC (buffer, n);
1595     if (newbuffer != NULL) break;   /* did we get it ? */
1596     if (current_buf_size == 0) break;   /* initial allocation must work */
1597     size = size / 2;          /* else can retry smaller */
1598   }
1599
1600   if (newbuffer == NULL) {
1601     memory_error("buffer", n);
1602     return buffer;            /* try and continue !!! */
1603   }
1604   buffer = newbuffer;
1605   update_statistics ((int) buffer, n, current_buf_size);
1606 #ifdef USEMEMSET
1607   memset(buffer + current_buf_size, 0, newsize - current_buf_size);
1608 #else
1609   for (k = current_buf_size; k < newsize; k++) buffer[k]= 0;
1610 #endif
1611   current_buf_size = newsize;
1612   if (trace_flag) {
1613     sprintf(log_line, "Current%s %d\n", "buffer", current_buf_size);
1614     show_line(log_line, 0);
1615     sprintf(log_line, "New Address %s == %d\n", "buffer", buffer);
1616     show_line(log_line, 0);
1617   }
1618   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1619   return buffer;
1620 }
1621 #endif
1622
1623 /* here is the main memory allocation routine -- calls the above */
1624 /* returns -1 if it fails */
1625 /* allocate rather than static 93/Nov/26 */
1626 int allocate_memory (void)
1627 {
1628 /*  int n;  */
1629 #ifdef PREALLOCHOLE
1630   char *holeadr = malloc (300000);  /* testing - preallocate 95/Jan/20 */
1631 #endif
1632
1633 #ifdef ALLOCATEHASH
1634   #error ERROR: Not ready for ALLOCATEHASH...
1635 #endif
1636
1637 /* probably not worth while/not a good idea allocating following */
1638 /* they are all rather small, and typically don't need expansion */
1639 /* WE ASSUME THIS DOESN'T HAPPEN, SO WON'T BOTHER WITH UPDATESTATISTICS */
1640 #ifdef ALLOCATEHASH
1641 /*  n = 9767 * sizeof (twohalves);  *//* 60 kilo bytes */   
1642 /*  n = (hash_size + 267) * sizeof (twohalves); */  /* 60 kilo bytes */
1643 /*  n = (9767 + eqtb_extra) * sizeof (twohalves); */
1644 #ifdef SHORTHASH
1645   n = (hash_size + 267 + eqtb_extra) * sizeof (htwohalves);   /* 95/Feb/19 */
1646   zzzae = (htwohalves *) malloc (roundup(n));
1647 #else
1648   n = (hash_size + 267 + eqtb_extra) * sizeof (twohalves);  /* 95/Feb/19 */
1649   zzzae = (twohalves *) malloc (roundup(n));
1650 #endif
1651   if (trace_flag)  trace_memory("hash table", n);
1652 /*  zzzae = (twohalves *) malloc ((hash_size + 267) * sizeof (twohalves)); */
1653   if (zzzae == NULL)
1654   {
1655     memory_error("hash table", n);
1656 //    exit (1);           /* serious error */
1657     return -1;            /* serious error */
1658   }
1659
1660   n = (inputsize + 1) * sizeof(memory_word);
1661
1662   if (trace_flag)
1663     trace_memory("input_stack", n);
1664
1665 /*  input_stack = (memory_word *) malloc ((inputsize + 1) * sizeof (memory_word)); */
1666   input_stack = (memory_word *) malloc (roundup(n));
1667
1668   if (input_stack == NULL)
1669   {
1670     memory_error("input_stack", n);
1671 //    exit (1);           /* serious error */
1672     return -1;            /* serious error */
1673   }
1674 #endif
1675
1676 /* no real reason to allocate dvi_buf - no need to ever grow it */
1677 #ifdef ALLOCATEDVIBUF
1678 /*  zdvibuf = NULL; */
1679   zdvibuf = allocatedvibuf (dvi_buf_size);
1680   if (zdvibuf == NULL) return -1;
1681 #endif
1682
1683 #ifdef ALLOCATEZEQTB
1684 /*  zeqtb = NULL; */
1685 #ifdef INCREASEFONTS
1686 /*  zeqtb = allocatezeqtb (13507 + eqtb_extra); */  /* 94/Mar/29 */
1687   zeqtb = allocatezeqtb (hash_size + 4007 + eqtb_extra);  /* 94/Mar/29 */
1688 #else
1689 /*  zeqtb = allocatezeqtb (13507); */
1690   zeqtb = allocatezeqtb (hash_size + 4007); 
1691 #endif
1692 #endif
1693
1694 #ifdef ALLOCATEINPUTSTACK
1695   input_stack = NULL;        /* new 1999/Jan/21 */
1696   current_stack_size = 0;
1697   input_stack = realloc_input_stack (initial_stack_size);  /* + 1 */
1698 #endif
1699
1700 #ifdef ALLOCATENESTSTACK
1701   nest = NULL;          /* new 1999/Jan/21 */
1702   current_nest_size = 0;
1703   nest = realloc_nest_stack (initial_nest_size);  /* + 1 */
1704 #endif
1705
1706 #ifdef ALLOCATEPARAMSTACK
1707   param_stack = NULL;          /* new 1999/Jan/21 */
1708   current_param_size = 0;
1709   param_stack = realloc_param_stack (initial_param_size); /* + 1 */
1710 #endif
1711
1712 #ifdef ALLOCATESAVESTACK
1713   save_stack = NULL;       /* new 1999/Jan/7 */
1714   current_save_size = 0;
1715   save_stack = realloc_save_stack (initial_save_size);
1716 #endif
1717
1718 #ifdef IGNORED
1719   buffer = NULL;        /* need to do earlier */
1720   current_buf_size = 0;
1721   buffer = realloc_buffer (initial_buf_size);
1722 #endif
1723
1724 #ifdef ALLOCATESTRING
1725   str_pool = NULL;
1726   current_pool_size = 0;
1727   str_start = NULL;
1728   current_max_strings = 0;
1729 /*  need to create space because iniTeX writes in before reading pool file */
1730 /*  for a start, puts in strings for 256 characters */
1731 /*  maybe taylor allocations to actual pool file 1300 strings 27000 bytes ? */
1732   if (is_initex) {
1733     if (trace_flag) show_line("ini TeX pool and string allocation\n", 0);
1734     str_pool = realloc_str_pool (initial_pool_size); 
1735     str_start = realloc_str_start (initial_max_strings);
1736   }
1737 #endif
1738
1739 /* the following can save a lot of the usual 800k fixed allocation */
1740 #ifdef ALLOCATEFONT
1741   font_info = NULL;
1742   current_font_mem_size = 0;
1743 /*  if not iniTeX, then do initial allocation on fmt file read in itex.c */
1744 /*  if ini-TeX we need to do it here - no format file read later */
1745   if (is_initex) font_info = realloc_font_info (initial_font_mem_size);
1746 #endif
1747     
1748 #ifdef ALLOCATEMAIN
1749   mainmemory = NULL;
1750   zzzaa = NULL;
1751   mem_min = mem_bot;        /* just to avoid complaints in texbody */
1752   mem_top = mem_initex;
1753   mem_max = mem_top;
1754 /*  allocate main memory here if this is iniTeX */
1755 /*  otherwise wait for format undumping in itex.c ... */  
1756   if (is_initex) {
1757 /*    avoid this if format specified on command line ??? */
1758 /*    allocate_main_memory(mem_initex); */   /* made variable ! */
1759     mem = allocate_main_memory(mem_initex);  /* made variable ! */
1760     if (mem == NULL)
1761 //      exit (1);
1762       return -1;            /* serious error */
1763   }
1764 #endif
1765
1766 /* now for the hyphenation exception stuff */
1767 #ifdef ALLOCATEHYPHEN
1768   hyph_word = NULL;
1769   hyph_list = NULL;
1770 /*  this will be overridden later by what is in format file */
1771   hyphen_prime = default_hyphen_prime;
1772 /*  non ini-TeX use assumes format will be read and that specifies size */
1773   if (is_initex)
1774   {
1775     if (new_hyphen_prime)
1776       hyphen_prime = new_hyphen_prime;
1777     if (realloc_hyphen(hyphen_prime)) /* allocate just in case no format */
1778       return -1;
1779   }
1780 #endif
1781
1782 /*  now for memory for the part of the hyphenation stuff that always needed */
1783 /*  if iniTeX, need to allocate pre-determined fixed amount - trie_size */
1784 /*  if iniTeX not selected, allocate only enough later - undump in itex.c ! */
1785 #ifdef ALLOCATETRIES
1786   if (is_initex)
1787   {
1788     if (allocate_tries (trie_size))
1789       return -1;
1790   }
1791 #endif
1792
1793 /*  now for memory for hyphenation stuff needed only when running iniTeX */
1794 #ifdef ALLOCATEINI
1795   if (is_initex)
1796   {
1797     if (allocate_ini(trie_size))
1798       return -1;
1799   }
1800   else
1801   {
1802     trie_l = trie_r = trie_o = trie_hash = NULL; /* (trie_size + 1) * integer */
1803     trie_c = NULL;       /* (trie_size + 1) * char */
1804     trie_taken = NULL;     /* (trie_size + 1) * bool */
1805   }
1806 #endif
1807 #ifdef PREALLOCHOLE
1808   free(holeadr);          /* create the hole */
1809 #endif
1810   return 0;           // success
1811 }
1812
1813 /* returns non-zero if error - done to test integrity of stack mostly */
1814 /* free in reverse order 93/Nov/26 */
1815 int free_memory (void)
1816 {
1817   int n;
1818   unsigned heaptotal = 0;
1819 /*  unsigned total; */
1820
1821   if (trace_flag) show_line("free_memory ", 0);
1822
1823   if (verbose_flag || trace_flag)
1824     show_maximums(stdout); 
1825
1826   if (trace_flag)
1827   {
1828     sprintf(log_line, "Heap total: %u bytes --- max address %u\n", 
1829         heaptotal, max_address);
1830     show_line(log_line, 0);
1831   }
1832
1833   if (trace_flag) {
1834     sprintf(log_line, "Main Memory: variable node %d (%d - %d) one word %d (%d - %d)\n",
1835       lo_mem_max - mem_min, mem_min, lo_mem_max, mem_end  - hi_mem_min, hi_mem_min, mem_end);
1836     show_line(log_line, 0);
1837   }
1838 /*  following only needed to check consistency of heap ... useful debugging */
1839   if (trace_flag) show_line("Freeing memory again\n", 0);
1840
1841 /*  if (trace_flag)
1842     show_line(log_line, "Zero Glue Reference Count %d\n", mem[0].hh.v.RH); */
1843
1844 /*  the following checks the heap integrity */
1845
1846 /*  if ((n = _heapchk ()) != _HEAPOK) { */      /* 94/Feb/18 */
1847   n = _HEAPOK;
1848 #ifdef SHOWHEAPERROR
1849   n = _heapchk();
1850   if (n != _HEAPOK) {     /* 94/Feb/18 */
1851     sprintf(log_line, "WARNING: Heap corrupted (%d)\n", n);
1852     show_line(log_line, 1);
1853     sprintf(log_line, "HEAP %s (%s)\n", heapstrings[-n], "free_memory");
1854     show_line(log_line, 0);
1855     return n;   /* non-zero and negative */ /* unreachable ??? */
1856   }
1857 #endif
1858 /*  only free memory if safe ... additional check */
1859 #ifdef ALLOCATEINI
1860   if (is_initex)
1861   {
1862     if (trie_taken != NULL) free(trie_taken);
1863     if (trie_hash  != NULL) free(trie_hash);
1864     if (trie_r     != NULL) free(trie_r);
1865     if (trie_c     != NULL) free(trie_c);
1866     if (trie_o     != NULL) free(trie_o);
1867     if (trie_l     != NULL) free(trie_l);
1868     trie_taken = NULL;
1869     trie_hash = trie_l = trie_r = NULL;
1870     trie_c = NULL;
1871     trie_o = NULL;
1872   }
1873 #endif  
1874 #ifdef ALLOCATETRIES
1875   if (trie_trc != NULL) free (trie_trc);
1876   if (trie_tro != NULL) free (trie_tro);
1877   if (trie_trl != NULL) free (trie_trl);
1878   trie_trc = NULL;
1879   trie_tro = trie_trl = NULL;
1880 #endif
1881 #ifdef ALLOCATEHYPHEN
1882   if (hyph_list != NULL) free(hyph_list);
1883   if (hyph_word != NULL) free(hyph_word);
1884   hyph_list = NULL;
1885   hyph_word = NULL;
1886 #endif
1887 #ifdef ALLOCATEMAIN
1888 /*  if (zzzaa != NULL) free(zzzaa); */  /* NO: zzzaa may be offset ! */
1889   if (mainmemory != NULL) free(mainmemory);
1890   mainmemory = NULL;
1891 #endif
1892 #ifdef ALLOCATEFONT
1893   if (font_info != NULL) free(font_info);
1894   font_info = NULL;
1895 #endif
1896 #ifdef ALLOCATESTRING
1897   if (str_start != NULL) free(str_start);
1898   if (str_pool != NULL) free(str_pool);
1899   str_start = NULL;
1900   str_pool = NULL;
1901 #endif
1902
1903 #ifdef ALLOCATEHASH
1904   if (zzzae != NULL) free(zzzae);
1905   zzzae = NULL;
1906 #endif
1907
1908 #ifdef ALLOCATEDVIBUF
1909   if (zdvibuf != NULL) free(zdvibuf);
1910   zdvibuf = NULL;
1911 #endif
1912 #ifdef ALLOCATEZEQTB
1913   if (zeqtb != NULL) free(zeqtb);
1914   zeqtb = NULL;
1915 #endif
1916
1917 #ifdef ALLOCATEPARAMSTACK
1918   if (param_stack != NULL) free(param_stack);
1919   param_stack = NULL;
1920 #endif
1921 #ifdef ALLOCATENESTSTACK
1922   if (nest != NULL) free(nest);
1923   nest = NULL;
1924 #endif
1925 #ifdef ALLOCATEINPUTSTACK
1926   if (input_stack != NULL) free(input_stack);
1927   input_stack = NULL;
1928 #endif
1929 #ifdef ALLOCATESAVESTACK
1930   if (save_stack != NULL) free(save_stack);
1931   save_stack = NULL;
1932 #endif
1933 /*  if (buffercopy != NULL) free (buffercopy); */ /* 94/Jun/27 */
1934   if (format_file != NULL) free(format_file);   /* 96/Jan/16 */
1935   if (string_file != NULL) free(string_file);   /* 96/Jan/16 */
1936   if (source_direct != NULL) free(source_direct); /* 98/Sep/29 */
1937   format_file = string_file = source_direct = NULL;
1938   if (dvi_file_name != NULL) free(dvi_file_name);
1939   if (log_file_name != NULL) free(log_file_name);
1940   if (pdf_file_name != NULL) free(pdf_file_name);
1941   pdf_file_name = log_file_name = dvi_file_name = NULL;       /* 00/Jun/18 */
1942   return 0;
1943 }
1944
1945 bool prime (int x)
1946 {
1947   int k;
1948   int sum = 1;    /* 1 + 3 + 5 + k = (k + 1) * (k + 1) / 4 */
1949   if (x % 2 == 0) return false;
1950   for (k = 3; k < x; k = k + 2) {
1951     if (x % k == 0) return false;
1952 /*    if (k * k > x) return true; */
1953     if (sum * 4 > x) return true;
1954     sum += k;
1955   }
1956   return true;
1957 }
1958
1959 int quitflag  = 0;
1960 bool show_use = false;
1961 bool floating = false;
1962
1963 void complainarg (int c, char *s)
1964 {
1965   sprintf(log_line, "ERROR: Do not understand `%c' argument value `%s'\n", c, s);
1966   show_line(log_line, 1);
1967   show_use = 1;           // 2000 June 21
1968 }
1969
1970 /* following is list of allowed command line flags and args */
1971
1972 /* char *allowedargs="+vitrdcyzpsqnwbfXABCDFGKLMNOQRSTYWZ?g=m=u=e=o=a=x=k=h=l=u=E=H="; */
1973
1974 /* only  01234567.9 still left to take ... maybe recycle u */
1975
1976 char *allowedargs = "+bcdfijnpqrstvwyzABCDFGIJKLMNOPQRSTVWXYZ023456789?a=e=g=h=k=l=m=o=u=x=E=H=P=U=";
1977
1978 /* char takeargs="gmueoazhluEH"; */ /* subset that takes args! needed here */
1979
1980 void reorderargs (int ac, char **av)
1981 {      /* put in 1993/Dec/28 */
1982   int n, m;
1983   char *s, *t;
1984 //  char takeargs[128];   /* large enough for all command line arg chars */
1985   char takeargs[256];   /* large enough for all command line arg chars */
1986
1987 /*  assumes arg pointers av[] are writeable */
1988 /*  for (n = 1; n < ac; n++) sprintf(log_line, "%s ", av[n]); */
1989
1990   if (ac < 3) { /* need more than one arg to reorder anything 94/Feb/25 */
1991 /*    show_line("No arguments?\n", 0); */  /* debugging */
1992     return;             /* no args ! */
1993   }
1994
1995   s = allowedargs;
1996   t = takeargs;   /* list of those that take args */
1997   while (*s != '\0' && *(s+1) != '\0') {
1998     if (*(s+1) == '=') *t++ = *s++;   /* copy over --- without the = */
1999     s++;
2000   }
2001   *t = '\0';
2002   if (trace_flag) {
2003     show_line(takeargs, 0);
2004     show_char('\n');
2005   }
2006   
2007   n = 1;
2008   for (;;) {              /* scan to end of command line args */
2009     if (*av[n] != '-') break;
2010 /*    does it take an argument ? and is this argument next ? */
2011     if (n+1 < ac &&
2012       *(av[n]+2) == '\0' &&
2013 /*        strchr("gmuhleoxE", *(av[n]+1)) != NULL) */
2014         strchr(takeargs, *(av[n]+1)) != NULL)
2015           n += 2; /* step over it */
2016     else n++;
2017     if (n == ac) break;
2018   }
2019
2020   for (;;) {              /* look for more command line args */
2021     if (n == ac) break;
2022     m = n;
2023 /*    while (*av[m] != '-' && m < ac) m++; */ /* first command */
2024     while (m < ac && *av[m] != '-') m++;  /* first command */
2025     if (m == ac) break;
2026 /* does it take an argument ? and is this argument next ? */
2027 /* check first whether the `-x' is isolated, or arg follows directly */
2028 /* then check whether this is one of those that takes an argument */
2029     if (m+1 < ac &&
2030       *(av[m]+2) == '\0' &&
2031         strchr(takeargs, *(av[m]+1)) != NULL) {
2032       s = av[m];      /*  move command down before non-command */
2033       t = av[m+1];
2034       for (; m > n; m--)  av[m+1] = av[m-1];
2035       av[n] = s;
2036       av[n+1] = t;
2037       n += 2;       /* step over moved args */
2038     }
2039     else {
2040       s = av[m];      /*  move command down before non-command */
2041       for (; m > n; m--)  av[m] = av[m-1];
2042       av[n] = s;
2043       n++;        /* step over moved args */
2044     }
2045   }
2046 }
2047
2048 int test_align (int address, int size, char *name)
2049 {
2050   int n;
2051   if (size > 4) n = address % 4;
2052   else n = address % size;
2053   if (n != 0) {
2054     sprintf(log_line, "OFFSET %d (ELEMENT %d) in %s\n", n, size, name);
2055     show_line(log_line, 0);
2056   }
2057   return n;
2058 }
2059
2060 /* activate detailed checking of alignment when trace_flag is set */
2061
2062 void check_fixed_align (int flag)
2063 {
2064   if (test_align ((int) &mem_top, 4, "FIXED ALIGNMENT")) {
2065     show_line("PLEASE RECOMPILE ME!\n", 1);
2066   }
2067 #ifdef CHECKALIGNMENT
2068   if (!flag) return;
2069   test_align ((int) &mem_top, 4, "mem_top");
2070   test_align ((int) &mem_max, 4, "mem_max");
2071   test_align ((int) &mem_min, 4, "mem_min");
2072   test_align ((int) &bad, 4, "bad");
2073   test_align ((int) &trie_size, 4, "trie_size");
2074   test_align ((int) &xord, sizeof(xord[0]), "xord"); /* no op */
2075   test_align ((int) &xchr, sizeof(xchr[0]), "xchr"); /* no op */
2076   test_align ((int) &name_length, 4, "name_length");
2077   test_align ((int) &first, 4, "first");
2078   test_align ((int) &last, 4, "last");
2079   test_align ((int) &max_buf_stack, 4, "max_buf_stack");
2080   test_align ((int) &pool_ptr, 4, "pool_ptr");
2081   test_align ((int) &str_ptr, 4, "str_ptr");
2082   test_align ((int) &init_pool_ptr, 4, "init_pool_ptr");
2083   test_align ((int) &init_str_ptr, 4, "init_str_ptr");
2084   test_align ((int) &log_file, 4, "log_file");
2085   test_align ((int) &tally, 4, "tally");
2086   test_align ((int) &term_offset, 4, "term_offset");
2087   test_align ((int) &file_offset, 4, "file_offset");
2088   test_align ((int) &trick_count, 4, "trick_count");
2089   test_align ((int) &first_count, 4, "first_count");
2090   test_align ((int) &deletions_allowed, 4, "deletions_allowed");
2091   test_align ((int) &set_box_allowed, 4, "set_box_allowed");
2092   test_align ((int) &help_line, sizeof(help_line[0]), "help_line");
2093   test_align ((int) &use_err_help, 4, "use_err_help");
2094   test_align ((int) &interrupt, 4, "interrupt");
2095   test_align ((int) &OK_to_interrupt, 4, "OK_to_interrupt");
2096   test_align ((int) &arith_error, 4, "arith_error");
2097   test_align ((int) &tex_remainder, 4, "tex_remainder");
2098   test_align ((int) &temp_ptr, 4, "temp_ptr");
2099   test_align ((int) &lo_mem_max, 4, "lo_mem_max");
2100   test_align ((int) &hi_mem_min, 4, "hi_mem_min");
2101   test_align ((int) &var_used, 4, "var_used");
2102   test_align ((int) &dyn_used, 4, "dyn_used");
2103   test_align ((int) &avail, 4, "avail");
2104   test_align ((int) &mem_end, 4, "mem_end");
2105   test_align ((int) &mem_start, 4, "mem_start");
2106   test_align ((int) &rover, 4, "rover");
2107   test_align ((int) &font_in_short_display, 4, "font_in_short_display");
2108   test_align ((int) &depth_threshold, 4, "depth_threshold");
2109   test_align ((int) &breadth_max, 4, "breadth_max");
2110   test_align ((int) &nest, sizeof(nest[0]), "nest");
2111
2112 #ifdef ALLOCZEQTB
2113   test_align ((int) &zeqtb, sizeof(zeqtb[0]), "zeqtb");  /* not any more ? */
2114 #endif
2115 /*  test_align ((int) &xeq_level, sizeof(xeq_level[0]), "xeq_level"); */
2116   test_align ((int) &zzzad, sizeof(zzzad[0]), "zzzad");
2117 /*  test_align ((int) &hash, sizeof(hash[0]), "hash"); */
2118   test_align ((int) &zzzae, sizeof(zzzae[0]), "zzzae");
2119
2120   test_align ((int) &save_stack, sizeof(save_stack[0]), "save_stack");
2121   test_align ((int) &input_stack, sizeof(input_stack[0]), "input_stack");
2122   test_align ((int) &input_file, sizeof(input_file[0]), "input_file");
2123   test_align ((int) &line_stack, sizeof(line_stack[0]), "line_stack");
2124   test_align ((int) &param_stack, sizeof(param_stack[0]), "param_stack");
2125   test_align ((int) &cur_mark, sizeof(cur_mark[0]), "cur_mark");
2126   test_align ((int) &pstack, sizeof(pstack[0]), "pstack");
2127   test_align ((int) &read_file, sizeof(read_file[0]), "read_file");
2128
2129   test_align ((int) &font_check, sizeof(font_check[0]), "font_check");
2130   test_align ((int) &font_size, sizeof(font_size[0]), "font_size");
2131   test_align ((int) &font_dsize, sizeof(font_dsize[0]), "font_dsize");
2132   test_align ((int) &font_params, sizeof(font_params[0]), "font_params");
2133   test_align ((int) &font_name, sizeof(font_name[0]), "font_name");
2134   test_align ((int) &font_area, sizeof(font_area[0]), "font_area");
2135   test_align ((int) &font_bc, sizeof(font_bc[0]), "font_bc");
2136   test_align ((int) &font_ec, sizeof(font_ec[0]), "font_ec");
2137   test_align ((int) &font_glue, sizeof(font_glue[0]), "font_glue");
2138   test_align ((int) &font_used, sizeof(font_used[0]), "font_used");
2139   test_align ((int) &hyphen_char, sizeof(hyphen_char[0]), "hyphen_char");
2140   test_align ((int) &skew_char, sizeof(skew_char[0]), "skew_char");
2141   test_align ((int) &bchar_label, sizeof(bchar_label[0]), "bchar_label");
2142   test_align ((int) &font_bchar, sizeof(font_bchar[0]), "font_bchar");
2143   test_align ((int) &font_false_bchar, sizeof(font_false_bchar[0]), "font_false_bchar");
2144   test_align ((int) &char_base, sizeof(char_base[0]), "char_base");
2145   test_align ((int) &width_base, sizeof(width_base[0]), "width_base");
2146   test_align ((int) &height_base, sizeof(height_base[0]), "height_base");
2147   test_align ((int) &depth_base, sizeof(depth_base[0]), "depth_base");
2148   test_align ((int) &italic_base, sizeof(italic_base[0]), "italic_base");
2149   test_align ((int) &lig_kern_base, sizeof(lig_kern_base[0]), "lig_kern_base");
2150   test_align ((int) &kern_base, sizeof(kern_base[0]), "kern_base");
2151   test_align ((int) &exten_base, sizeof(exten_base[0]), "exten_base");
2152   test_align ((int) &param_base, sizeof(param_base[0]), "param_base");
2153
2154 #ifdef ALLOCATEDVIBUF
2155   test_align ((int) &zdvibuf, sizeof(zdvibuf[0]), "zdvibuf"); /* no op */
2156 #endif
2157   test_align ((int) &total_stretch, sizeof(total_stretch[0]), "total_stretch");
2158   test_align ((int) &total_shrink, sizeof(total_shrink[0]), "total_shrink");
2159   test_align ((int) &active_width, sizeof(active_width[0]), "active_width");
2160   test_align ((int) &cur_active_width, sizeof(cur_active_width[0]), "cur_active_width");
2161   test_align ((int) &background, sizeof(background[0]), "background");
2162   test_align ((int) &break_width, sizeof(break_width[0]), "break_width");
2163   test_align ((int) &minimal_demerits, sizeof(minimal_demerits[0]), "minimal_demerits");
2164   test_align ((int) &best_place, sizeof(best_place[0]), "best_place");
2165   test_align ((int) &best_pl_line, sizeof(best_pl_line[0]), "best_pl_line");
2166   test_align ((int) &hc, sizeof(hc[0]), "hc");
2167   test_align ((int) &hu, sizeof(hu[0]), "hu");
2168   test_align ((int) &hyf, sizeof(hyf[0]), "hyf");
2169 /*  test_align ((int) &x, sizeof(x[0]), "x"); */
2170
2171   test_align ((int) &hyf_distance, sizeof(hyf_distance[0]), "hyf_distance");
2172   test_align ((int) &hyf_num, sizeof(hyf_num[0]), "hyf_num");
2173   test_align ((int) &hyf_next, sizeof(hyf_next[0]), "hyf_next");
2174   test_align ((int) &op_start, sizeof(op_start[0]), "op_start");
2175
2176 /*  test_align ((int) &trie_op_hash, sizeof(trie_op_hash[0]), "trie_op_hash"); */
2177   test_align ((int) &zzzaf, sizeof(zzzaf[0]), "zzzaf");
2178   test_align ((int) &trie_used, sizeof(trie_used[0]), "trie_used");
2179 /*  test_align ((int) &trie_op_lang, sizeof(trie_op_lang[0]), "trie_op_lang");*/
2180   test_align ((int) &trie_op_val, sizeof(trie_op_val[0]), "trie_op_val");
2181
2182   test_align ((int) &trie_min, sizeof(trie_min[0]), "trie_min");
2183   test_align ((int) &page_so_far, sizeof(page_so_far[0]), "page_so_far");
2184   test_align ((int) &write_file, sizeof(write_file[0]), "write_file");
2185   test_align ((int) &write_open, sizeof(write_open[0]), "write_open");
2186 #endif
2187 }
2188
2189 void check_alloc_align (int flag)
2190 {
2191   if (test_align ((int) eqtb, sizeof(eqtb[0]), "ALLOCATED ALIGNMENT"))
2192     show_line("PLEASE RECOMPILE ME!\n", 1);
2193 #ifdef CHECKALIGNMENT
2194   if (!flag) return;
2195 #ifndef ALLOCZEQTB
2196   test_align ((int) zeqtb, sizeof(zeqtb[0]), "zeqtb"); 
2197 #endif
2198 #ifndef ALLOCATEDVIBUF
2199   test_align ((int) &zdvibuf, sizeof(zdvibuf[0]), "zdvibuf");  /* no op */
2200 #endif
2201   test_align ((int) str_pool, sizeof(str_pool[0]), "str_pool"); /* no op */
2202   test_align ((int) str_start, sizeof(str_start[0]), "str_start");
2203   test_align ((int) zmem, sizeof(zmem[0]), "main memory");
2204   test_align ((int) font_info, sizeof(font_info[0]), "font memory");
2205   test_align ((int) trie_trl, sizeof(trie_trl[0]), "trie_trl");
2206   test_align ((int) trie_tro, sizeof(trie_tro[0]), "trie_tro");
2207   test_align ((int) trie_trc, sizeof(trie_trc[0]), "trie_trc");
2208   test_align ((int) hyph_word, sizeof(hyph_word[0]), "hyph_word");
2209   test_align ((int) hyph_list, sizeof(hyph_list[0]), "hyph_list");
2210 /*  test_align ((int) trie_c, sizeof(trie_c[0]), "trie_c"); *//* no op */
2211   test_align ((int) trie_o, sizeof(trie_o[0]), "trie_o");
2212   test_align ((int) trie_l, sizeof(trie_l[0]), "trie_l");
2213   test_align ((int) trie_r, sizeof(trie_r[0]), "trie_r");
2214   test_align ((int) trie_hash, sizeof(trie_hash[0]), "trie_hash");
2215   test_align ((int) trie_taken, sizeof(trie_taken[0]), "trie_taken");
2216 #endif
2217 }
2218
2219 /* *** *** *** *** *** *** *** NEW APPROACH TO `ENV VARS' *** *** *** *** */
2220
2221 /* grab `env var' from `dviwindo.ini' - or from DOS environment 94/May/19  */
2222 /* controlled by USEDVIWINDOINI environment variable            94/June/19 */
2223
2224 bool usedviwindo        = true;               /* use [Environment] section in `dviwindo.ini' */
2225 bool backwardflag       = false;              /* don't cripple all advanced features */
2226 bool shorten_file_name  = false;              /* don't shorten file names to 8+3 for DOS */
2227 char *inifilename       = "dviwindo.ini";     /* name of ini file we look for */
2228 char *dviwindo          = "";                 /* full file name for dviwindo.ini with path */
2229 char *envsection        = "[Environment]";    /* Env var section in `dviwindo.ini' */
2230 char *wndsection        = "[Window]";         /* Window section in `dviwindo.ini' */
2231 char *workdirect        = "WorkingDirectory"; /* key in [Window] section */
2232 bool usesourcedirectory = true;               /* use source file directory as local when WorkingDirectory is set */
2233 bool workingdirectory   = false;              /* if working directory set in ini */
2234
2235 /* cache to prevent allocating twice in a row */
2236
2237 char *lastname=NULL, *lastvalue=NULL;
2238
2239 /* get value of env var - try first in dviwindo.ini then DOS env */
2240 /* returns allocated string -- these strings are not freed again */
2241 /* is it safe to do that now ? 98/Jan/31 */
2242 char *grabenv (char *varname)
2243 {
2244   char line[PATH_MAX];
2245   FILE *pinput;
2246   char *s;
2247   int m, n;
2248
2249   if (varname == NULL) return NULL;    /* sanity check */
2250   if (*varname == '\0') return NULL;   /* sanity check */
2251 /*  speedup to avoid double lookup when called from set_paths in ourpaths.c */
2252 /*  if (lastname != NULL && strcmp(lastname, varname) == 0) { */
2253   if (lastname != NULL && _strcmpi(lastname, varname) == 0)
2254   {
2255     if (trace_flag)
2256     {
2257       sprintf(log_line, "Cache hit: %s=%s\n", lastname, lastvalue);
2258       show_line(log_line, 0);
2259     }
2260 /*    return lastvalue; */        /* save some time here */
2261     return xstrdup(lastvalue);
2262 /*    duplicate so can free safely 98/Jan/31 */
2263   }
2264
2265 /*  hmm, following was not xstrdup(...) */ /* not cached */
2266   if (usedviwindo == 0 || *dviwindo == '\0') {
2267 /*    return getenv(varname); */
2268     s = getenv(varname);
2269     if (s == NULL) return NULL;
2270     else return xstrdup(s);       /* make safe 98/Jan/31 */
2271   }
2272
2273   if (share_flag == 0) pinput = fopen(dviwindo, "r");
2274   else pinput = _fsopen(dviwindo, "r", share_flag);
2275
2276   if (pinput != NULL) {
2277     m = strlen(envsection);
2278 /*    search for [Environment] section */ /* should be case insensitive */
2279     while (fgets (line, sizeof(line), pinput) != NULL) {
2280       if (*line == ';') continue;
2281       if (*line == '\n') continue;
2282       if (_strnicmp(line, envsection, m) == 0) {  /* 98/Jan/31 */
2283 /*        search for varname=... */ /* should be case sensitive ? */
2284         n = strlen(varname);
2285         while (fgets (line, sizeof(line), pinput) != NULL) {
2286           if (*line == ';') continue;
2287           if (*line == '[') break;
2288 /*          if (*line == '\n') break; */  /* ??? */
2289           if (*line <= ' ') continue;   /* 95/June/23 */
2290 /*          if (strncmp(line, varname, n) == 0 && */
2291           if (_strnicmp(line, varname, n) == 0 &&
2292             *(line+n) == '=') { /* found it ? */
2293               (void) fclose (pinput);
2294 /*              flush trailing white space */
2295               s = line + strlen(line) - 1;
2296               while (*s <= ' ' && s > line) *s-- = '\0';
2297               if (trace_flag) { /* DEBUGGING ONLY */
2298                 sprintf(log_line, "%s=%s\n", varname, line+n+1);
2299                 show_line(log_line, 0);
2300               }
2301               s = line+n+1;
2302               if (lastname != NULL) free(lastname);
2303               lastname = xstrdup (varname);
2304               if (lastvalue != NULL) free(lastvalue);
2305               lastvalue = xstrdup(s);
2306               return xstrdup(s);    /* 98/Jan/31 */
2307           }   /* end of matching varname */
2308         }     /* end of while fgets */
2309 /*        break; */ /* ? not found in designated section */    
2310       }       /* end of search for [Environment] section */
2311     }
2312     (void) fclose (pinput);
2313   }           /* end of if fopen */
2314   s = getenv(varname);    /* failed, so try and get from environment */
2315 /*  if (s != NULL) return s;  */
2316   if (s != NULL) {
2317 /*    sdup = xstrdup(s); */   /* just to be safe --- 1995/Jan/31 */
2318     if (lastname != NULL) free(lastname);
2319     lastname = xstrdup (varname);
2320     if (lastvalue != NULL) free(lastvalue);
2321     lastvalue = xstrdup(s);   /* remember in case asked again ... */
2322 /*    return sdup; */
2323     return xstrdup(s);    /* 98/Jan/31 */
2324   }
2325   else return NULL;   /* return NULL if not found anywhere */
2326 }
2327
2328 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2329
2330 void flush_trailing_slash (char *directory)
2331 {
2332   char *s;
2333 /*  flush trailing \ or / in directory, if any 1993/Dec/12 */
2334   if (strcmp(directory, "") != 0) {
2335     s = directory + strlen(directory) - 1;
2336     if (*s == '\\' || *s == '/') *s = '\0';
2337   }
2338 }
2339
2340 void knuthify (void)
2341 {
2342 /*  show_current = false; */ /* show ultimate limits */
2343 /*  reorder_arg_flag = false; */ /* don't reorder command line */
2344 /*  deslash = false; */ /* don't unixify file names */
2345 /*  return_flag = false; */ /* don't allow just ^^M termination */
2346 /*  trimeof = false; */ /* don't trim ^^Z Ctrl-Z at end of file */
2347   restrict_to_ascii = false; /* don't complain non ASCII */
2348   allow_patterns    = false; /* don't allow pattern redefinition */
2349   show_in_hex       = true;  /* show character code in hex */
2350   show_in_dos       = false; /* redundant with previous */
2351   show_numeric      = false; /* don't show character code decimal */
2352   show_missing      = false; /* don't show missing characters */
2353   civilize_flag     = false; /* don't reorder date fields */
2354   c_style_flag      = false; /* don't add file name to error msg */
2355   show_fmt_flag     = false; /* don't show format file in log */
2356   show_tfm_flag     = false; /* don't show metric file in log */
2357 /* font_max = 255; */ /* revert to TeX 82 limit */
2358 /* if you want this, change in tex.h definition of font_max to `int' */
2359 /* and add define FONTMAX 511, and in local.c add font_max = FONTMAX; */
2360   tab_step = 0;
2361   show_line_break_stats = false;   /* do not show line break stats */
2362   show_fonts_used = false;
2363   default_rule = 26214;      /* revert to default rule thickness */
2364   pseudo_tilde = false;
2365   pseudo_space = false;
2366   show_texinput_flag = false;
2367   truncate_long_lines = false;
2368   allow_quoted_names = false;
2369   show_cs_names = false;
2370   font_dimen_zero = false;      /* 98/Oct/5 */
2371   ignore_frozen = false;     /* 98/Oct/5 */
2372   suppress_f_ligs = false;      /* 99/Jan/5 */
2373   full_file_name_flag = false;   // 00 Jun 18
2374   save_strings_flag = false;    // 00 Aug 15
2375   knuth_flag = true;       /* so other code can know about this */
2376 } /* end of knuthify */
2377
2378 /* following have already been used up */
2379
2380 /* abcdefghijklmnopqrstuvwxyz */
2381
2382 /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
2383
2384 /* ........ */
2385
2386 int nohandler = 0;    /* experiment to avoid Ctrl-C interrupt handler */
2387
2388 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2389
2390 /* following made global so analyze_flag can be made separate procedure */
2391
2392 // char *xchrfile=""; /* save space use xstrdup */
2393 char *xchrfile = NULL; /* save space use xstrdup */
2394 // char *replfile="";/* save space use xstrdup */
2395 char *replfile = NULL;/* save space use xstrdup */
2396
2397 /* abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ */
2398
2399 /* analyze command line flag or argument */
2400 /* c is the flag letter itself, while optarg is start of arg if any */
2401
2402 /* when making changes, revise allowedargs */
2403
2404
2405 int analyze_flag (int c, char *optarg)
2406 {
2407   switch (c)
2408   {
2409     case 'v':
2410       want_version = true;
2411       verbose_flag = true;
2412       break;
2413     case 'i':
2414       is_initex = true;
2415       break;
2416     case 'Q':
2417       interaction = batch_mode; /* quiet mode */
2418       break;
2419     case 'R':
2420       interaction = nonstop_mode; /* run mode */
2421       break;
2422     case 'S':
2423       interaction = scroll_mode; /* scroll mode */
2424       break;
2425     case 'T':
2426       interaction = error_stop_mode; /* tex mode */
2427       break;
2428     case 'K':
2429       backwardflag = true; /* 94/Jun/15 */
2430       knuthify();         /* revert to `standard' Knuth TeX */
2431       break;
2432     case 'L':
2433       c_style_flag = true; /* C style error msg 94/Mar/21 */
2434       break;
2435     case 'Z':
2436       show_tfm_flag = true; /* show TFM in log file 94/Jun/21 */
2437       break;
2438     case 'c':
2439       current_tfm = false; /* not look current dir for TFM */
2440       break;
2441     case 'C':
2442       current_flag = false; /* not look current dir for files */
2443       break;
2444     case 'M':
2445       show_missing = false; /* do not show missing 94/June/10 */
2446       break;
2447     case 'd':
2448       deslash = false; /* flipped 93/Nov/18 */
2449       /* pseudo_tilde = 0; */ /* new 95/Sep/26 */
2450       break;
2451     case 'p':
2452       allow_patterns = true; /* 93/Nov/26 */
2453       /* reset_exceptions = true; */ /* 93/Dec/23 */
2454       break;
2455 /*  case 'w':  show_in_hex = false; */ /* 94/Jan/26 */
2456     case 'w':
2457       show_in_hex = true; /* flipped 00/Jun/18 */
2458       break;
2459     case 'j':
2460       show_in_dos = true; /* 96/Jan/26 */
2461       break;
2462     case 'n':
2463       restrict_to_ascii = true; /* 0 - 127 1994/Jan/21 */
2464       break;
2465     case '6':
2466       workingdirectory = true; /* use source dir 98/Sep/29 */
2467       break;
2468     case '7':
2469       usesourcedirectory = false; /* use working dir 98/Sep/29 */
2470       break;
2471     case 'f':
2472       show_fonts_used = false; /* 97/Dec/24 */
2473       break;
2474     case '8':
2475       shorten_file_name = true; /* 95/Feb/20 */
2476       break;
2477     case '9':
2478       show_cs_names = true; /* 98/Mar/31 */
2479       break;
2480     case '4':
2481       ignore_frozen = true; /* 98/Oct/5 */
2482       break;
2483     case '5':
2484       font_dimen_zero = false; /* 98/Oct/5 */
2485       break;
2486     case 'F':
2487       show_texinput_flag = false; /* 98/Jan/28 */
2488       break;
2489 /*  case 'X':  truncate_long_lines = false; */ /* 98/Feb/2 */
2490               /* break; */
2491     case 'W':
2492       usedviwindo = false; /* 94/May/19 */
2493       break;
2494     case 'J':
2495       show_line_break_stats = false; /* 96/Feb/8 */
2496       break;
2497     case 'O':
2498       show_fmt_flag = false; /* 94/Jun/21 */
2499       break;
2500     case 'I':
2501       format_specific = false; /* 95/Jan/7 */
2502       break;
2503     case '3':
2504       encoding_specific = false; /* 98/Oct/5 */
2505       break;
2506     case '2':
2507       suppress_f_ligs = true; /* 99/Jan/5 f-lig */
2508       break;
2509 /* following are pretty obscure */
2510 /*  case 'y': cache_file_flag = false; */ /* 96/Nov/16 */
2511 /*            break; */
2512 /*  case 'r': return_flag = false; */ /* flipped 93/Nov/18 */
2513 /*            break; */
2514 /*  case 'z': trimeof = false; */ /* 93/Nov/24 */
2515 /*            break; */
2516     case 'z':
2517       full_file_name_flag = false; // 00 Jun 18
2518       break;
2519     case 'X':
2520       save_strings_flag = false; // 00 Aug 15
2521       break;
2522 /* following are unannounced options */ /* some may be recycled ... */
2523     case 't':
2524       trace_flag = true;
2525       break;
2526     case 'q':
2527       quitflag++; /* 93/Dec/16 */
2528       break;
2529 /* The following are really obscure and should not be advertized */
2530     case 's':
2531       show_current = false; /* tex8 93/Dec/14 */
2532       break;
2533     case 'N':
2534       show_numeric = false; /* 93/Dec/21 */
2535       break;
2536     case 'A':
2537       civilize_flag = false; /* 93/Dec/16 */
2538       break; 
2539     case 'B':
2540       open_trace_flag = true; /* openinou 1994/Jan/8 */
2541       break;
2542     case 'Y':
2543       reorder_arg_flag = false; /* local */
2544       break;
2545     case 'b':
2546       test_dir_access = false; /* 94/Feb/10 */
2547       break;
2548     case 'D':
2549       dir_method = false; /* 94/Feb/10 */
2550       break;
2551     case 'G':
2552       file_method = false; /* 94/Feb/13 */
2553       break;
2554 //  case 'V': share_flag = _SH_DENYNO; break; /* 0x40 - deny none mode */ 
2555 /*  case 'X': nohandler++; break; */
2556 /*  case 'f': waitflush = false; break; */
2557 /*  case 'F': floating = true; break; */
2558 /* *********** following command line options take arguments **************  */
2559     case 'm':
2560       if (optarg == 0)
2561         mem_initex = mem_top;
2562       else
2563         mem_initex = atoi(optarg) * 1024; /* 93 Dec/1 */
2564       if (mem_initex == 0)
2565         complainarg(c, optarg);
2566       mem_spec_flag = 1;
2567       break;
2568 #ifdef VARIABLETRIESIZE
2569     case 'h':
2570       if (optarg == 0)
2571         trie_size = default_trie_size;
2572       else
2573         trie_size = atoi(optarg); /* 93 Dec/1 */
2574       if (trie_size == 0)
2575         complainarg(c, optarg);
2576       break;
2577 #endif
2578 #ifdef ALLOCATEHYPHEN
2579     case 'e':
2580       if (optarg == 0)
2581         new_hyphen_prime = hyphen_prime * 2;
2582       else
2583         new_hyphen_prime = atoi(optarg); /* 93/Nov/26 */
2584       if (new_hyphen_prime == 0)
2585         complainarg(c, optarg);
2586       break;
2587 #endif
2588 #ifdef ALLOCATEDVIBUF
2589     case 'u':
2590       if (optarg == 0)
2591         dvi_buf_size = default_dvi_buf_size;
2592       else
2593         dvi_buf_size = atoi(optarg); /* 94/Mar/24 */
2594       if (dvi_buf_size == 0)
2595         complainarg(c, optarg);
2596       break;
2597 #endif
2598     case 'g':
2599       if (optarg == 0)
2600         percent_grow = 62;
2601       else
2602         percent_grow = atoi(optarg); /* 93/Dec/11 */
2603       if (percent_grow == 0)
2604         complainarg(c, optarg);
2605       break;
2606     case 'U':
2607       if (optarg == 0)
2608         pseudo_tilde = 0;
2609       else
2610         pseudo_tilde = atoi(optarg); /* 95/Sep/26 */
2611       if (pseudo_tilde > 255)
2612         pseudo_tilde = 255;
2613       else if (pseudo_tilde < 128)
2614         pseudo_tilde = 128;
2615       break;
2616 /*  case 'H':  if (optarg == 0) heapthreshold = 1024; else heapthreshold = atoi(optarg);
2617  *             if (heapthreshold == 0) complainarg(c, optarg); else heap_flag = 1;
2618  *             break; */
2619     case 'H':
2620       if (optarg == 0)
2621         tab_step = 8;
2622       else
2623         tab_step = atoi(optarg); /* 94/July/3 */
2624       if (tab_step == 0)
2625         complainarg(c, optarg);
2626       break;
2627     case 'x':
2628       if (optarg == 0)
2629         xchrfile = xstrdup("xchr.map");
2630       else
2631         xchrfile = xstrdup(optarg);
2632       if (xchrfile == NULL || *xchrfile == '\0')
2633         complainarg(c, optarg);
2634       break;
2635     case 'k':
2636       if (optarg == 0)
2637         replfile = xstrdup("repl.key");
2638       else
2639         replfile = xstrdup(optarg);
2640       if (replfile == NULL || *replfile == '\0')
2641         complainarg(c, optarg);
2642       break;
2643 /* more obscure stuff - ppssibly recycle */
2644     case 'P':
2645       if (optarg == 0)
2646         default_rule = 26214; /* 95/Oct/9 */
2647       else
2648         default_rule = atoi(optarg); /* 95/Oct/9 */
2649       if (default_rule == 0)
2650         complainarg(c, optarg);
2651       break;
2652     case 'E':
2653       if (optarg != 0)
2654         putenv(optarg);
2655       else
2656         complainarg(c, optarg);
2657       break;
2658     case 'o':
2659       if (optarg == 0)
2660         dvi_directory = "";
2661       else
2662         dvi_directory = xstrdup(optarg);
2663       if (strcmp(dvi_directory, "") == 0)
2664         complainarg(c, optarg);
2665       break;
2666     case '0':
2667       if (optarg == 0)
2668         pdf_output_flag = true;
2669       break;
2670     case 'l':
2671       if (optarg == 0)
2672         log_directory = "";
2673       else
2674         log_directory = xstrdup(optarg);
2675       if (strcmp(log_directory, "") == 0)
2676         complainarg(c, optarg);
2677       break;
2678     case 'a':
2679       if (optarg == 0)
2680         aux_directory = "";
2681       else
2682         aux_directory = xstrdup(optarg);
2683       if (strcmp(aux_directory, "") == 0)
2684         complainarg(c, optarg);
2685       break;
2686     case '?':
2687     default:
2688       show_use = true;
2689       return -1; // failed to recognize
2690       break;
2691   }
2692   return 0;
2693 }
2694
2695 /* Try and read default command file - YANDYTEX.CMD */
2696 /* in current directory and then in directory of YANDYTEX */
2697 /* (does not make sense in TeX file directory) */
2698 /* since we don't yet know where that is ! */
2699 /* can't conveniently include this in output file either - not open yet */
2700
2701 /* used both for yytex.cmd and @ indirect command line files */
2702 /* can this be reentered ? */
2703
2704 /* supply extension if none */
2705 void yy_extension (char *fname, char *ext)
2706 {
2707   char *s, *t;
2708   if ((s = strrchr(fname, '.')) == NULL ||
2709     ((t = strrchr(fname, '\\')) != NULL && s < t)) {
2710       strcat(fname, ".");
2711       strcat(fname, ext);
2712   }
2713 }
2714
2715 /* remove file name - keep only path - inserts '\0' to terminate */
2716
2717 void strip_name (char *pathname)
2718 {
2719   char *s;
2720   if ((s = strrchr(pathname, '\\')) != NULL);
2721   else if ((s = strrchr(pathname, '/')) != NULL);
2722   else if ((s = strrchr(pathname, ':')) != NULL) s++;
2723   else s = pathname;
2724   *s = '\0';
2725 }
2726
2727 /* char commandfile[PATH_MAX]; */ /* keep around so can open later */
2728
2729 char *programpath = ""; /* pathname of program */
2730                     /* redundant with texpath ? */
2731
2732 /* The following does not deslashify arguments ? Do we need to ? */
2733
2734 int read_commands (char *filename)
2735 {
2736   char commandfile[PATH_MAX]; 
2737   FILE *command;
2738   char line[PATH_MAX];
2739   char *linedup;      /* need to copy line to preserve args */
2740   char *s;
2741 /*  char *sn; */
2742   char *optarg;
2743   int c;
2744
2745 /*  Try first in current directory (or use full name as specified) */
2746   strcpy(commandfile, filename);
2747   yy_extension(commandfile, "cmd");
2748   if (share_flag == 0)
2749           command = fopen(commandfile, "r");
2750   else
2751           command = _fsopen(commandfile, "r", share_flag);
2752   if (command == NULL) {
2753 /*    If that fails, try in YANDYTeX program directory */
2754     strcpy(commandfile, programpath);
2755 /*    don't need fancy footwork, since programpath non-empty */
2756     strcat(commandfile, "\\");
2757     strcat(commandfile, filename);
2758     yy_extension(commandfile, "cmd");
2759     if (share_flag == 0)
2760                 command = fopen(commandfile, "r");
2761     else
2762                 command = _fsopen(commandfile, "r", share_flag);
2763     if (command == NULL) {
2764 /*      perrormod(commandfile); */      /* debugging only */
2765 /*      strcpy(commandfile, ""); */   /* indicate failed */
2766       return 0;       /* no command line file YYTEX.CMD */
2767     }
2768   }
2769
2770 /*  allow for multiple lines --- ignore args that don't start with `-' */
2771   while (fgets(line, PATH_MAX, command) != NULL) {
2772 /*    sprintf(log_line, "From %s:\t%s", commandfile, line); */
2773 /*    skip over comment lines and blank lines */
2774     if (*line == '%' || *line == ';' || *line == '\n') continue;
2775     if (strchr(line, '\n') == NULL) strcat(line, "\n");
2776 /*    sfplogline, rintf("From %s:\t%s", commandfile, line); */
2777     linedup = xstrdup (line);         /* 93/Nov/15 */
2778     if (linedup == NULL) {
2779       show_line("ERROR: out of memory\n", 1);    /* read_commands */
2780 //      exit(1);
2781       return -1;    // failure
2782     }
2783     s = strtok(linedup, " \t\n\r");       /* 93/Nov/15 */
2784     while (s != NULL) {
2785       if (*s == '-' || *s == '/') {
2786         c = *(s+1);
2787         optarg = s+2;
2788 /*        if (*optarg = '=') optarg++; */
2789         if (*optarg == '=') optarg++;
2790         if (analyze_flag(c, optarg) < 0) return -1;  // failure ???
2791       }
2792 /*      else break; */              /* ignore non-flag items */
2793       s = strtok(NULL, " \t\n\r");      /* go to next token */
2794     }
2795 /*    If you want to see command lines in file - put -v in the file */
2796 /*    if (verbose_flag != 0) sprintf(log_line, "From %s:\t%s", commandfile, line); */
2797   }
2798   (void) fclose(command);   /* no longer needed */
2799   return 1;       // success
2800 }
2801
2802 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2803
2804 /* try and read commands on command line */
2805 int read_command_line (int ac, char **av)
2806
2807   int c;
2808   char *optargnew;  /* equal to optarg, unless that starts with `='      */
2809                     /* in which case it is optarg+1 to step over the `=' */
2810                     /* if optarg = 0, then optargnew = 0 also            */
2811
2812 //  show_line("read_command_line\n", 0);
2813   if (ac < 2) return 0;     /* no args to analyze ? 94/Apr/10 */
2814
2815 /*  while ((c = getopt(ac, av, "+vitrdczp?m:h:x:E:")) != EOF) {              */
2816 /*  NOTE: keep `Y' in there for `do not reorder arguments !                  */
2817 /*  WARNING: if adding flags, change also `allowedargs' and  `takeargs' !!!! */
2818   while ((c = getopt(ac, av, allowedargs)) != EOF) {
2819     if (optarg != 0 && *optarg == '=')
2820       optargnew = optarg+1;
2821     else
2822       optargnew = optarg;
2823     analyze_flag (c, optargnew);
2824   }
2825   if (show_use || quitflag == 3) {
2826 //    showversion (stdout);
2827     stamp_it(log_line);
2828     strcat(log_line, "\n");
2829     show_line(log_line, 0);
2830     stampcopy(log_line);
2831     strcat(log_line, "\n");
2832     show_line(log_line, 0);
2833     if (show_use) show_usage();
2834     else if (quitflag == 3) {
2835       strcat(log_line, "\n");
2836       show_line(log_line, 0);
2837     }
2838 //    exit (0);
2839     return -1;        // failure
2840   } 
2841 #ifdef DEBUG
2842   if (floating) testfloating();   /* debugging */
2843 #endif
2844
2845   if (replfile != NULL && *replfile != '\0') {  /* read user defined replacement */
2846     if (read_xchr_file(replfile, 1, av)) {
2847       if (trace_flag) show_line("KEY REPLACE ON\n", 0);
2848       key_replace = true;
2849     }
2850   } 
2851 /*  key_replace used in texmf.c (input_line) */
2852   if (xchrfile != NULL && *xchrfile != '\0') {  /* read user defined xchr[] */
2853     if (read_xchr_file(xchrfile, 0, av)) {
2854       if (trace_flag) show_line("NON ASCII ON\n", 0);
2855       non_ascii = true;
2856     }
2857   } 
2858 /*  non_ascii used in texmf.c (t_open_in & input_line & call_edit) */
2859 /*  see also xchr [] & xord [] use in tex3.c and itex.c */
2860   return 0;
2861 }
2862
2863 int init_commands (int ac, char **av)
2864 {
2865 /*  NOTE: some defaults changed 1993/Nov/18 */
2866 /*  want_version = show_use = switchflag = return_flag = false;
2867   is_initex = trace_flag = deslash = non_ascii = false; */
2868   pdf_output_flag   = false;
2869   is_initex         = false; /* check for dumping format file */
2870   allow_patterns    = false; /* using \pattern after format file loaded */
2871   reset_exceptions  = false;
2872   non_ascii         = false;
2873   key_replace       = false;
2874   want_version      = false;
2875   open_trace_flag   = false;
2876   trace_flag        = false;
2877   verbose_flag      = false;
2878   heap_flag         = false;
2879   restrict_to_ascii = false;
2880   show_in_hex       = false; /* default is not to show as hex code ^^ 00/Jun/18 */
2881   show_in_dos       = false; /* default is not to translate to DOS 850 */ 
2882   return_flag       = true;  // hard wired now
2883   trimeof           = true;  // hard wired now
2884   deslash           = true;
2885   pseudo_tilde      = 254;   /* default '~' replace 95/Sep/26 filledbox DOS 850 */
2886   pseudo_space      = 255;   /* default ' ' replace 97/June/5 nbspace DOS 850 */
2887   default_rule      = 26214; /* default rule variable 95/Oct/9 */
2888   show_current      = true;
2889   civilize_flag     = true;
2890   show_numeric      = true;
2891   show_missing      = true;
2892   current_flag      = true;
2893   current_tfm       = true;  /* search for TFMs in current dir as well */
2894   test_dir_access   = true;  /* test if readable item is perhaps a sub-dir */
2895   dir_method        = true;  /* in dir_p: _findfirst instead of use fopen (nul) */
2896   file_method       = true;  /* use file_p (_findfirst) not readable (access) */
2897 /*  waitflush = true; */  /* flushed 97/Dec/24 */
2898   c_style_flag      = false; /* use c-style error output */
2899   show_fmt_flag     = true;  /* show format file in log */
2900   show_tfm_flag     = false; /* don't show metric file in log */
2901   shorten_file_name     = false; /* don't shorten file names to 8+3 */
2902   show_texinput_flag    = true;  /* show TEXINPUTS and TEXFONTS */
2903   truncate_long_lines   = true; /* truncate long lines */
2904   tab_step              = 0;      /* do not replace tabs with spaces */
2905   format_specific       = true;  /* do format specific TEXINPUTS 95/Jan/7 */
2906   encoding_specific     = true;  /* do encoding specific TEXFONTS 98/Jan/31 */
2907   show_line_break_stats = true;  /* show line break statistics 96/Feb/8 */
2908   show_fonts_used       = true; /* show fonts used in LOG file 97/Dec/24 */
2909   allow_quoted_names    = true;  /* allow quoted names with spaces 98/Mar/15 */
2910   show_cs_names         = false;  /* don't show csnames on start 98/Mar/31 */
2911   knuth_flag            = false;    /* allow extensions to TeX */
2912   cache_file_flag       = true; /* default is to cache full file names 96/Nov/16 */
2913   full_file_name_flag   = true;  /* new default 2000 June 18 */
2914   save_strings_flag     = true; // 2000 Aug 15
2915   errout                = stdout;    /* as opposed to stderr say --- used ??? */
2916   abort_flag            = 0;      // not yet hooked up ???
2917   err_level             = 0;     // not yet hooked up ???
2918   new_hyphen_prime      = 0;
2919 #ifdef VARIABLETRIESIZE
2920 /*  trie_size = default_trie_size; */
2921   trie_size = 0;
2922 #endif
2923   mem_extra_high = 0;
2924   mem_extra_low  = 0;
2925   mem_initex     = 0;
2926 #ifdef ALLOCATEDVIBUF
2927   dvi_buf_size = 0;
2928 #endif
2929 /*  share_flag = _SH_DENYNO; */ /* 0x40 - deny none mode */
2930 /*  share_flag = _SH_COMPAT; */ /* 0x00 - compatability mode */
2931   share_flag = 0; /* revert to fopen for now */
2932
2933 /*  strncpy(programpath, argv[0], PATH_MAX); */ /* 94/July/12 */
2934   programpath = xstrdup(av[0]); /* extract path executable */
2935   strip_name(programpath); /* strip off yandytex.exe */
2936
2937   format_name = "plain"; /* format name if specified on command line */
2938
2939   encoding_name = "";
2940
2941   if (read_command_line(ac, av) < 0)  /* move out to subr 94/Apr/10 */
2942     return -1;            // in case of error
2943
2944   if (optind == 0)
2945     optind = ac;
2946
2947   if (want_version)
2948   {
2949     stamp_it(log_line);
2950     strcat(log_line, "\n");
2951     show_line(log_line, 0);
2952     stampcopy(log_line);
2953     strcat(log_line, "\n");
2954     show_line(log_line, 0);
2955   }
2956
2957 /*  if we aren't including current directory in any directory lists */
2958 /*  then makes no sense to avoid them separately for TFM files ... */
2959 /*  (that is, the ./ is already omitted from the dir list in that case */
2960   if (!current_flag && !current_tfm)
2961     current_tfm = true; /* 94/Jan/24 */
2962
2963   return 0;
2964 }
2965
2966 /* E sets environment variable ? */
2967
2968 void initial_memory (void)
2969 {
2970   /* set initial memory allocations */
2971   if (mem_extra_high < 0)
2972     mem_extra_high = 0;
2973
2974   if (mem_extra_low < 0)
2975     mem_extra_low = 0;
2976
2977   if (mem_initex < 0)
2978     mem_initex = 0;
2979
2980   if (is_initex)
2981   {
2982  #if defined(ALLOCATEHIGH) || defined(ALLOCATELOW)
2983     if (mem_extra_high != 0 || mem_extra_low != 0)
2984     {
2985       show_line("ERROR: Cannot extend main memory in iniTeX\n", 1);
2986       mem_extra_high = 0;   mem_extra_low = 0;
2987     }
2988 #endif
2989   }
2990   else
2991   {
2992     if (mem_initex != 0)
2993     {
2994       show_line("ERROR: Can only set initial main memory size in iniTeX\n", 1);
2995       mem_initex = 0;
2996     }
2997
2998     if (trie_size != 0)
2999     {
3000       show_line("ERROR: Need only set hyphenation trie size in iniTeX\n", 1);
3001 /* trie_size = 0; */
3002     }
3003   }
3004   if (mem_initex == 0)
3005     mem_initex = default_mem_top;
3006   if (trie_size == 0)
3007     trie_size = default_trie_size;
3008 /* Just in case user mistakenly specified words instead of kilo words */
3009   if (mem_extra_high > 10000L * 1024L) mem_extra_high = mem_extra_high / 1024;
3010   if (mem_extra_low > 10000L * 1024L) mem_extra_low = mem_extra_low / 1024;
3011   if (mem_initex > 10000L * 1024L) mem_initex = mem_initex / 1024;
3012 #ifdef ALLOCATEHIGH         /* not used anymore */
3013   if (mem_extra_high > 2048L * 1024L) { /* extend SW area by 16 mega byte! */
3014     show_line("WARNING: There may be no benefit to asking for so much memory\n", 0);
3015     mem_extra_high = 2048 * 1024; /* limit to SW to 4 x VLR */
3016   }
3017 #endif
3018 #ifdef ALLOCATELOW          /* not used anymore */
3019   if (mem_extra_low > 2048L * 1024L) { /* extend VL area by 16 mega byte! */
3020     show_line("WARNING: There may be no benefit to asking for so much memory\n", 0);
3021     mem_extra_low = 2048 * 1024; /* limit VLR to 4 x SW */
3022   }
3023 #endif
3024   if (mem_initex > 2048L * 1024L) { /* extend main memory by 16 mega byte! */
3025     show_line("WARNING: There may be no benefit to asking for so much memory\n", 0);
3026 /* mem_initex = 2048 * 1024; */
3027   }
3028  #ifdef ALLOCATEDVIBUF
3029   if (dvi_buf_size == 0) dvi_buf_size = default_dvi_buf_size;
3030 /* if less than 1024 assume user specified kilo-bytes, not bytes */
3031   if (dvi_buf_size < 1024) dvi_buf_size = dvi_buf_size * 1024;
3032   if (dvi_buf_size % 8 != 0)        /* check multiple of eight */
3033     dvi_buf_size = (dvi_buf_size / 8 + 1) * 8;
3034  #endif
3035   if (new_hyphen_prime < 0) new_hyphen_prime = 0;
3036   if (new_hyphen_prime > 0) {
3037     if (! is_initex)
3038       show_line("ERROR: Can only set hyphen prime in iniTeX\n", 1);
3039     else {
3040       if (new_hyphen_prime % 2 == 0) new_hyphen_prime++;
3041       while (!prime(new_hyphen_prime)) new_hyphen_prime = new_hyphen_prime+2;
3042       if (trace_flag) {
3043         sprintf(log_line, "Using %d as hyphen prime\n", new_hyphen_prime);
3044         show_line(log_line, 0);
3045       }
3046     }
3047   }
3048   if (percent_grow > 100) percent_grow = percent_grow - 100;
3049   if (percent_grow > 100) percent_grow = 100;   /* upper limit - double */
3050   if (percent_grow < 10) percent_grow = 10;   /* lower limit - 10% */
3051 }
3052
3053 /**********************************************************************/
3054
3055 void perrormod (char *s)
3056 {
3057   sprintf(log_line, "`%s': %s\n", s, strerror(errno));
3058   show_line(log_line, 1);
3059 }
3060
3061 void pause (void)
3062 {
3063 #ifndef _WINDOWS
3064   fflush(stdout);     /* ??? */
3065   fflush(stderr);     /* ??? */
3066   (void) _getch();    /* ??? */
3067 #endif
3068 }
3069
3070 void checkpause (int flag)
3071 {            /* 95/Oct/28 */
3072   char *s;
3073   int debug_pause = 0;
3074 /*  don't stop if in Q (quiet) or R (run) mode */
3075 /*  stop only in S (scroll) and T (TeX) mode */
3076   if (interaction >= 0 && interaction < 2)
3077     flag = 0;    /* 98/Jun/30 */
3078   s = grabenv("DEBUGPAUSE");
3079   if (s != NULL) sscanf(s, "%d", &debug_pause);
3080   if (flag < 0) return;
3081   if (debug_pause) {
3082     if (debug_pause || flag > 0) {
3083       show_line("\n", 0);
3084 #ifndef _WINDOWS
3085       show_line("Press any key to continue . . .\n", 0);
3086       pause();
3087 #endif
3088     }
3089   }
3090 }
3091
3092
3093 /*************************************************************************/
3094
3095 /* convert tilde to pseudo_tilde to hide it from TeX --- 95/Sep/26 */
3096 /* convert space to pseudo_space to hide it from TeX --- 97/Jun/5 */
3097 /* called only if pseudo_tilde != 0 or pseudo_space != 0 */
3098 /* this is then undone in tex3.c both for fopen input and output */
3099 /* not ideal, since pseudo name appears in log and in error messages ... */
3100
3101 void hidetwiddle (char *name)
3102 {
3103   char *s = name;
3104
3105 #ifdef DEBUGTWIDDLE
3106   if (trace_flag)
3107   {
3108     sprintf(log_line, "Hidetwiddle %s", name);
3109     show_line(log_line, 0);
3110   }
3111 #endif
3112 /*  while (*s != '\0' && *s != ' ') { */
3113   while (*s != '\0')
3114   {
3115     if (*s == '~' && pseudo_tilde != 0)
3116       *s = (char) pseudo_tilde;  /* typically 254 */
3117     else if (*s == ' ' && pseudo_space != 0)
3118       *s = (char) pseudo_space;  /* typically 255 */
3119     s++;
3120   }
3121 #ifdef DEBUGTWIDDLE
3122   if (trace_flag)
3123   {
3124     sprintf(log_line, "=> %s\n", name);
3125     show_line(log_line, 0);
3126   }
3127 #endif
3128 }
3129
3130 void deslash_all (int ac, char **av)
3131 {
3132   char buffer[PATH_MAX];  
3133   char *s;
3134
3135 /* environment variables for output directories (as in PC TeX) */
3136
3137   if ((s = grabenv("TEXDVI")) != NULL) dvi_directory = s;
3138   if ((s = grabenv("TEXLOG")) != NULL) log_directory = s;
3139   if ((s = grabenv("TEXAUX")) != NULL) aux_directory = s;
3140   if ((s = grabenv("TEXFMT")) != NULL) fmt_directory = s;
3141   if ((s = grabenv("TEXPDF")) != NULL) pdf_directory = s;
3142
3143   strcpy(buffer, av[0]);            /* get path to executable */
3144
3145   if ((s = strrchr(buffer, '\\')) != NULL) *(s+1) = '\0';
3146   else if ((s = strrchr(buffer, '/')) != NULL) *(s+1) = '\0';
3147   else if ((s = strrchr(buffer, ':')) != NULL) *(s+1) = '\0';
3148   s = buffer + strlen(buffer) - 1;
3149   if (*s == '\\' || *s == '/') *s = '\0';   /* flush trailing PATH_SEP */
3150   texpath = xstrdup(buffer);
3151
3152 /*  Hmm, we may be operating on DOS environment variables here !!! */
3153
3154   if (strcmp(dvi_directory, "") != 0) flush_trailing_slash (dvi_directory);
3155   if (strcmp(log_directory, "") != 0) flush_trailing_slash (log_directory);
3156   if (strcmp(aux_directory, "") != 0) flush_trailing_slash (aux_directory);
3157   if (strcmp(fmt_directory, "") != 0) flush_trailing_slash (fmt_directory);
3158   if (strcmp(pdf_directory, "") != 0) flush_trailing_slash (pdf_directory);
3159
3160   if (deslash)
3161   {
3162       unixify (texpath);          /* 94/Jan/25 */
3163 /* if output directories given, deslashify them also 1993/Dec/12 */
3164       if (strcmp(dvi_directory, "") != 0) unixify(dvi_directory);
3165       if (strcmp(log_directory, "") != 0) unixify(log_directory);
3166       if (strcmp(aux_directory, "") != 0) unixify(aux_directory);
3167       if (strcmp(fmt_directory, "") != 0) unixify(fmt_directory);
3168       if (strcmp(pdf_directory, "") != 0) unixify(pdf_directory);
3169   }
3170
3171 /*  deslash TeX source file (and format, if format specified) */
3172 /*  and check args to see whether format was specified */
3173   format_spec = 0;
3174 /*  NOTE: assuming that command line arguments are in writable memory ! */
3175 /*  if (trace_flag || debug_flag)
3176     sprintf(log_line, "optind %d ac %d\n", optind, ac); */   /* debugging */ 
3177 /*  if (optind < ac) { */           /* bkph */
3178   if (optind < ac && optind > 0) {      /* paranoia 94/Apr/10 */
3179     if (deslash) {
3180       if (trace_flag || debug_flag) {
3181         sprintf(log_line, "deslash: k %d argv[k] %s (argc %d)\n",
3182           optind, av[optind], ac);
3183         show_line(log_line, 0);
3184       }
3185       unixify(av[optind]);
3186     }
3187     if (pseudo_tilde != 0 || pseudo_space != 0)
3188       hidetwiddle (av[optind]);     /* 95/Sep/25 */
3189 /* For Windows NT, lets allow + instead of & for format specification */
3190     if (*av[optind] == '&' || *av[optind] == '+') {
3191       format_spec = 1; /* format file specified */
3192       format_name = xstrdup(av[optind]+1); /* 94/Oct/25 */
3193 /*      uppercase (format_name); */    /* why ? 98/Jan/31 */
3194       if (optind + 1 < ac) {
3195         if (deslash) {
3196           if (trace_flag || debug_flag) {
3197             sprintf(log_line, "deslash: k %d argv[k] %s (argc %d)\n",
3198               optind+1, av[optind+1], ac);
3199             show_line(log_line, 0);
3200           }
3201           unixify(av[optind+1]);
3202         }
3203         if (pseudo_tilde != 0 || pseudo_space != 0)
3204           hidetwiddle (av[optind+1]); /* 95/Sep/25 */
3205       }
3206     }         
3207   }
3208 }
3209
3210 /* The above seems to assume that arguments that don't start with '-' */
3211 /* are file names or format names - what if type in control sequences? */
3212
3213 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3214
3215 /* main entry point follows */
3216
3217 /* this gets called pretty much right away in `main' in texmf.c */
3218
3219 /* note: those optarg == 0 test don't really work ... */
3220 /* note: optarg starts at = in case of x=... */
3221
3222 int main_init (int ac, char **av)
3223 {
3224   char initbuffer[PATH_MAX];
3225   int k;
3226
3227   kpse_set_program_name(av[0], NULL);
3228
3229   if (sizeof(memory_word) != 8) /* compile time test */
3230   {
3231     sprintf(log_line, "ERROR: Bad word size %d!\n", sizeof(memory_word));
3232     show_line(log_line, 1);
3233   }
3234
3235   start_time = clock();    /* get time */
3236   main_time = start_time;   /* fill in, in case file never opened */
3237
3238   initbuffer[0] = '\0';         /* paranoia 94/Apr/10 */
3239
3240 /*  reset all allocatable memory pointers to NULL - in case we drop out */
3241   mainmemory = NULL;
3242   font_info = NULL;
3243   str_pool = NULL;
3244   str_start = NULL;
3245
3246 #ifdef ALLOCATESAVESTACK
3247   save_stack = NULL; 
3248 #endif
3249
3250 #ifdef ALLOCATEBUFFER
3251   buffer = NULL;        /* new 1999/Jan/7 need to do early */
3252   current_buf_size = 0;
3253   buffer = realloc_buffer (initial_buf_size);
3254 #endif
3255
3256   hyph_list = NULL;
3257   hyph_word = NULL;
3258   trie_taken = NULL;
3259   trie_hash = NULL;
3260   trie_r = NULL;
3261   trie_c = NULL;
3262   trie_o = NULL;
3263   trie_l = NULL;
3264   trie_trc = NULL;
3265   trie_tro = NULL;
3266   trie_trl = NULL;
3267
3268   log_opened = false;       /* so can tell whether opened */
3269   interaction = -1;         /* default state => 3 */
3270   missing_characters = 0;   /* none yet! */
3271   workingdirectory = false; /* set from dviwindo.ini & command line */
3272   font_dimen_zero = true;   /* \fontdimen0 for checksum 98/Oct/5 */
3273   ignore_frozen = false;    /* default is not to ignore 98/Oct/5 */
3274   suppress_f_ligs = false;  /* default is not to ignore f-ligs */
3275
3276   if (ac > 1 && !strncmp(av[1], "-Y", 2))
3277     reorder_arg_flag = false;
3278
3279   if (reorder_arg_flag)
3280     reorderargs(ac, av);  
3281
3282   if (init_commands(ac, av))
3283     return -1;          // failure
3284
3285   check_fixed_align(trace_flag);       /* sanity check 1994/Jan/8 */
3286
3287   format_file   = NULL;
3288   string_file   = NULL;
3289   source_direct = NULL;
3290   dvi_file_name = NULL;
3291   log_file_name = NULL;
3292   pdf_file_name = NULL;
3293
3294   first_pass_count  = 0;
3295   second_pass_count = 0;
3296   final_pass_count  = 0;
3297   paragraph_failed  = 0;
3298   single_line       = 0;
3299   overfull_hbox     = 0;
3300   underfull_hbox    = 0;
3301   overfull_vbox     = 0;
3302   underfull_vbox    = 0;
3303
3304   closed_already=0;        // so can only do once
3305
3306   if (trace_flag)
3307     show_line("Entering init (local)\n", 0);
3308
3309 /*   Print version *after* banner ? */ /* does this get in log file ? */
3310
3311   probe_memory();             /* show top address */
3312   ini_max_address = max_address;       /* initial max address */
3313
3314   if (trace_flag)
3315     show_maximums(stdout);
3316
3317   initial_memory();
3318
3319   deslash_all(ac, av);    /* deslash and note if format specified */
3320
3321   no_interrupts = 0;
3322
3323   if (format_spec && mem_spec_flag)
3324   {
3325     show_line("WARNING: Cannot change initial main memory size when format specified", 1);
3326   }
3327
3328   if (allocate_memory() != 0)   /* NOW, try and ALLOCATE MEMORY if needed */
3329     return -1;         // if failed to allocate
3330
3331 /*   following is more or less useless since most all things not yet alloc */
3332    check_alloc_align(trace_flag);    /* sanity check 1994/Jan/8 */
3333
3334   if (trace_flag)
3335     show_line("Leaving init (local)\n", 0);
3336
3337   return 0;         // success
3338 }
3339
3340 #define CLK_TCK  CLOCKS_PER_SEC
3341
3342 void show_inter_val (clock_t interval)
3343 {
3344   int seconds, tenths, hundredth, thousands;
3345
3346   if (interval >= CLK_TCK * 10)
3347   {
3348     tenths = (interval * 10 + CLK_TCK / 2) / CLK_TCK; 
3349     seconds = tenths / 10; 
3350     tenths = tenths % 10;
3351     sprintf(log_line, "%d.%d", seconds, tenths);
3352     show_line(log_line, 0);
3353   }
3354   else
3355     if (interval >= CLK_TCK)     /* 94/Feb/25 */
3356     {
3357       hundredth = (interval * 100 + CLK_TCK / 2) / CLK_TCK;
3358       seconds = hundredth / 100;
3359       hundredth = hundredth % 100;
3360       sprintf(log_line, "%d.%02d", seconds, hundredth);
3361       show_line(log_line, 0);
3362     }
3363     else
3364       if (interval > 0)         /* 94/Oct/4 */
3365       {
3366         thousands = (interval * 1000 + CLK_TCK / 2) / CLK_TCK;
3367         seconds = thousands / 1000;
3368         thousands = thousands % 1000;
3369         sprintf(log_line, "%d.%03d", seconds, thousands);
3370         show_line(log_line, 0);
3371       }
3372       else
3373         show_line("0", 0);          /* 95/Mar/1 */
3374 }
3375
3376 /* final cleanup opportunity */ /* flag is non-zero if error exit */
3377 /* shows various times, warning about missing chars */
3378
3379 int endit (int flag)
3380 {
3381   finish_time = clock();
3382
3383   if (missing_characters != 0)
3384     flag = 1;
3385
3386   if (missing_characters)
3387   {
3388     sprintf(log_line, "! There %s %d missing character%s --- see log file\n",
3389       (missing_characters == 1) ? "was" : "were",  missing_characters,
3390       (missing_characters == 1) ? "" : "s");
3391     show_line(log_line, 0);
3392   }
3393
3394   if (free_memory() != 0)
3395     flag++;
3396
3397   if (verbose_flag)
3398   {
3399     show_line("Total ", 0);
3400     show_inter_val(finish_time - start_time);
3401     show_line(" sec (", 0);
3402     show_inter_val(main_time - start_time);
3403     show_line(" format load + ", 0);
3404     show_inter_val(finish_time - main_time);
3405     show_line(" processing) ", 0);
3406
3407     if (total_pages > 0)
3408     {
3409       show_inter_val ((finish_time - main_time) / total_pages);
3410       show_line(" sec per page", 0);
3411     }
3412
3413     show_line("\n", 0);
3414   }
3415
3416   checkpause(flag);
3417
3418   return flag;
3419 }
3420
3421 /********************************************************************************/
3422
3423 /* addition 98/Mar/31 print_csnames Frank Mittelbach */
3424
3425 #define MAXCOLUMN 78
3426
3427 void print_cs_name (FILE *output, int h)
3428 {
3429   int c, textof, n;
3430
3431   memset(log_line, 0, sizeof(log_line));
3432
3433   textof = hash[h].v.RH;
3434
3435   if (textof == 0)
3436     return;
3437
3438   c = sprintf(log_line, "(%d), ", h);
3439   n = length(textof);
3440
3441   memmove(log_line + c, str_pool + str_start[textof], n);
3442   memmove(log_line + c + n, "\n", 2);
3443
3444   if (output == stderr)
3445   {
3446     show_line(log_line, 1);
3447   }
3448   else
3449   {
3450     if (output == stdout)
3451       show_line(log_line, 0);
3452     else
3453       fprintf(output, log_line);
3454   }
3455
3456 }
3457
3458 int compare_strn (int, int, int, int); /* in tex9.c */
3459
3460 /* compare two csnames in qsort */
3461
3462 int compare_cs (const void *cp1, const void *cp2)
3463 {
3464   int c1, c2, l1, l2, k1, k2, textof1, textof2;
3465
3466   c1 = *(int *)cp1;
3467   c2 = *(int *)cp2;
3468   textof1 = hash[c1].v.RH;
3469   textof2 = hash[c2].v.RH;
3470   l1 = length(textof1); 
3471   l2 = length(textof2); 
3472   k1 = str_start[textof1]; 
3473   k2 = str_start[textof2]; 
3474
3475   return compare_strn (k1, l1, k2, l2);
3476 }
3477
3478 char *csused = NULL;
3479
3480 /* Allocate table of indeces to allow sorting on csname */
3481 /* Allocate flags to remember which ones already listed at start */
3482 /* pass = 0 --> fmt */
3483 /* pass = 1 --> after */
3484 void print_cs_names (FILE *output, int pass)
3485 {
3486   int h, k, ccount, repeatflag;
3487   int *cnumtable;
3488   int nfcs = frozen_control_sequence;
3489
3490   if (pass == 0 && csused == NULL)
3491   {
3492     csused = (char *) malloc (nfcs);
3493
3494     if (csused == NULL)
3495       return;
3496
3497 #ifdef USEMEMSET
3498     memset(csused, 0, nfcs);
3499 #else
3500     for (h = 0; h < (hash_size + 780); h++)
3501       csused[h] = 0;
3502 #endif
3503   }
3504
3505   ccount = 0;
3506
3507   for (h = hash_base + 1; h < nfcs; h++)
3508   {
3509     if (pass == 1 && csused[h])
3510       continue;
3511
3512     if (hash[h].v.RH != 0)
3513     {
3514       if (pass == 0)
3515         csused[h] = 1;
3516
3517       ccount++;
3518     }
3519   }
3520
3521   sprintf(log_line, "\n%d %s multiletter control sequences:\n",
3522       ccount, (pass == 1) ? "new" : "");
3523
3524   if (output == stderr)
3525   {
3526     show_line(log_line, 1);
3527   }
3528   else
3529   {
3530     if (output == stdout)
3531       show_line(log_line, 0);
3532     else
3533       fprintf(output, log_line);
3534   }
3535
3536   if (ccount > 0) /* don't bother to get into trouble */
3537   {
3538     cnumtable = (int *) malloc (ccount * sizeof(int));
3539
3540     if (cnumtable == NULL)
3541       return;
3542
3543     ccount = 0;
3544 /*    for (h = 515; h < (hash_size + 780); h++) { */
3545     for (h = hash_base + 1; h < nfcs; h++)
3546     {
3547       if (pass == 1 && csused[h])
3548         continue;
3549
3550       if (hash[h].v.RH != 0)
3551         cnumtable[ccount++] = h;
3552     }
3553
3554     //qsort ((void *)cnumtable, ccount, sizeof (int), &compare_cs);
3555
3556     repeatflag = 0;
3557
3558     for (k = 0; k < ccount; k++)
3559     {
3560       h = cnumtable[k];
3561
3562       if (pass == 1 && csused[h])
3563         continue;
3564
3565       print_cs_name(output, h);
3566     }
3567
3568     sprintf(log_line, "\n");
3569
3570     if (output == stderr)
3571     {
3572       show_line(log_line, 1);
3573     }
3574     else
3575     {
3576       if (output == stdout)
3577         show_line(log_line, 0);
3578       else
3579         fprintf(output, log_line);
3580     }
3581
3582     free((void *)cnumtable);
3583   }
3584
3585   if (pass == 1 && csused != NULL)
3586   {
3587     free(csused);
3588     csused = NULL;
3589   }
3590 }
3591
3592 /***************** font info listing moved from TEX9.C ******************/
3593 /* compare two strings in str_pool (not null terminated) */
3594 /* k1 and k2 are positions in string pool */
3595 /* l1 and l2 are lengths of strings */
3596
3597 int compare_strn (int k1, int l1, int k2, int l2)
3598 {
3599   int c1, c2;
3600
3601   while (l1 > 0 && l2 > 0)
3602   {
3603     c1 = str_pool[k1];
3604     c2 = str_pool[k2];
3605
3606     if (c1 > c2)
3607       return 1;
3608     else if (c2 > c1)
3609       return -1;
3610
3611     l1--; l2--;
3612     k1++; k2++;
3613   }
3614
3615   if (l1 > 0)
3616     return 1;   /* first string longer */
3617   else if (l2 > 0)
3618     return -1; /* second string longer */
3619
3620   return 0;         /* strings match */
3621 }
3622
3623 /* compare two font names and their at sizes in qsort */
3624
3625 int compare_fnt (const void *fp1, const void *fp2)
3626 {
3627   int f1, f2, l1, l2, k1, k2, s;
3628
3629   f1 = *(short *)fp1;
3630   f2 = *(short *)fp2;
3631   l1 = length(font_name[f1]);
3632   l2 = length(font_name[f2]);
3633   k1 = str_start[font_name[f1]]; 
3634   k2 = str_start[font_name[f2]]; 
3635
3636   s = compare_strn (k1, l1, k2, l2);
3637
3638   if (s != 0)
3639     return s;
3640
3641   if (font_size[f1] > font_size[f2])
3642     return 1;
3643   else if (font_size[f1] < font_size[f2])
3644     return -1;
3645
3646   return 0;         /* should not ever get here */
3647 }
3648
3649 /* compare two font names */
3650
3651 int compare_fnt_name (int f1, int f2)
3652 {
3653   int l1, l2, k1, k2, s;
3654
3655   l1 = length(font_name[f1]);
3656   l2 = length(font_name[f2]); 
3657   k1 = str_start[font_name[f1]]; 
3658   k2 = str_start[font_name[f2]]; 
3659
3660   s = compare_strn (k1, l1, k2, l2);
3661
3662   return s;
3663 }
3664
3665 /* decode checksum information */
3666
3667 unsigned long checkdefault = 0x59265920;  /* default signature */
3668
3669 int decode_fourty (unsigned long checksum, char *codingvector)
3670 {
3671   int c;
3672   int k;
3673 /*  char codingvector[6+1]; */
3674
3675   if (checksum == 0)
3676   {
3677     strcpy(codingvector, "unknwn");
3678     return 1;
3679   }
3680   else
3681     if ((checksum >> 8) == (checkdefault >> 8))  /* last byte random */
3682     {
3683 /*    strcpy (codingvector,  "native"); */  /* if not specified ... */
3684       strcpy (codingvector,  "fixed ");   /* if not specified ... */
3685       return 1;               /* no info available */
3686     }
3687     else
3688     {
3689       for (k = 0; k < 6; k++)
3690       {
3691         c = (int) (checksum % 40);
3692         checksum = checksum / 40;
3693         if (c <= 'z' - 'a') c = c + 'a';
3694         else if (c < 36) c = (c + '0') - ('z' - 'a') - 1;
3695         else if (c == 36) c = '-';
3696         else if (c == 37) c = '&';
3697         else if (c == 38) c = '_';
3698         else c = '.';       /* unknown */
3699         codingvector[5-k] = (char) c;
3700       }
3701       codingvector[6] = '\0';
3702     }
3703 /*  sprintf(log_line, "Reconstructed vector %s\n", codingvector); */
3704   return 0;         /* encoding info returned in codingvector */
3705 }
3706
3707 double sclpnt (long x)
3708 {
3709   double pt;
3710
3711   pt = (double) x / 65536.0;
3712   pt = (double) ((int) (pt * 1000.0 + 0.5)) / 1000.0;
3713
3714   return (pt);
3715 }
3716
3717 // Shows list of fonts in log file
3718
3719 void dvi_font_show(internal_font_number f, int suppressname)
3720 {
3721   int a, l, k, n;
3722   unsigned long checksum;
3723   char checksumvector[8];
3724   char buffer[32];
3725
3726   putc(' ', log_file);
3727
3728   if (suppressname == 0)
3729   {
3730     a = length(font_area[f]);
3731     l = length(font_name[f]);
3732
3733     k = str_start[font_area[f]];
3734
3735     memcpy(buffer, str_pool + k, length(font_area[f]));
3736     fwrite(buffer, sizeof(char), length(font_area[f]), log_file);
3737
3738     k = str_start[font_name[f]];
3739
3740     memcpy(buffer, str_pool + k, length(font_name[f]));
3741     fwrite(buffer, sizeof(char), length(font_name[f]), log_file);
3742   }
3743   else a = l = 0;
3744
3745   for (k = a + l; k < 16; k++)
3746     putc(' ', log_file);
3747
3748   sprintf(buffer, "at %lgpt ", sclpnt(font_size[f]));
3749   fputs(buffer, log_file);
3750
3751   if (suppressname == 0)
3752   {
3753     n = strlen(buffer);
3754
3755     for (k = n; k < 16; k++)
3756       putc(' ', log_file);
3757
3758     checksum = (((font_check[f].b0) << 8 | font_check[f].b1) << 8 | font_check[f].b2) << 8 | font_check[f].b3;
3759     decode_fourty(checksum, checksumvector);
3760     fprintf(log_file, "encoding: %s..", checksumvector);
3761   }
3762
3763   putc('\n', log_file);
3764 }
3765
3766 /* Allocate table of indeces to allow sorting on font name */
3767
3768 void show_font_info (void)
3769 {
3770   int k, m, fcount, repeatflag;
3771   short *fnumtable;
3772
3773   fcount = 0;
3774
3775   for (k = 1; k <= font_ptr; k++)
3776     if (font_used[k])
3777       fcount++;
3778
3779   if (fcount == 0)
3780     return;
3781
3782   fnumtable = (short *) malloc (fcount * sizeof(short));
3783
3784   fprintf(log_file, "\nUsed %d font%s:\n", fcount, (fcount == 1) ? "" : "s");
3785
3786   fcount = 0;
3787
3788   for (k = 1; k <= font_ptr; k++) 
3789     if (font_used[k])
3790       fnumtable[fcount++] = (short) k;
3791
3792   qsort ((void *)fnumtable, fcount, sizeof (short), &compare_fnt);
3793
3794   repeatflag = 0;
3795
3796   for (m = 0; m < fcount; m++)
3797   {
3798     if (m > 0)
3799     {
3800       if (compare_fnt_name(fnumtable[m-1], fnumtable[m]) == 0)
3801         repeatflag = 1;
3802       else
3803         repeatflag = 0;
3804     }
3805
3806     dvi_font_show(fnumtable[m], repeatflag);
3807   }
3808
3809   free((void *)fnumtable);
3810 }
3811
3812 /*  NOTE: current_tfm = false (-c)
3813   not checking for TFM in current directory saves 0.1 sec
3814   (0.2 if file_method = false (-G) */
3815
3816 /*  NOTE: test_dir_access = false (-b):
3817   not checking whether readable file is a directory saves maybe 0.5 sec
3818   BUT only if file_method = false (-G) - otherwise its irrelevant */
3819
3820 /*  NOTE: dir_method = false (-D) --- method for checking whether directory
3821   using fopen instead of _findfirst in dir_p slows job maybe 0.05 sec
3822   BUT not if current_tfm = false (-c) */
3823
3824 /*  NOTE: file_method = false (-G) --- method for checking file accessible
3825   using _access (readable) instead of _findfirst (file_p) costs 0.5 sec */
3826
3827 /*  Fast flag combinations: nothing, bG, bcG, bcDG */
3828
3829 /* buffercopy no longer used */
3830
3831 /* To Knuthian reset right when command line interpreted */
3832