OSDN Git Service

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