OSDN Git Service

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