OSDN Git Service

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