OSDN Git Service

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