OSDN Git Service

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