OSDN Git Service

binding with libharu.
[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 #ifdef _WINDOWS
20   #define NOCOMM
21   #define NOSOUND
22   #define NODRIVERS
23   #define STRICT
24   #pragma warning(disable:4115) // kill rpcasync.h complaint
25   #include <windows.h>
26   #define MYLIBAPI __declspec(dllexport)
27 #endif
28
29 #include "texwin.h"
30
31 #pragma warning(disable:4996)
32 #pragma warning(disable:4131) // old style declarator
33 #pragma warning(disable:4135) // conversion between different integral types 
34 #pragma warning(disable:4127) // conditional expression is constant
35
36 #include <setjmp.h>
37
38 #define EXTERN extern
39
40 #include "texd.h"
41
42 /* Most Y & Y changes are localized here -- init() */
43
44 /* Note int main (int ac, char *av[]) is in texmf.c */
45 /* and that calls main_program = texbody in itex.c => initialize */
46 /* which in turn calls init here in local.c */
47 /* which then calls init_commands here in local.c */ 
48
49 #define USEOUREALLOC      /* 96/Jan/20 */
50
51 #define USEMEMSET       /* 98/Jan/23 */
52
53 /* #define PREALLOCHOLE */    /* make hole in heap at bottom debugging */
54
55 /* #define CHECKALIGNMENT */  /* reactivated 95/Jan/7 */
56
57 /* #define HEAPSHOW */      /* debugging 96/Jan/20 */
58
59 /* #ifdef TRYANDOPEN */     /* debugging only */
60
61 /* #define SHOWHEAPERROR */   /* debugging 96/Jan/10 */
62
63 #ifndef _WINDOWS
64 /* #define HEAPWALK */      /* debugging 96/Oct/22 */
65 #endif
66
67 #ifdef USEOUREALLOC
68   #define REALLOC ourrealloc
69 #else
70   #define REALLOC realloc
71 #endif
72
73 #include <time.h>
74 #include <malloc.h> /* _msize, _expand, HEAPOK et.c */
75 #include <direct.h> /* for _getcwd() */
76
77 #pragma warning(disable:4032) // different type when promoted
78 #ifndef _WINDOWS
79   #include <conio.h>            /* for _getch() */
80 #endif
81 #pragma warning(default:4032) // different type when promoted`
82
83
84 /* Argument handling, etc.  */ /* from common.h - setup `main' in texmf.c */
85 /* extern int gargc; */
86 /* extern char **gargv; */
87
88 int wantcopyrght=1;
89
90 /* appears in reverse order in EXE file */
91
92 char *compiletime  =  __TIME__;
93 char *compiledate  =  __DATE__;
94 char *www          = "http://www.tug.org/yandy";
95 char *rights       = "All Rights Reserved.";
96 char *copyright    = "Copyright (C) 2007--2014 TeX Users Group.";
97 char *yandyversion = "2.2.3"; /* 00/Jun/18 */
98 char *application  = "Y & Y TeX"; /* 96/Jan/17 */
99 char *tex_version  = "This is TeX, Version 3.14159265"; /* change with upgrade */
100
101 /* #define COPYHASH 1890382 */
102 /* #define COPYHASH 13862905 */
103 /* #define COPYHASH 10558802 */
104 /* #define COPYHASH 7254699 */
105 /* #define COPYHASH 3950596 */
106 /* #define COPYHASH 646493 */
107 #define COPYHASH 12905299
108
109 clock_t start_time, main_time, finish_time;
110
111 char *dvi_directory = ""; /* user specified directory for dvi file */
112 char *log_directory = ""; /* user specified directory for log file */
113 char *aux_directory = ""; /* user specified directory for aux file */
114
115 char *texpath = "";   /* path to executable - used if env vars not set */
116
117 // #define MAXLINE 256
118
119 char log_line[MAXLINE];  // used also in tex9.c
120
121 int mem_spec_flag     = 0;    /* non-zero if `-m=...' was used */ 
122 int format_spec       = 0;    /* non-zero if a format specified on command line */
123 int closed_already    = 0;    /* make sure we don't try this more than once */
124 bool reorder_arg_flag = true; /* put command line flags/arguments first */
125
126 /* Mapping from Windows ANSI to DOS code page 850 96/Jan/20 */
127 /* Used in tex0.c with wintodos[c-128]                      */
128
129 unsigned char wintodos[128] = {
130     0,   0,   0, 159,   0,   0,   0,   0, 
131    94,   0,   0,   0,   0,   0,   0,   0, 
132     0,  96,  39,   0,   0,   7,   0,   0,
133   126,   0,   0,   0,   0,   0,   0,   0, 
134    32, 173, 189, 156, 207, 190, 221,  21, 
135     0, 184, 166, 174, 170,  45, 169,   0, 
136   248, 241, 253, 252,   0, 230,  20, 250, 
137     0, 251, 167, 175, 172, 171, 243, 168, 
138   183, 181, 182, 199, 142, 143, 146, 128, 
139   212, 144, 210, 211, 222, 214, 215, 216, 
140   209, 165, 227, 224, 226, 229, 153, 158, 
141   157, 235, 233, 234, 154, 237, 232, 225, 
142   133, 160, 131, 198, 132, 134, 145, 135, 
143   138, 130, 136, 137, 141, 161, 140, 139, 
144   208, 164, 149, 162, 147, 228, 148, 246,
145   155, 151, 163, 150, 129, 236, 231, 152
146 };  
147
148 void show_usage (char * program) {
149   char * s = log_line;
150   sprintf (s, "\n\
151 %s [-?ivnwdrzpK] [-m=ini_mem] [-e=hyph_size] [-h=trie_size]\n\
152 \t[-x=xchr_file] [-k=key_file] [-o=dvi_dir] [-l=log_dir] [-a=aux_dir]\n\
153 \t[+format_file] [tex_file]\n\
154 ", program);
155   s += strlen(s);
156   sprintf (s, "\
157     -?    show this usage summary\n\
158     -i    start up as iniTeX (create format file)\n\
159     -v    be verbose (show implementation version number)\n\
160     -n    do not allow `non ASCII' characters in input files (complain instead)\n\
161     -w    do not show `non ASCII' characters in hexadecimal (show as is)\n\
162     -d    do not allow DOS style file names - i.e. do not convert \\ to /\n\
163     -r    do not allow Mac style termination - i.e. do not convert \\r to \\n\n\
164     -p    allow use of \\patterns after loading format (iniTeX only)\n\
165     -K    disable all extensions to basic TeX\n\
166     -m    initial main memory size in kilo words (iniTeX only)\n\
167     -e    hyphenation exception dictionary size (iniTeX only)\n\
168     -h    hyphenation pattern trie size (iniTeX only)\n\
169     -x    use `non ASCII' character mapping (xchr[]) defined in file\n\
170     -k    use `key replacement' defined in file\n\
171     -o    write DVI file in specified directory (default current directory)\n\
172     -l    write LOG file in specified directory (default current directory)\n\
173     -a    write AUX file in specified directory (default current directory)");
174   strcat(s, "\n");
175   show_line(log_line, 1);
176 #ifndef _WINDOWS
177   uexit(1);     // has this been setup yet ???
178 #endif
179 }
180
181 /* -z    do not discard control-Z at end of input file (treat as character)\n\ */
182
183 /* -c    prepend current directory (.) to TFM directory list\n\ */
184 /* -b    check that files with read access are not actually directories\n\ */
185
186 /* \t-d\tallow DOS style file names - i.e. convert \\ to / \n\ */
187 /* \t\t(applies to file name and format file name, if present)\n\ */
188 /* \t-r\tallow Mac style line termination - i.e. convert \\r to \\n \n\ */
189
190 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
191
192 /* Sep 27 1990 => 1990 Sep 27 */
193 /* 012456789      0123456789  */
194
195 void scivilize (char * date)
196 {
197   int k;
198   char pyear[6];
199   strcpy (pyear, date + 7);
200   for (k = 5; k >= 0; k--) date[k + 5] = date[k];
201   for (k = 0; k < 4; k++) date[k] = pyear[k];
202   date[4] = ' ';
203   if (date[9] == ' ') date[9] = '0'; /* replace space by '0' */
204   return;
205 }
206
207 /* Thu Sep 27 06:26:35 1990 => 1990 Sep 27 06:26:35 */
208
209 void lcivilize (char * date)
210 {
211   int k;
212   char pyear[6];
213
214   strcpy (pyear, date + 20);
215   for (k = 18; k >= 0; k--) date[k+1] = date[k];
216 /*  date[20] = '\n'; */
217 /*  date[21] = '\0'; */
218   date[20] = '\0'; 
219   for (k = 0; k < 4; k++) date[k] = pyear[k];
220   date[4] = ' ';
221   return;
222 }
223
224 // void stamp_it (FILE *outfile)
225 // now writes result into given buffer
226 void stamp_it (char *s)
227 {
228   char date[11 + 1];
229
230   strcpy(date, compiledate);
231   scivilize(date);   
232   sprintf(s, "%s %s ", application, yandyversion);
233   s += strlen(s);
234   sprintf(s, "(compiled time: %s %s)", date, compiletime);
235   s += strlen(s);
236 }
237
238 void stampcopy (char *s)
239 {
240   if (wantcopyrght) {
241     sprintf(s, "%s %s", copyright, www);    /* 99/Oct/25 */
242   }
243 }
244
245 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
246
247 #define MAXCHRS 256
248 #define NOTDEF 127
249
250 void read_xchr_sub (FILE *pinput)
251 {
252   char buffer[PATH_MAX];
253   int k, from, to, count = 0;
254   char *s;
255
256 #ifdef USEMEMSET
257   memset (xchr, NOTDEF, MAXCHRS);           /* mark unused */
258 #else
259   for (k = 0; k < MAXCHRS; k++) xchr[k]= -1; /* mark unused */
260 #endif
261 #ifdef USEMEMSET
262   memset (xord, NOTDEF, MAXCHRS);           /* mark unused */
263 #else
264   for (k = 0; k < MAXCHRS; k++) xord[k]= -1;  /* mark unused */
265 #endif
266
267 #ifdef ALLOCATEBUFFER
268   while (fgets(buffer, current_buf_size, pinput) != NULL) 
269 #else
270   while (fgets(buffer, sizeof(buffer), pinput) != NULL)
271 #endif
272   {
273     if (*buffer == '%' || *buffer == ';' || *buffer == '\n') continue;
274 /*    if (sscanf (buffer, "%d %d", &from, &to) < 2)
275       sprintf(log_line, "Do not understand: %s", buffer); */
276     from = (int) strtol (buffer, &s, 0);
277     to = (int) strtol (s, NULL, 0);
278 /*    what if line is bad ? do we just get from = 0 and to = 0 ? */
279     if (from >= 0 && from < MAXCHRS && to >= 0 && to < MAXCHRS) {
280       if (xchr[from]== (unsigned char) NOTDEF)
281         xchr[from]= (unsigned char) to;
282       else {
283         sprintf(log_line, "NOTE: %s collision: %d => %d, %d\n", "xchr", from, xchr[from], to);
284         show_line(log_line, 0);
285       }
286       if (xord[to]== NOTDEF)
287         xord[to]= (unsigned char) from;
288       else {
289         sprintf(log_line, "NOTE: %s collision: %d => %d, %d\n", "xord", to, xord[to], from);
290         show_line(log_line, 0);
291       }
292       count++;
293     }
294   }
295 /*  now fill in the gaps */ /* not clear this is a good idea ... */
296   for (k = 0; k < MAXCHRS; k++) {
297     if (xchr[k]== NOTDEF) {   /* if it has not been filled */
298       if (xord[k]== NOTDEF) { /* see whether used already */
299         xchr[k]= (unsigned char) k; /* no, so make identity */
300         xord[k]= (unsigned char) k; /* no, so make identity */
301       }
302     }
303   }
304   xchr[NOTDEF]= NOTDEF;         /* fixed point of mapping */
305   if (trace_flag) {
306     sprintf(log_line, "Read %d xchr[] pairs:\n", count);
307     show_line(log_line, 0);
308     for (k = 0; k < MAXCHRS; k++) {
309       if (xchr[k]!= NOTDEF) {
310         sprintf(log_line, "%d => %d\n", k, xchr[k]);
311         show_line(log_line, 0);
312       }
313     }
314   }
315 }
316
317 char *replacement[MAXCHRS];     /* pointers to replacement strings */
318
319 void read_repl_sub (FILE *pinput)
320 {
321   int k, n, m, chrs;
322   char buffer[PATH_MAX];
323   char charname[128];
324   int charnum[10];
325   char *s, *t;
326   
327 #ifdef USEMEMSET
328   memset(replacement, 0, MAXCHRS * sizeof(replacement[ 0]));
329 #else
330   for (k = 0; k < MAXCHRS; k++) replacement[k] = NULL; 
331 #endif
332
333   while (fgets(buffer, PATH_MAX, pinput) != NULL) {
334     if (*buffer == '%' || *buffer == ';' || *buffer == '\n') continue;
335     if ((m = sscanf (buffer, "%d%n %s", &chrs, &n, &charname)) == 0)
336       continue; 
337     else if (m == 2) {
338       if (*charname == '"') {   /* deal with quoted string "..." */
339         s = buffer + n;
340         t = charname;
341         while (*s != '"' && *s != '\0') s++;  /* step up to " */
342         if (*s++ == '\0') continue;       /* sanity check */
343         while (*s != '\0') {  
344           if (*s == '"') {
345             s++;            /* is it "" perhaps ? */
346             if (*s != '"') break;   /* no, end of string */
347           }
348           *t++ = *s++;          /* copy over */
349         }
350         *t = '\0';              /* and terminate */
351       }
352       if (chrs >= 0 && chrs < MAXCHRS)
353         replacement[chrs] = xstrdup(charname);
354     }
355 /*    presently the following can never get triggered */
356 /*    which is good, because it is perhaps not right ... */
357     else if ((m = sscanf (buffer, "%d %d %d %d %d %d %d %d %d %d %d",
358       &chrs, charnum, charnum+1, charnum+2, charnum+3, charnum+4,
359         charnum+5, charnum+6, charnum+7, charnum+8, charnum+9)) > 1) {
360 /*      for (k = 0; k < n-1; k++) charname[k] = (char) charnum; */
361       for (k = 0; k < n-1; k++) charname[k] = (char) charnum[k];
362       charname[m] = '\0';
363       if (chrs >= 0 && chrs < MAXCHRS)
364         replacement[chrs] = xstrdup(charname);      
365     }
366     else {
367       sprintf(log_line, "ERROR: don't understand %s", buffer);
368       show_line(log_line, 1);
369     }
370   }
371   if (trace_flag) {                  /* debugging output */
372     show_line("Key replacement table\n", 0);
373     for (k = 0; k < MAXCHRS; k++) {
374       if (replacement[k] != NULL) {
375         sprintf(log_line, "%d\t%s\n", k, replacement[k]);
376         show_line(log_line, 0);
377       }
378     }
379   }
380 }
381
382 /* Following used both to read xchr[] file and key replacement file */
383 /* the flag is 0 for -x=... and the flag is 1 for -k=... */
384
385 int read_xchr_file (char *filename, int flag, char *argv[])
386 {
387   FILE *pinput;
388   char infile[PATH_MAX];
389   char *s;
390
391   if (filename == NULL) return -1;
392   if (trace_flag) {
393     sprintf(log_line, "Reading xchr/repl %s\n", filename);
394     show_line(log_line, 0);
395   }
396
397 /*  first try using file as specified */
398   strcpy(infile, filename);
399   if (trace_flag) {
400     sprintf(log_line, "Trying %s\n", infile);
401     show_line(log_line, 0);
402   }
403   if (share_flag == 0) pinput = fopen (infile, "r");
404   else pinput = _fsopen (infile, "r", share_flag);    /* 94/July/12 */
405   if (pinput == NULL) {
406     if (strrchr(infile, '.') == NULL) {
407       if (flag == 0) strcat(infile, ".map");
408       else strcat(infile, ".key");
409       if (trace_flag) {
410         sprintf(log_line, "Trying %s\n", infile);
411         show_line(log_line, 0);
412       }
413       if (share_flag == 0) pinput = fopen (infile, "r");
414       else pinput = _fsopen (infile, "r", share_flag);  /* 94/July/12 */
415     }
416   }
417   if (pinput == NULL) {
418 /*    strcpy (infile, gargv[0]); */   /* try TeX program path */
419     strcpy (infile, argv[0]);     /* try TeX program path */
420     if ((s = strrchr (infile, '\\')) != NULL) *(s+1) = '\0';
421     else if ((s = strrchr (infile, '/')) != NULL) *(s+1) = '\0';
422     else if ((s = strrchr (infile, ':')) != NULL) *(s+1) = '\0';
423     strcat (infile, filename);
424     if (trace_flag) {
425       sprintf(log_line, "Trying %s\n", infile);
426       show_line(log_line, 0);
427     }
428     if (share_flag == 0) pinput = fopen (infile, "r");
429     else pinput = _fsopen (infile, "r", share_flag);    /* 94/July/12 */
430     if (pinput == NULL) {
431       if (strchr(infile, '.') == NULL) {
432         if (flag == 0) strcat(infile, ".map");
433         else strcat(infile, ".key");
434         if (trace_flag) {
435           sprintf(log_line, "Trying %s\n", infile);
436           show_line(log_line, 0);
437         }
438         if (share_flag == 0) pinput = fopen (infile, "r");
439         else pinput = _fsopen (infile, "r", share_flag); /* 94/July/12 */
440       }
441     }
442   }
443   if (pinput == NULL) {          /* 97/July/31 */
444 /*    strcpy (infile, gargv[0]); */   /* try TeX program path\keyboard */
445     strcpy (infile, argv[0]);     /* try TeX program path */
446     if ((s = strrchr (infile, '\\')) != NULL) *(s+1) = '\0';
447     else if ((s = strrchr (infile, '/')) != NULL) *(s+1) = '\0';
448     else if ((s = strrchr (infile, ':')) != NULL) *(s+1) = '\0';
449     strcat (infile, "keyboard\\");
450     strcat (infile, filename);
451     if (trace_flag) {
452       sprintf(log_line, "Trying %s\n", infile);
453       show_line(log_line, 0);
454     }
455     if (share_flag == 0) pinput = fopen (infile, "r");
456     else pinput = _fsopen (infile, "r", share_flag);
457     if (pinput == NULL) {
458       if (strchr(infile, '.') == NULL) {
459         if (flag == 0) strcat(infile, ".map");
460         else strcat(infile, ".key");
461         if (trace_flag) {
462           sprintf(log_line, "Trying %s\n", infile);
463           show_line(log_line, 0);
464         }
465         if (share_flag == 0) pinput = fopen (infile, "r");
466         else pinput = _fsopen (infile, "r", share_flag);
467       }
468     }
469   }
470 /*  Note: can't look in TeX source file dir, since that is not known yet */
471   if (pinput == NULL) {
472     sprintf(log_line, "ERROR: Sorry, cannot find %s file %s",
473         flag ? " xchr[]" : "key mapping", filename);
474     show_line(log_line, 1);
475     perrormod (filename);
476     return 0;         // failed
477   }
478
479   if (flag == 0)
480     read_xchr_sub (pinput);
481   else
482     read_repl_sub (pinput);
483
484   (void) fclose (pinput);
485   return 1;
486 }
487
488 /* need to also set `key_replace' here based on command line */
489 /* need to also allocate `buffercopy' here and free at end */
490 /* need to call `readreplace' in appropriate place */
491
492 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
493
494 /* Following may be useful if link without floating point emulation */
495
496 #ifdef DEBUG
497 void testfloating (void) {
498 /*  double x = 1.0; */
499 /*  double dx = DBL_EPSILON; */
500   double dx = 1.0;
501   double dxold = 0.0;
502   int k = 0;
503 /*  while (x + dx != 1.0) { */
504   while (1.0 + dx != 1.0) {
505     dxold = dx;
506     dx = dx / 2.0;
507     k++;
508   }
509   sprintf(log_line, "Floating test: dx = %lg (k = %d)\n", dxold, k - 1);
510   show_line(log_line, 0);
511 }
512 #endif
513
514 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
515
516 char *debugfile;      /* NULL or name of file to try and open */
517
518 #ifdef SHOWHEAPERROR
519   char *heapstrings[] = {
520     "", "Empty", "OK", "Bad Begin", "Bad Node", "End", "Bad Pointer"
521   };
522 #endif
523
524 /* Attempt to get at problem with eqtb ... temporarily abandoned */
525
526 #ifdef CHECKEQTB
527 void check_eqtb (char *act) {
528   int k, count=0;
529   memory_word *eqtb = zeqtb;
530 /*  for (k = 10280 + hash_extra; k < 10280 + eqtb_extra; k++) { */
531   for (k = hash_size + 780 + hash_extra; k < hash_size + 780 + eqtb_extra; k++) {
532     if (eqtb[k].cint != 0) {
533       if (count == 0) {
534         show_char('\n');
535         show_line("EQTB ", 0);
536       }
537       sprintf(log_line, "%d ", k);
538       show_line(log_line, 0);
539       if (count++ > 256) break;
540     }
541   }
542   if (count != 0) show_char('\n');
543 }
544 #endif
545
546 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
547
548 #define MAXSPLITS 3
549
550 /* ad hoc default minimum growth in memory realloc is 62% */
551 /* golden ratio (1 + \sqrt{5}) / 2 = 1.618033989... */
552 int percent_grow    = 62; /* default minimum growth in memory realloc is 62% */
553 int total_allocated = 0;  /* total memory allocated so far */
554 int ini_max_address = 0;  /* maximum address when starting */
555 int max_address     = 0;  /* maximum address seen in allocated memory */
556
557 /* see texd.h */
558
559 // DON'T USE THIS in DLL VERSION
560
561 #ifndef _WINDOWS
562 #ifdef HEAPWALK
563 unsigned int heapthreshold=0; /* smallest size block interested in ... */
564
565 unsigned int heap_dump (FILE *output, int verbose)
566 {
567   unsigned int total=0;
568   struct _heapinfo hinfo;
569   int heapstatus;
570   int end_block=0;
571   int n;
572
573   if (verbose) fprintf(output, "HEAP DUMP:\n");
574
575 /*  if ((n = _heapchk ()) != _HEAPOK) { */
576   n = _HEAPOK;
577 #ifdef SHOWHEAPERROR
578   n = _heapchk();
579 #endif
580   if (n != _HEAPOK) { 
581     fprintf(stderr, "WARNING: Heap corrupted (%d)\n", n);
582 #ifdef SHOWHEAPERROR
583     fprintf(stderr, "HEAP %s (%s)\n", heapstrings[-n], "heap_dump");
584 #endif
585   }
586   hinfo._pentry = NULL;
587   while ((heapstatus = _heapwalk(&hinfo)) == _HEAPOK) {
588     if (end_block > 0 && (int) hinfo._pentry > end_block + 1024) {
589 //      if (verbose) printf("GAP of %d bytes!\n", (int) hinfo._pentry - end_block);
590     }
591     end_block = (int) hinfo._pentry + hinfo._size;
592     if (hinfo._useflag == _USEDENTRY) total += hinfo._size;
593     if (hinfo._size >= heapthreshold && verbose)
594     fprintf(output, "%6s block at %p (%7d) of size %6X (%7d) => (%7d)\n",
595       (hinfo._useflag == _USEDENTRY ? "USED" : "...."),
596         hinfo._pentry, hinfo._pentry, hinfo._size, hinfo._size,
597           end_block);
598   }
599   switch (heapstatus) {
600     case _HEAPEMPTY:
601       if (verbose) fprintf(output, "OK - empty heap\n");
602       break;
603     case _HEAPEND:
604       if (verbose) fprintf(output, "OK - end of heap (%u bytes used)\n", total);
605       break;
606     case _HEAPBADPTR:
607       fprintf(output, "ERROR - %s\n", "bad pointer to heap");
608       break;
609     case _HEAPBADBEGIN:
610       fprintf(output, "ERROR - %s\n", "bad start of heap");
611       break;
612     case _HEAPBADNODE:
613       fprintf(output, "ERROR - %s\n", "bad node in heap");
614       break;  
615   }
616   return total;
617 }
618 #endif
619 #endif
620
621 void show_maximums (FILE *output)
622 {
623 #ifdef HEAPWALK
624   unsigned heaptotal=0;           /* no longer used */
625   heaptotal = heap_dump(stdout, 0);      /* 94/Apr/3 */
626 #endif
627   sprintf(log_line, "Max allocated %d --- max address %d\n", total_allocated, max_address); 
628 //  if (output != NULL) fputs(log_line, output); // log file
629 //  else if (flag == 0) show_line(log_line, 0); // informative
630 //  else if (flag == 1) show_line(log_line, 1); // error
631   if (output == stderr) show_line(log_line, 1);
632   else if (output == stdout) show_line(log_line, 0);
633   else fputs(log_line, output);
634 }
635
636 /* our own version of realloc --- avoid supposed MicroSoft version bug */
637 /* also tries _expand first, which can avoid address growth ... */
638
639 #ifdef USEOUREALLOC 
640 void *ourrealloc (void *old, size_t new_size)
641 {
642   void * mnew;
643   size_t old_size, overlap;
644
645 /*  round up to nearest multiple of four bytes *//* avoid unlikely alignment */
646   if ((new_size % 4) != 0) new_size = ((new_size / 4) + 1) * 4;
647
648   if (old == NULL) return malloc (new_size);  /* no old block - use malloc */
649
650   old_size = _msize (old);
651   if (old_size >= new_size && old_size < new_size + 4) return old;
652 /*  _heapmin(); */  /* release unused heap space to the system - no op ? */
653 #ifdef HEAPSHOW
654   if (trace_flag) {
655     show_line("BEFORE REALLOC: \n", 0);
656 #ifdef HEAPWALK
657     (void) heap_dump(stdout, 1);     /* debugging 96/Jan/18 */
658 #endif
659   }
660 #endif
661   mnew = _expand (old, new_size);      /* first try and expand in place */
662   if (mnew != NULL) {
663     if (trace_flag) {
664       sprintf(log_line, "EXPANDED! %d (%d) == %d (%d)\n",
665         mnew, new_size, old, old_size);
666       show_line(log_line, 0);
667     }
668     return mnew;
669   }
670 /*  *********************************************************************** */
671 /*  do this if you want to call the real realloc next -  */
672   mnew = realloc (old, new_size);
673 #ifdef HEAPSHOW
674   if (trace_flag) {
675     show_line("AFTER REALLOC: \n", 0);
676 #ifdef HEAPWALK
677     (void) heap_dump(stdout, 1);     /* debugging 96/Jan/18 */
678 #endif
679   }
680 #endif
681   if (mnew != NULL) return mnew;
682 /*  we are screwed typically if we ever drop through here - no more space */
683 /*  *********************************************************************** */
684   mnew = malloc (new_size);          /* otherwise find new space */
685   if (mnew == NULL) return mnew;        /* if unable to allocate */
686   if (old_size < new_size) overlap = old_size;
687   else overlap = new_size;
688   memcpy (mnew, old, overlap);         /* copy old data to new area */
689   free(old);                  /* free the old area */
690   return mnew;
691 }
692 #endif
693
694 void memory_error (char *s, int n)
695 {
696   if (log_opened) {
697     fprintf(log_file, "\n! Unable to allocate %d bytes for %s\n", n, s);
698     show_maximums(log_file);
699 #ifdef HEAPWALK
700     if (heap_flag) (void) heap_dump(log_file, 1);
701 #endif
702   }
703   sprintf(log_line, "\n! Unable to allocate %d bytes for %s\n", n, s);
704   show_line(log_line, 1);
705   show_maximums(stderr);
706 #ifdef HEAPWALK
707   if (heap_flag) (void) heap_dump(stderr, 1);
708 #endif
709 /*  exit (1); */      /* 94/Jan/22 */
710 /*  return to let TeX do its thing (such as complain about runaway) */  
711 /*  don't set abort_flag here */
712 }
713
714 void trace_memory (char *s, int n)
715 {
716   sprintf(log_line, "Allocating %d bytes for %s\n", n, s);
717   show_line(log_line, 0);
718 }
719
720 void update_statistics (int address, int size, int oldsize)
721 {
722   if (address + size > max_address) max_address = address + size;
723   total_allocated =  total_allocated + size - oldsize;
724 }
725
726 void probe_memory (void)
727 {
728   char *s;
729   s = (char *) malloc (4); /* get current top address */
730   free(s);
731   update_statistics ((int) s, 0, 0); /* show where we are */
732 }
733
734 void probe_show (void)
735 {
736   probe_memory();
737   show_maximums(stdout);
738 #ifdef HEAPWALK
739   if (heap_flag) (void) heap_dump(stdout, 1);
740 #endif
741 }
742
743 size_t roundup (size_t n)
744 {
745   if ((n % 4) == 0) return n;
746   else return ((n / 4) + 1) * 4;
747 }
748
749 #ifdef ALLOCATETRIES
750 /* using allocating hyphenation trie slows things down maybe 1%              */
751 /* but saves typically (270k - 55k) = 215k of memory                         */
752 /* NOTE: it's safe to allocate based on the trie_max read from fmt file      */
753 /* since hyphenation trie cannot be extended (after iniTeX)                  */
754 /* for iniTeX, however, we need to allocate the full trie_size ahead of time */
755 /*                                                                           */
756 /* NOTE: we don't ever reallocate these                                      */
757 /* returns -1 if it fails                                                    */
758
759 int allocate_tries (int trie_max)
760 {
761   int n, nl, no, nc;
762 /*  if (trie_max > trie_size) {
763     sprintf(log_line, "ERROR: invalid trie size (%d > %d)\n",
764       trie_max, trie_size);
765       show_line(log_line, 1);
766     exit (1);
767   } */ /* ??? removed 1993/dec/17 */
768   if (trie_max > 1000000) trie_max = 1000000; /* some sort of sanity limit */
769 /*  important + 1 because original was halfword trie_trl[trie_size + 1] etc. */
770   nl = (trie_max + 1) * sizeof(halfword);    /* trie_trl[trie_size + 1] */
771   no = (trie_max + 1) * sizeof(halfword);    /* trie_tro[trie_size + 1] */
772   nc = (trie_max + 1) * sizeof(quarterword); /* trie_trc[trie_size + 1] */
773   n = nl + no + nc;
774   if (trace_flag) trace_memory("hyphen trie", n);
775   trie_trl = (halfword *) malloc (roundup(nl));
776   trie_tro = (halfword *) malloc (roundup(no));
777   trie_trc = (quarterword *) malloc (roundup(nc));
778   if (trie_trl == NULL || trie_tro == NULL || trie_trc == NULL) {
779     memory_error("hyphen trie", n);
780     return -1;
781   }
782   if (trace_flag) {
783     sprintf(log_line, "Addresses trie_trl %d trie_tro %d trie_trc %d\n", trie_trl, trie_tro, trie_trc);
784     show_line(log_line, 0);
785   }
786   update_statistics ((int) trie_trl, nl, 0);
787   update_statistics ((int) trie_tro, no, 0);
788   update_statistics ((int) trie_trc, nc, 0);
789 /*  sprintf(log_line, "trie_size %d trie_max %d\n", trie_size, trie_max); */ /* debug */
790   trie_size = trie_max;           /* BUG FIX 98/Jan/5 */
791   if (trace_flag)  probe_show();     /* 94/Mar/25 */
792   return 0;               // success
793 }
794 #endif
795
796 #ifdef ALLOCATEHYPHEN
797 bool prime (int);       /* test function later in this file */
798
799 int currentprime = 0;         /* remember in case reallocated later */
800
801 /* we don't return an address here, since TWO memory regions allocated */
802 /* plus, we don't really reallocate, we FLUSH the old information totally */
803 /* returns -1 if it fails */
804
805 int realloc_hyphen (int hyphen_prime)
806 {
807   int n, nw, nl;
808   if (!prime(hyphen_prime)) {
809     sprintf(log_line, "ERROR: non-prime hyphen exception number (%d)\n", hyphen_prime); 
810     show_line(log_line, 1);
811 //    exit (1);
812     return -1;
813   }
814 /*  need not/cannot preserve old contents when hyphen prime is changed */
815 /*  if (hyph_list != NULL) free(hyph_list); */
816 /*  if (hyph_word != NULL) free(hyph_word); */
817 /*  important + 1 since str_number hyph_word[hyphen_prime + 1]  in original etc. */
818   nw = (hyphen_prime + 1) * sizeof(str_number);
819   nl = (hyphen_prime + 1) * sizeof(halfword);
820   n = nw + nl;
821   if (trace_flag) trace_memory("hyphen exception", n);
822 /*  initially hyph_word will be NULL so this acts like malloc */
823 /*  hyph_word = (str_number *) malloc (nw); */
824   hyph_word = (str_number *) REALLOC (hyph_word, nw);  /* 94/Mar/24 */
825 /*  initially hyph_list will be NULL so this acts like malloc */
826 /*  hyph_list = (halfword *) malloc (nl); */
827   hyph_list = (halfword *) REALLOC (hyph_list, nl);   /* 94/Mar/24 */
828   if (hyph_word == NULL || hyph_list == NULL) {
829     memory_error("hyphen exception", n);
830     return -1;
831   }
832   if (trace_flag) {
833     sprintf(log_line, "Addresses hyph_word %d hyph_list %d\n", 
834          hyph_word, hyph_list);
835     show_line(log_line, 0);
836   }
837 /*  cannot preserve old contents when hyphen prime is changed */
838 #ifdef USEMEMSET
839   memset(hyph_word, 0, (hyphen_prime + 1) * sizeof (hyph_word[0]));
840 #else
841   for (k = 0; k <= hyphen_prime; k++) hyph_word[k]= 0; 
842 #endif
843 #ifdef USEMEMSET
844   memset(hyph_list, 0, (hyphen_prime + 1) * sizeof (hyph_list[0]));
845 #else
846   for (k = 0; k <= hyphen_prime; k++) hyph_list[k]= 0; 
847 #endif
848   hyph_count = 0;   /* or use reset_hyphen() in itex.c */
849   if (currentprime != 0) {
850     update_statistics ((int) hyph_word, nw, 
851       (currentprime + 1) * sizeof(str_number));
852     update_statistics ((int) hyph_list, nl, 
853       (currentprime + 1) * sizeof(halfword));
854   }
855   else {
856     update_statistics ((int) hyph_word, nw, 0);
857     update_statistics ((int) hyph_list, nl, 0);
858   }
859   currentprime = hyphen_prime;
860   if (trace_flag)  probe_show();     /* 94/Mar/25 */
861   return 0;               // success
862 }
863 #endif
864
865 int current_mem_size=0;   /* current total words in main mem allocated -1 */
866
867 /* this gets called from itex.c when it figures out what mem_top is */
868 /* or gets called from here when in ini_TeX mode */ /* and nowhere else */
869 /* initial allocation only, may get expanded later */
870 /* NOTE: we DON't use ALLOCATEHIGH & ALLOCATELOW anymore */
871 /* returns NULL if it fails */
872
873 #ifdef ALLOCATEMAIN   
874 /* initial main memory alloc - mem_top */
875 memory_word *allocate_main_memory (int size)
876 {
877   int n;
878   
879 /*  Using -i *and* pre-loading format */ /* in this case get called twice */
880 /*  Get rid of initial blank memory again or use realloc ... */
881 /*  Could we avoid this by detecting presence of & before allocating ? */
882 /*  Also, if its already large enough, maybe we can avoid this ? */
883 /*  don't bother if current_mem_size == mem_max - mem_start ? */
884   if (mainmemory != NULL) {
885 /*    free(mainmemory); */
886 /*    mainmemory = NULL; */
887     if (trace_flag) show_line("Reallocating initial memory allocation\n", 1);
888 /*    if (mem_spec_flag)
889   show_line("Cannot change initial main memory size when format is read\n", 1);*/
890   } 
891
892   mem_top = mem_bot + size;
893 #ifdef ALLOCATEHIGH         /* NOT USED ANYMORE */
894   if (mem_extra_high != 0 && !is_initex) mem_max = mem_top + mem_extra_high;  
895 #endif
896   mem_max = mem_top;
897 #ifdef ALLOCATELOW          /* NOT USED ANYMORE */
898   if (mem_extra_low != 0 && !is_initex)
899     mem_start = mem_bot - mem_extra_low;  /* increase main memory */
900 #endif
901   mem_start = 0;     /* bottom of memory allocated by system */
902 /*  mem_min = mem_start; */ /* bottom of area made available to TeX */
903   mem_min = 0;       /* bottom of area made available to TeX */
904   n = (mem_max - mem_start + 1) * sizeof (memory_word); /* 256k * 8 = 2000 k */
905   if (trace_flag) trace_memory("main memory", n);
906 /*  mainmemory = (memory_word *) malloc (n); */  /* 94/March/24 */
907 /*  normally mainmemory == NULL here so acts like malloc ... */
908   mainmemory = (memory_word *) REALLOC (mainmemory, n);
909   if (mainmemory == NULL) {
910     memory_error("initial main memory", n);
911 //    exit (1);             /* serious error */
912     return NULL;
913   }
914   if (trace_flag) {
915     sprintf(log_line, "Address main memory == %d\n", mainmemory);
916     show_line(log_line, 0);
917   }
918   zzzaa = mainmemory;
919   if (mem_start != 0 && !is_initex) zzzaa = mainmemory - mem_start; 
920   if (trace_flag) {
921     sprintf(log_line, "Offset address main memory == %d\n", zzzaa);
922     show_line(log_line, 0);
923   }
924   update_statistics ((int) mainmemory, n,
925     (current_mem_size + 1) * sizeof (memory_word));
926 /*  current_mem_size = (mem_max - mem_start + 1); */
927   current_mem_size = mem_max - mem_start;   /* total number of words - 1 */
928   if (trace_flag)  probe_show();     /* 94/Mar/25 */
929   return zzzaa;             /* same as zmem, mem 94/Jan/24 */
930 }
931 #endif  /* end of ALLOCATEMAIN */
932
933 #ifdef ALLOCATEMAIN
934 /* int firstallocation = 1; */
935
936 /* increase main memory allocation at low end and high end */
937 /* called only from tex0.c *//* called with one of losize or hisize == 0 */
938 /* returns NULL if it fails */
939
940 memory_word *realloc_main (int losize, int hisize)
941 {  
942   int k, minsize;
943   int newsize=0;        /* to quieten compiler */
944   int n=0;          /* to quieten compiler */
945   memory_word *newmemory = NULL; /* to quieten compiler */
946
947 /*  if (losize == 0 && hisize > 0) runawayflag = 1;     
948   else runawayflag = 0; */ /* 94/Jan/22 */
949
950   if (trace_flag) {
951     sprintf(log_line, "WARNING: Entering realloc_main lo %d hi %d\n", losize, hisize);
952     show_line(log_line, 0);
953   }
954   if (is_initex) {
955     show_line("ERROR: Cannot extent main memory in iniTeX\n", 1);
956     if (! knuth_flag) 
957       show_line("Please use `-m=...' on command line\n", 0);
958 //    abort_flag++;  // ???
959     return NULL;
960   }
961   if (trace_flag) {
962     sprintf(log_line, "Old Address %s == %d\n", "main memory", mainmemory);
963     show_line(log_line, 0);
964   }
965   if (current_mem_size + 1 == max_mem_size) {/* if we REALLY run up to limit ! */
966     memory_error("main memory", (max_mem_size + 1) * sizeof(memory_word));
967 //    abort_flag++;  // ???
968     return NULL;
969   }
970 /*  first allocation should expand *both* lo and hi */
971   if (hisize == 0 && mem_end == mem_max) hisize = losize;
972   if (losize == 0 && mem_start == mem_min) losize = hisize;
973 /*  try and prevent excessive frequent reallocations */
974 /*  while avoiding over allocation by too much */
975   minsize = current_mem_size / 100 * percent_grow;
976   if (losize + hisize < minsize) {
977     if (losize > 0 && hisize > 0) {
978       losize = minsize / 2;
979       hisize = minsize / 2;
980     }
981     else if (losize > 0) losize = minsize;
982     else if (hisize > 0) hisize = minsize;
983   }
984   if (losize > 0 && losize < mem_top / 2) losize = mem_top / 2;
985   if (hisize > 0 && hisize < mem_top / 2) hisize = mem_top / 2;
986
987   for (k = 0; k < MAXSPLITS; k++) {
988     newsize = current_mem_size + losize + hisize;
989     if (newsize >= max_mem_size) {    /* bump against limit - ha ha ha */
990       while (newsize >= max_mem_size) {
991         losize = losize / 2; hisize = hisize / 2;
992         newsize = current_mem_size + losize + hisize;
993       }
994     }
995     n = (newsize + 1) * sizeof (memory_word);
996     if (trace_flag) trace_memory("main memory", n);
997     newmemory = (memory_word *) REALLOC (mainmemory, n);
998     if (newmemory != NULL) break; /* did we get it ? */
999     if (current_mem_size == 0) break; /* in case we ever use for initial */
1000     losize = losize / 2; hisize = hisize / 2;
1001   }
1002
1003   if (newmemory == NULL) {
1004     memory_error("main memory", n);
1005     return zzzaa;           /* try and continue with TeX !!! */
1006   }
1007   if (trace_flag) {
1008     sprintf(log_line, "New Address %s == %d\n", "main memory", newmemory);
1009     show_line(log_line, 0);
1010   }
1011   if (losize > 0) {
1012 /*  shift everything upward to make space for new low area */
1013     if (trace_flag) {
1014       sprintf(log_line, "memmove %d %d %d \n", newmemory + losize,
1015           newmemory, (current_mem_size + 1) * sizeof(memory_word));
1016       show_line(log_line, 0);
1017     }
1018     memmove (newmemory + losize, newmemory, 
1019 /*      current_mem_size * sizeof(memory_word));  */
1020       (current_mem_size + 1) * sizeof(memory_word));
1021 /*  could reduce words moved by (mem_max - mem_end) */
1022   }
1023   mainmemory = newmemory;       /* remember for free later */
1024   if (losize > 0) mem_start = mem_start - losize; /* update lower limit */
1025   if (hisize > 0) mem_max = mem_max + hisize;   /* update upper limit */
1026   update_statistics ((int) mainmemory, n,
1027     (current_mem_size + 1) * sizeof (memory_word));
1028   current_mem_size = newsize;
1029   if (current_mem_size != mem_max - mem_start) {
1030     show_line("ERROR: Impossible Memory Error\n", 1);
1031   }
1032   if (mem_start != 0) zzzaa = mainmemory - mem_start; /* ??? sign ??? */
1033   else zzzaa = mainmemory;
1034   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1035   return zzzaa;
1036 }
1037 #endif
1038
1039 #ifdef ALLOCATEFONT
1040 /* font_mem_size = 10000L ==> font_info array 100k * 8 = 800 kilobytes */
1041
1042 int current_font_mem_size=0;
1043
1044 /* fmemoryword can be either halfword or memory_word */
1045 fmemoryword *realloc_font_info (int size)
1046 { /* number of memorywords */
1047   fmemoryword *newfontinfo=NULL;
1048   int k, minsize;
1049   int newsize=0;        /* to quieten compiler */
1050   int n=0;          /* to quieten compiler */
1051
1052   if (trace_flag) {
1053     sprintf(log_line, "Old Address %s == %d\n",  "font_info", font_info);
1054     show_line(log_line, 0);
1055   }
1056 /*  during initial allocation, font_info == NULL - realloc acts like malloc */
1057 /*  during initial allocation current_font_mem_size == 0 */
1058   if (current_font_mem_size == font_mem_size) { /* if we REALLY run up to limit */
1059 /*    memory_error("font", (font_mem_size + 1) * sizeof(memory_word)); */
1060     return font_info;    /* pass it back to TeX 99/Fabe/4 */
1061   }
1062 /*  try and prevent excessive frequent reallocations */
1063 /*  while avoiding over allocation by too much */
1064 /*  minsize = current_font_mem_size / 2; */
1065   minsize = current_font_mem_size / 100 * percent_grow;
1066   if (size < minsize) size = minsize;
1067   if (size < initial_font_mem_size) size = initial_font_mem_size;
1068
1069   for (k=0; k < MAXSPLITS; k++) {
1070     newsize = current_font_mem_size + size;
1071     if (newsize > font_mem_size) newsize = font_mem_size; /* bump against limit */
1072 /*    important + 1 since fmemoryword font_info[font_mem_size + 1]  original */
1073     n = (newsize + 1) * sizeof (fmemoryword);
1074     if (trace_flag) trace_memory("font_info", n);
1075     newfontinfo = (fmemoryword *) REALLOC (font_info, n);
1076     if (newfontinfo != NULL) break;   /* did we get it ? */
1077     if (current_font_mem_size == 0) break; /* initial allocation must work */
1078     size = size / 2;
1079   }
1080
1081   if (newfontinfo == NULL) {
1082     memory_error("font", n);
1083     return font_info;        /* try and continue !!! */
1084   }
1085   font_info = newfontinfo;
1086   if (trace_flag) {
1087     sprintf(log_line, "New Address %s == %d\n", "font_info", font_info);
1088     show_line(log_line, 0);
1089   }
1090   update_statistics ((int) font_info, n, current_font_mem_size * sizeof(fmemoryword));
1091   current_font_mem_size = newsize;
1092   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1093   return font_info;
1094 }
1095 #endif
1096
1097 #ifdef ALLOCATESTRING
1098 int current_pool_size=0;
1099
1100 packed_ASCII_code *realloc_str_pool (int size)
1101 {
1102   int k, minsize;
1103   int newsize=0;
1104   int n=0;
1105   packed_ASCII_code *newstrpool=NULL;
1106
1107   if (trace_flag) {
1108     sprintf(log_line, "Old Address %s == %d\n", "string pool", str_pool);
1109     show_line(log_line, 0);
1110   }
1111   if (current_pool_size == pool_size) {
1112 /*    memory_error ("string pool", (pool_size + 1) * sizeof(packed_ASCII_code)); */
1113 /*    exit (1); */
1114     return str_pool;   /* pass it back to TeX 99/Fabe/4 */
1115   }
1116 /*  minsize =  current_pool_size / 2; */
1117   minsize =  current_pool_size / 100 * percent_grow;
1118   if (size < minsize) size = minsize;
1119   if (size < initial_pool_size) size = initial_pool_size;
1120
1121   for (k = 0; k < MAXSPLITS; k++) {
1122     newsize = current_pool_size + size;
1123     if (newsize > pool_size) newsize = pool_size;
1124 /* important + 1 since  packed_ASCII_code str_pool[pool_size + 1]; in original */
1125     n = (newsize + 1) * sizeof (packed_ASCII_code);
1126     if (trace_flag) trace_memory("str_pool", n);
1127     newstrpool = (packed_ASCII_code *) REALLOC (str_pool, n); /* 95/Sep/24 */
1128     if (newstrpool != NULL) break;    /* did we get it ? */
1129     if (current_pool_size == 0) break;  /* initial allocation must work */
1130     size = size / 2;          /* else can retry smaller */
1131   }
1132
1133   if (newstrpool == NULL) {
1134     memory_error("string pool", n);
1135     return str_pool;           /* try and continue !!! */
1136   }
1137   str_pool = newstrpool;
1138   update_statistics ((int) str_pool, n, current_pool_size);
1139   current_pool_size = newsize;
1140   if (trace_flag) {
1141     sprintf(log_line, "New Address %s == %d\n", "string pool", str_pool);
1142     show_line(log_line, 0);
1143   }
1144   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1145   return str_pool;
1146 }
1147 #endif
1148
1149 #ifdef ALLOCATESTRING
1150 int current_max_strings=0;
1151
1152 pool_pointer *realloc_str_start (int size)
1153 {
1154   int k, minsize;
1155   int n=0;
1156   int newsize=0;
1157   pool_pointer *newstrstart=NULL;
1158
1159   if (trace_flag) {
1160     sprintf(log_line, "Old Address %s == %d\n", "string start", str_start);
1161     show_line(log_line, 0);
1162   }
1163   if (current_max_strings == max_strings) {
1164 /*    memory_error ("string pointer", (max_strings + 1) * sizeof(pool_pointer)); */
1165 /*    exit (1); */
1166     return str_start;    /* pass it back to TeX 99/Fabe/4 */
1167   }
1168 /*  minsize = current_max_strings / 2; */
1169   minsize = current_max_strings / 100 * percent_grow;
1170   if (size < minsize) size = minsize;
1171   if (size < initial_max_strings) size = initial_max_strings;
1172
1173   for (k = 0; k < MAXSPLITS; k++) {
1174     newsize = current_max_strings + size;
1175     if (newsize > max_strings) newsize = max_strings;
1176 /*    important + 1 since str_start[maxstring + 1] originally */
1177     n = (newsize + 1) * sizeof (pool_pointer); 
1178     if (trace_flag) trace_memory("str_start", n);
1179     newstrstart = (pool_pointer *) REALLOC (str_start, n);
1180     if (newstrstart != NULL) break;   /* did we get it ? */
1181     if (current_max_strings == 0) break;  /* initial allocation must work */
1182     size = size / 2;          /* otherwise can try smaller */
1183   }
1184
1185   if (newstrstart == NULL) {
1186     memory_error("string pointer", n);
1187     return str_start;          /* try and continue */
1188   }
1189   str_start = newstrstart;
1190   update_statistics((int) str_start, n, current_max_strings * sizeof (pool_pointer));
1191   current_max_strings = newsize;
1192   if (trace_flag) {
1193     sprintf(log_line, "New Address %s == %d\n", "string start", str_start);
1194     show_line(log_line, 0);
1195   }
1196   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1197   return str_start;
1198 }
1199 #endif
1200
1201 #ifdef ALLOCATEINI
1202
1203 /* returns -1 if it fails */
1204
1205 int allocate_ini (int size)
1206 {    /* size == trie_size */
1207   int n, nl, no, nc, nr, nh, nt;
1208     nh = nr = nl = (size + 1) *  sizeof(trie_pointer);
1209     no = (size + 1) *  sizeof(trie_op_code);
1210     nc = (size + 1) *  sizeof(packed_ASCII_code);
1211 /*    nt = (size + 1) *  sizeof(bool); */
1212     nt = (size + 1) *  sizeof(char);
1213     n = nl + no + nc + nr + nh + nt;
1214 /*    n = (size + 1) * (sizeof(packed_ASCII_code) + sizeof(trie_op_code) +
1215       3 *  sizeof(trie_pointer) + sizeof (char)); */
1216     if (trace_flag) trace_memory ("iniTeX hyphen trie", n);
1217     trie_l = (trie_pointer *) malloc (roundup(nl));
1218     trie_o = (trie_op_code *) malloc (roundup(no));
1219     trie_c = (packed_ASCII_code *) malloc (roundup(nc));
1220     trie_r = (trie_pointer *) malloc (roundup(nr));
1221     trie_hash = (trie_pointer *) malloc (roundup(nh));
1222 /*    trie_taken = (bool *) malloc (nt); */
1223     trie_taken = (char *) malloc (roundup(nt));
1224     if (trie_c == NULL || trie_o == NULL || trie_l == NULL || trie_r == NULL ||
1225       trie_hash == NULL || trie_taken == NULL) {
1226       memory_error("iniTeX hyphen trie", n);
1227 //      exit (1);           /* serious error */     
1228       return -1;
1229     }
1230     if (trace_flag) {
1231       sprintf(log_line, "Addresses trie_l %d trie_o %d trie_c %d\n", 
1232           trie_l, trie_o, trie_c);
1233       show_line(log_line, 0);
1234       sprintf(log_line, "Addresses trie_r %d trie_hash %d trie_taken %d\n", 
1235           trie_r, trie_hash, trie_taken);
1236       show_line(log_line, 0);
1237     }
1238     update_statistics ((int) trie_l, nl, 0);
1239     update_statistics ((int) trie_o, no, 0);
1240     update_statistics ((int) trie_c, nc, 0);
1241     update_statistics ((int) trie_r, nr, 0);
1242     update_statistics ((int) trie_hash, nh, 0);
1243     update_statistics ((int) trie_taken, nt, 0);
1244 /*    trie_size = size; */ /* ??? */
1245     if (trace_flag)  probe_show();     /* 94/Mar/25 */
1246     return 0;               // success
1247 }
1248 #endif
1249
1250 #ifdef ALLOCATESAVESTACK
1251 int current_save_size=0;
1252
1253 memory_word *realloc_save_stack (int size)
1254 {
1255   int k, minsize;
1256   int n=0, newsize=0;
1257   memory_word *newsave_stack=NULL;
1258
1259   if (trace_flag) {
1260     sprintf(log_line, "Old Address %s == %d\n", "save stack", save_stack);
1261     show_line(log_line, 0);
1262   }
1263   if (current_save_size == save_size) {  /* arbitrary limit */
1264 /*    memory_error ("save stack", (save_size + 1) * sizeof(memory_word)); */
1265 /*    exit (1); */
1266     return save_stack;       /* let TeX handle the error */
1267   }
1268   minsize =  current_save_size / 100 * percent_grow;
1269   if (size < minsize) size = minsize;
1270   if (size < initial_save_size) size = initial_save_size;
1271
1272   for (k = 0; k < MAXSPLITS; k++) {
1273     newsize = current_save_size + size;
1274     if (newsize > save_size) newsize = save_size;
1275     n = (newsize + 1) * sizeof (memory_word); /* save_stack[save_size + 1] */
1276     if (trace_flag) trace_memory("save_stack", n);
1277     newsave_stack = (memory_word *) REALLOC (save_stack, n);
1278     if (newsave_stack != NULL) break;    /* did we get it ? */
1279     if (current_save_size == 0) break;  /* initial allocation must work */
1280     size = size / 2;          /* else can retry smaller */
1281   }
1282
1283   if (newsave_stack == NULL) {
1284     memory_error("save stack", n);
1285     return save_stack;           /* try and continue !!! */
1286   }
1287   save_stack = newsave_stack;
1288   update_statistics ((int) save_stack, n, current_save_size);
1289   current_save_size = newsize;
1290   if (trace_flag) {
1291     sprintf(log_line, "Current%s %d\n", "save_size", current_save_size);
1292     show_line(log_line, 0);
1293     sprintf(log_line, "New Address %s == %d\n", "save stack", save_stack);
1294     show_line(log_line, 0);
1295   }
1296   if (trace_flag) probe_show();      /* 94/Mar/25 */
1297   return save_stack;
1298 }
1299 #endif
1300
1301 #ifdef ALLOCATEINPUTSTACK
1302 int current_stack_size=0;       /* input stack size */
1303
1304 in_state_record *realloc_input_stack (int size)
1305 {
1306   int k, minsize;
1307   int n=0, newsize=0;
1308   in_state_record *newinputstack=NULL;
1309
1310   if (trace_flag) {
1311     sprintf(log_line, "Old Address %s == %d\n",  "input stack", input_stack);
1312     show_line(log_line, 0);
1313   }
1314   if (current_stack_size == stack_size) {  /* arbitrary limit */
1315 /*    memory_error ("input stack", (stack_size + 1) * sizeof(in_state_record)); */
1316 /*    exit (1); */
1317     return input_stack;
1318   }
1319   minsize =  current_stack_size / 100 * percent_grow;
1320   if (size < minsize) size = minsize;
1321   if (size < initial_stack_size) size = initial_stack_size;
1322
1323   for (k = 0; k < MAXSPLITS; k++) {
1324     newsize = current_stack_size + size;
1325     if (newsize > stack_size) newsize = stack_size;
1326     n = (newsize + 1) * sizeof (in_state_record); /* input_stack[stack_size + 1] */
1327     if (trace_flag) trace_memory("input_stack", n);
1328     newinputstack = (in_state_record *) REALLOC (input_stack, n);
1329     if (newinputstack != NULL) break;   /* did we get it ? */
1330     if (current_stack_size == 0) break; /* initial allocation must work */
1331     size = size / 2;          /* else can retry smaller */
1332   }
1333
1334   if (newinputstack == NULL) {
1335     memory_error("input stack", n);
1336     return input_stack;            /* try and continue !!! */
1337   }
1338   input_stack = newinputstack;
1339   update_statistics ((int) input_stack, n, current_stack_size);
1340   current_stack_size = newsize;
1341   if (trace_flag) {
1342     sprintf(log_line, "Current%s %d\n", "stack_size", current_stack_size);
1343     show_line(log_line, 0);
1344     sprintf(log_line, "New Address %s == %d\n", "input stack", input_stack);
1345     show_line(log_line, 0);
1346   }
1347   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1348   return input_stack;
1349 }
1350 #endif
1351
1352 #ifdef ALLOCATENESTSTACK
1353 int current_nest_size=0;        /* current nest size */
1354
1355 list_state_record *realloc_nest_stack (int size)
1356 {
1357   int k, minsize;
1358   int n=0, newsize=0;
1359   list_state_record *newnest=NULL;
1360
1361   if (trace_flag) {
1362     sprintf(log_line, "Old Address %s == %d\n",  "nest stack", nest);
1363     show_line(log_line, 0);
1364   }
1365   if (current_nest_size == nest_size) {  /* arbitrary limit */
1366 /*    memory_error ("nest stack", (nest_size + 1) * sizeof(list_state_record)); */
1367 /*    exit (1); */
1368     return nest;        /* let TeX handle the error */
1369   }
1370   minsize =  current_nest_size / 100 * percent_grow;
1371   if (size < minsize) size = minsize;
1372   if (size < initial_nest_size) size = initial_nest_size;
1373
1374   for (k = 0; k < MAXSPLITS; k++) {
1375     newsize = current_nest_size + size;
1376     if (newsize > nest_size) newsize = nest_size;
1377     n = (newsize + 1) * sizeof (list_state_record); /* nest[nest_size + 1] */
1378     if (trace_flag) trace_memory("nest stack", n);
1379     newnest = (list_state_record *) REALLOC (nest, n);
1380     if (newnest != NULL) break;   /* did we get it ? */
1381     if (current_nest_size == 0) break;  /* initial allocation must work */
1382     size = size / 2;          /* else can retry smaller */
1383   }
1384
1385   if (newnest == NULL) {
1386     memory_error("nest stack", n);
1387     return nest;            /* try and continue !!! */
1388   }
1389   nest = newnest;
1390   update_statistics ((int) nest, n, current_nest_size);
1391   current_nest_size = newsize;
1392   if (trace_flag) {
1393     sprintf(log_line, "Current%s %d\n", "nest_size", current_nest_size);
1394     show_line(log_line, 0);
1395     sprintf(log_line, "New Address %s == %d\n", "nest stack", nest);
1396     show_line(log_line, 0);
1397   }
1398   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1399   return nest;
1400 }
1401 #endif
1402
1403 #ifdef ALLOCATEPARAMSTACK
1404 int current_param_size=0;       /* current param size */
1405
1406 halfword *realloc_param_stack (int size)
1407 {
1408   int k, minsize;
1409   int n=0, newsize=0;
1410   halfword *newparam=NULL;
1411
1412   if (trace_flag) {
1413     sprintf(log_line, "Old Address %s == %d\n",  "param stack", param_stack);
1414     show_line(log_line, 0);
1415   }
1416   if (current_param_size == param_size) {  /* arbitrary limit */
1417 /*    memory_error ("param stack", (param_size + 1) * sizeof(halfword)); */
1418 /*    exit (1); */
1419     return param_stack;        /* let TeX handle the error */
1420   }
1421   minsize =  current_param_size / 100 * percent_grow;
1422   if (size < minsize) size = minsize;
1423   if (size < initial_param_size) size = initial_param_size;
1424
1425   for (k = 0; k < MAXSPLITS; k++) {
1426     newsize = current_param_size + size;
1427     if (newsize > param_size) newsize = param_size;
1428     n = (newsize + 1) * sizeof (halfword); /* param_stack[param_size + 1] */
1429     if (trace_flag) trace_memory("param stack", n);
1430     newparam = (halfword *) REALLOC (param_stack, n); 
1431     if (newparam != NULL) break;    /* did we get it ? */
1432     if (current_param_size == 0) break; /* initial allocation must work */
1433     size = size / 2;          /* else can retry smaller */
1434   }
1435
1436   if (newparam == NULL) {
1437     memory_error("param stack", n);
1438     return param_stack;            /* try and continue !!! */
1439   }
1440   param_stack = newparam;
1441   update_statistics ((int) param_stack, n, current_param_size);
1442   current_param_size = newsize;
1443   if (trace_flag) {
1444     sprintf(log_line, "Current%s %d\n", "param_size", current_param_size);
1445     show_line(log_line, 0);
1446     sprintf(log_line, "New Address %s == %d\n", "param stack", param_stack);
1447     show_line(log_line, 0);
1448   }
1449   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1450   return param_stack;
1451 }
1452 #endif
1453
1454 #ifdef ALLOCATEBUFFER
1455 int current_buf_size=0;
1456
1457 ASCII_code *realloc_buffer (int size)
1458 {
1459   int k, minsize;
1460   int n=0, newsize=0;
1461   ASCII_code *newbuffer=NULL;
1462
1463   if (trace_flag) {
1464     sprintf(log_line, "Old Address %s == %d\n", "buffer", buffer);
1465     show_line(log_line, 0);
1466   }
1467   if (current_buf_size == buf_size) {  /* arbitrary limit */
1468 /*    memory_error ("buffer", buf_size); */
1469 /*    exit (1); */
1470     return buffer;    /* pass it back to TeX 99/Fabe/4 */
1471   }
1472   minsize =  current_buf_size / 100 * percent_grow;
1473   if (size < minsize) size = minsize;
1474   if (size < initial_buf_size) size = initial_buf_size;
1475
1476   for (k = 0; k < MAXSPLITS; k++) {
1477     newsize = current_buf_size + size;
1478     if (newsize > buf_size) newsize = buf_size;
1479     n = (newsize + 1) * sizeof(ASCII_code);  /* buffer[buf_size + 1] */
1480     if (trace_flag) trace_memory("buffer", n);
1481     newbuffer = (ASCII_code *) REALLOC (buffer, n);
1482     if (newbuffer != NULL) break;   /* did we get it ? */
1483     if (current_buf_size == 0) break;   /* initial allocation must work */
1484     size = size / 2;          /* else can retry smaller */
1485   }
1486
1487   if (newbuffer == NULL) {
1488     memory_error("buffer", n);
1489     return buffer;            /* try and continue !!! */
1490   }
1491   buffer = newbuffer;
1492   update_statistics ((int) buffer, n, current_buf_size);
1493 #ifdef USEMEMSET
1494   memset(buffer + current_buf_size, 0, newsize - current_buf_size);
1495 #else
1496   for (k = current_buf_size; k < newsize; k++) buffer[k]= 0;
1497 #endif
1498   current_buf_size = newsize;
1499   if (trace_flag) {
1500     sprintf(log_line, "Current%s %d\n", "buffer", current_buf_size);
1501     show_line(log_line, 0);
1502     sprintf(log_line, "New Address %s == %d\n", "buffer", buffer);
1503     show_line(log_line, 0);
1504   }
1505   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1506   return buffer;
1507 }
1508 #endif
1509
1510 /* we used to allocate this one only to reduce the size of the PE file */
1511 /* not used anymore - NO advantage */
1512
1513 #ifdef ALLOCATEDVIBUF
1514 eight_bits *allocatedvibuf (int size)
1515 {
1516   eight_bits *dvi_buf;
1517   int n;
1518
1519   n = (size + 1) * sizeof(eight_bits);
1520   if (trace_flag) trace_memory("dvi_buf", n);
1521   dvi_buf = (eight_bits *) malloc (roundup(n));
1522   if (dvi_buf == NULL) {
1523     memory_error("dvi_buf", n);
1524     return NULL;
1525   }
1526   if (trace_flag) {
1527     sprintf(log_line, "Address dvi_buf %d\n", dvi_buf);
1528     show_line(log_line, 0);
1529   }
1530   update_statistics ((int) dvi_buf, n, 0);
1531   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1532   return dvi_buf;
1533 }
1534 #endif
1535
1536 /* we used to allocate this one only to reduce the size of the PE file */
1537 /* it can be done without loss in performance, since register eqtb = zeqtb */
1538 #ifdef ALLOCATEZEQTB
1539 memory_word *allocatezeqtb (int k)
1540 {
1541   memory_word *zeqtb;
1542   int n;
1543
1544   n = k * sizeof (memory_word);  /* 13507 * 8 = 108 kilobytes */
1545   if (trace_flag)  trace_memory("eqtb", n);
1546   zeqtb = (memory_word *) malloc (roundup(n));
1547   if (zeqtb == NULL)  {
1548     memory_error("eqtb", n);
1549 //    exit (1);           /* serious error */   
1550     return NULL;
1551   }
1552   if (trace_flag) {
1553     sprintf(log_line, "Address zeqtb %d\n", zeqtb);
1554     show_line(log_line, 0);
1555   }
1556   update_statistics ((int) zeqtb, n, 0);
1557   if (trace_flag)  probe_show();     /* 94/Mar/25 */
1558   return zeqtb;
1559 }
1560 #endif
1561
1562 /* here is the main memory allocation routine -- calls the above */
1563 /* returns -1 if it fails */
1564
1565 int allocate_memory (void)
1566 { /* allocate rather than static 93/Nov/26 */
1567 /*  int n;  */
1568 #ifdef PREALLOCHOLE
1569   char *holeadr = malloc (300000);  /* testing - preallocate 95/Jan/20 */
1570 #endif
1571
1572 #ifdef ALLOCATEHASH
1573 #error ERROR: Not ready for ALLOCATEHASH...
1574 #endif
1575
1576 /* probably not worth while/not a good idea allocating following */
1577 /* they are all rather small, and typically don't need expansion */
1578 /* WE ASSUME THIS DOESN'T HAPPEN, SO WON'T BOTHER WITH UPDATESTATISTICS */
1579 #ifdef ALLOCATEHASH
1580 /*  n = 9767 * sizeof (twohalves);  *//* 60 kilo bytes */   
1581 /*  n = (hash_size + 267) * sizeof (twohalves); */  /* 60 kilo bytes */
1582 /*  n = (9767 + eqtb_extra) * sizeof (twohalves); */
1583 #ifdef SHORTHASH
1584   n = (hash_size + 267 + eqtb_extra) * sizeof (htwohalves);   /* 95/Feb/19 */
1585 #else
1586   n = (hash_size + 267 + eqtb_extra) * sizeof (twohalves);  /* 95/Feb/19 */
1587 #endif
1588   if (trace_flag)  trace_memory("hash table", n);
1589 #ifdef SHORTHASH
1590   zzzae = (htwohalves *) malloc (roundup(n));
1591 #else
1592   zzzae = (twohalves *) malloc (roundup(n));
1593 #endif
1594 /*  zzzae = (twohalves *) malloc ((hash_size + 267) * sizeof (twohalves)); */
1595   if (zzzae == NULL)  {
1596     memory_error("hash table", n);
1597 //    exit (1);           /* serious error */
1598     return -1;            /* serious error */
1599   }
1600
1601   n = (inputsize + 1) * sizeof(memory_word);
1602   if (trace_flag)  trace_memory("input_stack", n);
1603 /*  input_stack = (memory_word *) malloc ((inputsize + 1) * sizeof (memory_word)); */
1604   input_stack = (memory_word *) malloc (roundup(n));
1605   if (input_stack == NULL)   {
1606     memory_error("input_stack", n);
1607 //    exit (1);           /* serious error */
1608     return -1;            /* serious error */
1609   }
1610 #endif
1611
1612 /* no real reason to allocate dvi_buf - no need to ever grow it */
1613 #ifdef ALLOCATEDVIBUF
1614 /*  zdvibuf = NULL; */
1615   zdvibuf = allocatedvibuf (dvi_buf_size);
1616   if (zdvibuf == NULL) return -1;
1617 #endif
1618
1619 #ifdef ALLOCATEZEQTB
1620 /*  zeqtb = NULL; */
1621 #ifdef INCREASEFONTS
1622 /*  zeqtb = allocatezeqtb (13507 + eqtb_extra); */  /* 94/Mar/29 */
1623   zeqtb = allocatezeqtb (hash_size + 4007 + eqtb_extra);  /* 94/Mar/29 */
1624 #else
1625 /*  zeqtb = allocatezeqtb (13507); */
1626   zeqtb = allocatezeqtb (hash_size + 4007); 
1627 #endif
1628 #endif
1629
1630 #ifdef ALLOCATEINPUTSTACK
1631   input_stack = NULL;        /* new 1999/Jan/21 */
1632   current_stack_size = 0;
1633   input_stack = realloc_input_stack (initial_stack_size);  /* + 1 */
1634 #endif
1635
1636 #ifdef ALLOCATENESTSTACK
1637   nest = NULL;          /* new 1999/Jan/21 */
1638   current_nest_size = 0;
1639   nest = realloc_nest_stack (initial_nest_size);  /* + 1 */
1640 #endif
1641
1642 #ifdef ALLOCATEPARAMSTACK
1643   param_stack = NULL;          /* new 1999/Jan/21 */
1644   current_param_size = 0;
1645   param_stack = realloc_param_stack (initial_param_size); /* + 1 */
1646 #endif
1647
1648 #ifdef ALLOCATESAVESTACK
1649   save_stack = NULL;       /* new 1999/Jan/7 */
1650   current_save_size = 0;
1651   save_stack = realloc_save_stack (initial_save_size);
1652 #endif
1653
1654 #ifdef IGNORED
1655   buffer = NULL;        /* need to do earlier */
1656   current_buf_size = 0;
1657   buffer = realloc_buffer (initial_buf_size);
1658 #endif
1659
1660 #ifdef ALLOCATESTRING
1661   str_pool = NULL;
1662   current_pool_size = 0;
1663   str_start = NULL;
1664   current_max_strings = 0;
1665 /*  need to create space because iniTeX writes in before reading pool file */
1666 /*  for a start, puts in strings for 256 characters */
1667 /*  maybe taylor allocations to actual pool file 1300 strings 27000 bytes ? */
1668   if (is_initex) {
1669     if (trace_flag) show_line("ini TeX pool and string allocation\n", 0);
1670     str_pool = realloc_str_pool (initial_pool_size); 
1671     str_start = realloc_str_start (initial_max_strings);
1672   }
1673 #endif
1674
1675 /* the following can save a lot of the usual 800k fixed allocation */
1676 #ifdef ALLOCATEFONT
1677   font_info = NULL;
1678   current_font_mem_size = 0;
1679 /*  if not iniTeX, then do initial allocation on fmt file read in itex.c */
1680 /*  if ini-TeX we need to do it here - no format file read later */
1681   if (is_initex) font_info = realloc_font_info (initial_font_mem_size);
1682 #endif
1683     
1684 #ifdef ALLOCATEMAIN
1685   mainmemory = NULL;
1686   zzzaa = NULL;
1687   mem_min = mem_bot;        /* just to avoid complaints in texbody */
1688   mem_top = mem_initex;
1689   mem_max = mem_top;
1690 /*  allocate main memory here if this is iniTeX */
1691 /*  otherwise wait for format undumping in itex.c ... */  
1692   if (is_initex) {
1693 /*    avoid this if format specified on command line ??? */
1694 /*    allocate_main_memory(mem_initex); */   /* made variable ! */
1695     mem = allocate_main_memory(mem_initex);  /* made variable ! */
1696     if (mem == NULL)
1697 //      exit (1);
1698       return -1;            /* serious error */
1699   }
1700 #endif
1701
1702 /* now for the hyphenation exception stuff */
1703 #ifdef ALLOCATEHYPHEN
1704   hyph_word = NULL;
1705   hyph_list = NULL;
1706 /*  this will be overridden later by what is in format file */
1707   hyphen_prime = default_hyphen_prime;
1708 /*  non ini-TeX use assumes format will be read and that specifies size */
1709   if (is_initex) {
1710     if (new_hyphen_prime) hyphen_prime = new_hyphen_prime;
1711     if (realloc_hyphen (hyphen_prime)) /* allocate just in case no format */
1712       return -1;
1713   }
1714 #endif
1715
1716 /*  now for memory for the part of the hyphenation stuff that always needed */
1717 /*  if iniTeX, need to allocate pre-determined fixed amount - trie_size */
1718 /*  if iniTeX not selected, allocate only enough later - undump in itex.c ! */
1719 #ifdef ALLOCATETRIES
1720   if (is_initex) {
1721     if (allocate_tries (trie_size)) return -1;
1722   }
1723 #endif
1724
1725 /*  now for memory for hyphenation stuff needed only when running iniTeX */
1726 #ifdef ALLOCATEINI
1727   if (is_initex) {
1728     if (allocate_ini(trie_size)) return -1;
1729   }
1730   else {
1731     trie_l = trie_r = trie_o = trie_hash = NULL; /* (trie_size + 1) * integer */
1732     trie_c = NULL;       /* (trie_size + 1) * char */
1733     trie_taken = NULL;     /* (trie_size + 1) * bool */
1734   }
1735 #endif
1736 #ifdef PREALLOCHOLE
1737   free(holeadr);          /* create the hole */
1738 #endif
1739   return 0;           // success
1740 }
1741
1742 /* returns non-zero if error - done to test integrity of stack mostly */
1743
1744 int free_memory (void)
1745 {     /* free in reverse order 93/Nov/26 */
1746   int n;
1747   unsigned heaptotal=0;
1748 /*  unsigned total; */
1749
1750   if (trace_flag) show_line("free_memory ", 0);
1751
1752 #ifdef CHECKEQTB
1753   if (debug_flag) check_eqtb("free_memory");
1754 #endif
1755   if (verbose_flag || trace_flag) show_maximums(stdout); 
1756 #ifdef HEAPWALK
1757   if (heap_flag) (void) heap_dump(stdout, 1);
1758 #endif
1759   if (trace_flag) {
1760 #ifdef HEAPWALK
1761     heaptotal = (void) heap_dump(stdout, 0);
1762 #endif
1763     sprintf(log_line, "Heap total: %u bytes --- max address %u\n", 
1764         heaptotal, max_address);
1765     show_line(log_line, 0);
1766   }
1767   if (trace_flag) {
1768     sprintf(log_line, "Main Memory: variable node %d (%d - %d) one word %d (%d - %d)\n",
1769       lo_mem_max - mem_min, mem_min, lo_mem_max, mem_end  - hi_mem_min, hi_mem_min, mem_end);
1770     show_line(log_line, 0);
1771   }
1772 /*  following only needed to check consistency of heap ... useful debugging */
1773   if (trace_flag) show_line("Freeing memory again\n", 0);
1774
1775 /*  if (trace_flag)
1776     show_line(log_line, "Zero Glue Reference Count %d\n", mem[0].hh.v.RH); */
1777
1778 /*  the following checks the heap integrity */
1779
1780 /*  if ((n = _heapchk ()) != _HEAPOK) { */      /* 94/Feb/18 */
1781   n = _HEAPOK;
1782 #ifdef SHOWHEAPERROR
1783   n = _heapchk();
1784   if (n != _HEAPOK) {     /* 94/Feb/18 */
1785     sprintf(log_line, "WARNING: Heap corrupted (%d)\n", n);
1786     show_line(log_line, 1);
1787     sprintf(log_line, "HEAP %s (%s)\n", heapstrings[-n], "free_memory");
1788     show_line(log_line, 0);
1789     return n;   /* non-zero and negative */ /* unreachable ??? */
1790   }
1791 #endif
1792 /*  only free memory if safe ... additional check */
1793 #ifdef ALLOCATEINI
1794   if (is_initex) {
1795     if (trie_taken != NULL) free(trie_taken);
1796     if (trie_hash != NULL) free(trie_hash);
1797     if (trie_r != NULL) free(trie_r);
1798     if (trie_c != NULL) free(trie_c);
1799     if (trie_o != NULL) free(trie_o);
1800     if (trie_l != NULL) free(trie_l);
1801     trie_taken = NULL;
1802     trie_hash = trie_l = trie_r = NULL;
1803     trie_c = NULL;
1804     trie_o = NULL;
1805   }
1806 #endif  
1807 #ifdef ALLOCATETRIES
1808   if (trie_trc != NULL) free (trie_trc);
1809   if (trie_tro != NULL) free (trie_tro);
1810   if (trie_trl != NULL) free (trie_trl);
1811   trie_trc = NULL;
1812   trie_tro = trie_trl = NULL;
1813 #endif
1814 #ifdef ALLOCATEHYPHEN
1815   if (hyph_list != NULL) free(hyph_list);
1816   if (hyph_word != NULL) free(hyph_word);
1817   hyph_list = NULL;
1818   hyph_word = NULL;
1819 #endif
1820 #ifdef ALLOCATEMAIN
1821 /*  if (zzzaa != NULL) free(zzzaa); */  /* NO: zzzaa may be offset ! */
1822   if (mainmemory != NULL) free(mainmemory);
1823   mainmemory = NULL;
1824 #endif
1825 #ifdef ALLOCATEFONT
1826   if (font_info != NULL) free(font_info);
1827   font_info = NULL;
1828 #endif
1829 #ifdef ALLOCATESTRING
1830   if (str_start != NULL) free(str_start);
1831   if (str_pool != NULL) free(str_pool);
1832   str_start = NULL;
1833   str_pool = NULL;
1834 #endif
1835
1836 #ifdef ALLOCATEHASH
1837   if (zzzae != NULL) free(zzzae);
1838   zzzae = NULL;
1839 #endif
1840
1841 #ifdef ALLOCATEDVIBUF
1842   if (zdvibuf != NULL) free(zdvibuf);
1843   zdvibuf = NULL;
1844 #endif
1845 #ifdef ALLOCATEZEQTB
1846   if (zeqtb != NULL) free(zeqtb);
1847   zeqtb = NULL;
1848 #endif
1849
1850 #ifdef ALLOCATEPARAMSTACK
1851   if (param_stack != NULL) free(param_stack);
1852   param_stack = NULL;
1853 #endif
1854 #ifdef ALLOCATENESTSTACK
1855   if (nest != NULL) free(nest);
1856   nest = NULL;
1857 #endif
1858 #ifdef ALLOCATEINPUTSTACK
1859   if (input_stack != NULL) free(input_stack);
1860   input_stack = NULL;
1861 #endif
1862 #ifdef ALLOCATESAVESTACK
1863   if (save_stack != NULL) free(save_stack);
1864   save_stack = NULL;
1865 #endif
1866 /*  if (buffercopy != NULL) free (buffercopy); */ /* 94/Jun/27 */
1867   if (format_file != NULL) free(format_file);   /* 96/Jan/16 */
1868   if (string_file != NULL) free(string_file);   /* 96/Jan/16 */
1869   if (source_direct != NULL) free(source_direct); /* 98/Sep/29 */
1870   format_file = string_file = source_direct = NULL;
1871   if (dvi_file_name != NULL) free(dvi_file_name);
1872   if (log_file_name != NULL) free(log_file_name);
1873   log_file_name = dvi_file_name = NULL;       /* 00/Jun/18 */
1874   return 0;
1875 }
1876
1877 bool prime (int x)
1878 {
1879   int k;
1880   int sum = 1;    /* 1 + 3 + 5 + k = (k + 1) * (k + 1) / 4 */
1881   if (x % 2 == 0) return false;
1882   for (k = 3; k < x; k = k + 2) {
1883     if (x % k == 0) return false;
1884 /*    if (k * k > x) return true; */
1885     if (sum * 4 > x) return true;
1886     sum += k;
1887   }
1888   return true;
1889 }
1890
1891 int quitflag=0;
1892 bool show_use=false;
1893 bool floating=false;
1894
1895 void complainarg (int c, char *s)
1896 {
1897   sprintf(log_line, "ERROR: Do not understand `%c' argument value `%s'\n", c, s);
1898   show_line(log_line, 1);
1899   show_use = 1;           // 2000 June 21
1900 }
1901
1902 /* following is list of allowed command line flags and args */
1903
1904 /* char *allowedargs="+vitrdcyzpsqnwbfXABCDFGKLMNOQRSTYWZ?g=m=u=e=o=a=x=k=h=l=u=E=H="; */
1905
1906 /* only  01234567.9 still left to take ... maybe recycle u */
1907
1908 char *allowedargs="+bcdfijnpqrstvwyzABCDFGIJKLMNOPQRSTVWXYZ23456789?a=e=g=h=k=l=m=o=u=x=E=H=P=U=";
1909
1910 /* char takeargs="gmueoazhluEH"; */ /* subset that takes args! needed here */
1911
1912 void reorderargs (int ac, char **av)
1913 {      /* put in 1993/Dec/28 */
1914   int n, m;
1915   char *s, *t;
1916 //  char takeargs[128];   /* large enough for all command line arg chars */
1917   char takeargs[256];   /* large enough for all command line arg chars */
1918
1919 /*  assumes arg pointers av[] are writeable */
1920 /*  for (n = 1; n < ac; n++) sprintf(log_line, "%s ", av[n]); */
1921
1922   if (ac < 3) { /* need more than one arg to reorder anything 94/Feb/25 */
1923 /*    show_line("No arguments?\n", 0); */  /* debugging */
1924     return;             /* no args ! */
1925   }
1926
1927   s = allowedargs;
1928   t = takeargs;   /* list of those that take args */
1929   while (*s != '\0' && *(s+1) != '\0') {
1930     if (*(s+1) == '=') *t++ = *s++;   /* copy over --- without the = */
1931     s++;
1932   }
1933   *t = '\0';
1934   if (trace_flag) {
1935     show_line(takeargs, 0);
1936     show_char('\n');
1937   }
1938   
1939   n = 1;
1940   for (;;) {              /* scan to end of command line args */
1941     if (*av[n] != '-') break;
1942 /*    does it take an argument ? and is this argument next ? */
1943     if (n+1 < ac &&
1944       *(av[n]+2) == '\0' &&
1945 /*        strchr("gmuhleoxE", *(av[n]+1)) != NULL) */
1946         strchr(takeargs, *(av[n]+1)) != NULL)
1947           n += 2; /* step over it */
1948     else n++;
1949     if (n == ac) break;
1950   }
1951
1952   for (;;) {              /* look for more command line args */
1953     if (n == ac) break;
1954     m = n;
1955 /*    while (*av[m] != '-' && m < ac) m++; */ /* first command */
1956     while (m < ac && *av[m] != '-') m++;  /* first command */
1957     if (m == ac) break;
1958 /* does it take an argument ? and is this argument next ? */
1959 /* check first whether the `-x' is isolated, or arg follows directly */
1960 /* then check whether this is one of those that takes an argument */
1961     if (m+1 < ac &&
1962       *(av[m]+2) == '\0' &&
1963         strchr(takeargs, *(av[m]+1)) != NULL) {
1964       s = av[m];      /*  move command down before non-command */
1965       t = av[m+1];
1966       for (; m > n; m--)  av[m+1] = av[m-1];
1967       av[n] = s;
1968       av[n+1] = t;
1969       n += 2;       /* step over moved args */
1970     }
1971     else {
1972       s = av[m];      /*  move command down before non-command */
1973       for (; m > n; m--)  av[m] = av[m-1];
1974       av[n] = s;
1975       n++;        /* step over moved args */
1976     }
1977   }
1978 }
1979
1980 int testalign (int address, int size, char *name)
1981 {
1982   int n;
1983   if (size > 4) n = address % 4;
1984   else n = address % size;
1985   if (n != 0) {
1986     sprintf(log_line, "OFFSET %d (ELEMENT %d) in %s\n", n, size, name);
1987     show_line(log_line, 0);
1988   }
1989   return n;
1990 }
1991
1992 /* activate detailed checking of alignment when trace_flag is set */
1993
1994 void check_fixed_align (int flag)
1995 {
1996   if (testalign ((int) &mem_top, 4, "FIXED ALIGNMENT")) {
1997     show_line("PLEASE RECOMPILE ME!\n", 1);
1998   }
1999 #ifdef CHECKALIGNMENT
2000   if (!flag) return;
2001   testalign ((int) &mem_top, 4, "mem_top");
2002   testalign ((int) &mem_max, 4, "mem_max");
2003   testalign ((int) &mem_min, 4, "mem_min");
2004   testalign ((int) &bad, 4, "bad");
2005   testalign ((int) &trie_size, 4, "trie_size");
2006   testalign ((int) &xord, sizeof(xord[0]), "xord"); /* no op */
2007   testalign ((int) &xchr, sizeof(xchr[0]), "xchr"); /* no op */
2008   testalign ((int) &name_length, 4, "name_length");
2009   testalign ((int) &first, 4, "first");
2010   testalign ((int) &last, 4, "last");
2011   testalign ((int) &max_buf_stack, 4, "max_buf_stack");
2012   testalign ((int) &pool_ptr, 4, "pool_ptr");
2013   testalign ((int) &str_ptr, 4, "str_ptr");
2014   testalign ((int) &init_pool_ptr, 4, "init_pool_ptr");
2015   testalign ((int) &init_str_ptr, 4, "init_str_ptr");
2016   testalign ((int) &log_file, 4, "log_file");
2017   testalign ((int) &tally, 4, "tally");
2018   testalign ((int) &term_offset, 4, "term_offset");
2019   testalign ((int) &file_offset, 4, "file_offset");
2020   testalign ((int) &trick_count, 4, "trick_count");
2021   testalign ((int) &first_count, 4, "first_count");
2022   testalign ((int) &deletions_allowed, 4, "deletions_allowed");
2023   testalign ((int) &set_box_allowed, 4, "set_box_allowed");
2024   testalign ((char *) &help_line, sizeof(help_line[0]), "help_line");
2025   testalign ((int) &use_err_help, 4, "use_err_help");
2026   testalign ((int) &interrupt, 4, "interrupt");
2027   testalign ((int) &OK_to_interrupt, 4, "OK_to_interrupt");
2028   testalign ((int) &arith_error, 4, "arith_error");
2029   testalign ((int) &tex_remainder, 4, "tex_remainder");
2030   testalign ((int) &temp_ptr, 4, "temp_ptr");
2031   testalign ((int) &lo_mem_max, 4, "lo_mem_max");
2032   testalign ((int) &hi_mem_min, 4, "hi_mem_min");
2033   testalign ((int) &var_used, 4, "var_used");
2034   testalign ((int) &dyn_used, 4, "dyn_used");
2035   testalign ((int) &avail, 4, "avail");
2036   testalign ((int) &mem_end, 4, "mem_end");
2037   testalign ((int) &mem_start, 4, "mem_start");
2038   testalign ((int) &rover, 4, "rover");
2039   testalign ((int) &font_in_short_display, 4, "font_in_short_display");
2040   testalign ((int) &depth_threshold, 4, "depth_threshold");
2041   testalign ((int) &breadth_max, 4, "breadth_max");
2042   testalign ((int) &nest, sizeof(nest[0]), "nest");
2043
2044 #ifdef ALLOCZEQTB
2045   testalign ((int) &zeqtb, sizeof(zeqtb[0]), "zeqtb");  /* not any more ? */
2046 #endif
2047 /*  testalign ((int) &xeq_level, sizeof(xeq_level[0]), "xeq_level"); */
2048   testalign ((int) &zzzad, sizeof(zzzad[0]), "zzzad");
2049 /*  testalign ((int) &hash, sizeof(hash[0]), "hash"); */
2050   testalign ((int) &zzzae, sizeof(zzzae[0]), "zzzae");
2051
2052   testalign ((int) &save_stack, sizeof(save_stack[0]), "save_stack");
2053   testalign ((int) &input_stack, sizeof(input_stack[0]), "input_stack");
2054   testalign ((int) &input_file, sizeof(input_file[0]), "input_file");
2055   testalign ((int) &line_stack, sizeof(line_stack[0]), "line_stack");
2056   testalign ((int) &param_stack, sizeof(param_stack[0]), "param_stack");
2057   testalign ((int) &cur_mark, sizeof(cur_mark[0]), "cur_mark");
2058   testalign ((int) &pstack, sizeof(pstack[0]), "pstack");
2059   testalign ((int) &read_file, sizeof(read_file[0]), "read_file");
2060
2061   testalign ((int) &font_check, sizeof(font_check[0]), "font_check");
2062   testalign ((int) &font_size, sizeof(font_size[0]), "font_size");
2063   testalign ((int) &font_dsize, sizeof(font_dsize[0]), "font_dsize");
2064   testalign ((int) &font_params, sizeof(font_params[0]), "font_params");
2065   testalign ((int) &font_name, sizeof(font_name[0]), "font_name");
2066   testalign ((int) &font_area, sizeof(font_area[0]), "font_area");
2067   testalign ((int) &font_bc, sizeof(font_bc[0]), "font_bc");
2068   testalign ((int) &font_ec, sizeof(font_ec[0]), "font_ec");
2069   testalign ((int) &font_glue, sizeof(font_glue[0]), "font_glue");
2070   testalign ((int) &font_used, sizeof(font_used[0]), "font_used");
2071   testalign ((int) &hyphen_char, sizeof(hyphen_char[0]), "hyphen_char");
2072   testalign ((int) &skew_char, sizeof(skew_char[0]), "skew_char");
2073   testalign ((int) &bchar_label, sizeof(bchar_label[0]), "bchar_label");
2074   testalign ((int) &font_bchar, sizeof(font_bchar[0]), "font_bchar");
2075   testalign ((int) &font_false_bchar, sizeof(font_false_bchar[0]), "font_false_bchar");
2076   testalign ((int) &char_base, sizeof(char_base[0]), "char_base");
2077   testalign ((int) &width_base, sizeof(width_base[0]), "width_base");
2078   testalign ((int) &height_base, sizeof(height_base[0]), "height_base");
2079   testalign ((int) &depth_base, sizeof(depth_base[0]), "depth_base");
2080   testalign ((int) &italic_base, sizeof(italic_base[0]), "italic_base");
2081   testalign ((int) &lig_kern_base, sizeof(lig_kern_base[0]), "lig_kern_base");
2082   testalign ((int) &kern_base, sizeof(kern_base[0]), "kern_base");
2083   testalign ((int) &exten_base, sizeof(exten_base[0]), "exten_base");
2084   testalign ((int) &param_base, sizeof(param_base[0]), "param_base");
2085
2086 #ifdef ALLOCATEDVIBUF
2087   testalign ((int) &zdvibuf, sizeof(zdvibuf[0]), "zdvibuf"); /* no op */
2088 #endif
2089   testalign ((int) &totalstretch, sizeof(totalstretch[0]), "totalstretch");
2090   testalign ((int) &totalshrink, sizeof(totalshrink[0]), "totalshrink");
2091   testalign ((int) &active_width, sizeof(active_width[0]), "active_width");
2092   testalign ((int) &cur_active_width, sizeof(cur_active_width[0]), "cur_active_width");
2093   testalign ((int) &background, sizeof(background[0]), "background");
2094   testalign ((int) &break_width, sizeof(break_width[0]), "break_width");
2095   testalign ((int) &minimal_demerits, sizeof(minimal_demerits[0]), "minimal_demerits");
2096   testalign ((int) &best_place, sizeof(best_place[0]), "best_place");
2097   testalign ((int) &best_pl_line, sizeof(best_pl_line[0]), "best_pl_line");
2098   testalign ((int) &hc, sizeof(hc[0]), "hc");
2099   testalign ((int) &hu, sizeof(hu[0]), "hu");
2100   testalign ((int) &hyf, sizeof(hyf[0]), "hyf");
2101 /*  testalign ((int) &x, sizeof(x[0]), "x"); */
2102
2103   testalign ((int) &hyf_distance, sizeof(hyf_distance[0]), "hyf_distance");
2104   testalign ((int) &hyf_num, sizeof(hyf_num[0]), "hyf_num");
2105   testalign ((int) &hyf_next, sizeof(hyf_next[0]), "hyf_next");
2106   testalign ((int) &op_start, sizeof(op_start[0]), "op_start");
2107
2108 /*  testalign ((int) &trie_op_hash, sizeof(trie_op_hash[0]), "trie_op_hash"); */
2109   testalign ((int) &zzzaf, sizeof(zzzaf[0]), "zzzaf");
2110   testalign ((int) &trie_used, sizeof(trie_used[0]), "trie_used");
2111 /*  testalign ((int) &trie_op_lang, sizeof(trie_op_lang[0]), "trie_op_lang");*/
2112   testalign ((int) &trie_op_val, sizeof(trie_op_val[0]), "trie_op_val");
2113
2114   testalign ((int) &trie_min, sizeof(trie_min[0]), "trie_min");
2115   testalign ((int) &page_so_far, sizeof(page_so_far[0]), "page_so_far");
2116   testalign ((int) &write_file, sizeof(write_file[0]), "write_file");
2117   testalign ((int) &write_open, sizeof(write_open[0]), "write_open");
2118 #endif
2119 }
2120
2121 void check_alloc_align (int flag) {
2122   if (testalign ((int) eqtb, sizeof(eqtb[0]), "ALLOCATED ALIGNMENT"))
2123     show_line("PLEASE RECOMPILE ME!\n", 1);
2124 #ifdef CHECKALIGNMENT
2125   if (!flag) return;
2126 #ifndef ALLOCZEQTB
2127   testalign ((int) zeqtb, sizeof(zeqtb[0]), "zeqtb"); 
2128 #endif
2129 #ifndef ALLOCATEDVIBUF
2130   testalign ((int) &zdvibuf, sizeof(zdvibuf[0]), "zdvibuf");  /* no op */
2131 #endif
2132   testalign ((int) str_pool, sizeof(str_pool[0]), "str_pool"); /* no op */
2133   testalign ((int) str_start, sizeof(str_start[0]), "str_start");
2134   testalign ((int) zmem, sizeof(zmem[0]), "main memory");
2135   testalign ((int) font_info, sizeof(font_info[0]), "font memory");
2136   testalign ((int) trie_trl, sizeof(trie_trl[0]), "trie_trl");
2137   testalign ((int) trie_tro, sizeof(trie_tro[0]), "trie_tro");
2138   testalign ((int) trie_trc, sizeof(trie_trc[0]), "trie_trc");
2139   testalign ((int) hyph_word, sizeof(hyph_word[0]), "hyph_word");
2140   testalign ((int) hyph_list, sizeof(hyph_list[0]), "hyph_list");
2141 /*  testalign ((int) trie_c, sizeof(trie_c[0]), "trie_c"); *//* no op */
2142   testalign ((int) trie_o, sizeof(trie_o[0]), "trie_o");
2143   testalign ((int) trie_l, sizeof(trie_l[0]), "trie_l");
2144   testalign ((int) trie_r, sizeof(trie_r[0]), "trie_r");
2145   testalign ((int) trie_hash, sizeof(trie_hash[0]), "trie_hash");
2146   testalign ((int) trie_taken, sizeof(trie_taken[0]), "trie_taken");
2147 #endif
2148 }
2149
2150 #ifdef HEAPSHOW
2151 void showaddresses (void)
2152 {         /* 96/Jan/20 */
2153   int c;
2154   int d;
2155   sprintf(log_line, "STACK %d %d (grows %s) ", &c, &d, (&d > &c) ? "upward" : "downward");
2156   show_line(log_line, 0);
2157   sprintf(log_line, "eqtb %d hash %d ", zeqtb, zzzae);
2158   show_line(log_line, 0);
2159   sprintf(log_line, "dvi_buf %d xchr %d xord %d nest %d\n",
2160       zdvibuf, xchr, xord, nest);
2161   show_line(log_line, 0);
2162   sprintf(log_line, "save_stack %d input_stack %d line_stack %d param_stack %d\n",
2163        save_stack, input_stack, line_stack, param_stack);
2164   show_line(log_line, 0);
2165   sprintf(log_line, "font_check %d font_size %d font_dsize %d font_params %d font_name %d\n",
2166        font_check, font_size, font_dsize, font_params, font_name);
2167   show_line(log_line, 0);
2168   sprintf(log_line, "main %d font_info %d str_pool %d str_start %d hyph_word %d hyph_list %d\n",
2169       zmem, font_info, str_pool, str_start, hyph_word, hyph_list);
2170   show_line(log_line, 0);
2171 }
2172 #endif
2173
2174 /* *** *** *** *** *** *** *** NEW APPROACH TO `ENV VARS' *** *** *** *** */
2175
2176 /* grab `env var' from `dviwindo.ini' - or from DOS environment 94/May/19 */
2177 /* controlled by USEDVIWINDOINI environment variable 94/June/19 */
2178
2179 bool usedviwindo = true;    /* use [Environment] section in `dviwindo.ini' */
2180 bool backwardflag = false;           /* don't cripple all advanced features */
2181 bool shorten_file_name = false;        /* don't shorten file names to 8+3 for DOS */
2182 char *inifilename = "dviwindo.ini";   /* name of ini file we look for */
2183 char *dviwindo = "";      /* full file name for dviwindo.ini with path */
2184 char *envsection = "[Environment]";   /* Env var section in `dviwindo.ini' */
2185 char *wndsection = "[Window]";      /* Window section in `dviwindo.ini' */
2186 char *workdirect = "WorkingDirectory";  /* key in [Window] section */
2187 bool usesourcedirectory = true;   /* use source file directory as local */
2188                     /* when WorkingDirectory is set */
2189 bool workingdirectory = false;    /* if working directory set in ini */
2190 /* set up full file name for dviwindo.ini and check for [Environment] */
2191
2192 bool setupdviwindo (void)
2193 { /* set up full file name for dviwindo.ini */
2194   char dviwindoini[PATH_MAX];
2195   char line[PATH_MAX];
2196   FILE *pinput;
2197   char *windir;
2198   int em = strlen(envsection);
2199   int wm = strlen(wndsection);
2200   int dm = strlen(workdirect);
2201   int wndflag = 0;
2202   int envflag = 0;
2203
2204 /*  Easy to find Windows directory if Windows runs */
2205 /*  Or if user kindly set WINDIR environment variable */
2206 /*  Or if running in Windows NT */  
2207   if ((windir = getenv("windir")) != NULL ||    /* 94/Jan/22 */
2208     (windir = getenv("WINDIR")) != NULL ||
2209     (windir = getenv("winbootdir")) != NULL ||  /* 95/Aug/14 */
2210     (windir = getenv("SystemRoot")) != NULL ||  /* 95/Jun/23 */
2211     (windir = getenv("SYSTEMROOT")) != NULL) {  /* 95/Jun/23 */
2212     strcpy(dviwindoini, windir);
2213     strcat(dviwindoini, "\\");
2214     strcat(dviwindoini, inifilename);
2215 /*    sprintf(log_line, "Using WINDIR %s\n", dviwindoini); */
2216   }
2217   else {
2218     _searchenv (inifilename, "PATH", dviwindoini);
2219 /*    sprintf(log_line, "Using SEARCHENV %s\n", dviwindoini); */
2220   }
2221
2222   wndflag = envflag = 0;
2223 /*  workingdirectory = false; */
2224   if (*dviwindoini != '\0') {
2225     dviwindo = xstrdup(dviwindoini);    /* avoid PATH_MAX string */
2226 /*    check whether dviwindo.ini actually has [Environment] section */
2227     if (share_flag == 0) pinput = fopen(dviwindo, "r");
2228     else pinput = _fsopen(dviwindo, "r", share_flag);
2229     if (pinput != NULL) {
2230       while (fgets (line, sizeof(line), pinput) != NULL) {
2231         if (*line == ';') continue;
2232         if (*line == '\n') continue;
2233         if (*line == '[') {
2234           if (wndflag && envflag) break;  /* escape early */
2235         }
2236         if (_strnicmp(line, wndsection, wm) == 0) {
2237           if (trace_flag) {
2238             sprintf(log_line, "Found %s", line);  /* DEBUGGING */
2239             show_line(log_line, 0);
2240           }
2241           wndflag++;
2242         }
2243         else if (_strnicmp(line, envsection, em) == 0) {
2244           if (trace_flag) {
2245             sprintf(log_line, "Found %s", line);  /* DEBUGGING */
2246             show_line(log_line, 0);
2247           }
2248 /*          fclose(input); */
2249 /*          return true; */
2250           envflag++;
2251         } else if (wndflag && _strnicmp(line, workdirect, dm) == 0) {
2252           if (trace_flag) {
2253             sprintf(log_line, "Found %s", line);  /* DEBUGGING */
2254             show_line(log_line, 0);
2255           }
2256           workingdirectory = true;
2257         }
2258       }
2259       if (envflag) {
2260         (void) fclose(pinput); 
2261         return true;
2262       }
2263       if (trace_flag)
2264         show_line("Failed to find [Environment]", 1); /* DEBUGGING */
2265       (void) fclose(pinput);
2266     }
2267     else if (trace_flag) perrormod(dviwindo);  /* DEBUGGING */
2268     strcpy(dviwindo, ""); /* failed, for one reason or another */
2269   }
2270   return false;
2271 }
2272
2273 /* cache to prevent allocating twice in a row */
2274
2275 char *lastname=NULL, *lastvalue=NULL;
2276
2277 /* get value of env var - try first in dviwindo.ini then DOS env */
2278 /* returns allocated string -- these strings are not freed again */
2279 /* is it safe to do that now ? 98/Jan/31 */
2280 char *grabenv (char *varname)
2281 {
2282   char line[PATH_MAX];
2283   FILE *pinput;
2284   char *s;
2285   int m, n;
2286 /*  int m = strlen(envsection); */
2287 /*  int n = strlen(varname); */
2288
2289   if (varname == NULL) return NULL;   /* sanity check */
2290   if (*varname == '\0') return NULL;    /* sanity check */
2291 /*  speedup to avoid double lookup when called from set_paths in ourpaths.c */
2292 /*  if (lastname != NULL && strcmp(lastname, varname) == 0) { */
2293   if (lastname != NULL && _strcmpi(lastname, varname) == 0) {
2294     if (trace_flag) {
2295       sprintf(log_line, "Cache hit: %s=%s\n", lastname, lastvalue);
2296       show_line(log_line, 0);
2297     }
2298 /*    return lastvalue; */        /* save some time here */
2299     return xstrdup(lastvalue);
2300 /*    duplicate so can free safely 98/Jan/31 */
2301   }
2302
2303 /*  hmm, following was not xstrdup(...) */ /* not cached */
2304   if (usedviwindo == 0 || *dviwindo == '\0') {
2305 /*    return getenv(varname); */
2306     s = getenv(varname);
2307     if (s == NULL) return NULL;
2308     else return xstrdup(s);       /* make safe 98/Jan/31 */
2309   }
2310
2311   if (share_flag == 0) pinput = fopen(dviwindo, "r");
2312   else pinput = _fsopen(dviwindo, "r", share_flag);
2313
2314   if (pinput != NULL) {
2315     m = strlen(envsection);
2316 /*    search for [Environment] section */ /* should be case insensitive */
2317     while (fgets (line, sizeof(line), pinput) != NULL) {
2318       if (*line == ';') continue;
2319       if (*line == '\n') continue;
2320       if (_strnicmp(line, envsection, m) == 0) {  /* 98/Jan/31 */
2321 /*        search for varname=... */ /* should be case sensitive ? */
2322         n = strlen(varname);
2323         while (fgets (line, sizeof(line), pinput) != NULL) {
2324           if (*line == ';') continue;
2325           if (*line == '[') break;
2326 /*          if (*line == '\n') break; */  /* ??? */
2327           if (*line <= ' ') continue;   /* 95/June/23 */
2328 /*          if (strncmp(line, varname, n) == 0 && */
2329           if (_strnicmp(line, varname, n) == 0 &&
2330             *(line+n) == '=') { /* found it ? */
2331               (void) fclose (pinput);
2332 /*              flush trailing white space */
2333               s = line + strlen(line) - 1;
2334               while (*s <= ' ' && s > line) *s-- = '\0';
2335               if (trace_flag) { /* DEBUGGING ONLY */
2336                 sprintf(log_line, "%s=%s\n", varname, line+n+1);
2337                 show_line(log_line, 0);
2338               }
2339               s = line+n+1;
2340               if (lastname != NULL) free(lastname);
2341               lastname = xstrdup (varname);
2342               if (lastvalue != NULL) free(lastvalue);
2343               lastvalue = xstrdup(s);
2344               return xstrdup(s);    /* 98/Jan/31 */
2345           }   /* end of matching varname */
2346         }     /* end of while fgets */
2347 /*        break; */ /* ? not found in designated section */    
2348       }       /* end of search for [Environment] section */
2349     }
2350     (void) fclose (pinput);
2351   }           /* end of if fopen */
2352   s = getenv(varname);    /* failed, so try and get from environment */
2353 /*  if (s != NULL) return s;  */
2354   if (s != NULL) {
2355 /*    sdup = xstrdup(s); */   /* just to be safe --- 1995/Jan/31 */
2356     if (lastname != NULL) free(lastname);
2357     lastname = xstrdup (varname);
2358     if (lastvalue != NULL) free(lastvalue);
2359     lastvalue = xstrdup(s);   /* remember in case asked again ... */
2360 /*    return sdup; */
2361     return xstrdup(s);    /* 98/Jan/31 */
2362   }
2363   else return NULL;   /* return NULL if not found anywhere */
2364 }
2365
2366 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2367
2368 void flush_trailing_slash (char *directory){
2369   char *s;
2370 /*  flush trailing \ or / in directory, if any 1993/Dec/12 */
2371   if (strcmp(directory, "") != 0) {
2372     s = directory + strlen(directory) - 1;
2373     if (*s == '\\' || *s == '/') *s = '\0';
2374   }
2375 }
2376
2377 void knuthify (void)
2378 {
2379 /*  show_current = false; */ /* show ultimate limits */
2380 /*  reorder_arg_flag = false; */ /* don't reorder command line */
2381 /*  deslash = false; */ /* don't unixify file names */
2382 /*  return_flag = false; */ /* don't allow just ^^M termination */
2383 /*  trimeof = false; */ /* don't trim ^^Z Ctrl-Z at end of file */
2384   restrict_to_ascii = false; /* don't complain non ASCII */
2385   allow_patterns    = false; /* don't allow pattern redefinition */
2386   show_in_hex       = true;  /* show character code in hex */
2387   show_in_dos       = false; /* redundant with previous */
2388   show_numeric      = false; /* don't show character code decimal */
2389   show_missing      = false; /* don't show missing characters */
2390   civilize_flag     = false; /* don't reorder date fields */
2391   c_style_flag      = false; /* don't add file name to error msg */
2392   show_fmt_flag     = false; /* don't show format file in log */
2393   show_tfm_flag     = false; /* don't show metric file in log */
2394 /* font_max = 255; */ /* revert to TeX 82 limit */
2395 /* if you want this, change in tex.h definition of font_max to `int' */
2396 /* and add define FONTMAX 511, and in local.c add font_max = FONTMAX; */
2397   tab_step = 0;
2398   show_line_break_stats = false;   /* do not show line break stats */
2399   show_fonts_used = false;
2400   default_rule = 26214;      /* revert to default rule thickness */
2401   pseudo_tilde = false;
2402   pseudo_space = false;
2403   show_texinput_flag = false;
2404   truncate_long_lines = false;
2405   allow_quoted_names = false;
2406   show_cs_names = false;
2407   font_dimen_zero = false;      /* 98/Oct/5 */
2408   ignore_frozen = false;     /* 98/Oct/5 */
2409   suppress_f_ligs = false;      /* 99/Jan/5 */
2410   full_file_name_flag = false;   // 00 Jun 18
2411   save_strings_flag = false;    // 00 Aug 15
2412   knuth_flag = true;       /* so other code can know about this */
2413 } /* end of knuthify */
2414
2415 /* following have already been used up */
2416
2417 /* abcdefghijklmnopqrstuvwxyz */
2418
2419 /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
2420
2421 /* ........ */
2422
2423 int nohandler=0;    /* experiment to avoid Ctrl-C interrupt handler */
2424
2425 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2426
2427 /* following made global so analyze_flag can be made separate procedure */
2428
2429 // char *xchrfile=""; /* save space use xstrdup */
2430 char *xchrfile = NULL; /* save space use xstrdup */
2431 // char *replfile="";/* save space use xstrdup */
2432 char *replfile = NULL;/* save space use xstrdup */
2433
2434 /* abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ */
2435
2436 /* analyze command line flag or argument */
2437 /* c is the flag letter itself, while optarg is start of arg if any */
2438
2439 /* when making changes, revise allowedargs */
2440
2441
2442 int analyze_flag (int c, char *optarg)
2443 {
2444   switch (c)  {
2445     case 'v': want_version = true;
2446               verbose_flag = true;
2447               break;
2448     case 'i': is_initex = true;
2449               break;
2450     case 'Q': interaction = 0; /* quiet mode */
2451               break;
2452     case 'R': interaction = 1; /* run mode */
2453               break;
2454     case 'S': interaction = 2; /* scroll mode */
2455               break;
2456     case 'T': interaction = 3; /* tex mode */
2457               break;
2458     case 'K': backwardflag = true; /* 94/Jun/15 */
2459               knuthify();         /* revert to `standard' Knuth TeX */
2460               break;
2461     case 'L': c_style_flag = true; /* C style error msg 94/Mar/21 */
2462               break;
2463     case 'Z': show_tfm_flag = true; /* show TFM in log file 94/Jun/21 */
2464               break;
2465     case 'c': current_tfm = false; /* not look current dir for TFM */
2466               break;
2467     case 'C': current_flag = false; /* not look current dir for files */
2468               break;
2469     case 'M': show_missing = false; /* do not show missing 94/June/10 */
2470               break;
2471     case 'd': deslash = false; /* flipped 93/Nov/18 */
2472               /* pseudo_tilde = 0; */ /* new 95/Sep/26 */
2473               break;
2474     case 'p': allow_patterns = true; /* 93/Nov/26 */
2475               /* reset_exceptions = true; */ /* 93/Dec/23 */
2476               break;
2477 /*  case 'w':  show_in_hex = false; */ /* 94/Jan/26 */
2478     case 'w': show_in_hex = true; /* flipped 00/Jun/18 */
2479               break;
2480     case 'j': show_in_dos = true; /* 96/Jan/26 */
2481               break;
2482     case 'n': restrict_to_ascii = true; /* 0 - 127 1994/Jan/21 */
2483               break;
2484     case '6': workingdirectory = true; /* use source dir 98/Sep/29 */
2485               break;
2486     case '7': usesourcedirectory = false; /* use working dir 98/Sep/29 */
2487               break;
2488     case 'f': show_fonts_used = false; /* 97/Dec/24 */
2489               break;
2490     case '8': shorten_file_name = true; /* 95/Feb/20 */
2491               break;
2492     case '9': show_cs_names = true; /* 98/Mar/31 */
2493               break;
2494     case '4': ignore_frozen = true; /* 98/Oct/5 */
2495               break;
2496     case '5': font_dimen_zero = false; /* 98/Oct/5 */
2497               break;
2498     case 'F': show_texinput_flag = false; /* 98/Jan/28 */
2499               break;
2500 /*  case 'X':  truncate_long_lines = false; */ /* 98/Feb/2 */
2501               /* break; */
2502     case 'W': usedviwindo = false; /* 94/May/19 */
2503               break;
2504     case 'J': show_line_break_stats = false; /* 96/Feb/8 */
2505               break;
2506     case 'O': show_fmt_flag = false; /* 94/Jun/21 */
2507               break;
2508     case 'I': format_specific = false; /* 95/Jan/7 */
2509               break;
2510     case '3': encoding_specific = false; /* 98/Oct/5 */
2511               break;
2512     case '2': suppress_f_ligs = true; /* 99/Jan/5 f-lig */
2513               break;
2514 /* following are pretty obscure */
2515 /*  case 'y': cache_file_flag = false; */ /* 96/Nov/16 */
2516 /*            break; */
2517 /*  case 'r': return_flag = false; */ /* flipped 93/Nov/18 */
2518 /*            break; */
2519 /*  case 'z': trimeof = false; */ /* 93/Nov/24 */
2520 /*            break; */
2521     case 'z': full_file_name_flag = false; // 00 Jun 18
2522               break;
2523     case 'X': save_strings_flag = false; // 00 Aug 15
2524               break;
2525 /* following are unannounced options */ /* some may be recycled ... */
2526     case 't': trace_flag = true;
2527               break;
2528     case 'q': quitflag++; /* 93/Dec/16 */
2529               break;
2530 /* The following are really obscure and should not be advertized */
2531     case 's': show_current = false; /* tex8 93/Dec/14 */
2532               break;
2533     case 'N': show_numeric = false; /* 93/Dec/21 */
2534               break;
2535     case 'A': civilize_flag = false; /* 93/Dec/16 */
2536               break; 
2537     case 'B': open_trace_flag = true; /* openinou 1994/Jan/8 */
2538               break;
2539     case 'Y': reorder_arg_flag = false; /* local */
2540               break;
2541     case 'b': test_dir_access = false; /* 94/Feb/10 */
2542               break;
2543     case 'D': dir_method = false; /* 94/Feb/10 */
2544               break;
2545     case 'G': file_method = false; /* 94/Feb/13 */
2546               break;
2547 //  case 'V': share_flag = _SH_DENYNO; break; /* 0x40 - deny none mode */ 
2548 /*  case 'X': nohandler++; break; */
2549 /*  case 'f': waitflush = false; break; */
2550 /*  case 'F': floating = true; break; */
2551 /* *********** following command line options take arguments **************  */
2552     case 'm': if (optarg == 0) mem_initex = mem_top; else mem_initex = atoi(optarg) * 1024; /* 93 Dec/1 */
2553               if (mem_initex == 0) complainarg(c, optarg);
2554               mem_spec_flag = 1;
2555               break;
2556 #ifdef VARIABLETRIESIZE
2557     case 'h': if (optarg == 0) trie_size = default_trie_size; else trie_size = atoi(optarg); /* 93 Dec/1 */
2558               if (trie_size == 0) complainarg(c, optarg);
2559               break;
2560 #endif
2561 #ifdef ALLOCATEHYPHEN
2562     case 'e': if (optarg == 0) new_hyphen_prime = hyphen_prime * 2; else new_hyphen_prime = atoi(optarg); /* 93/Nov/26 */
2563               if (new_hyphen_prime == 0) complainarg(c, optarg);
2564               break;
2565 #endif
2566 #ifdef ALLOCATEDVIBUF
2567     case 'u': if (optarg == 0) dvi_buf_size = default_dvi_buf_size; else dvi_buf_size = atoi(optarg); /* 94/Mar/24 */
2568               if (dvi_buf_size == 0) complainarg(c, optarg);
2569               break;
2570 #endif
2571     case 'g': if (optarg == 0) percent_grow = 62; else percent_grow = atoi(optarg); /* 93/Dec/11 */
2572               if (percent_grow == 0) complainarg(c, optarg);
2573               break;
2574     case 'U': if (optarg == 0) pseudo_tilde = 0; else pseudo_tilde = atoi(optarg); /* 95/Sep/26 */
2575               if (pseudo_tilde > 255) pseudo_tilde = 255; else if (pseudo_tilde < 128) pseudo_tilde = 128;
2576               break;
2577 /*  case 'H':  if (optarg == 0) heapthreshold = 1024; else heapthreshold = atoi(optarg);
2578  *             if (heapthreshold == 0) complainarg(c, optarg); else heap_flag = 1;
2579  *             break; */
2580     case 'H': if (optarg == 0) tab_step = 8; else tab_step = atoi(optarg); /* 94/July/3 */
2581               if (tab_step == 0) complainarg(c, optarg);
2582               break;
2583     case 'x': if (optarg == 0) xchrfile=xstrdup("xchr.map"); else xchrfile = xstrdup(optarg);
2584               if (xchrfile == NULL || *xchrfile == '\0') complainarg(c, optarg);
2585               break;
2586     case 'k': if (optarg == 0) replfile =xstrdup("repl.key"); else replfile = xstrdup(optarg);
2587               if (replfile == NULL || *replfile == '\0')
2588                 complainarg(c, optarg);
2589               break;
2590 /* more obscure stuff - ppssibly recycle */
2591     case 'P': if (optarg == 0) default_rule = 26214; /* 95/Oct/9 */
2592               else default_rule = atoi(optarg); /* 95/Oct/9 */
2593               if (default_rule == 0) complainarg(c, optarg);
2594               break;
2595     case 'E': if (optarg != 0) putenv(optarg); else complainarg(c, optarg);
2596               break;
2597     case 'o': if (optarg == 0) dvi_directory = ""; else dvi_directory = xstrdup(optarg);
2598               if (strcmp(dvi_directory, "") == 0) complainarg(c, optarg);
2599               break;
2600     case 'l': if (optarg == 0) log_directory = ""; else log_directory = xstrdup(optarg);
2601               if (strcmp(log_directory, "") == 0) complainarg(c, optarg);
2602               break;
2603     case 'a': if (optarg == 0) aux_directory = ""; else aux_directory = xstrdup(optarg);
2604               if (strcmp(aux_directory, "") == 0) complainarg(c, optarg);
2605               break;
2606     case '?':
2607     default : show_use = true;
2608               return -1; // failed to recognize
2609               break;
2610   }
2611   return 0;
2612 }
2613
2614 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2615 //char *yytexcmd="yandytex.cmd";
2616 char *yytexcmd="YANDYTEX.CMD";    /* name of command line file */
2617
2618 /* Try and read default command file - YANDYTEX.CMD */
2619 /* in current directory and then in directory of YANDYTEX */
2620 /* (does not make sense in TeX file directory) */
2621 /* since we don't yet know where that is ! */
2622 /* can't conveniently include this in output file either - not open yet */
2623
2624 /* used both for yytex.cmd and @ indirect command line files */
2625 /* can this be reentered ? */
2626
2627 /* supply extension if none */
2628 void yy_extension (char *fname, char *ext)
2629 {
2630   char *s, *t;
2631     if ((s = strrchr(fname, '.')) == NULL ||
2632     ((t = strrchr(fname, '\\')) != NULL && s < t)) {
2633       strcat(fname, "."); 
2634       strcat(fname, ext);
2635   }
2636 }
2637
2638 /* remove file name - keep only path - inserts '\0' to terminate */
2639
2640 void strip_name (char *pathname)
2641 {
2642   char *s;
2643   if ((s=strrchr(pathname, '\\')) != NULL);
2644   else if ((s=strrchr(pathname, '/')) != NULL);
2645   else if ((s=strrchr(pathname, ':')) != NULL) s++;
2646   else s = pathname;
2647   *s = '\0';
2648 }
2649
2650 /* char commandfile[PATH_MAX]; */ /* keep around so can open later */
2651
2652 char *programpath = ""; /* pathname of program */
2653                     /* redundant with texpath ? */
2654
2655 /* The following does not deslashify arguments ? Do we need to ? */
2656
2657 int read_commands (char *filename)
2658 {
2659   char commandfile[PATH_MAX]; 
2660   FILE *command;
2661   char line[PATH_MAX];
2662   char *linedup;      /* need to copy line to preserve args */
2663   char *s;
2664 /*  char *sn; */
2665   char *optarg;
2666   int c;
2667
2668 /*  Try first in current directory (or use full name as specified) */
2669   strcpy(commandfile, filename);
2670   yy_extension(commandfile, "cmd");
2671   if (share_flag == 0)
2672           command = fopen(commandfile, "r");
2673   else
2674           command = _fsopen(commandfile, "r", share_flag);
2675   if (command == NULL) {
2676 /*    If that fails, try in YANDYTeX program directory */
2677     strcpy(commandfile, programpath);
2678 /*    don't need fancy footwork, since programpath non-empty */
2679     strcat(commandfile, "\\");
2680     strcat(commandfile, filename);
2681     yy_extension(commandfile, "cmd");
2682     if (share_flag == 0)
2683                 command = fopen(commandfile, "r");
2684     else
2685                 command = _fsopen(commandfile, "r", share_flag);
2686     if (command == NULL) {
2687 /*      perrormod(commandfile); */      /* debugging only */
2688 /*      strcpy(commandfile, ""); */   /* indicate failed */
2689       return 0;       /* no command line file YYTEX.CMD */
2690     }
2691   }
2692
2693 /*  allow for multiple lines --- ignore args that don't start with `-' */
2694   while (fgets(line, PATH_MAX, command) != NULL) {
2695 /*    sprintf(log_line, "From %s:\t%s", commandfile, line); */
2696 /*    skip over comment lines and blank lines */
2697     if (*line == '%' || *line == ';' || *line == '\n') continue;
2698     if (strchr(line, '\n') == NULL) strcat(line, "\n");
2699 /*    sfplogline, rintf("From %s:\t%s", commandfile, line); */
2700     linedup = xstrdup (line);         /* 93/Nov/15 */
2701     if (linedup == NULL) {
2702       show_line("ERROR: out of memory\n", 1);    /* read_commands */
2703 //      exit(1);
2704       return -1;    // failure
2705     }
2706     s = strtok(linedup, " \t\n\r");       /* 93/Nov/15 */
2707     while (s != NULL) {
2708       if (*s == '-' || *s == '/') {
2709         c = *(s+1);
2710         optarg = s+2;
2711 /*        if (*optarg = '=') optarg++; */
2712         if (*optarg == '=') optarg++;
2713         if (analyze_flag(c, optarg) < 0) return -1;  // failure ???
2714       }
2715 /*      else break; */              /* ignore non-flag items */
2716       s = strtok(NULL, " \t\n\r");      /* go to next token */
2717     }
2718 /*    If you want to see command lines in file - put -v in the file */
2719 /*    if (verbose_flag != 0) sprintf(log_line, "From %s:\t%s", commandfile, line); */
2720   }
2721   (void) fclose(command);   /* no longer needed */
2722   return 1;       // success
2723 }
2724
2725 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2726
2727 /* try and read commands on command line */
2728 int read_command_line (int ac, char **av)
2729
2730   int c;
2731   char *optargnew;  /* equal to optarg, unless that starts with `='      */
2732                     /* in which case it is optarg+1 to step over the `=' */
2733                     /* if optarg = 0, then optargnew = 0 also            */
2734
2735 //  show_line("read_command_line\n", 0);
2736   if (ac < 2) return 0;     /* no args to analyze ? 94/Apr/10 */
2737
2738 /*  while ((c = getopt(ac, av, "+vitrdczp?m:h:x:E:")) != EOF) {              */
2739 /*  NOTE: keep `Y' in there for `do not reorder arguments !                  */
2740 /*  WARNING: if adding flags, change also `allowedargs' and  `takeargs' !!!! */
2741   while ((c = getopt(ac, av, allowedargs)) != EOF) {
2742     if (optarg != 0 && *optarg == '=')
2743                 optargnew = optarg+1;
2744     else
2745                 optargnew = optarg;
2746     analyze_flag (c, optargnew);
2747   }
2748   if (show_use || quitflag == 3) {
2749 //    showversion (stdout);
2750     stamp_it(log_line);
2751     strcat(log_line, "\n");
2752     show_line(log_line, 0);
2753     stampcopy(log_line);
2754     strcat(log_line, "\n");
2755     show_line(log_line, 0);
2756     if (show_use) show_usage(av[0]);
2757     else if (quitflag == 3) {
2758       strcat(log_line, "\n");
2759       show_line(log_line, 0);
2760     }
2761 //    exit (0);
2762     return -1;        // failure
2763   } 
2764 #ifdef DEBUG
2765   if (floating) testfloating();   /* debugging */
2766 #endif
2767
2768   if (replfile != NULL && *replfile != '\0') {  /* read user defined replacement */
2769     if (read_xchr_file(replfile, 1, av)) {
2770       if (trace_flag) show_line("KEY REPLACE ON\n", 0);
2771       key_replace = true;
2772     }
2773   } 
2774 /*  key_replace used in texmf.c (input_line) */
2775   if (xchrfile != NULL && *xchrfile != '\0') {  /* read user defined xchr[] */
2776     if (read_xchr_file(xchrfile, 0, av)) {
2777       if (trace_flag) show_line("NON ASCII ON\n", 0);
2778       non_ascii = true;
2779     }
2780   } 
2781 /*  non_ascii used in texmf.c (t_open_in & input_line & call_edit) */
2782 /*  see also xchr [] & xord [] use in tex3.c and itex.c */
2783   return 0;
2784 }
2785
2786 #ifdef IGNORED
2787 void uppercase (char *s) {
2788   int c;
2789   while ((c = *s) != '\0') {
2790 /*    if (islower(c)) *s = toupper (*s); */
2791     *s = toupper (*s);
2792     s++;
2793   }
2794 }
2795 #endif
2796
2797 int init_commands (int ac, char **av)
2798 {
2799 /*  NOTE: some defaults changed 1993/Nov/18 */
2800 /*  want_version = show_use = switchflag = return_flag = false;
2801   is_initex = trace_flag = deslash = non_ascii = false; */
2802   is_initex         = false; /* check for dumping format file */
2803   allow_patterns    = false; /* using \pattern after format file loaded */
2804   reset_exceptions  = false; 
2805   non_ascii         = false;
2806   key_replace       = false;
2807   want_version      = false;
2808   open_trace_flag   = false;
2809   trace_flag        = false;
2810   verbose_flag      = false;
2811   heap_flag         = false;
2812   restrict_to_ascii = false;
2813   show_in_hex       = false; /* default is not to show as hex code ^^ 00/Jun/18 */
2814   show_in_dos       = false; /* default is not to translate to DOS 850 */ 
2815   return_flag       = true;  // hard wired now
2816   trimeof           = true;  // hard wired now
2817   deslash           = true;
2818   pseudo_tilde      = 254;   /* default '~' replace 95/Sep/26 filledbox DOS 850 */
2819   pseudo_space      = 255;   /* default ' ' replace 97/June/5 nbspace DOS 850 */
2820   default_rule      = 26214; /* default rule variable 95/Oct/9 */
2821   show_current      = true;
2822   civilize_flag     = true;
2823   show_numeric      = true;
2824   show_missing      = true;
2825   current_flag      = true;
2826   current_tfm       = true;  /* search for TFMs in current dir as well */
2827   test_dir_access   = true;  /* test if readable item is perhaps a sub-dir */
2828   dir_method        = true;  /* in dir_p: _findfirst instead of use fopen (nul) */
2829   file_method       = true;  /* use file_p (_findfirst) not readable (access) */
2830 /*  waitflush = true; */  /* flushed 97/Dec/24 */
2831   c_style_flag      = false; /* use c-style error output */
2832   show_fmt_flag     = true;  /* show format file in log */
2833   show_tfm_flag     = false; /* don't show metric file in log */
2834   shorten_file_name     = false; /* don't shorten file names to 8+3 */
2835   show_texinput_flag    = true;  /* show TEXINPUTS and TEXFONTS */
2836   truncate_long_lines   = true; /* truncate long lines */
2837   tab_step              = 0;      /* do not replace tabs with spaces */
2838   format_specific       = true;  /* do format specific TEXINPUTS 95/Jan/7 */
2839   encoding_specific     = true;  /* do encoding specific TEXFONTS 98/Jan/31 */
2840   show_line_break_stats = true;  /* show line break statistics 96/Feb/8 */
2841   show_fonts_used       = true; /* show fonts used in LOG file 97/Dec/24 */
2842   allow_quoted_names    = true;  /* allow quoted names with spaces 98/Mar/15 */
2843   show_cs_names         = false;  /* don't show csnames on start 98/Mar/31 */
2844   knuth_flag            = false;    /* allow extensions to TeX */
2845   cache_file_flag       = true; /* default is to cache full file names 96/Nov/16 */
2846   full_file_name_flag   = true;  /* new default 2000 June 18 */
2847   save_strings_flag     = true; // 2000 Aug 15
2848   errout                = stdout;    /* as opposed to stderr say --- used ??? */
2849   abort_flag            = 0;      // not yet hooked up ???
2850   err_level             = 0;     // not yet hooked up ???
2851
2852   new_hyphen_prime = 0;
2853 #ifdef VARIABLETRIESIZE
2854 /*  trie_size = default_trie_size; */
2855   trie_size = 0;
2856 #endif
2857   mem_extra_high = 0;
2858   mem_extra_low  = 0;
2859   mem_initex     = 0;
2860 #ifdef ALLOCATEDVIBUF
2861   dvi_buf_size = 0;
2862 #endif
2863 /*  share_flag = _SH_DENYNO; */ /* 0x40 - deny none mode */
2864 /*  share_flag = _SH_COMPAT; */ /* 0x00 - compatability mode */
2865   share_flag = 0; /* revert to fopen for now */
2866
2867 /*  strncpy(programpath, argv[0], PATH_MAX); */ /* 94/July/12 */
2868   programpath = xstrdup(av[0]); /* extract path executable */
2869   strip_name(programpath); /* strip off yandytex.exe */
2870
2871   //format_name = "yandytex";
2872   format_name = "plain"; /* format name if specified on command line */
2873
2874   encoding_name = "";
2875
2876   if (read_commands(yytexcmd) < 0)   /* read yandytex.cmd 1994/July/12 */
2877     return -1;            // in case of error
2878
2879   if (read_command_line(ac, av) < 0)  /* move out to subr 94/Apr/10 */
2880     return -1;            // in case of error
2881
2882   if (optind == 0) optind = ac;   /* no arg case paranoia 94/Apr/10 */
2883
2884 /*  Print version *after* banner ? */ /* does this get in log file ? */
2885   if (want_version) {
2886 //  showversion (stdout);
2887 //  showversion (log_line);
2888     stamp_it(log_line);
2889     strcat(log_line, "\n");
2890     show_line(log_line, 0);
2891     stampcopy(log_line);
2892     strcat(log_line, "\n");
2893     show_line(log_line, 0);
2894   }
2895 /*  if (show_use) show_usage(av[0]);   */  /* show usage and quit */
2896
2897 /*  if we aren't including current directory in any directory lists */
2898 /*  then makes no sense to avoid them separately for TFM files ... */
2899 /*  (that is, the ./ is already omitted from the dir list in that case */
2900   if (!current_flag && !current_tfm) current_tfm = true; /* 94/Jan/24 */
2901   return 0;               // success
2902 }
2903
2904 /* E sets environment variable ? */
2905
2906 void initial_memory (void)
2907 {   /* set initial memory allocations */
2908     if (mem_extra_high < 0) mem_extra_high = 0;
2909     if (mem_extra_low < 0) mem_extra_low = 0;
2910     if (mem_initex < 0) mem_initex = 0;
2911     if (is_initex) {
2912  #if defined(ALLOCATEHIGH) || defined(ALLOCATELOW)
2913       if (mem_extra_high != 0 || mem_extra_low != 0) {
2914         show_line("ERROR: Cannot extend main memory in iniTeX\n", 1);
2915         mem_extra_high = 0;   mem_extra_low = 0;
2916       }
2917  #endif
2918     }
2919     else {
2920       if (mem_initex != 0) {
2921         show_line("ERROR: Can only set initial main memory size in iniTeX\n", 1);
2922         mem_initex = 0;
2923       }
2924       if (trie_size != 0) {
2925         show_line("ERROR: Need only set hyphenation trie size in iniTeX\n", 1);
2926 /*        trie_size = 0; */
2927       }
2928     }
2929     if (mem_initex == 0) mem_initex = default_mem_top;
2930     if (trie_size == 0) trie_size = default_trie_size;
2931 /* Just in case user mistakenly specified words instead of kilo words */
2932     if (mem_extra_high > 10000L * 1024L) mem_extra_high = mem_extra_high / 1024;
2933     if (mem_extra_low > 10000L * 1024L) mem_extra_low = mem_extra_low / 1024;
2934     if (mem_initex > 10000L * 1024L) mem_initex = mem_initex / 1024;
2935 #ifdef ALLOCATEHIGH         /* not used anymore */
2936     if (mem_extra_high > 2048L * 1024L) { /* extend SW area by 16 mega byte! */
2937       show_line(
2938       "WARNING: There may be no benefit to asking for so much memory\n", 0); 
2939       mem_extra_high = 2048 * 1024; /* limit to SW to 4 x VLR */
2940     }
2941 #endif
2942 #ifdef ALLOCATELOW          /* not used anymore */
2943     if (mem_extra_low > 2048L * 1024L) { /* extend VL area by 16 mega byte! */
2944       show_line(
2945       "WARNING: There may be no benefit to asking for so much memory\n", 0); 
2946       mem_extra_low = 2048 * 1024; /* limit VLR to 4 x SW */
2947     }
2948 #endif
2949     if (mem_initex > 2048L * 1024L) { /* extend main memory by 16 mega byte! */
2950       show_line(
2951       "WARNING: There may be no benefit to asking for so much memory\n", 0); 
2952 /*      mem_initex = 2048 * 1024; */
2953     }
2954  #ifdef ALLOCATEDVIBUF
2955     if (dvi_buf_size == 0) dvi_buf_size = default_dvi_buf_size;
2956     /* if less than 1024 assume user specified kilo-bytes, not bytes */
2957     if (dvi_buf_size < 1024) dvi_buf_size = dvi_buf_size * 1024;
2958     if (dvi_buf_size % 8 != 0)        /* check multiple of eight */
2959        dvi_buf_size = (dvi_buf_size / 8 + 1) * 8;
2960  #endif
2961     if (new_hyphen_prime < 0) new_hyphen_prime = 0;
2962     if (new_hyphen_prime > 0) {
2963       if (! is_initex) 
2964         show_line("ERROR: Can only set hyphen prime in iniTeX\n", 1);
2965       else {
2966         if (new_hyphen_prime % 2 == 0) new_hyphen_prime++;
2967         while (!prime(new_hyphen_prime)) new_hyphen_prime = new_hyphen_prime+2;
2968         if (trace_flag) {
2969           sprintf(log_line, "Using %d as hyphen prime\n", new_hyphen_prime);
2970           show_line(log_line, 0);
2971         }
2972       }
2973     }
2974
2975     if (percent_grow > 100) percent_grow = percent_grow - 100;
2976     if (percent_grow > 100) percent_grow = 100;   /* upper limit - double */
2977     if (percent_grow < 10) percent_grow = 10;   /* lower limit - 10% */
2978 }
2979
2980 /**********************************************************************/
2981
2982 void perrormod (char *s)
2983 {
2984   sprintf(log_line, "`%s': %s\n", s, strerror(errno));
2985   show_line(log_line, 1);
2986 }
2987
2988 void pause (void)
2989 {
2990 #ifndef _WINDOWS
2991   fflush(stdout);     /* ??? */
2992   fflush(stderr);     /* ??? */
2993   (void) _getch();    /* ??? */
2994 #endif
2995 }
2996
2997 void checkpause (int flag)
2998 {            /* 95/Oct/28 */
2999   char *s;
3000   int debug_pause = 0;
3001 /*  don't stop if in Q (quiet) or R (run) mode */
3002 /*  stop only in S (scroll) and T (TeX) mode */
3003   if (interaction >= 0 && interaction < 2) flag = 0;    /* 98/Jun/30 */
3004   s = grabenv("DEBUGPAUSE");
3005   if (s != NULL) sscanf(s, "%d", &debug_pause);
3006   if (flag < 0) return;
3007   if (debug_pause) {
3008     if (debug_pause || flag > 0) {
3009       show_line("\n", 0);
3010 #ifndef _WINDOWS
3011       show_line("Press any key to continue . . .\n", 0);
3012       pause();
3013 #endif
3014     }
3015   }
3016 }
3017
3018 void check_enter (int argc, char *argv[])
3019 {/* 95/Oct/28 */
3020   int m;
3021   char current[FILENAME_MAX];
3022   if (grabenv("DEBUGPAUSE") != NULL) {
3023     (void) _getcwd(current, sizeof(current));
3024     sprintf(log_line, "Current directory: `%s'\n", current);
3025     show_line(log_line, 0);
3026     for (m = 0; m < argc; m++) {
3027       sprintf(log_line, "%2d: `%s'\n", m, argv[m]); 
3028       show_line(log_line, 0);
3029     }
3030     checkpause(-1);
3031   }
3032 }
3033
3034 #ifdef IGNORED
3035 void checkexit (int n) {              /* 95/Oct/28 */
3036   checkpause(1);
3037   exit(n);
3038 }
3039 #endif
3040
3041 /*************************************************************************/
3042
3043 /* convert tilde to pseudo_tilde to hide it from TeX --- 95/Sep/26 */
3044 /* convert space to pseudo_space to hide it from TeX --- 97/Jun/5 */
3045 /* called only if pseudo_tilde != 0 or pseudo_space != 0 */
3046 /* this is then undone in tex3.c both for fopen input and output */
3047 /* not ideal, since pseudo name appears in log and in error messages ... */
3048
3049 void hidetwiddle (char *name)
3050 {
3051   char *s=name;
3052 #ifdef DEBUGTWIDDLE
3053   if (trace_flag) {
3054     sprintf(log_line, "Hidetwiddle %s", name);
3055     show_line(log_line, 0);
3056   }
3057 #endif
3058 /*  while (*s != '\0' && *s != ' ') { */
3059   while (*s != '\0')  {
3060     if (*s == '~' && pseudo_tilde != 0)
3061       *s = (char) pseudo_tilde;  /* typically 254 */
3062     else if (*s == ' ' && pseudo_space != 0)
3063       *s = (char) pseudo_space;  /* typically 255 */
3064     s++;
3065   }
3066 #ifdef DEBUGTWIDDLE
3067   if (trace_flag) {
3068     sprintf(log_line, "=> %s\n", name);
3069     show_line(log_line, 0);
3070   }
3071 #endif
3072 }
3073
3074 void deslash_all (int ac, char **av)
3075 {
3076   char buffer[PATH_MAX];  
3077   char *s;
3078
3079   if ((s = getenv("USEDVIWINDOINI")) != NULL) 
3080     sscanf(s, "%d", &usedviwindo);      /* 94/June/14 */
3081
3082   if (usedviwindo) setupdviwindo();   // moved to yandytex ?
3083
3084   check_enter(ac, av);           /* 95/Oct/28 */
3085
3086 /* environment variables for output directories (as in PC TeX) */
3087
3088   if ((s = grabenv("TEXDVI")) != NULL) dvi_directory = s;
3089   if ((s = grabenv("TEXLOG")) != NULL) log_directory = s;
3090   if ((s = grabenv("TEXAUX")) != NULL) aux_directory = s;
3091
3092   strcpy(buffer, av[0]);            /* get path to executable */
3093   if ((s = strrchr(buffer, '\\')) != NULL) *(s+1) = '\0';
3094   else if ((s = strrchr(buffer, '/')) != NULL) *(s+1) = '\0';
3095   else if ((s = strrchr(buffer, ':')) != NULL) *(s+1) = '\0';
3096   s = buffer + strlen(buffer) - 1;
3097   if (*s == '\\' || *s == '/') *s = '\0';   /* flush trailing PATH_SEP */
3098   texpath = xstrdup(buffer);
3099
3100 /*  Hmm, we may be operating on DOS environment variables here !!! */
3101
3102   if (strcmp(dvi_directory, "") != 0) flush_trailing_slash (dvi_directory);
3103   if (strcmp(log_directory, "") != 0) flush_trailing_slash (log_directory);
3104   if (strcmp(aux_directory, "") != 0) flush_trailing_slash (aux_directory);
3105
3106   if (deslash) {
3107       unixify (texpath);          /* 94/Jan/25 */
3108 /* if output directories given, deslashify them also 1993/Dec/12 */
3109       if (strcmp(dvi_directory, "") != 0) unixify(dvi_directory);
3110       if (strcmp(log_directory, "") != 0) unixify(log_directory);
3111       if (strcmp(aux_directory, "") != 0) unixify(aux_directory);
3112   }
3113
3114 /*  deslash TeX source file (and format, if format specified) */
3115 /*  and check args to see whether format was specified */
3116
3117   format_spec = 0;
3118 /*  NOTE: assuming that command line arguments are in writable memory ! */
3119 /*  if (trace_flag || debug_flag)
3120     sprintf(log_line, "optind %d ac %d\n", optind, ac); */   /* debugging */ 
3121 /*  if (optind < ac) { */           /* bkph */
3122   if (optind < ac && optind > 0) {      /* paranoia 94/Apr/10 */
3123     if (deslash) {
3124       if (trace_flag || debug_flag) {
3125         sprintf(log_line, "deslash: k %d argv[k] %s (argc %d)\n",
3126           optind, av[optind], ac);
3127         show_line(log_line, 0);
3128       }
3129       unixify(av[optind]);
3130     }
3131     if (pseudo_tilde != 0 || pseudo_space != 0)
3132       hidetwiddle (av[optind]);     /* 95/Sep/25 */
3133 /* For Windows NT, lets allow + instead of & for format specification */
3134     if (*av[optind] == '&' || *av[optind] == '+') {
3135       format_spec = 1; /* format file specified */
3136       format_name = xstrdup(av[optind]+1); /* 94/Oct/25 */
3137 /*      uppercase (format_name); */    /* why ? 98/Jan/31 */
3138       if (optind + 1 < ac) {
3139         if (deslash) {
3140           if (trace_flag || debug_flag) {
3141             sprintf(log_line, "deslash: k %d argv[k] %s (argc %d)\n",
3142               optind+1, av[optind+1], ac);
3143             show_line(log_line, 0);
3144           }
3145           unixify(av[optind+1]);
3146         }
3147         if (pseudo_tilde != 0 || pseudo_space != 0)
3148           hidetwiddle (av[optind+1]); /* 95/Sep/25 */
3149       }
3150     }         
3151   }
3152 }
3153
3154 /* The above seems to assume that arguments that don't start with '-' */
3155 /* are file names or format names - what if type in control sequences? */
3156
3157 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3158
3159 /* interaction == 0 => batch mode (omit all stops and omit terminal output) */
3160 /* interaction == 1 => nonstop mode (omit all stops)                        */
3161 /* interaction == 2 => scroll mode (omit error stops)                       */
3162 /* interaction == 3 => error_stop mode (stops at every opportunity)         */
3163
3164 /* main entry point follows */
3165
3166 /* this gets called pretty much right away in `main' in texmf.c */
3167
3168 /* note: those optarg == 0 test don't really work ... */
3169 /* note: optarg starts at = in case of x=... */
3170
3171 int init (int ac, char **av)
3172 {
3173   char initbuffer[PATH_MAX];
3174   int k;
3175   
3176   debugfile = getenv("TEXDEBUG");     /* 94/March/28 */
3177   if (debugfile)
3178     debug_flag = 1;
3179   else
3180     debug_flag = 0;
3181
3182   if (debug_flag) {
3183     show_line("TEXDEBUG\n", 0);
3184     trace_flag = 1;            /* 94/April/14 */
3185   }
3186
3187   if (sizeof(memory_word) != 8) {  /* compile time test */
3188     sprintf(log_line, "ERROR: Bad word size %d!\n", sizeof(memory_word));
3189     show_line(log_line, 1);
3190   }
3191
3192   start_time = clock();    /* get time */
3193   main_time = start_time;   /* fill in, in case file never opened */
3194
3195   initbuffer[0] = '\0';         /* paranoia 94/Apr/10 */
3196
3197 /*  reset all allocatable memory pointers to NULL - in case we drop out */
3198   mainmemory = NULL;
3199   font_info = NULL;
3200   str_pool = NULL;
3201   str_start = NULL;
3202 #ifdef ALLOCATEZEQTB
3203   zeqtb = NULL;
3204 #endif
3205 #ifdef ALLOCATEHASH
3206   zzzae = NULL;
3207 #endif
3208 #ifdef ALLOCATESAVESTACK
3209   save_stack = NULL; 
3210 #endif
3211 #ifdef ALLOCATEDVIBUF
3212   zdvibuf = NULL; 
3213 #endif
3214 #ifdef ALLOCATEBUFFER
3215   buffer = NULL;        /* new 1999/Jan/7 need to do early */
3216   current_buf_size = 0;
3217   buffer = realloc_buffer (initial_buf_size);
3218 /*  sprintf(log_line, "buffer %x, current_buf_size %d\n", buffer, current_buf_size); */
3219 #endif
3220   hyph_list = NULL;  hyph_word = NULL;
3221   trie_taken = NULL; trie_hash = NULL;
3222   trie_r = NULL; trie_c = NULL; trie_o = NULL; trie_l = NULL;
3223   trie_trc = NULL; trie_tro = NULL; trie_trl = NULL;
3224
3225   log_opened = false;       /* so can tell whether opened */
3226   interaction = -1;       /* default state => 3 */
3227   missing_characters = 0;      /* none yet! */
3228   workingdirectory = false;   /* set from dviwindo.ini & command line */
3229   font_dimen_zero = true;     /* \fontdimen0 for checksum 98/Oct/5 */
3230   ignore_frozen = false;     /* default is not to ignore 98/Oct/5 */
3231   suppress_f_ligs = false;      /* default is not to ignore f-ligs */
3232 /*  if (*av[1] == '-Y') reorder_arg_flag = false; */  /* 94/April/14 */
3233   if (ac > 1 && *av[1] == '-Y') reorder_arg_flag = false;
3234
3235   if (reorder_arg_flag) reorderargs(ac, av);  
3236
3237   if (init_commands(ac, av))
3238     return -1;          // failure
3239
3240   check_fixed_align(trace_flag);       /* sanity check 1994/Jan/8 */
3241
3242   format_file = NULL;        /* to be set in openinou.c 94/Jun/21 */
3243   string_file = NULL;        /* to be set in openinou.c 96/Jan/15 */
3244   source_direct = NULL;      /* to be set in openinou.c 98/Sep/29 */
3245   dvi_file_name = NULL;       /* to be set in openinou.c 00/Jun/18 */
3246   log_file_name = NULL;       /* to be set in openinou.c 00/Jun/18 */
3247
3248   first_pass_count  = 0;
3249   second_pass_count = 0;
3250   final_pass_count  = 0;
3251   paragraph_failed  = 0;
3252   singleline        = 0;
3253   overfull_hbox     = 0;
3254   underfull_hbox    = 0;
3255   overfull_vbox     = 0;
3256   underfull_vbox    = 0;
3257
3258   closed_already=0;        // so can only do once
3259
3260   if (trace_flag) show_line("Entering init (local)\n", 0);
3261
3262 /*   Print version *after* banner ? */ /* does this get in log file ? */
3263
3264   probe_memory();             /* show top address */
3265   ini_max_address = max_address;       /* initial max address */
3266   if (trace_flag) show_maximums(stdout);
3267 #ifdef HEAPWALK
3268   if (heap_flag) (void) heap_dump(stdout, 1);
3269 #endif
3270
3271   initial_memory();
3272
3273   deslash_all(ac, av);    /* deslash and note if format specified */
3274
3275 /*  sprintf(log_line, "%s\n", initbuffer); */    /* debugging, remove later */
3276
3277   no_interrupts = 0;
3278
3279   if (format_spec && mem_spec_flag) {
3280     show_line("WARNING: Cannot change initial main memory size when format specified", 1);
3281   }
3282
3283    if (allocate_memory() != 0)   /* NOW, try and ALLOCATE MEMORY if needed */
3284      return -1;         // if failed to allocate
3285
3286 /*   following is more or less useless since most all things not yet alloc */
3287    check_alloc_align(trace_flag);    /* sanity check 1994/Jan/8 */
3288 #ifdef HEAPSHOW
3289    if (trace_flag) showaddresses();  /* debugging only 1996/Jan/20 */
3290 #endif
3291
3292 #ifdef HEAPWALK
3293 /*   if (heap_flag) heap_dump(stdout, 1); */  /* redundant ? */
3294 #endif
3295
3296     if (trace_flag) show_line("Leaving init (local)\n", 0);
3297     return 0;         // success
3298 }
3299
3300 /* #define CLOCKS_PER_SEC 1000 */ /* #define CLK_TCK  CLOCKS_PER_SEC */
3301
3302 /* void show_inter_val (clock_t start, clock_t end) { */
3303 void show_inter_val (clock_t interval)
3304 {
3305 /*  clock_t interval; */
3306 /*  int seconds, tenths; */
3307 /*  int seconds, tenths, hundredth;  */
3308   int seconds, tenths, hundredth, thousands;
3309 /*  interval = end - start; */
3310 /*  sanity check whether positive ? */
3311   if (interval >= CLK_TCK * 10) {
3312     tenths = (interval * 10 + CLK_TCK / 2) / CLK_TCK; 
3313     seconds = tenths / 10; 
3314     tenths = tenths % 10;
3315     sprintf(log_line, "%d.%d", seconds, tenths);
3316     show_line(log_line, 0);
3317   }
3318   else if (interval >= CLK_TCK) {       /* 94/Feb/25 */
3319     hundredth = (interval * 100 + CLK_TCK / 2) / CLK_TCK; 
3320     seconds = hundredth / 100;
3321     hundredth = hundredth % 100;
3322     sprintf(log_line, "%d.%02d", seconds, hundredth);
3323     show_line(log_line, 0);
3324   }
3325   else if (interval > 0) {          /* 94/Oct/4 */
3326     thousands = (interval * 1000 + CLK_TCK / 2) / CLK_TCK;  
3327     seconds = thousands / 1000;
3328     thousands = thousands % 1000;
3329     sprintf(log_line, "%d.%03d", seconds, thousands);
3330     show_line(log_line, 0);
3331   }
3332   else show_line("0", 0);          /* 95/Mar/1 */
3333 }
3334
3335 /* final cleanup opportunity */ /* flag is non-zero if error exit */
3336 /* shows various times, warning about missing chars */
3337
3338 int endit (int flag)
3339 {
3340 /*  int msec; */
3341   finish_time = clock();
3342   if (missing_characters != 0) flag = 1;
3343   if (missing_characters) {
3344     sprintf(log_line,
3345                 "! There %s %d missing character%s --- see log file\n",
3346                 (missing_characters == 1) ? "was" : "were",  missing_characters,
3347                 (missing_characters == 1) ? "" : "s");
3348     show_line(log_line, 0);
3349   }
3350   if (free_memory() != 0) flag++;
3351 /*  dumpaccess(); */
3352 /*  show per page time also ? */
3353   if (verbose_flag) {
3354 /*    sprintf(log_line, "start %ld main %ld finish %ld\n",
3355       start_time, main_time, finish_time); */
3356     show_line("Total ", 0);
3357 /*    show_inter_val(start_time, finish_time); */
3358     show_inter_val(finish_time - start_time);
3359     show_line(" sec (", 0);
3360 /*    show_inter_val(start_time, main_time); */
3361     show_inter_val(main_time - start_time);
3362     show_line(" format load + ", 0);
3363 /*    show_inter_val(main_time, finish_time); */
3364     show_inter_val(finish_time - main_time);
3365     show_line(" processing) ", 0);
3366     if (total_pages > 0) {
3367 /*      msec = (finish_time - main_time) * 1000 / (CLK_TCK * total_pages); */
3368 /*      sprintf(log_line, " %d.%d sec per page", msec / 1000, msec % 1000); */
3369 /*      sprintf(log_line, " %d.%03d sec per page", msec / 1000, msec % 1000); */
3370       show_inter_val ((finish_time - main_time) / total_pages);
3371       show_line(" sec per page", 0);
3372     }
3373     show_line("\n", 0);
3374   }
3375
3376   checkpause(flag);
3377 //  checkpause(1);
3378   return flag;
3379 }
3380
3381 /********************************************************************************/
3382
3383 /* addition 98/Mar/31 print_csnames Frank Mittelbach */
3384
3385 int textcolumn;
3386
3387 #define MAXCOLUMN 78
3388
3389 void print_cs_name (FILE *output, int h)
3390 {
3391   int c, textof, n;
3392   char *s;
3393   
3394   textof = hash[h].v.RH;
3395   if (textof == 0) return;  /* ignore if text() == 0 */
3396   n = str_start[textof + 1] - str_start[textof];
3397   if (textcolumn != 0) {
3398     sprintf(log_line, ", ");
3399     if (output != NULL) fprintf(output, log_line);
3400     else show_line(log_line, 0);
3401     textcolumn += 2;
3402   }
3403   if (textcolumn + n + 2 >= MAXCOLUMN) {
3404     sprintf(log_line, "\n");
3405     if (output == stderr) show_line(log_line, 1);
3406     else if (output == stdout) show_line(log_line, 0);
3407     else fputs(log_line, output);
3408     textcolumn=0;
3409   }
3410   s = log_line;
3411   for (c = str_start[textof]; c < str_start[textof+1]; c++) {
3412     *s++ = str_pool[c];
3413   }
3414   if (output == stderr) show_line(log_line, 1);
3415   else if (output == stdout) show_line(log_line, 0);
3416   else fprintf(output, log_line);
3417   textcolumn += n;
3418 }
3419
3420 int comparestrn (int, int, int, int); /* in tex9.c */
3421
3422 /* compare two csnames in qsort */
3423
3424 int comparecs (const void *cp1, const void *cp2)
3425 {
3426   int c1, c2, l1, l2, k1, k2, textof1, textof2;
3427   c1 = *(int *)cp1;
3428   c2 = *(int *)cp2;
3429   textof1 = hash[c1].v.RH;
3430   textof2 = hash[c2].v.RH;
3431   l1 =(str_start[textof1 + 1] - str_start[textof1]); 
3432   l2 =(str_start[textof2 + 1] - str_start[textof2]); 
3433   k1 = str_start[textof1]; 
3434   k2 = str_start[textof2]; 
3435 /*  showstring (k1, l1); */
3436 /*  showstring (k2, l2); */
3437   return comparestrn (k1, l1, k2, l2);
3438 }
3439
3440 char *csused=NULL;
3441
3442 /* Allocate table of indeces to allow sorting on csname */
3443 /* Allocate flags to remember which ones already listed at start */
3444
3445 void print_cs_names (FILE *output, int pass)
3446 {
3447   int h, k, ccount, repeatflag;
3448   int *cnumtable;
3449   int nfcs = hash_base + hash_size + hash_extra;  /* frozen_control_sequence */
3450
3451   if (pass == 0 && csused == NULL) {
3452     csused = (char *) malloc (nfcs);
3453     if (csused == NULL) return; 
3454 #ifdef USEMEMSET
3455     memset(csused, 0, nfcs); 
3456 #else
3457     for (h = 0; h < (hash_size+780); h++) csused[h] = 0;
3458 #endif
3459   }
3460
3461   ccount=0;
3462   for (h = hash_base + 1; h < nfcs; h++) {
3463     if (pass == 1 && csused[h]) continue;
3464     if (hash[h].v.RH != 0) {
3465       if (pass == 0) csused[h] = 1;
3466       ccount++;
3467     }
3468   }
3469
3470   sprintf(log_line, "\n%d %s multiletter control sequences:\n\n",
3471       ccount, (pass == 1) ? "new" : "");
3472   if (output == stderr) show_line(log_line, 1); 
3473   else if (output == stdout) show_line(log_line, 0);  
3474   else fprintf(output, log_line);
3475
3476   if (ccount > 0) { /* don't bother to get into trouble */
3477     textcolumn=0;
3478     cnumtable = (int *) malloc (ccount * sizeof(int));
3479     if (cnumtable == NULL) return;
3480
3481     ccount=0;
3482 /*    for (h = 515; h < (hash_size + 780); h++) { */
3483     for (h = hash_base+1; h < nfcs; h++) {
3484       if (pass == 1 && csused[ h]) continue; 
3485       if (hash[h].v.RH != 0) cnumtable[ccount++] = h;
3486     }
3487
3488     qsort ((void *)cnumtable, ccount, sizeof (int), &comparecs);
3489
3490     repeatflag = 0;
3491     for (k = 0; k < ccount; k++) {
3492       h = cnumtable[ k];
3493       if (pass == 1 && csused[ h]) continue; 
3494       print_cs_name(output, h);
3495     }
3496     sprintf(log_line, "\n");
3497     if (output == stderr) show_line(log_line, 1);
3498     else if (output == stdout) show_line(log_line, 0);
3499     else fprintf(output, log_line);
3500     free((void *)cnumtable);
3501   }
3502
3503   if (pass == 1 && csused != NULL) {
3504     free(csused);
3505     csused = NULL;
3506   }
3507 }
3508
3509 /***************** font info listing moved from TEX9.C ******************/
3510
3511 void showstring (int k, int l)
3512 {
3513   char *s=log_line;
3514   while (l-- > 0) *s++ = str_pool[k++];
3515   *s++ = ' ';
3516   *s = '\0';
3517   show_line(log_line, 0);
3518 }
3519
3520 /* compare two strings in str_pool (not null terminated) */
3521 /* k1 and k2 are positions in string pool */
3522 /* l1 and l2 are lengths of strings */
3523
3524 int comparestrn (int k1, int l1, int k2, int l2)
3525 {
3526   int c1, c2;
3527 /*  while (l1-- > 0 && l2-- > 0) { */
3528   while (l1 > 0 && l2 > 0) {
3529     c1 = str_pool[k1];
3530     c2 = str_pool[k2];
3531 /*    sprintf(log_line, "%c%d%c%d ", c1, l1, c2, l2); */
3532     if (c1 > c2) return 1;
3533     else if (c2 > c1) return -1;
3534     l1--; l2--;
3535     k1++; k2++;
3536   }
3537   if (l1 > 0) return 1;   /* first string longer */
3538   else if (l2 > 0) return -1; /* second string longer */
3539   return 0;         /* strings match */
3540 }
3541
3542 /* compare two font names and their at sizes in qsort */
3543
3544 int comparefnt (const void *fp1, const void *fp2)
3545 {
3546   int f1, f2, l1, l2, k1, k2, s;
3547   f1 = *(short *)fp1;
3548   f2 = *(short *)fp2;
3549   l1 =(str_start[font_name[f1]+ 1] - str_start[font_name[f1]]); 
3550   l2 =(str_start[font_name[f2]+ 1] - str_start[font_name[f2]]); 
3551   k1 = str_start[font_name[f1]]; 
3552   k2 = str_start[font_name[f2]]; 
3553 /*  showstring (k1, l1); */
3554 /*  showstring (k2, l2); */
3555   s = comparestrn (k1, l1, k2, l2);
3556 /*  sprintf(log_line, "%d\n", s); */
3557   if (s != 0) return s;
3558   if (font_size[f1]> font_size[f2]) return 1;
3559   else if (font_size[f1]< font_size[f2]) return -1;
3560   return 0;         /* should not ever get here */
3561 }
3562
3563 /* compare two font names */
3564
3565 int comparefntname (int f1, int f2)
3566 {
3567   int l1, l2, k1, k2, s;
3568   l1 =(str_start[font_name[f1]+ 1] - str_start[font_name[f1]]); 
3569   l2 =(str_start[font_name[f2]+ 1] - str_start[font_name[f2]]); 
3570   k1 = str_start[font_name[f1]]; 
3571   k2 = str_start[font_name[f2]]; 
3572 /*  showstring (k1, l1); */
3573 /*  showstring (k2, l2); */
3574   s = comparestrn (k1, l1, k2, l2);
3575 /*  sprintf(log_line, "%d\n", s); */
3576   return s;
3577 }
3578
3579 /* decode checksum information */
3580
3581 unsigned long checkdefault = 0x59265920;  /* default signature */
3582
3583 int decode_fourty (unsigned long checksum, char *codingvector)
3584 {
3585   int c;
3586   int k;
3587 /*  char codingvector[6+1]; */
3588
3589 /*  if (checksum == checkdefault) { */
3590   if (checksum == 0) {
3591 /*    strcpy(codingvector, "unknown"); */
3592     strcpy(codingvector, "unknwn");
3593     return 1;
3594   }
3595   else if ((checksum >> 8) == (checkdefault >> 8)) {  /* last byte random */
3596 /*    strcpy (codingvector,  "native"); */  /* if not specified ... */
3597     strcpy (codingvector,  "fixed ");   /* if not specified ... */
3598     return 1;               /* no info available */
3599   }
3600   else {
3601     for (k = 0; k < 6; k++) {
3602       c = (int) (checksum % 40);
3603       checksum = checksum / 40;
3604       if (c <= 'z' - 'a')c = c + 'a';
3605       else if (c < 36) c = (c + '0') - ('z' - 'a') - 1;
3606       else if (c == 36) c = '-';
3607       else if (c == 37) c = '&';
3608       else if (c == 38) c = '_';
3609       else c = '.';       /* unknown */
3610       codingvector[5-k] = (char) c;
3611     }
3612     codingvector[6] = '\0';
3613   }
3614 /*  sprintf(log_line, "Reconstructed vector %s\n", codingvector); */
3615   return 0;         /* encoding info returned in codingvector */
3616 }
3617
3618 double sclpnt (long x)
3619 {
3620   double pt;
3621   pt = (double) x / 65536.0;
3622   pt = (double) ((int) (pt * 1000.0 + 0.5)) / 1000.0;
3623   return (pt);
3624 }
3625
3626 // Shows list of fonts in log file
3627
3628 void dvi_font_show(internal_font_number f, int suppressname)
3629 {
3630   int a, l, k, n, for_end;
3631   unsigned long checksum;
3632   char checksumvector[8];
3633   char buffer[32];
3634
3635 /*  fprintf (log_file, "DAMN! %d ", suppressname); */
3636 /*  fprintf (log_file, "%d ", suppressname); */
3637 /*  suppressname = 0; */
3638   putc(' ', log_file);
3639   if (suppressname == 0) {
3640     a = (str_start[font_area[f]+ 1]- str_start[font_area[f]]); 
3641     l = (str_start[font_name[f]+ 1]- str_start[font_name[f]]); 
3642     k = str_start[font_area[f]];
3643     for_end = str_start[font_area[f]+ 1]- 1;
3644     if (k <= for_end) do {
3645       putc(str_pool[k], log_file);
3646     } while(k++ < for_end, stdout); 
3647     k = str_start[font_name[f]];
3648     for_end = str_start[font_name[f]+ 1]- 1;
3649     if (k <= for_end) do {
3650       putc(str_pool[k], log_file);
3651     } while(k++ < for_end);
3652   }
3653   else a = l = 0;
3654   for (k = a+l; k < 16; k++) putc(' ', log_file);
3655   sprintf(buffer, "at %lgpt ", sclpnt(font_size[f]));
3656   fputs(buffer, log_file);
3657 //  fprintf(log_file, "at %lgpt ", sclpnt(font_size[f]));
3658   if (suppressname == 0) {
3659     n = strlen(buffer);
3660 //    n = strlen(log_file);
3661     for (k = n; k < 16; k++) putc(' ', log_file);
3662     checksum = (((font_check[f].b0) << 8 | font_check[f].b1) << 8 |
3663           font_check[f].b2) << 8 | font_check[f].b3;
3664     decode_fourty(checksum, checksumvector);
3665     fprintf(log_file, "encoding: %s..", checksumvector);
3666   }
3667   putc('\n', log_file);
3668 }
3669
3670 /* Allocate table of indeces to allow sorting on font name */
3671
3672 void show_font_info (void)
3673 {
3674   int k, m, fcount, repeatflag;
3675   short *fnumtable;
3676
3677   fcount=0;
3678   for (k = 1; k <= font_ptr; k++)
3679     if (font_used[k])fcount++;
3680
3681   if (fcount == 0) return;  /* don't bother to get into trouble */
3682
3683   fnumtable = (short *) malloc (fcount * sizeof(short));
3684
3685 /*  if (verbose_flag) sprintf(log_line, "\nUsed %d fonts:\n", fcount); */
3686
3687   fprintf(log_file, "\nUsed %d font%s:\n",
3688       fcount, (fcount == 1) ? "" : "s");
3689
3690   fcount=0;
3691   for (k = 1; k <= font_ptr; k++) 
3692     if (font_used[k])fnumtable[fcount++] = (short) k;
3693
3694   qsort ((void *)fnumtable, fcount, sizeof (short), &comparefnt);
3695
3696   repeatflag = 0;
3697   for (m = 0; m < fcount; m++) {
3698     if (m > 0) {
3699       if (comparefntname(fnumtable[m-1], fnumtable[m]) == 0)
3700         repeatflag = 1;
3701       else repeatflag = 0;
3702     }
3703     dvi_font_show(fnumtable[ m], repeatflag);
3704   }
3705
3706   free((void *)fnumtable);
3707 }
3708
3709 ////////////////////////////////////////////////////////////////////////////
3710
3711 // Here follows the new stuff for the DLL version
3712
3713 #ifdef _WINDOWS
3714
3715 int showlineinx=0;
3716
3717 #define SHOWLINEBUFLEN 256
3718
3719 char showlinebuf[SHOWLINEBUFLEN];
3720
3721 // char log_line[MAXLINE];
3722
3723 #define WHITESPACE " \t\n\r"
3724
3725 HINSTANCE hInstanceDLL=NULL;    /* remember for this DLL */
3726
3727 /* This is the callback function for the EDITTEXT Control in CONSOLETEXT */
3728
3729 #define GET_WM_COMMAND_CMD(wParam, lParam)  (HIWORD(wParam))
3730 #define GET_WM_COMMAND_ID(wParam, lParam) (LOWORD(wParam))
3731 #define GET_WM_COMMAND_HWND(wParam, lParam) ((HWND)lParam)
3732
3733 HWND hConsoleWnd=NULL;    /* Console Text Window Handle passed from DVIWindo */
3734
3735 void ClearShowBuffer (void)
3736 {
3737   showlinebuf[showlineinx++] = '\0';    // clear out accumulated stuff
3738   if (hConsoleWnd != NULL)
3739     SendMessage(hConsoleWnd, ICN_ADDTEXT, (WPARAM) showlinebuf, 0L);
3740   showlineinx = 0;
3741 }
3742
3743 // communicate with DVIWindo (for yandytex.dll)
3744
3745 void show_line (char *line, int errflag) {     /* 99/June/11 */
3746   int ret;
3747
3748   if (IsWindow(hConsoleWnd) == 0) {   // in case the other end died
3749     sprintf(line, "NO CONSOLE WINDOW? %08X %s", hConsoleWnd, line);
3750     ret = MessageBox(NULL, line, "YandYTeX", MB_ICONSTOP | MB_OKCANCEL | MB_TASKMODAL);
3751     hConsoleWnd = NULL;
3752 //    abort_flag++;            // kill job in this case ???
3753     return;
3754   }
3755
3756   if (showlineinx > 0) ClearShowBuffer();
3757
3758   if (hConsoleWnd != NULL)
3759     SendMessage(hConsoleWnd, ICN_ADDTEXT, (WPARAM) line, 0L);
3760
3761   if (errflag) {
3762     err_level++;
3763     ret =  MessageBox(NULL, line, "YandYTeX", MB_ICONSTOP | MB_OKCANCEL | MB_TASKMODAL);
3764     if (ret == IDCANCEL) {
3765 //      abort_flag++;
3766       uexit(1);   // dangerous reentry possibility ?
3767     }
3768   }
3769 }
3770
3771 //  Provide means for buffering up individual characters
3772
3773 void show_char (int chr) {
3774   if (showlineinx +2 >= SHOWLINEBUFLEN) ClearShowBuffer();
3775   showlinebuf[showlineinx++] = (char) chr;
3776   if (chr == '\n') ClearShowBuffer();
3777 }
3778
3779 void winshow(char *line) {
3780   (void) MessageBox(NULL, line, "YandYTeX", MB_ICONINFORMATION | MB_OK | MB_TASKMODAL);
3781 }
3782
3783 void winerror (char *line) {
3784   int ret;
3785   ret = MessageBox(NULL, line, "YandYTeX", MB_ICONSTOP | MB_OKCANCEL | MB_TASKMODAL);
3786   if (ret == IDCANCEL) abort_flag++;
3787 }
3788
3789 // argument info constructed from command line 
3790
3791 int xargc;
3792
3793 char **xargv=NULL;
3794
3795 // need to be careful here because of quoted args with spaces in them
3796 // e.g. -d="G:\Program Files\Adobe\Acrobat\*.pdf"
3797
3798 int makecommandargs (char *line)
3799 {
3800   int xargc;
3801 //  char *s, *t;
3802   unsigned char *s, *t;       // fix 2000 June 18
3803
3804   if (line == NULL) return -1;    /* sanity check */
3805
3806 //  winerror(line);           // debugging only
3807
3808 //  s = strtok(line, WHITESPACE);
3809 //  while (s != NULL) {         /* count arguments */
3810 //    xargc++;
3811 //    s = strtok(NULL, WHITESPACE);
3812 //  }
3813
3814   xargc = 0;
3815   s = line;
3816   while (*s != '\0') {
3817     while (*s <= 32 && *s > 0) s++;
3818     if (*s == '\0') break;
3819     t = s;
3820     while (*t > 32 && *t != '\"') t++;
3821     if (*t == '\"') {
3822       t++;
3823       while (*t > 0 && *t != '\"') t++;
3824       if (*t == '\0') break;
3825       t++;
3826     }
3827 //    xargv[xargc] = s;
3828     xargc++;
3829     if (*t == '\0') break;
3830 //    *t = '\0';
3831     s = t+1;
3832   }
3833
3834   if (xargc == 0) return -1;      /* nothing to do */
3835
3836   xargv = (char **) malloc(xargc * sizeof(char *));
3837   if (xargv == NULL) {
3838     sprintf(log_line, "ERROR: Unable to allocate memory for %s\n", "arguments");
3839     winerror(log_line);
3840     return -1;
3841   }
3842
3843   xargc = 0;
3844   s = line;
3845   while (*s != '\0') {
3846     while (*s <= ' ' && *s > '\0') s++; /* eat white space */
3847     if (*s == '\0') break;
3848     t = s;
3849     while (*t > ' ' && *t != '\"') t++;
3850     if (*t == '\"') {
3851       t++;
3852       while (*t > 0 && *t != '\"') t++;
3853       if (*t == '\0') break;
3854       t++;
3855     }
3856 //    winerror(s);    // debugging only
3857     xargv[xargc] = s;
3858     xargc++;
3859     if (*t == '\0') break;
3860     *t = '\0';
3861     s = t+1;
3862   }
3863
3864 //  s = line;
3865 //  for (k = 0; k < xargc; k++) { /* create pointers to args */
3866 //    while (*s > '\0' && *s <= ' ') s++; /* eat white space */
3867 //    xargv[k] = s;
3868 //    s += strlen(s) +1;
3869 //  }
3870
3871 #ifdef DEBUGGING
3872   s = log_line;
3873   *s = '\0';
3874   for (k = 0; k < xargc; k++) {
3875     sprintf(s, "%d\t%s\n", k, xargv[k]);
3876     s += strlen(s);
3877   }
3878   winshow(log_line);
3879 #endif
3880   return xargc;
3881 }
3882
3883 // refers to TeXAsk in dviwindo.c
3884
3885 // int (* AskUserCall) (char *, char *) = NULL; // callback for user questions
3886 int (* AskUserCall) (char *, char *, char *) = NULL;  // callback for user questions
3887
3888 // called from tex0.c only  ---  by initterm and term_input
3889
3890 //int ConsoleInput (char *question, char *buffer) 
3891 int ConsoleInput (char *question, char *help, char *buffer)
3892 {
3893   int ret=0;
3894 //  char *s;
3895   if (AskUserCall == NULL) return 0;
3896 //  sprintf(log_line, "str_start %x %x\n", str_start, str_start [831]);
3897 //  show_line(log_line, 1);
3898
3899   *buffer = '\0';
3900   ret = AskUserCall (question, help, buffer);   // value returned by dialogbox
3901 //  strcpy(buffer, "x");
3902 //  strcat(buffer, " ");      // ???
3903 //  sprintf(log_line, "str_start %x %x\n", str_start, str_start[831]);
3904 //  show_line(log_line, 1);
3905 //  input_line_finish();      // ???
3906 //  s = buffer + strlen(buffer);
3907 //  *s++ = ' ';           // space terminate
3908 //  *s++ = '\0';          // and null terminate
3909 //  returning != 0 means EOF or ^Z
3910   return ret;
3911 }
3912
3913 //  This is the new entry point of DLL called from DVIWindo 
3914 //  ARGS: console window to send messages to, command line, callback fun
3915 //  no console window output if hConsole is NULL
3916 //  returns -1 if it fails --- returns 0 if it succeeds
3917
3918 // MYLIBAPI int yandytex (HWND hConsole, char *line, int (* AskUser) (char *, char *)) {
3919 MYLIBAPI int yandytex (HWND hConsole, char *line, int (* AskUser) (char *, char *, char *))
3920 {
3921   int flag;
3922
3923   abort_flag = 0;            // redundant
3924   hConsoleWnd = NULL;         // redundant
3925
3926   AskUserCall = AskUser;        // remember callback
3927
3928   hConsoleWnd = hConsole;       // remember console window handle
3929
3930 //  can't getenv("DEBUGPAUSE") cause setupdviwindo not called yet
3931 //  if (grabenv("DEBUGPAUSE") != NULL) {
3932 //    show_line(line, 0);          // debugging - show command line
3933 //    show_line("\n", 0);
3934 //  }
3935
3936   xargc = makecommandargs(line);      // sets up global *xargv[]
3937
3938   if (xargc < 0) return -1;       // sanity check
3939
3940   if (hConsoleWnd != NULL) 
3941     SendMessage(hConsoleWnd, ICN_SETTITLE, (WPARAM) "YandYTeX", 0L);
3942 //  SendMessage(hConsoleWnd, ICN_RESET, 0, 0L); // if want to clear window
3943
3944
3945   (void) main(xargc, xargv);  // now run YandYTeX proper in texmf.c 
3946
3947   if (err_level > 0 || abort_flag > 0) {
3948 //    sprintf(log_line, "ERRORS in Processing (err %d abort %d)\n",
3949 //        err_level, abort_flag);
3950 //    winerror(log_line);
3951   }
3952
3953 //  if (psbufpos > 0) sendpsbuffer(output);   // empty out PS buffer
3954 //  if (psbufpos > 0) PSputs("", output);   // output already closed
3955
3956   if (hConsoleWnd != NULL) {
3957     if (err_level > 0 || abort_flag > 0) flag = 1;
3958     else flag = 0;              // pass along error indication
3959     SendMessage(hConsoleWnd, ICN_DONE, flag, 0);  // flush out console buffer
3960   }
3961 //  PScallback = NULL;
3962   hConsoleWnd = NULL;
3963
3964   if (xargv != NULL) free(xargv);
3965   if (abort_flag) return -1;
3966   else return 0;
3967 }
3968
3969 BOOL WINAPI DllMain (HINSTANCE hInstDll, DWORD fdwReason, LPVOID fImpLoad)
3970 {
3971
3972   switch (fdwReason) {
3973     case DLL_PROCESS_ATTACH:
3974       // The DLL is being mapped into the process's address space
3975       // place to allocate memory ???
3976       // return FALSE if this fails
3977       hInstanceDLL = hInstDll;    /* remember it */
3978       break;
3979
3980     case DLL_THREAD_ATTACH:
3981       // A thread is being created
3982       break;
3983
3984     case DLL_THREAD_DETACH:
3985       // A thread is exiting cleanly
3986       break;
3987
3988     case DLL_PROCESS_DETACH:
3989       // The DLL is being unmapped from the process's address space
3990       // place to free any memory allocated
3991       // but make sure it in fact *was* allocated
3992       hInstanceDLL = NULL;    /* forget it */
3993       break;
3994   }
3995   return(TRUE); // used only for DLL_PROCESS_ATTACH
3996 }
3997 #endif  // end of new stuff for DLL version
3998
3999 //////////////////////////////////////////////////////////////////////////////
4000
4001
4002
4003 /*  NOTE: current_tfm = false (-c)
4004   not checking for TFM in current directory saves 0.1 sec
4005   (0.2 if file_method = false (-G) */
4006
4007 /*  NOTE: test_dir_access = false (-b):
4008   not checking whether readable file is a directory saves maybe 0.5 sec
4009   BUT only if file_method = false (-G) - otherwise its irrelevant */
4010
4011 /*  NOTE: dir_method = false (-D) --- method for checking whether directory
4012   using fopen instead of _findfirst in dir_p slows job maybe 0.05 sec
4013   BUT not if current_tfm = false (-c) */
4014
4015 /*  NOTE: file_method = false (-G) --- method for checking file accessible
4016   using _access (readable) instead of _findfirst (file_p) costs 0.5 sec */
4017
4018 /*  Fast flag combinations: nothing, bG, bcG, bcDG */
4019
4020 /* constants for _heapchk/_heapset/_heapwalk routines */
4021 /* #define _HEAPEMPTY (-1) */
4022 /* #define _HEAPOK  (-2) */
4023 /* #define _HEAPBADBEGIN  (-3) */
4024 /* #define _HEAPBADNODE (-4) */
4025 /* #define _HEAPEND (-5) */
4026 /* #define _HEAPBADPTR  (-6) */
4027
4028 /* new arg -H=8 for horizontal tab *//* tab_step = 0 means no tab replacement */
4029
4030 /* buffercopy no longer used */
4031
4032 /* To Knuthian reset right when command line interpreted */
4033