OSDN Git Service

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