OSDN Git Service

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