OSDN Git Service

ce295fe4ec6f8bdcacee3ac77c1d9a813063c8b9
[putex/putex.git] / src / dvisourc / dvipslog.c
1 /* Copyright 1990,1991,1992,1993,1994,1995,1996,1997,1998,1999 Y&Y, Inc.
2    Copyright 2007 TeX Users Group
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 /**********************************************************************
20 *
21 * DVI analyzer to extract font and character usage
22 * part of DVIPSONE
23 *
24 **********************************************************************/
25
26 /* Revised 1999 June 13 to run in DLL form */
27
28 #ifdef _WINDOWS
29 #define NOCOMM
30 #define NOSOUND
31 #define NODRIVERS
32 #define STRICT
33 #include <windows.h>
34 #endif
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <malloc.h>
40 #include <setjmp.h>
41
42 #ifdef _WINDOWS
43 // We must define MYLIBAPI as __declspec(dllexport) before including
44 // dvipsone.h, then dvipsone.h will see that we have already
45 // defined MYLIBAPI and will not (re)define it as __declspec(dllimport)
46 #define MYLIBAPI __declspec(dllexport)
47 // #include "dvipsone.h"
48 #endif
49
50 #include "dvipsone.h"
51
52 #ifdef _WINDOWS
53 #pragma warning(disable:4100) // unreferenced formal variable 
54 #endif
55
56 #pragma warning(disable:4996)
57 #pragma warning(disable:4127) // conditional expression is constant
58
59 #pragma hdrstop
60
61 #include <io.h>         /* for _access */
62                 /* for _findfirst, _findnext, _findclose */
63
64 /* #define DEBUGALIAS */
65
66 /* #define DEBUGCOLORSTACK */
67
68 /* #define DEBUGATM */
69
70 COLORSPEC CurrColor;
71
72 /* tables to store background color for each page on prescan 98/Jun/30 */
73
74 COLORSPEC *BackColors=NULL;
75
76 /* font k is to be used at mag * s / (1000 * d) times its normal size */
77
78 int fonthit[MAXFONTS];      /* which fonts have been seen - NOT ACCESSED */
79
80 /* char *currentfont;  */       /* pointer to current font */
81 char *currentfont;        /* pointer to current font */
82
83 long pageno;  /* for convenience in error messages - may be logical page */
84
85 /* now for the scan of the DVI file for font character log generation */
86
87 /* now for the scan of the DVI file for PS output generation */
88
89 void reset_stack(void)
90 {
91   stinx = 0;
92 }
93
94 void check_stack(int pageno)
95 {
96   if (stinx != 0)
97   {
98     sprintf(logline, " ERROR: stack not empty at EOP: %d on page %d ", stinx, pageno); /* pageno ? logical page */
99     showline(logline, 1);
100     tellwhere(input, 1);
101 /*    errcount(0); */
102 /*    giveup(3); */
103   }
104 }
105
106 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
107  
108 /* we don't have to worry about sign extension here - no need for short int */
109
110 /* static unsigned int ureadone (FILE *infile) {
111   return getc(infile);
112 } */
113
114 static unsigned int ureadtwo (FILE *infile)
115 {
116   return (getc(infile) << 8) | getc(infile);
117 }
118
119 static unsigned long ureadthree (FILE *infile)
120 {
121   int c, d, e; 
122 /*  unsigned int c, d, e; */
123   c = getc(infile); d = getc(infile); e = getc(infile);
124   return ((((unsigned long) c << 8) | d) << 8) | e;
125 }
126
127 static unsigned long ureadfour (FILE *infile)
128 {
129   int c, d, e, f;
130   c = getc(infile); d = getc(infile);
131   e = getc(infile); f = getc(infile);
132   return ((((((unsigned long) c << 8) | (unsigned long) d) << 8) | e) << 8) | f;
133 }
134
135 /* we do have to worry about sign extension here - use short int if needed */
136
137 /* static int sreadone (FILE *infile) {
138   int c;
139   c = getc(infile);
140   if (c > 127) return (c - 256);
141   else return c;
142 } */
143
144 #ifdef IGNORED
145 /* static short int sreadtwo (FILE *infile) { */  /* ??? */
146 static int sreadtwo (FILE *infile)
147 {
148   short int result;
149 /*  return (getc(infile) << 8) | getc(infile); */ /* 1995/Nov/15 */
150 /*  result = (getc(infile) << 8) | getc(infile); */
151   result = ((short int) getc(infile) << 8) | (short int) getc(infile);
152   return result;
153 } /* needed now for code imported from dviextra.c readtfm etc */
154 #endif
155
156 /* avoid possible compiler optimization error */
157
158 static int sreadtwo (FILE *input)    /* experiment 98/Feb/7 */
159 {
160   int c, d;
161   c = getc(input);  d = getc(input);
162   if (c > 127) c = c - 256;
163   return  (c << 8) | d;
164 }
165
166 /* static long sreadthree (FILE *infile) {
167   int c, d, e;
168   c = getc(infile); d = getc(infile); e = getc(infile);
169   if (c > 127) c = c - 256; 
170   return ((((long) c << 8) | d) << 8) | e;
171  } */
172
173 static long sreadfour (FILE *infile)
174 {
175   int c, d, e, f;
176   c = getc(infile); d = getc(infile);
177   e = getc(infile); f = getc(infile);
178   return ((((((long) c << 8) | (long) d) << 8) | e) << 8) | f;
179
180
181 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
182
183 int MaxColor;   /* size of save area allocated for color stacks */
184 /* int MaxBack; */    /* size of save area allocated for background color */
185
186 COLORSPEC **ColorStacks=NULL; /* array of saved color stacks, one per page */
187
188 /*  restore at start of page what was current at end of page-1 */
189 /*  called from dvianal.c */ /* page is physical DVI page from start of file */
190
191 void RestoreColorStack (int page)
192 {
193   COLORSPEC *SavedStack;
194   int k;
195 /*  don't bother if color \special{...} was never used */
196   if (bCarryColor == 0 || bColorUsed == 0) return;
197   if (page >= MaxColor) return;         /* sanity check */
198   page--;     /* restore what was saved at eop of *previous* */
199   if (page < 1) { /* nothing saved to restore at start of first page */
200     colorindex = 0;
201     return;
202   }
203   if (ColorStacks == NULL) return;    /* sanity check */
204 /*  GrabColor(); */
205   SavedStack = ColorStacks[page];
206   if (SavedStack == NULL)
207   {
208     sprintf(logline, " Bad Color Restore page %d (%d)",
209         page, MaxColor-1);
210     showline(logline, 1);
211     colorindex = 0;
212     return;
213   }
214   colorindex = (int) (SavedStack[0].D + 0.5); /* depth of saved stack */
215 #ifdef DEBUGCOLORSTACK
216   if (traceflag)
217   {
218     sprintf(logline, " RestoreColorStack from page-1 %d colorindex %d\n",
219               page, colorindex);
220     showline(logline, 0);
221   }
222 #endif
223   if (colorindex > 0 && colorindex < MAXCOLORSTACK) {
224     for (k = 0; k < colorindex; k++) ColorStack[k] = SavedStack[k+1];
225   }
226   else {
227     sprintf(logline, " ERROR: colorindex %d", colorindex);  /* BUG */
228     showline(logline, 1);
229   }
230 /*  ReleaseColor(); */
231 }
232
233 /*  Save at end of page for start of page+1 */
234 /*  called from logdo_eop dvipslog.c */ /* page is DVI page from start of file */
235
236 void SaveColorStack (int page, int colorindex)
237 {
238   COLORSPEC *SavedStack;
239   int k;
240 /*  if (bCarryColor == 0 || bColorUsed == 0) return; */
241   if (bCarryColor == 0) return;
242 /*  if (page < 0 || page >= MaxColor) return; */
243 /*  GrabColor(); */
244   if (ColorStacks == NULL) return;    /* sanity check */
245   if (ColorStacks[page] != NULL) {
246     sprintf(logline, " Bad Color Save page %d (%d) %08x",
247         page, MaxColor, ColorStacks[page]);
248     showline(logline, 1);
249 /*    free(lpColor[page]); */
250   }
251 #ifdef DEBUGCOLORSTACK
252   if (traceflag)
253   {
254     sprintf(logline, " SaveColorStack page %d colorindex %d\n",
255         page, colorindex);
256     showline(logline, 0);
257   }
258 #endif
259   if (colorindex == 0) return;    /* nothing to save ??? */
260   SavedStack = (COLORSPEC *) malloc ((colorindex+1) * sizeof(COLORSPEC));
261   ColorStacks[page] = SavedStack;
262   SavedStack[0].A = SavedStack[0].B = SavedStack[0].C = 0.0F;
263   SavedStack[0].D = (float) colorindex;
264   for (k = 0; k < colorindex; k++) SavedStack[k+1] = ColorStack[k];
265 /*  ReleaseColor(); */
266 }
267
268 /* format of allocated area is count followed by stack dump */
269
270 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
271
272 void logdo_push(void)
273 {
274   if (skipflag == 0) {
275     stinx++;
276     if (stinx > maxstinx) maxstinx = stinx;
277 /*    if (stinx >= maxstack - 1) {
278       showline(" WARNING: The stack will overflow\n", 1);
279       errcount(0);
280     } */
281   }
282 }
283
284 void logdo_pop(void)
285 {
286   if (skipflag == 0)
287   {
288     stinx--;
289     if (stinx < 0)
290     {
291       sprintf(logline,
292            " ERROR: The stack will underflow on page %d ",
293            pageno); /* pagenumber ??? logical page */
294       showline(logline, 1);
295       tellwhere(input, 1);
296 /*      errcount(0); */
297     }
298   }
299 }
300
301 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
302
303 void invalidset(int c)
304 {
305   sprintf(logline, " ERROR: Setting char %d without font on page %d ",
306       c, pageno); /* pagenumber ??? logical page */
307   showline(logline, 1);
308   tellwhere(input, 1);
309 /*  errcount(0); */
310 }
311
312 /* common subroutine for set2 set3 set4 --- which should not occur */
313
314 void logdo_setsub(unsigned long c)
315 {
316   if (skipflag == 0) {
317 /*    if (ff < 0) invalidset((int) c); */
318     if (ff == BLANKFONT) invalidset((int) c);
319     else if (c < 256) {
320 /*      if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
321       if (bRemapControl || bRemapFont) {
322         if (c < MAXREMAP) c = remaptable[c];
323 #if MAXREMAP < 128
324         else if (c == 32) c = 195;
325         else if (c == 127) c = 196;
326 #endif
327       }
328 /* NOTE: this must match corresponding code in DVIANAL.C */
329       else if (bRemapSpace && c <= 32) {      /* 1995/Oct/17 */
330         if (c == 32) c = 195;   /* not 160 */
331         else if (c == 13) c = 176;  /* 1996/June/4 */
332         else if (c == 10) c = 173;  /* 1996/June/4 */
333         else if (c == 9) c = 170;   /* 1996/June/4 */
334         else if (c == 0) c = 161;
335       }
336       currentfont[c] = 1;
337     }
338   }
339 }
340
341 /* For speed we keep the set1 case separate since it occurs often */
342
343 void logdo_set1(FILE *infile)
344 {
345   unsigned int c;
346 /*  c = ureadone(infile); */
347   c = getc(infile);
348   if (skipflag == 0) {
349 /*    if (ff < 0) invalidset((int) c); */
350     if (ff == BLANKFONT) invalidset((int) c);
351     else {
352 /*      if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
353       if (bRemapControl || bRemapFont) {
354         if (c < MAXREMAP) c = remaptable[c];
355 #if MAXREMAP < 128
356         else if (c == 32) c = 195;
357         else if (c == 127) c = 196;
358 #endif
359       }
360       else if (bRemapSpace && c <= 32) {      /* 1995/Oct/17 */
361         if (c == 32) c = 195;   /* not 160 */
362         else if (c == 13) c = 176;  /* 1996/June/4 */
363         else if (c == 10) c = 173;  /* 1996/June/4 */
364         else if (c == 9) c = 170;   /* 1996/June/4 */
365         else if (c == 0) c = 161;
366       }
367       currentfont[c] = 1;
368     }
369   }
370 }
371
372 /* simplified 95/Oct/17 by using logo_setsub for logdo_set2 */
373
374 void logdo_set2(FILE *infile)
375 {
376   logdo_setsub(ureadtwo(infile));
377 }
378
379 #ifdef IGNORED
380 void logdo_set2(FILE *infile)
381 {
382   unsigned int c;
383   c = ureadtwo(infile);
384   if (skipflag == 0) {
385 /*    if (ff < 0) invalidset((int) c); */
386     if (ff == BLANKFONT) invalidset((int) c);
387     else if (c < 256) {
388 /*      if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
389       if (bRemapControl || bRemapFont) {
390         if (c < MAXREMAP) c = remaptable[c];
391 #if MAXREMAP < 128
392         else if (c == 32) c = 195;
393         else if (c == 127) c = 196;
394 #endif
395       }
396       else if (bRemapSpace && c <= 32) {      /* 1995/Oct/17 */
397         if (c == 32) c = 195;   /* not 160 */
398         else if (c == 13) c = 176;  /* 1996/June/4 */
399         else if (c == 10) c = 173;  /* 1996/June/4 */
400         else if (c == 9) c = 170;   /* 1996/June/4 */
401         else if (c == 0) c = 161;
402       }
403       currentfont[c] = 1;
404     }
405   }
406 }
407 #endif
408
409 void logdo_set3(FILE *infile)
410 {
411   logdo_setsub(ureadthree(infile));
412 }
413
414 void logdo_set4(FILE *infile)
415 {
416   logdo_setsub(ureadfour(infile));
417 }
418
419 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
420
421 /* common subroutine for put2, put3, pu4 --- which should not occur */
422
423 void logdo_putsub(unsigned long c)
424 {
425   if (skipflag == 0)
426   {
427 /*    if (ff < 0) invalidset((int) c); */
428     if (ff == BLANKFONT) invalidset((int) c);
429     else if (c < 256) {
430 /*      if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
431       if (bRemapControl || bRemapFont) {
432         if (c < MAXREMAP) c = remaptable[c];
433 #if MAXREMAP < 128
434         else if (c == 32) c = 195;
435         else if (c == 127) c = 196;
436 #endif
437       }
438       else if (bRemapSpace && c <= 32) {      /* 1995/Oct/17 */
439         if (c == 32) c = 195;   /* not 160 */
440         else if (c == 13) c = 176;  /* 1996/June/4 */
441         else if (c == 10) c = 173;  /* 1996/June/4 */
442         else if (c == 9) c = 170;   /* 1996/June/4 */
443         else if (c == 0) c = 161;
444       }
445       currentfont[c] = 1;
446     }
447   }
448 }
449
450 /* For speed we keep the set1 case separate since it occurs sometimes */
451
452 void logdo_put1(FILE *infile)
453 {
454   unsigned int c;
455 /*  c = ureadone(infile); */
456   c = getc(infile);
457   if (skipflag == 0) {
458 /*    if (ff < 0) invalidset((int) c); */
459     if (ff == BLANKFONT) invalidset((int) c);
460     else {
461 /*      if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
462       if (bRemapControl || bRemapFont) {
463         if (c < MAXREMAP) c = remaptable[c];
464 #if MAXREMAP < 128
465         else if (c == 32) c = 195;
466         else if (c == 127) c = 196;
467 #endif
468       }
469       else if (bRemapSpace && c <= 32) {      /* 1995/Oct/17 */
470         if (c == 32) c = 195;   /* not 160 */
471         else if (c == 13) c = 176;  /* 1996/June/4 */
472         else if (c == 10) c = 173;  /* 1996/June/4 */
473         else if (c == 9) c = 170;   /* 1996/June/4 */
474         else if (c == 0) c = 161;
475       }
476       currentfont[c] = 1;
477     }
478   }
479 }
480
481 /* simplified 95/Oct/17 by using logo_putsub for logdo_put2 */
482
483 void logdo_put2(FILE *infile)
484 {
485   logdo_putsub(ureadtwo(infile));
486 }
487
488 #ifdef IGNORED
489 void logdo_put2(FILE *infile)
490 {
491   unsigned int c;
492   c = ureadtwo(infile);
493   if (skipflag == 0) {
494 /*    if (ff < 0) invalidset((int) c); */
495     if (ff == BLANKFONT) invalidset((int) c);
496     else if (c < 256) {
497 /*      if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
498       if (bRemapControl || bRemapFont) {
499         if (c < MAXREMAP) c = remaptable[c];
500 #if MAXREMAP < 128
501         else if (c == 32) c = 195;
502         else if (c == 127) c = 196;
503 #endif
504       }
505       else if (bRemapSpace && c <= 32) {      /* 1995/Oct/17 */
506         if (c == 32) c = 195;   /* not 160 */
507         else if (c == 13) c = 176;  /* 1996/June/4 */
508         else if (c == 10) c = 173;  /* 1996/June/4 */
509         else if (c == 9) c = 170;   /* 1996/June/4 */
510         else if (c == 0) c = 161;
511       }
512       currentfont[c] = 1;
513     }
514   }
515 }
516 #endif
517
518 void logdo_put3(FILE *infile)
519 {
520   logdo_putsub(ureadthree(infile));
521 }
522
523 void logdo_put4(FILE *infile)
524 {
525   logdo_putsub(ureadfour(infile));
526 }
527
528 void logdo_set_rule(FILE *infile)
529 {
530   int k;
531   for (k=0; k < 8; k++) (void) getc(infile);
532 }
533
534 void logdo_put_rule(FILE *infile)
535 {
536   int k;
537   for (k=0; k < 8; k++) (void) getc(infile);
538 }
539
540 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
541
542 /* int currentrange; */ /* range currently working in */
543 long currentpage;   /* page currently working in */
544 int prescanflag;    /* prescan is always forward */
545 int pagesequence;   /* count of ascending page sequence */
546
547 /* returns zero if page is to be printed */ /* non-zero if to be skipped */
548
549 int skipthispage(long pageno)
550 {
551   int k;
552 /*  int hitrange=0; */
553 /*  int wantpage=0; */
554
555   if (rangeindex == 0) return 0;    /* easy, no page ranges specified! */
556
557   if (countzeroflag != 0) {
558     if (prescanflag != 0 || reverseflag == 0) {
559 /* going forward, we remain in same page sequence if: */
560 /* (positive and ascending) or (negative and descending) */
561       if (currentpage == -LINFINITY) ;  /* first time */
562       else if (currentpage >= 0 && pageno >= 0 && pageno > currentpage) ;
563       else if (currentpage <= 0 && pageno <= 0 && pageno < currentpage) ;
564       else pagesequence++;
565     }
566     else if (reverseflag != 0) {
567 /* going backward, we remain in same page sequence if: */
568 /* (positive and descending) or (negative and ascending) */
569       if (currentpage == -LINFINITY) ;  /* first time */
570       else if (currentpage >= 0 && pageno >= 0 && pageno < currentpage) ;
571       else if (currentpage <= 0 && pageno <= 0 && pageno > currentpage) ;
572       else pagesequence--;
573     }
574     currentpage = pageno;           /* remember page number */
575   }
576
577   for (k = 0; k < rangeindex; k++) { 
578 /*    is current page in this page range ? */
579     if ((pageno >= beginpages[k]) && (pageno <= endpages[k]))  {
580       if (countzeroflag == 0) return 0; /* easy, not using count[0] */
581       if (pagerangeseq[k] < 0)      /* no instance specified */
582         return 0;           /* means always print */
583       if (pagerangeseq[k] == pagesequence) /* matches instance */
584         return 0;           /* OK, print it */
585     }
586   }
587   return 1;             /* not inside any specified range */
588 }
589
590 void logdo_bop(FILE *infile) /* beginning of page */
591 {
592   int k;
593   long current;       /* ??? */
594
595   current = ftell(input) - 1;
596
597   pagenumber++;     /* increment pages seen - going forward here */
598   reset_stack();      /*  stinx = 0; */
599   ff = -1;        /* undefined font */
600   fnt = finx[0];      /* just in case - not clear could be -1 ! or 255 */
601 //  currentfont = fontchar;         /* just in case */
602   currentfont = fontchar[0];        /* just in case ??? */
603
604   for(k=0; k < 10; k++) counter[k] = sreadfour(infile);
605
606   previous = sreadfour(infile);
607 /*  skipflag = 0; */
608   if (countzeroflag != 0) pageno = counter[0];
609   else pageno = (long) pagenumber;
610   skipflag = skipthispage(pageno);  /* figure out if skipped */
611 /*  if (beginpage != -LINFINITY && pageno < beginpage)  skipflag++;
612   if (endpage != LINFINITY && pageno > endpage) skipflag++;  */
613 /*  following is the logic for two-sided printing */
614   if (skipflag == 0) {
615     if (oddpageflag != 0 && (counter[0] & 1) == 0) skipflag++;
616     if (evenpageflag != 0 && (counter[0] & 1) == 1) skipflag++;
617   }
618 /*  what about first page ? */
619   if (bCarryColor) {
620     if (colorindex > 0)       /* avoid error on first page */
621       doColorPop(pagenumber);   /* 98/Feb/15 to match ColorPush in eop */
622   }
623   if (bBackGroundFlag) {        /* carry background color 99/Apr/05 */
624     if (pagenumber > 0)       /* avoid on first page */
625       BackColors[pagenumber] = BackColors[pagenumber-1];
626 /*    else if (pagenumber == 0) {
627       BackColors[0].A = BackColors[0].B = BackColors[0].C = -1.0F;
628       BackColors[0].D = -1.0F;
629     } */
630   }
631 }
632
633 void logdo_eop(FILE *infile) { /* end of page */
634   int c;
635
636   if (bAbort) abortjob();         /* 1992/Nov/24 */
637   if (abortflag) return;
638   check_stack(pagenumber);
639   if (bCarryColor) {
640     doColorPush(pagenumber);          /* 98/Feb/15 ??? */
641     SaveColorStack(pagenumber, colorindex);   /* 98/Feb/19 ??? */
642   }
643   if (textures != 0) 
644     (void) ureadfour(infile); /* flush Textures length code */
645 /*  may want to check whether length is something reasonable ? */
646   c = getc(infile); (void) ungetc(c, infile);   /* peek ahead */
647 /*  here we expect to see bop, nop or fnt_def's ONLY */
648   if (c >= 0 && c <= 127) {
649     sprintf(logline, " ERROR: Invalid DVI code (%d) between EOP and BOP ", c);
650     showline(logline, 1);
651     tellwhere(infile, 1);
652 /*    errcount(0); */
653     finish = -1;
654   }
655   if (skipflag == 0)  numpages++;       /* 94/Oct/12 */
656   skipflag = 0;
657 }
658
659 void logdo_right1(FILE *infile) /* rare */
660 {
661   (void) getc(infile);
662 }
663
664 void logdo_right2(FILE *infile)
665 {
666   (void) getc(infile); (void) getc(infile);
667
668
669 void logdo_right3(FILE *infile)
670 {
671   (void) getc(infile); (void) getc(infile); (void) getc(infile);
672
673
674 void logdo_right4(FILE *infile)
675 {
676   (void) getc(infile); (void) getc(infile);
677   (void) getc(infile); (void) getc(infile);
678
679
680 void logdo_w0(void)
681 {
682 }
683
684 void logdo_w1(FILE *infile) /* rare */
685 {
686   (void) getc(infile);
687 }
688
689 void logdo_w2(FILE *infile)
690 {
691   (void) getc(infile); (void) getc(infile);
692
693
694 void logdo_w3(FILE *infile)
695 {
696   (void) getc(infile); (void) getc(infile); (void) getc(infile);
697
698
699 void logdo_w4(FILE *infile)
700 {
701   (void) getc(infile); (void) getc(infile);
702   (void) getc(infile); (void) getc(infile);
703 }
704
705 void logdo_x0(void)
706 {
707 }
708
709 void logdo_x1(FILE *infile) /* rare */
710 {
711   (void) getc(infile);
712 }
713
714 void logdo_x2(FILE *infile)
715 {
716   (void) getc(infile); (void) getc(infile);
717
718
719 void logdo_x3(FILE *infile)
720 {
721   (void) getc(infile); (void) getc(infile); (void) getc(infile);
722 }
723
724 void logdo_x4(FILE *infile)
725 {
726   (void) getc(infile); (void) getc(infile);
727   (void) getc(infile); (void) getc(infile);
728 }
729
730 void logdo_down1(FILE *infile) /* rare */
731 {
732   (void) getc(infile);
733 }
734
735 void logdo_down2(FILE *infile) /* rare */
736 {
737   (void) getc(infile); (void) getc(infile);
738 }
739
740 void logdo_down3(FILE *infile)
741 {
742   (void) getc(infile); (void) getc(infile); (void) getc(infile);
743 }
744
745 void logdo_down4(FILE *infile)
746 {
747   (void) getc(infile); (void) getc(infile);
748   (void) getc(infile); (void) getc(infile);
749 }
750
751 void logdo_y0(void)
752 {
753 }
754
755 void logdo_y1(FILE *infile) /* rare */
756 {
757   (void) getc(infile);
758 }
759
760 void logdo_y2(FILE *infile)
761 {
762   (void) getc(infile); (void) getc(infile);
763 }
764
765 void logdo_y3(FILE *infile)
766 {
767   (void) getc(infile); (void) getc(infile); (void) getc(infile);
768
769
770 void logdo_y4(FILE *infile) /* not used */
771 {
772   (void) getc(infile); (void) getc(infile);
773   (void) getc(infile); (void) getc(infile);
774 }
775
776 void logdo_z0(void)
777 {
778 }
779
780 void logdo_z1(FILE *infile)  /* rare */
781 {
782   (void) getc(infile);
783 }
784
785 void logdo_z2(FILE *infile)
786 {
787   (void) getc(infile); (void) getc(infile);
788
789
790 void logdo_z3(FILE *infile)
791 {
792   (void) getc(infile); (void) getc(infile); (void) getc(infile);
793
794
795 void logdo_z4(FILE *infile)
796 {
797   (void) getc(infile); (void) getc(infile);
798   (void) getc(infile); (void) getc(infile);
799 }
800
801 void logswitchfont(int fn, FILE *infile) /* switching to other font */
802 {
803   int c;
804   ff = fn;      /* set state */
805   fnt = finx[fn];
806 /*  if (fnt < 0) { */
807   if (fnt == BLANKFONT) {               /* 93/Dec/11 */
808     if (fn == 52) {
809       c = getc(infile); (void) ungetc(c, infile);
810       if (c == 171 + 52) {
811         sprintf(logline, " ERROR: Unexpected encounter of DVI trailer on page %d ", pagenumber);
812         showline(logline, 1);
813 /*        errcount(0); */
814 /*        finish = -1; */
815         giveup(9); 
816         return;
817       }
818     }
819     sprintf(logline, " ERROR: switch to undefined font (%d) on page %d ",
820         fn, pagenumber);
821     showline(logline, 1);
822     tellwhere(infile, 1);
823 /*    errcount(0); */
824     fnt = 0; 
825   }
826 //  currentfont = fontchar + MAXCHRS * fnt;
827   if (fontchar[fnt] == NULL) setupfontchar(fnt);
828   currentfont = fontchar[fnt]; 
829   fonthit[fnt] = 1;   /* even if skipflag != 0 ? */
830 }
831
832 void logdo_fnt1(FILE *infile) /* switch fonts */
833 {
834   int fn;
835 /*  fn = ureadone(infile); */
836   fn = getc(infile);
837 /*  if (skipflag == 0) */
838   logswitchfont(fn, infile);
839 }
840
841 void logdo_fnt2(FILE *infile) /* switch fonts */
842 {
843   unsigned int fn;
844   fn = ureadtwo(infile);
845 /*  if (skipflag == 0) */
846   if (fn >= MAXFONTNUMBERS) fn = MAXFONTNUMBERS-1;
847   logswitchfont((int) fn, infile);
848 }
849
850 void logdo_fntsub(unsigned long fn, FILE *infile) /* switch fonts */
851 {
852 /*  if (skipflag == 0) */
853   if (fn >= MAXFONTNUMBERS) fn = MAXFONTNUMBERS-1;
854   logswitchfont((int) fn, infile);
855 }
856
857 void logdo_fnt3(FILE *infile) /* switch fonts */
858 {
859 /*  unsigned long fn;
860   fn = ureadthree(infile); */
861   logdo_fntsub(ureadthree(infile), infile);
862 }
863
864 void logdo_fnt4(FILE *infile) /* switch fonts */
865 {
866   long fn;
867   fn = sreadfour(infile);
868 /*  if (skipflag == 0) */
869   if (fn < 0) fn = 0;
870   logdo_fntsub((unsigned long) fn, infile);
871 }
872
873 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
874
875 void getheadername (FILE *infile) /* new version 95/Aug/30 */
876 {
877   char fname[FNAMELEN];     /* buffer to get token into */
878   char *s;
879
880 /*  if (gettoken(infile, headerfile, FNAMELEN) == 0) {*/
881   if (gettoken(infile, fname, sizeof(fname)) == 0) {  /* FNAMELEN */
882     showline(" Can't find header\n", 1);
883     errcount(0); 
884     return;
885   }
886
887 //  check whether this header file has already been listed 
888 //  if ((s = strstr(headerfile, fname)) != NULL) {
889   if (headerfile != NULL) {
890     if ((s = strstr(headerfile, fname)) != NULL) {
891       s += strlen(fname);
892       if (*s == '\0' || *s == ',') {
893         return;
894       }
895     }
896   }
897
898 //  check whether there is enough space for the new name to add 
899 //  if (strlen(headerfile) + strlen(fname) + 2 >= sizeof(headerfile)) {
900 //    sprintf(logline, " No more space for HEADER (> %d)\n", sizeof(headerfile));
901 //    showline(logline, 1);
902 //    errcount(0);
903 //    return;
904 //  }
905
906   if (headerfile == NULL) {
907 //    nheaderlength = strlen(headerfile) + 2;
908     nheaderlength = strlen(fname) + 2;
909     headerfile = malloc(nheaderlength);
910     if (headerfile == NULL) return;     // allocation error - complain ???
911     *headerfile = '\0';
912   }
913
914   while (strlen(headerfile) + strlen(fname) + 2 > (size_t) nheaderlength) {
915     nheaderlength += strlen(fname) + 2;
916     headerfile = realloc(headerfile, nheaderlength);
917   }
918   if (headerfile == NULL) return;   // allocation error - complain ???
919
920 //  add a comma separator, unless this is the first one 
921   if (*headerfile != '\0') {
922     s = headerfile + strlen(headerfile);
923     *s++ = ',';           // comma
924     *s = '\0';            // not needed
925   }
926   else s = headerfile;        // first time
927
928 //  finally: append the header file name  ...
929   strcpy(s, fname);
930 }
931
932 /* get name of file with DSC header comments */ /* only one allowed */
933
934 void getcustomname (FILE *infile)
935 {
936 /*  int n=0; */
937
938   if (dscfile != NULL) {
939     showline(" More than one DSCheader", 1);
940     errcount(0);
941     return;
942   }
943 /*  if (gettoken(infile, line, MAXLINE) == 0) { */
944   if (gettoken(infile, line, sizeof(line)) == 0) { /* MAXLINE */
945     showline(" Can't find header\n", 1);
946     errcount(0); 
947   }
948   else {
949     dscfile = zstrdup(line);    /* remember single file name */
950   }
951 }
952
953 /* accumulate verbatim PS header text for prolog */
954
955 void getheadertext (FILE *infile)   /* new 1993/Dec/29 */
956 {
957   char *headernew;
958   char *u;
959   int n;
960
961 /*  if (headertext == NULL) headernew = malloc (nspecial+2); else */
962 /*  first time around, headertext will be NULL, so it acts like malloc */
963   n = headertextlen + (int) nspecial + 2;
964 /*  headernew = realloc (headertext, n); */
965   headernew = realloc (headertext, n);
966   if (headernew == NULL) {
967     showline(" Unable to allocate memory\n", 1);
968 /*    flushspecial(infile); */
969 /*    errcount(0); */
970 /*    return; */
971     checkexit(1);             /* 1995/July/15 */
972 //    more serious exit(1) ???
973   }
974   headertext = headernew;
975   u = headernew + headertextlen;
976   headertextlen = headertextlen + (int) nspecial + 1;
977   while (nspecial-- > 0) *u++ = (char) getc(infile);
978   *u++ = '\n'; *u++ = '\0';       /* terminating linefeed and \0 */
979 }
980
981 /* accumulate command line args for DVIPSONE - passed through DVI file */
982
983 void getcommandspec (FILE *infile)    // 99/Sept/6
984 {
985   char *commandnew;
986   char *u;
987   int n;
988
989 /*  first time around, commandspec will be NULL, so it acts like malloc */
990   n = commandspeclen + (int) nspecial + 2;
991   commandnew = realloc (commandspec, n);
992   if (commandnew == NULL) {
993     showline(" Unable to allocate memory\n", 1);
994     checkexit(1);
995   }
996   commandspec = commandnew;
997   u = commandnew + commandspeclen;
998   commandspeclen = commandspeclen + (int) nspecial + 1;
999   while (nspecial-- > 0) *u++ = (char) getc(infile);
1000   *u++ = '\n'; *u++ = '\0';   // terminating linefeed and \0 
1001  }
1002
1003 /* accumulate verbatim PS header text for prolog */
1004
1005 void getcustomtext (FILE *infile)     /* new 1995/July/15 */
1006 {
1007   int c, n, needpercent=0;
1008   char *customnew;
1009   char *u;
1010
1011   c = getc(infile); ungetc(c, infile);
1012   if (c != '%') needpercent = 1;
1013 /*  if (dsccustom == NULL) customnew = malloc (nspecial+2); else */
1014 /*  first time around, dsccustom will be NULL, so it acts like malloc */
1015   n = dsccustomlen + (int) nspecial + 2;
1016   if (needpercent) n = n+2;
1017 /*  customnew = realloc (dsccustom, n); */
1018   customnew = realloc (dsccustom, n);
1019   if (customnew == NULL) {
1020     showline(" Unable to allocate memory\n", 1);
1021 /*    flushspecial(infile); */
1022 /*    errcount(0); */
1023 /*    return; */
1024     checkexit(1);             /* 1995/July/15 */
1025 //    more serious exit(1) ???
1026   }
1027   dsccustom = customnew;
1028   u = customnew + dsccustomlen;
1029   dsccustomlen = dsccustomlen + (int) nspecial + 1;
1030   if (needpercent) {
1031     *u++ = '%';   *u++ = '%';
1032     dsccustomlen = dsccustomlen + 2;
1033   }
1034   while (nspecial-- > 0) *u++ = (char) getc(infile);
1035   *u++ = '\n'; *u++ = '\0';       /* terminating linefeed and \0 */
1036 }
1037
1038 void getbbox (FILE *infile) /* Use for CropBox pdfmark not tested */
1039 {
1040 /*  Right now this is in PS coordinates, should be in TeX coordinates */
1041   if (gettoken(infile, line, sizeof(line)) != 0) { /* MAXLINE */
1042     sscanf(line, "%d", &BBxll);
1043   }
1044   if (gettoken(infile, line, sizeof(line)) != 0) { /* MAXLINE */
1045     sscanf(line, "%d", &BByll);
1046   }
1047   if (gettoken(infile, line, sizeof(line)) != 0) { /* MAXLINE */
1048     sscanf(line, "%d", &BBxur);
1049   }
1050   if (gettoken(infile, line, sizeof(line)) != 0) { /* MAXLINE */
1051     sscanf(line, "%d", &BByur);
1052   }
1053
1054
1055 /* accumulate Keywords for DOCINFO pdfmark */
1056
1057 void getkeywords (FILE *infile)     /* 1996/May/10 */
1058 {
1059   char *keywordsnew;
1060   char *u;
1061   int n, c;
1062   int needcomma=0;    /* 0 or 2 if comma and space needed */
1063
1064 /*  if (headertext == NULL) headernew = malloc (nspecial+2); else */
1065 /*  will add comma separator unless first, or comma or space already */
1066   if (keywordslen == 0) needcomma = 0;
1067   else {
1068     c = *(keywords + keywordslen - 1);
1069     if (c == ',' || c == ' ' || c == '\t') needcomma = 0;
1070     else needcomma = 2;
1071   }
1072 /*  n = keywordslen + (int) nspecial + 2; */  /* space for , and \0 */
1073   n = keywordslen + (int) nspecial + needcomma + 1; 
1074 /*  first time around, keywords will be NULL, so it acts like malloc(n) */
1075   keywordsnew = realloc (keywords, n);
1076   if (keywordsnew == NULL) {
1077     showline(" Unable to allocate memory\n", 1);
1078 /*    flushspecial(infile); */
1079 /*    errcount(0); */
1080 /*    return; */
1081     checkexit(1);             /* 1995/July/15 */
1082 //    more serious exit(1) ???
1083   }
1084   keywords = keywordsnew;
1085   u = keywordsnew + keywordslen;
1086   if (needcomma > 0) {
1087     *u++ = ',';     /* add , if needed */
1088     *u++ = ' ';     /* add   if needed */
1089   }
1090   keywordslen = keywordslen + (int) nspecial + needcomma;
1091   while (nspecial-- > 0) *u++ = (char) getc(infile);
1092   *u++ = '\0';        /* terminating \0 */
1093 }
1094
1095 // void getcommonstring (FILE *infile, char *newstring) 
1096 char *getcommonstring (FILE *infile)
1097 {
1098   char *u;
1099   char *newstring = malloc ((size_t) (nspecial+1));
1100   if (newstring == NULL) {
1101     showline(" Unable to allocate memory\n", 1);
1102     checkexit(1);
1103     return NULL;
1104   }
1105   u = newstring;
1106   while (nspecial-- > 0) *u++ = (char) getc(infile);
1107   *u++ = '\0';        /* terminating \0 */  
1108   return newstring;
1109 }
1110
1111 // unadvertized ability to change Creator fieldin DocInfo
1112
1113 void getcreator (FILE *infile)
1114 {
1115   if (creatorstring != NULL) return;  /* ignore all but first */
1116 //  creatorstring = malloc ((size_t) (nspecial+1));
1117 //  getcommonstring(infile, creatorstring);
1118   creatorstring = getcommonstring(infile);
1119 }
1120
1121 void gettitle (FILE *infile)
1122 {
1123   if (titlestring != NULL) return;  /* ignore all but first */
1124 //  titlestring = malloc ((size_t) (nspecial+1));
1125 //  getcommonstring(infile, titlestring);
1126   titlestring = getcommonstring(infile);
1127 }
1128
1129 void getsubject (FILE *infile)
1130 {
1131   if (subjectstring != NULL) return;  /* ignore all but first */
1132 //  subjectstring = malloc ((size_t) (nspecial+1));
1133 //  getcommonstring(infile, subjectstring);
1134   subjectstring = getcommonstring(infile);
1135 }
1136
1137 void getauthor (FILE *infile)
1138 {
1139   if (authorstring != NULL) return; /* ignore all but first */
1140 //  authorstring = malloc ((size_t) (nspecial+1));
1141 //  getcommonstring(infile, authorstring);
1142   authorstring = getcommonstring(infile);
1143 }
1144
1145 void getbase (FILE *infile)
1146 {
1147   if (basestring != NULL) return; /* ignore all but first */
1148 //  basestring = malloc ((size_t) (nspecial+1));
1149 //  getcommonstring(infile, basestring);
1150   basestring = getcommonstring(infile);
1151 }
1152
1153 void getpagemode (FILE *infile)
1154 {
1155   if (pagemode != NULL) return; /* ignore all but first */
1156 //  pagemode = malloc ((size_t) (nspecial+1));
1157 //  getcommonstring(infile, pagemode);
1158   pagemode = getcommonstring(infile);
1159 }
1160
1161 /* example \special{papersize=5.04in,3.751in} */
1162
1163 void getpapersize (FILE *infile)
1164 {
1165 //  if (strcmp(papersize,"") != 0) return;  /* ignore all but first */
1166   if (papersize != NULL) return;
1167 //  papersize = malloc ((size_t) (nspecial+1));
1168 //  getcommonstring(infile, papersize);
1169   papersize = getcommonstring(infile);
1170 }
1171
1172 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
1173
1174 int bComplainSpecial=1;
1175
1176 /* Attempt at \special{background rgb 0 0 1} support 98 June 30 */
1177
1178 void DoBackGround (FILE *infile, int c)
1179 {
1180   char *s;
1181   int n, m;
1182   int setcolor=0;
1183   COLORSPEC SavedColor;
1184
1185   if (bBackGroundFlag == 0)
1186   {
1187     flushspecial(infile);
1188     return;
1189   }
1190
1191   s = line + strlen(line);
1192   if (c > 0) *s++ = (char) c;       /* stick in terminator */
1193   *s = '\0';                /* just in case */
1194   (void) scanspecial(input, line, MAXLINE);
1195
1196   if (traceflag)
1197   {
1198     sprintf(logline, "\n%s %c (%d) ", line, c, c);
1199     showline(logline, 0);
1200   }
1201
1202 /*  if (c > 0) return; */         /* only do in prescan ! */
1203   s = line;
1204   if (*s == '\0') return;
1205   if (bKeepBlack) return;         /* 96/Nov/3 */
1206
1207   SavedColor = CurrColor;         /* 99/Apr/06 */
1208   if (strncmp(s, "rgb", 3) == 0)
1209   {
1210     s += 3;
1211     m = sscanf(s, "%g %g %g%n\n", &CurrColor.A, &CurrColor.B, &CurrColor.C, &n);
1212     if (m == 3)
1213     {
1214       CurrColor.D = -1.0F;
1215       setcolor=1;
1216       s += n;
1217     }
1218     else
1219     {
1220       complainspecial(input);
1221       return;
1222     }
1223   }
1224   else if (strncmp(s, "cmyk", 4) == 0) {
1225     s += 4;
1226     m = sscanf(s, "%g %g %g %g%n",
1227          &CurrColor.A, &CurrColor.B, &CurrColor.C, &CurrColor.D, &n);
1228     if (m == 4) {
1229       setcolor=1;
1230       s += n;
1231     }
1232     else {
1233       complainspecial(input);
1234       return;
1235     }
1236   }
1237   else if (strncmp(s, "gray", 4) == 0) {
1238     s += 4;
1239     m = sscanf(s, "%g%n", &CurrColor.A, &n);
1240     if (m == 1) {
1241 /*      CurrentC = CurrentB = CurrentA; CurrentD = -2.0F; */
1242       CurrColor.C = CurrColor.B = CurrColor.A;
1243       CurrColor.D = -2.0F;
1244       setcolor = 1;
1245       s += n;
1246     }
1247     else {
1248       complainspecial(input);
1249       return;
1250     }
1251   }
1252   else if (_strnicmp(s, "black", 5) == 0) {
1253     s += 5;
1254     setcolor=1;
1255 /*    CurrentC = CurrentB = CurrentA = 0.0F; CurrentD = 1.0F; */
1256     CurrColor.C = CurrColor.B = CurrColor.A = 0.0F;
1257     CurrColor.D = 1.0F;   
1258   }
1259   else if (_strnicmp(s, "white", 5) == 0) {
1260     s += 5;
1261     setcolor=1;
1262 /*    CurrentC = CurrentB = CurrentA = 0.0F;
1263     CurrentD = 0.0F; */
1264     CurrColor.C = CurrColor.B = CurrColor.A = 0.0F;
1265     CurrColor.D = 0.0F; 
1266   }
1267   else {
1268     complainspecial(input); /* 1995/April/15 */
1269     return;
1270   }
1271
1272   if (traceflag)
1273   {
1274     sprintf(logline, " PAGENUMBER %d (%d %d) ", pagenumber, dvi_t, MaxColor);
1275     showline(logline, 0);
1276   }
1277   
1278 /*  if (pagenumber < 0 || pagenumber >= dvi_t)  */
1279   if (pagenumber < 0 || pagenumber > dvi_t) {     /* 99/Feb/21 */
1280     sprintf(logline, " ERROR: bad page number %d\n", pagenumber);
1281     showline(logline, 1);
1282     return;
1283   }
1284
1285   if (traceflag)
1286   {
1287     sprintf(logline, "\npage %d %g %g %g %g\n",
1288          pagenumber, CurrColor.A, CurrColor.B, CurrColor.C,
1289          CurrColor.D);
1290     showline(logline, 0);
1291   }
1292   BackColors[pagenumber] = CurrColor;     /* ??? */
1293   bBackUsed = 1;        /* mark background color used */
1294   CurrColor = SavedColor;         /* 99/Apr/06 */
1295 }
1296
1297   
1298 #ifdef TPIC
1299
1300 /* TPIC commands */
1301
1302 /* char *tpiccommand[] = {
1303   "pa", "fp", "ip", "da", "dt", "sp", "pn", "ar", "ia", 
1304     "sh", "wh", "bk", "tx", ""
1305 }; */
1306
1307 char *tpiccommands = "pa fp ip da dt sp pn ar ia sh wh bk tx";
1308
1309 #endif
1310
1311 /* Maybe check for TPIC specials only in selected page range ... */
1312 /* Hmm, may want to search for inserted figure files here and extract */
1313 /* DocumentNeededResources, DocumentFonts to save for writing in header ... */
1314 /* No, use IncludeResource: font ... and IncludeFont: ... ? */
1315 /* also check for \special{insertimage: ...} TIFF images re level2 96/Dec/20 */
1316 /* also check for \special{color ...} */
1317 /* also check for \special{background ...} 98/Jun/30 */
1318
1319 void logdo_com (FILE *infile)
1320 {
1321   int c;
1322 /*  int k=0; */
1323
1324   if (bIgnoreSpecials)
1325   {
1326     flushspecial(infile);
1327     return;
1328   }
1329   nspecialsav = nspecial;       /* 99/Feb/21 */
1330   specstart = ftell(input);     /* for complainspecial 99/Feb/21 */
1331   c = getc(infile);         /* peek ahead for ! */
1332   ungetc (c, infile);
1333   if (c == 0 && bFirstNull) {     /* is first byte null ? 96/Aug/29 */
1334     flushspecial(infile);
1335     return;
1336   }
1337   if (c == '!') {
1338 /*    if (verbatimflag != 0) { */   /* flushed 97/Mar/9 */
1339       c = getc(infile); nspecial--;
1340       getheadertext(infile);
1341 /*    } */
1342     flushspecial(infile);
1343     return;
1344   }
1345 /*  c = getalphatoken(infile, line, MAXLINE); */
1346   c = getalphatoken(infile, line, sizeof(line)); /* MAXLINE */
1347 #ifdef TPIC
1348 /*  check whether maybe a TPIC \special */
1349   if (allowtpic != 0 && needtpic == 0 && (c == ' ' || c == 0)) {
1350 /*    while (strcmp(tpiccommand[k], "") != 0) {
1351       if (strcmp(line, tpiccommand[k]) == 0) {
1352         needtpic++; break;
1353       }
1354       k++;
1355     } */
1356     if (strlen(line) == 2 && strstr(tpiccommands, line) != NULL)
1357         needtpic++; 
1358   }
1359 #endif
1360   if (c == ' ' || c == ':') {
1361     if (strcmp(line, "color") == 0) {
1362       doColor(NULL, input, c, 0);   /* no PS output */
1363       bColorUsed = 1;   /* 98/Feb/14 */
1364     }
1365     else if (strcmp(line, "background") == 0) {
1366       DoBackGround (infile, c);
1367 /*      bColorUsed = 1; */ /* ? */
1368     }
1369     else if (strcmp(line, "landscape") == 0) {    /* 99/Apr/5 foils.cls */
1370       bLandScape = ! bLandScape;          /* sets globally ! */
1371     }
1372   }
1373 /*  check whether a special calling for a header or prolog file */
1374 /*  if(c == '=' && strcmp(line, "header") == 0) getheadername(infile); */
1375 /*  Separator is `=' */
1376   if(c == '=') {            /* extended 93/Dec/29 */
1377 /*    if (strcmp(line, "header") == 0) getheadername(infile); */
1378     if (_strcmpi(line, "header") == 0) getheadername(infile);
1379 /*    else if (strcmp(line, "headertext") == 0) getheadertext(infile); */
1380     else if (_strcmpi(line, "headertext") == 0) getheadertext(infile);
1381 /*    following added in 1995 July */
1382     else if (strcmp(line, "DSCheader") == 0) getcustomname(infile);
1383     else if (strcmp(line, "DSCtext") == 0) getcustomtext(infile);
1384     else if (strcmp(line, "papersize") == 0) getpapersize(infile);
1385     else if (strcmp(line, "DVIPSONE") == 0) getcommandspec(infile);
1386     else if (strcmp(line, "DVIWindo") == 0) flushspecial(infile);
1387 /*    else complain ??? */
1388   }
1389 /*  else if (c == ':' && strcmp(line, "dvitops") == 0) { */
1390 /*  Separator is `:' */
1391   else if (c == ':') {
1392     if (strcmp(line, "dvitops") == 0) {
1393 /*      (void) getalphatoken(infile, line, MAXLINE); */
1394       (void) getalphatoken(infile, line, sizeof(line)); /* MAXLINE */
1395       if (strcmp(line, "prolog") == 0) getheadername(infile);
1396     }
1397     else if (strcmp(line, "PDF") == 0) {    /* 1996/July/4 */
1398       c = getalphatoken(infile, line, sizeof(line));   /* MAXLINE */
1399       if (c == ' ' || c == '=') {
1400         if (_strcmpi(line, "Keywords") == 0) getkeywords(infile);
1401         else if (strcmp(line, "BBox") == 0) getbbox(infile); 
1402         else if (_strcmpi(line, "Creator") == 0) getcreator(infile);
1403         else if (_strcmpi(line, "Title") == 0) gettitle(infile);
1404         else if (_strcmpi(line, "Subject") == 0) getsubject(infile);
1405         else if (_strcmpi(line, "Author") == 0) getauthor(infile);
1406         else if (_strcmpi(line, "Base") == 0) getbase(infile);
1407         else if (_strcmpi(line, "PageMode") == 0) getpagemode(infile);
1408       }
1409     }
1410 /*    check whether TIFF image inserted re level2 features 96/Dec/20 */
1411     else if (strcmp(line, "insertimage") == 0)  bInsertImage++;
1412   }
1413   flushspecial(infile);
1414 }
1415
1416 void logdo_xxxi(FILE *infile, unsigned int n)
1417 {
1418 /*  unsigned int k; */
1419   nspecial = (long) n;
1420   logdo_com(infile);
1421 /*  for(k = 0; k < n; k++)  getc(infile); */
1422 }
1423
1424 void logdo_xxx1(FILE *infile) /* for /special */
1425 {
1426   unsigned int k;
1427   k = getc(infile);
1428   logdo_xxxi(infile, k);
1429 }
1430
1431 void logdo_xxx2(FILE *infile) /* for /special */
1432 {
1433   unsigned int k;
1434   k = ureadtwo(infile);
1435   logdo_xxxi(infile, k);
1436 }
1437
1438 void logdo_xxxl(FILE *infile, unsigned long n)
1439 {
1440 /*  unsigned long k; */
1441   nspecial=(long) n;
1442   logdo_com(infile);
1443 /*  for(k = 0; k < n; k++)  getc(infile); */
1444 }
1445
1446 void logdo_xxx3(FILE *infile)
1447 {
1448   logdo_xxxl(infile, ureadthree(infile));
1449 }
1450
1451 void logdo_xxx4(FILE *infile)
1452 {
1453   logdo_xxxl(infile, ureadfour(infile));
1454 }
1455
1456 /* need to do this even if skipping pages */
1457
1458 void logfnt_def(FILE *infile, unsigned int k)
1459 {
1460   int fn;
1461   unsigned int na, nl, i;
1462   int newfont=1;    /* if this is a new one (not defined before) */
1463 //  char *tempfont;
1464   char *fp;
1465   char namebuffer[FNAMELEN];
1466
1467   if (finx[k] != BLANKFONT) {   /* seen this font before !!! */
1468     sprintf(logline, " ERROR: Font %d being redefined ", k);
1469     showline(logline, 1);
1470     tellwhere(infile, 1);
1471 /*    errcount(0); */
1472     newfont = 0;
1473     fn = finx[k];
1474   }
1475   else {        /* definition of font not seen before */
1476     fn = fnext++;  /* grab next slot */
1477     finx[k] = (short) fn;
1478     if (fnext > maxfonts) {     /* 94/May/23 */
1479       sprintf(logline, " ERROR: More than %d fonts in use\n", maxfonts);
1480       showline(logline, 1);
1481       fnext--;
1482 /*      errcount(0); */
1483       checkexit(1);     /* 1993/Dec/11 */
1484     }
1485   }
1486   
1487   fc[fn] = ureadfour(infile);   /* read checksum (encoding info) */
1488 /*  (void) ureadfour(infile); */
1489   fs[fn] = ureadfour(infile);   /* read at size */
1490 /*  fd[fn] = ureadfour(infile); */  /* design size */
1491   (void) ureadfour(infile);   /* skip over design size */
1492   na = getc(infile);
1493   nl = getc(infile);
1494   if (newfont == 0) { /* just skip over if already defined */
1495     for (i = 0; i < na + nl; i++) (void) getc(infile);
1496     return;
1497   }
1498 /*  fp = fontname[fn]; */
1499   fp = namebuffer;
1500   if (na + nl >= sizeof(namebuffer)-1) {  /* FNAMELEN */
1501     sprintf(logline, " Font name too long: %d (> %d) ",
1502         na + nl, sizeof(namebuffer)-1);
1503     showline(logline, 1);
1504     showline("\n", 0);
1505 //    errcount(0);
1506     tellwhere(infile, 1);
1507     for (i = 0; i < na+nl; i++) (void) getc(infile);
1508   }
1509   else {
1510     for (i = 0; i < na+nl; i++) *fp++ = (char) getc(infile);
1511   }
1512   *fp++ = '\0';
1513   if (fontname[fn] != NULL) free(fontname[fn]);
1514   fontname[fn] = zstrdup(namebuffer);
1515 /*  strcpy(subfontname[fn], ""); */   /* blank it out */
1516   if (subfontname[fn] != NULL) {    /* blank it out */
1517     free(subfontname[fn]);
1518     subfontname[fn] = NULL; 
1519   }
1520 //  strcpy(fontvector[fn], "");     /* 1992/May/4 */
1521 //  *(fontvector + fn * MAXVECNAME) = '\0';     /* blank it out */
1522   if (fontvector[fn] != NULL) {
1523     free(fontvector[fn]);
1524     fontvector[fn] = NULL;      /* blank it out */
1525   }
1526   fontsubflag[fn] = -1;       /* all this goes to extract now */
1527   fontproper[fn] = 0;         /* 1992/May/4 */
1528 /*  possibly determine whether we need to reencode *control* range ??? */
1529 /*  if (substitute != 0) fontsubflag[fn] = fontremap(fontname[fn]);
1530   if (uppercaseflag != 0) uppercase(font, fontname[fn]);  else */ 
1531 /*  strcpy(font, fontname[fn]); */    /* what for ??? */
1532 //  tempfont = fontchar[fn];      /* reset character counts */
1533 //  tempfont = fontchar + MAXCHRS * fn;
1534 /*  for (i = 0; i < MAXCHRS; i++) tempfont[i] = 0;  */
1535 //  for (i = 0; i < MAXCHRS; i++) *tempfont++ = 0;    /* 1994/Feb/3 */
1536   if (fontchar[fn] == NULL) {
1537     fontchar[fn] = (char *) malloc(MAXCHRS);
1538     if (fontchar[fn] == NULL) {
1539       showline(" Unable to allocate memory\n", 1);
1540       checkexit(1);
1541       return;
1542     }
1543   }
1544   memset(fontchar[fn], 0, MAXCHRS);
1545 }
1546
1547 void logdo_fnt_def1(FILE *infile) /* define font */
1548 {
1549   unsigned int k;
1550 /*  k = ureadone(infile); */
1551   k = getc(infile);
1552   logfnt_def(infile, k);
1553 }
1554
1555 void logdo_fnt_def2(FILE *infile) /* define font */
1556 {
1557   unsigned int k;
1558   k = ureadtwo(infile);
1559   if (k >= MAXFONTNUMBERS) k = MAXFONTNUMBERS-1;
1560   logfnt_def(infile, k);
1561 }
1562
1563 void logdo_fnt_defsub(FILE *infile, unsigned long k)
1564 {
1565   if (k >= MAXFONTNUMBERS) k = MAXFONTNUMBERS-1;
1566   logfnt_def(infile, (unsigned int) k);
1567 }
1568
1569 void logdo_fnt_def3(FILE *infile) /* define font */
1570 {
1571 /*  unsigned long k;
1572   k = ureadthree(infile); */
1573   logdo_fnt_defsub(infile, ureadthree(infile));
1574 }
1575
1576 void logdo_fnt_def4(FILE *infile) /* define font */
1577 {
1578   long k;
1579   k = sreadfour(infile);
1580   if (k < 0) k = 0;
1581   logdo_fnt_defsub(infile, (unsigned long) k);
1582 }
1583
1584 /* need to do this even if skipping pages */
1585
1586 void logdo_pre(FILE *infile)
1587 {
1588   unsigned int i, k, j;
1589   int c;
1590   char *s;
1591   
1592 /*  i = ureadone(infile); */
1593   i = getc(infile);
1594   if (i < 1 || i > 3)
1595   {
1596     showline("Not a valid DVI file ", 1);
1597     giveup(3); 
1598     return;
1599   }
1600   else if (i != ID_BYTE)
1601   {
1602     sprintf(logline, "File is DVI version %d - *not* %d\n",
1603       i, ID_BYTE);
1604     showline(logline, 1);
1605     errcount(0);
1606   }
1607   num = ureadfour(infile);
1608   den = ureadfour(infile);
1609   mag = ureadfour(infile);
1610 /*  k = ureadone(infile); */
1611   k = getc(infile);         /* bytes needed for TeX's comment */
1612 /*  s = comment; */           /* was to char comment[MAXCOMMENT] */
1613 //  if (strcmp(comment, "") != 0) {   /* free if still in use */
1614   if (comment != NULL) {    /* free if still in use */
1615     free(comment);
1616 //    comment = "";
1617     comment = NULL;
1618   }
1619   comment = malloc(k+1);
1620   if (comment == NULL)
1621   {
1622     showline(" Unable to allocate memory\n", 1);
1623     checkexit(1);
1624 //    more serious exit(1) ???
1625   }
1626   s = comment;
1627 /*  if (traceflag) fprintf(stdout, "Comment:"); */
1628   c = getc(infile);         /* try and discard initial space */
1629   if (c == ' ') k--;
1630   else (void) ungetc(c, infile);
1631   for (j=0; j < k; j++)
1632   {
1633     c = getc(infile);
1634     if (j < MAXCOMMENT) *s++ = (char) c;
1635 /*    if (verboseflag) putc(c, stdout); */
1636   }
1637   *s++ = '\0';
1638   if (verboseflag) {
1639     showline(comment, 0);
1640     showline("\n", 0);
1641   }
1642   if (textures != 0) 
1643     (void) ureadfour(infile); /* flush length code */
1644 }
1645
1646 /* need to do this even if skipping pages */
1647
1648 void logdo_post(FILE *infile)
1649 {
1650 /*  int k; */
1651   previous = sreadfour(infile); /* was ureadfour ... */
1652   num = ureadfour(infile);
1653   den = ureadfour(infile);
1654   mag = ureadfour(infile);
1655
1656   if (traceflag)
1657   {
1658     sprintf(logline, " POST: previous %ld num %ld den %ld mag %ld\n",
1659               previous, num, den, mag);
1660     showline(logline, 0);
1661   }
1662 /* compare these with what was in preamble ? */
1663
1664   dvi_l = ureadfour(infile);      /* max page height plus depth */
1665   dvi_u = ureadfour(infile);      /* max page width */
1666   dvi_s = (int) ureadtwo(infile);   /* max stack depth */
1667   dvi_t = (int) ureadtwo(infile);   /* number bops limit 65535 */
1668   if (traceflag) {
1669     sprintf(logline, "l %ld u %ld s %ld t %ld\n",
1670               dvi_l, dvi_u, dvi_s, dvi_t);
1671     showline(logline, 0);
1672   }
1673 /*  here l and u could be used for bbox info ? */
1674 /*  except: don't include headers and footers and other problems */ 
1675   finish = -1; 
1676 }
1677
1678 /* could do this even in forward mode to check on number of pages ? */
1679
1680 void logdo_post_post(FILE *infile) /* only in reverse ? */
1681 {
1682 /*  unsigned long q;   */
1683 /*  unsigned int i;    */
1684
1685   if (traceflag) showline("Hit POSTPOST!\n", 0);
1686
1687 /*  q = ureadfour(infile); */
1688   (void) ureadfour(infile);
1689 /*  i = ureadone(infile); */
1690   (void) getc(infile);
1691 /*  check ID_BYTE again ? */
1692 /*  followed by at least four 223's */
1693 /*  if (reverseflag != 0) fseek(infile, previous, SEEK_SET);
1694   else fputs("%% This is really the end !\n", output); */
1695 }
1696
1697 /* This version scans for Textures length code followed by pre & DVI code */
1698 /* could do something more fancy to get quickly to resource fork */
1699 /* should be fairly safe, unless initial length code is > 256 */
1700 /* Search for 3 or more zeros in a row, followed by dont-care (length) */
1701 /* - followed by pre and ID_BYTE */
1702
1703 int readovertext(FILE *infile)
1704 {
1705   int c, n;
1706
1707   c = getc(infile);
1708   for(;;) {
1709 /*    if ((c = getc(infile)) == 0) { */
1710     if (c == 0) {
1711       n = 1;
1712       while ((c = getc(infile)) == 0) n++;
1713       if (c == EOF) return 0;
1714       if (n >= 3) {
1715         if((c = getc(infile)) == (int) pre) {
1716           (void) ungetc(c, infile);
1717           dvistart = ftell(infile);
1718           c = getc(infile);
1719           if ((c = getc(infile)) == ID_BYTE) {
1720             if (fseek(infile, dvistart, SEEK_SET) != 0)
1721               return 0;   /* seek error */
1722             else return -1;   /* think we found it ! */
1723           }
1724         }
1725       }
1726     }
1727     else if ((c = getc(infile)) == EOF) return 0;
1728   } 
1729 }
1730
1731 void resetpagerangehit (int flag)
1732 {
1733 /*  int k; */
1734 /*  for (k = 0; k < rangeindex; k++) pagerangehit[k] = 0; */  /* 1994/Jan/16 */
1735 /*  currentrange = -1; */
1736   currentpage = -LINFINITY; /* indicate first time */
1737   prescanflag = flag;     /* remember whether in prescan or not */
1738   if (prescanflag != 0 || reverseflag == 0)
1739      pagesequence = 1;    /* 1994/Feb/16 */
1740 /* NOTE: don't reset page sequence instance if going in reverse order */
1741 }
1742
1743 /***************************************************************************/
1744
1745 void alloccolorsave (int npages)
1746 {
1747   int k;
1748
1749   if (ColorStacks != NULL)
1750   {
1751     showline(" ERROR: color save stacks allocation\n", 1);
1752     freecolorsave();
1753   }
1754 #ifdef DEBUGCOLORSTACK
1755   if (traceflag)
1756   {
1757     sprintf(logline, "Allocating color save stack for %d pages\n", npages);
1758     showline(logline, 0);
1759   }
1760 #endif
1761   if (npages == 0) npages = 1;
1762   ColorStacks = (COLORSPEC **) malloc((npages+1) * sizeof(COLORSPEC *));
1763   if (ColorStacks == NULL) {
1764     showline(" Unable to allocate memory\n", 1);
1765     checkexit(1);
1766 //    more serious exit(1) ???
1767   }
1768   for (k = 0; k <= npages; k++) ColorStacks[k] = NULL;
1769   MaxColor = npages+1;      /* make note of size of allocation */
1770 }
1771
1772 void freecolorsave (void)
1773 {
1774   int k, npages = MaxColor;
1775   
1776   if (ColorStacks == NULL) return;
1777 #ifdef DEBUGCOLORSTACK
1778   if (traceflag) showline("Freeing Saved Color Stacks\n", 0);
1779 #endif
1780   for (k = 0; k < npages; k++) {
1781     if (ColorStacks[k] != NULL) {
1782       free(ColorStacks[k]);
1783       ColorStacks[k] = NULL;
1784     }
1785   }
1786   if (ColorStacks != NULL) {
1787     free(ColorStacks);
1788     ColorStacks = NULL;
1789   }
1790 }
1791
1792 #ifdef DEBUGCOLORSTACK
1793 void dumpcolorsave (void)    /* debugging only */
1794 {
1795   int k, m, i, npages = MaxColor-1;
1796   COLORSPEC *ColorSaved;
1797
1798   if (ColorStacks == NULL)
1799   {
1800     showline(" No saved color stacks to show\n", 1);
1801     return;
1802   }
1803   sprintf(logline, " Saved color stacks for %d pages after prescan:\n", npages);
1804   showline(logline, 1);
1805 /*  for (k = 0; k < npages; k++) { */
1806   for (k = 1; k <= npages; k++) {
1807     if (ColorStacks[k] != NULL) {
1808       sprintf(logline, "For page %d:\n", k);
1809       showline(logline, 1);
1810       ColorSaved = ColorStacks[k];
1811       m = (int) (ColorSaved[0].D + 0.5);
1812       for (i = 1; i <= m; i++) {
1813         sprintf(logline, "%d\t%g\t%g\t%g\t%g\n", i,
1814              ColorSaved[i].A,  ColorSaved[i].B,
1815              ColorSaved[i].C,  ColorSaved[i].D);
1816         showline(logline, 1);
1817       }
1818     }
1819     else {
1820       sprintf(logline, " ERROR: ColorStack[%d] is NULL\n", k);
1821       showline(logline, 1);
1822     }
1823   }
1824 }
1825 #endif
1826
1827 void allocbackground (int npages)
1828 {
1829   int k;
1830   if (BackColors != NULL) {
1831     showline(" ERROR: background allocation\n", 1);
1832     freebackground();
1833   }
1834   if (npages == 0) npages = 1;
1835 /*  BackColors = (COLORSPEC *) malloc(npages * sizeof(COLORSPEC)); */
1836   BackColors = (COLORSPEC *) malloc((npages+1) * sizeof(COLORSPEC));
1837   if (BackColors == NULL) {
1838     showline(" Unable to allocate memory\n", 1);
1839     checkexit(1);
1840 //    more serious exit(1) ???
1841   }
1842 /*  for (k = 0; k < npages; k++) */
1843   for (k = 0; k <= npages; k++) {     /* may not be needed */
1844     BackColors[k].A = BackColors[k].B = BackColors[k].C = -1.0F;
1845     BackColors[k].D = -1.0F;
1846   }
1847 }
1848
1849 void freebackground (void) {
1850   if (BackColors != NULL) free(BackColors);
1851   BackColors = NULL;
1852 }
1853
1854 /***************************************************************************/
1855
1856 int scanlogfileaux(FILE *fp_in)
1857 {
1858   int c, k, fn;
1859 /*  long filptr; */
1860
1861 //  strcpy (headerfile, "");        /* reset to no headers seen */
1862   if (headerfile != NULL) free(headerfile);
1863   headerfile = NULL;
1864   if (countzeroflag) resetpagerangehit (1);
1865
1866   numpages = 0;     /* number of pages actually processed 94/Oct/12 */
1867   pagenumber = 0;     /* pages seen in scan */
1868
1869   ff = -1;            /* redundant */
1870   for (k = 0; k < MAXFONTS; k++) fonthit[k] = 0;
1871 /*  for (k = 0; k < maxfonts; k++) fonthit[k] = 0; */ /* ah what the hell */
1872 //  currentfont = fontchar;     /* just in case */
1873   currentfont = fontchar[0];    /* just in case ??? */
1874   fnext = 0;
1875   for (k = 0; k < MAXFONTNUMBERS; k++)  /* reset status to unused */
1876     finx[k] = (short) BLANKFONT;
1877
1878 /*  Get dvi_t up front 98/Jun/30 */
1879   postposition = -1;
1880   bBackUsed=0;      /* non-zero of \special{background ...} used */
1881   bColorUsed = 0;     /* assume no color \special until ... 98/Feb/15 */
1882
1883   if (bCarryColor || bBackGroundFlag)
1884   {
1885     postposition = gotopost(input); /* in dvianal.c */
1886     (void) getc(input);       /* absorb the post byte */
1887     logdo_post(input);
1888     rewind(input);
1889     if (bCarryColor)
1890       alloccolorsave(dvi_t);    /* allocated space for color table */
1891     if (bBackGroundFlag)
1892       allocbackground(dvi_t);   /* allocate background color table */
1893     pagenumber = 0;
1894     pageno = 0;
1895     finish = 0;
1896   }
1897
1898   finish = 0;
1899   stinx = 0; maxstinx = 0;    /* redundant, hopefully */
1900   
1901   textures=0;     /* start off by assuming normal DVI file */
1902   c = getc(fp_in);
1903   (void) ungetc(c, fp_in);
1904   if (c != (int) pre) { /* not standard DVI file - can figure out ? */
1905     if (readovertext(fp_in) == 0) {
1906       if (strstr(fn_in, ".tex") != NULL) {      /* 1994/Feb/24 */
1907         showline("Can't find DVI file ", 1);
1908       }
1909       else {
1910         showline("Not a valid DVI (or Textures) file ", 1);
1911       }
1912       input = NULL;  /* to stop at byte message ? */
1913       giveup(3);
1914       return -1;
1915     }
1916     else {
1917       if (verboseflag) {
1918         showline("Textures DVI file - ", 0);
1919       }
1920       textures=1;
1921     }
1922   }
1923
1924 /* in the above, may also want to look 100 bytes into the file for start */
1925 /* some Mac files come that way... */
1926
1927   for(;;) {
1928     c = getc(fp_in);
1929     if (c == EOF) {
1930       sprintf(logline, " Unexpected EOF (%s)\n", "scanlogfile");
1931       showline(logline, 1);
1932       errcount(0);
1933       finish = -1;
1934 /*      giveup(13); */
1935     }
1936     if (c < 128) {
1937       if (skipflag == 0) {
1938         if (ff < 0) invalidset((int) c);
1939         else {
1940 /*          if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
1941           if (bRemapControl || bRemapFont) {
1942             if (c < MAXREMAP) c = remaptable[c];
1943 #if MAXREMAP < 128
1944             else if (c == 32) c = 195;
1945             else if (c == 127) c = 196;
1946 #endif
1947           }
1948           else if (bRemapSpace && c <= 32) {      /* 1995/Oct/17 */
1949             if (c == 32) c = 195;   /* not 160 */
1950             else if (c == 13) c = 176;  /* 1996/June/4 */
1951             else if (c == 10) c = 173;  /* 1996/June/4 */
1952             else if (c == 9) c = 170;   /* 1996/June/4 */
1953             else if (c == 0) c = 161;
1954           }
1955           currentfont[c]=1;
1956         }
1957       }
1958     }
1959     else if (c >= 171 && c <= 234) { /* switch to font (c - 171) */
1960       fn = (c - 171);
1961       logswitchfont(fn, fp_in);
1962     }
1963     else {
1964       switch(c) {
1965         case set1: logdo_set1(fp_in); break;
1966         case set2: logdo_set2(fp_in); break;  /* silly */
1967         case set3: logdo_set3(fp_in); break;  /* silly */
1968         case set4: logdo_set4(fp_in); break;  /* silly */
1969         case set_rule: logdo_set_rule(fp_in); break;
1970         case put1: logdo_put1(fp_in); break ;
1971         case put2: logdo_put2(fp_in); break;  /* silly */
1972         case put3: logdo_put3(fp_in); break;  /* silly */
1973         case put4: logdo_put4(fp_in); break;  /* silly */
1974         case put_rule: logdo_put_rule(fp_in); break;  
1975         case nop: break;      /* do nothing */
1976         case bop: logdo_bop(fp_in); break;
1977         case eop: logdo_eop(fp_in); break;
1978         case push: logdo_push(); break;
1979         case pop: logdo_pop(); break;
1980         case right1: logdo_right1(fp_in); break;
1981         case right2: logdo_right2(fp_in); break;  
1982         case right3: logdo_right3(fp_in); break; 
1983         case right4: logdo_right4(fp_in); break; 
1984         case w0: logdo_w0(); break;
1985         case w1: logdo_w1(fp_in); break;
1986         case w2: logdo_w2(fp_in); break; 
1987         case w3: logdo_w3(fp_in); break; 
1988         case w4: logdo_w4(fp_in); break;  /* not used ? */
1989         case x0: logdo_x0(); break;
1990         case x1: logdo_x1(fp_in); break;
1991         case x2: logdo_x2(fp_in); break; 
1992         case x3: logdo_x3(fp_in); break; 
1993         case x4: logdo_x4(fp_in); break;  /* not used ? */
1994         case down1: logdo_down1(fp_in); break;
1995         case down2: logdo_down2(fp_in); break; 
1996         case down3: logdo_down3(fp_in); break; 
1997         case down4: logdo_down4(fp_in); break; 
1998         case y0: logdo_y0(); break;
1999         case y1: logdo_y1(fp_in); break;
2000         case y2: logdo_y2(fp_in); break; 
2001         case y3: logdo_y3(fp_in); break; 
2002         case y4: logdo_y4(fp_in); break;  /* not used ? */
2003         case z0: logdo_z0(); break;
2004         case z1: logdo_z1(fp_in); break;
2005         case z2: logdo_z2(fp_in); break; 
2006         case z3: logdo_z3(fp_in); break; 
2007         case z4: logdo_z4(fp_in); break;  /* not used ? */
2008         case fnt1: logdo_fnt1(fp_in); break;
2009         case fnt2: logdo_fnt2(fp_in); break;  /* silly */
2010         case fnt3: logdo_fnt3(fp_in); break;  /* silly */
2011         case fnt4: logdo_fnt4(fp_in); break;  /* silly */
2012         case xxx1: logdo_xxx1(fp_in); break;
2013         case xxx2: logdo_xxx2(fp_in); break; /* not used ? */
2014         case xxx3: logdo_xxx3(fp_in); break; /* not used ? */
2015         case xxx4: logdo_xxx4(fp_in); break; 
2016         case fnt_def1: logdo_fnt_def1(fp_in); break;
2017         case fnt_def2: logdo_fnt_def2(fp_in); break;  /* silly */
2018         case fnt_def3: logdo_fnt_def3(fp_in); break;  /* silly */
2019         case fnt_def4: logdo_fnt_def4(fp_in); break;  /* silly */
2020         case post: logdo_post(fp_in); break;
2021         case pre: logdo_pre(fp_in); break;
2022         case post_post: logdo_post_post(fp_in); break;
2023   
2024         default: {
2025           sprintf(logline, 
2026             " ERROR: Unrecognized DVI command: %d", c);
2027           showline(logline, 1);
2028           tellwhere(fp_in, 1);
2029 /*          errcount(0); */
2030           finish = -1;    /* ? */
2031 /*          giveup(7); */
2032          }
2033          break;
2034       }
2035     }
2036     if (finish != 0) break;
2037     if (bAbort) abortjob(); /* fine grained */
2038     if (abortflag) break;
2039   }
2040 /*  if (maxstinx >= maxstack-1) {
2041     showline( WARNING: The PS stack will probably overflow %d > %d\n",
2042         maxstinx, maxstack -1 );
2043     errcount(0);
2044   }  */
2045   if (abortflag) return -1;
2046   return 0;
2047 }
2048
2049 /* main entry point, prescan DVI file font usage, \specials */
2050
2051 int scanlogfile (FILE *fp_in)
2052 {
2053   int c, d;
2054   input = fp_in;      /* remember file handle */
2055
2056   if (traceflag) showline("Start PreScan DVI file\n", 0);
2057 /*  strcpy (headerfile, ""); */ /* reset to no headers seen */
2058   c = getc(fp_in);
2059   d = getc(fp_in);
2060   rewind(fp_in);
2061 //  we now forget about Textures files 99/July/14
2062   if (c != pre || d != ID_BYTE)
2063   {
2064     sprintf(logline, " Not a proper DVI file `%s'\n",
2065         (filenamex != NULL) ? filenamex : "");
2066     showline(logline, 1);
2067     errcount(0);
2068     return -1;
2069   }
2070   scanlogfileaux(fp_in);
2071 /*  if (showlogflag != 0) showlog(stdout); */
2072   if (bBackGroundFlag != 0 && bBackUsed == 0)
2073     freebackground();     /* not needed in this case */
2074   if (bCarryColor != 0 && bColorUsed == 0)
2075     freecolorsave();      /* not needed in this case */
2076   if (traceflag) showline("End PreScan DVI file\n", 0);
2077 #ifdef DEBUGCOLORSTACK
2078   if (traceflag) dumpcolorsave();
2079 #endif
2080   if (abortflag) return -1;
2081   return 0;
2082 }
2083
2084 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2085
2086 /* Use `texfonts.map' in directory path TEXFONTS for aliasing */
2087
2088 #define FONTMAP
2089
2090 #ifdef FONTMAP
2091
2092 typedef struct map_element_struct {   /* list element key . value pair */
2093   char *key;
2094   char *value;
2095   struct map_element_struct *next;
2096 } map_element_type;
2097
2098 typedef map_element_type **map_type;
2099
2100 /* **************************** auxiliary functions *********************** */
2101
2102 static void complain_mem (unsigned int size)  /* out of memory */
2103 {
2104   sprintf(logline, "Unable to honor request for %u bytes.\n", size);
2105   showline(logline, 1);
2106   checkexit(1);
2107 }
2108
2109 static void *xmalloc (unsigned int size)
2110 {
2111   void *new_mem = (void *) malloc (size);
2112   if (new_mem == NULL) complain_mem(size);
2113   return new_mem;
2114 }
2115
2116 static void *xrealloc (void *old_ptr, unsigned int size)
2117 {
2118   void *new_mem;
2119   if (old_ptr == NULL)
2120 /*    new_mem = xmalloc (size); *//* could just let realloc do this case? */
2121     new_mem = malloc (size);  /* could just let realloc do this case? */
2122   else {
2123     new_mem = (void *) realloc (old_ptr, size);
2124 /*    if (new_mem == NULL) complain_mem(size); */
2125   }
2126   if (new_mem == NULL) complain_mem(size);
2127   return new_mem;
2128 }
2129
2130 static char *xstrdup (char *s)
2131 {
2132   char *new_string = (char *) xmalloc (strlen (s) + 1);
2133   return strcpy (new_string, s);
2134 }
2135
2136 /* static char *concat3 (char *s1, char *s2, char *s3) {
2137   char *answer
2138     = (char *) xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
2139   strcpy (answer, s1);
2140   strcat (answer, s2);
2141   strcat (answer, s3);
2142   return answer;
2143 } */  /* used by extend_filename only */
2144
2145 static void *xcalloc (unsigned int nelem, unsigned int elsize)
2146 {
2147   void *new_mem = (void *) calloc (nelem, elsize);
2148   if (new_mem == NULL) complain_mem (nelem * elsize);
2149   return new_mem;
2150 }
2151
2152 /*  Here we work only with suffix-free names - so this is silly */
2153
2154 /* static char *find_suffix (char *name) {
2155   char *dot_pos; 
2156   char *slash_pos; 
2157   
2158   dot_pos = strrchr (name, '.');
2159   if (dot_pos == NULL) return NULL; 
2160   if ((slash_pos = strrchr (name, '/')) != NULL) ;
2161   else if ((slash_pos = strrchr (name, '\\')) != NULL) ;  
2162   else if ((slash_pos = strrchr (name, ':')) != NULL) ;
2163   else slash_pos = name;
2164   if (dot_pos < slash_pos) return NULL;
2165   return dot_pos + 1;
2166 } */
2167
2168 /* static char *extend_filename (char *name, char *default_suffix) {
2169   char *suffix = find_suffix (name);
2170   char *new_s;
2171   if (suffix != NULL) return name;  
2172   new_s = concat3 (name, ".", default_suffix);
2173   return new_s;           
2174 } */
2175
2176 /* static char *remove_suffix (char *s) {
2177   char *ret;
2178   char *suffix = find_suffix (s);
2179   
2180   if (suffix == NULL) return NULL;
2181   suffix--;
2182   ret = (char *) xmalloc (suffix - s + 1);
2183   strncpy (ret, s, suffix - s);
2184   ret[suffix - s] = 0;
2185   return ret; 
2186 } */
2187
2188 /* only used by fontmap.c */ /* why not just use fgets on global line ? */
2189
2190 #define BLOCK_SIZE 40
2191
2192 static char *read_line (FILE *f)
2193 {
2194   int c;
2195   unsigned int limit = BLOCK_SIZE;
2196   unsigned int loc = 0;
2197   char *line;
2198
2199   line = (char *) xmalloc (limit);
2200   
2201   while ((c = getc (f)) != EOF && c != '\n') {
2202     line[loc] = (char) c;
2203     loc++;
2204     if (loc == limit) {
2205       limit += BLOCK_SIZE;
2206       line = (char *) xrealloc (line, limit);
2207     }
2208   }
2209   
2210   if (c != EOF) line[loc] = 0;    /* not EOF */
2211   else if (loc > 0) line[loc] = 0;  /* c == EOF, but line not empty */
2212   else {    /* c == EOF and nothing on the line --- at end of file.  */
2213     free (line);
2214     line = NULL;
2215   }
2216   return line;
2217 }
2218
2219 /* ************************************************************************* */
2220
2221 /* Fontname mapping.  We use a straightforward hash table. Should be prime? */
2222
2223 #define MAP_SIZE 307
2224
2225 /* The hash function.  We go for simplicity here.  */
2226
2227 static unsigned int map_hash (char *key)
2228 {
2229   unsigned int n = 0;
2230   char *s = key;
2231 /*  There are very few font names which are anagrams of each other
2232   so no point in weighting the characters.  */
2233   while (*s != 0) n += *s++;
2234   n %= MAP_SIZE;
2235 #ifdef DEBUGALIAS
2236   if (traceflag) {
2237     sprintf(logline, "hash %u for %s\n", n, key);
2238     showline(logline, 0);
2239   }
2240 #endif
2241   return n;
2242 }
2243
2244 /* Look up STR in MAP.  Return the corresponding `value' or NULL.  */
2245
2246 static char *map_lookup_str (map_type map, char *key)
2247 {
2248   unsigned int n = map_hash (key);
2249   map_element_type *p;
2250   
2251   for (p = map[n]; p != NULL; p = p->next) {
2252 #ifdef DEBUGALIAS
2253     if (traceflag) {
2254       sprintf(logline, "Trying %s against %s\n", key, p->key);
2255       showline(logline, 0);
2256     }
2257 #endif
2258     if (strcmp (key, p->key) == 0) return p->value;
2259 #ifdef DEBUGALIAS
2260     if (traceflag) {
2261       sprintf(logline, "p->next %p\n", p->next);
2262       showline(logline, 0);
2263     }
2264 #endif
2265   }
2266 #ifdef DEBUGALIAS
2267   if (traceflag) {
2268     sprintf(logline, " failed to find %s\n", key);
2269     showline(logline, 0);
2270   }
2271 #endif
2272   return NULL;          /* failed to find it */
2273 }
2274
2275 #ifdef DEBUGALIAS
2276 static void map_show (map_type map) /* debugging tool */
2277 {
2278   map_element_type *p;
2279   unsigned int n;
2280   
2281   for (n = 0; n < MAP_SIZE; n++) {
2282     for (p = map[n]; p != NULL; p = p->next) {
2283       sprintf(logline, "n %u key %s next %p\n", n, p->key, p->next);
2284       showline(logline, 0);
2285     }
2286   }
2287 }
2288 #endif
2289
2290 /*  Look up KEY in MAP; if it's not found, remove any suffix from KEY and
2291   try again.  Then paste key back into answer ... */
2292
2293 /* OK, the original KEY didn't work.  Let's check for the KEY without
2294     an extension -- perhaps they gave foobar.tfm, but the mapping only
2295     defines `foobar'.  */
2296
2297 /* Append the same suffix we took off, if necessary.  */
2298 /*  if (ret) ret = extend_filename (ret, suffix); */
2299
2300 char *map_lookup (map_type map, char *key)
2301 {
2302   char *ret = map_lookup_str(map, key);
2303 /*  char *suffix; */
2304   
2305 /*  lets assume we never have to deal with names that have extensions */
2306 /*  suffix = find_suffix (key); 
2307   if (!ret) {
2308     if (suffix) {
2309       char *base_key = remove_suffix (key);
2310       ret = map_lookup_str(map, base_key);
2311       free (base_key);
2312     }
2313   }
2314   if (ret && suffix) ret = extend_filename (ret, suffix);  */
2315
2316   return ret;
2317 }
2318
2319 /* If KEY is not already in MAP, insert it and VALUE.  */
2320 /* This was a total mess! Fixed 1994/March/18 */
2321
2322 static void map_insert (map_type map, char *key, char *value)
2323 {
2324   unsigned int n = map_hash (key);
2325   map_element_type **ptr = &map[n];
2326
2327   while (*ptr != NULL && !(strcmp(key, (*ptr)->key) == 0))
2328     ptr = &((*ptr)->next);
2329
2330   if (*ptr == NULL) {
2331     *ptr = (map_element_type *) xmalloc (sizeof(map_element_type));
2332     (*ptr)->key = xstrdup (key);
2333     (*ptr)->value = xstrdup (value);
2334     (*ptr)->next = NULL;
2335   }
2336 }
2337
2338 /* Open and read the mapping file FILENAME, putting its entries into
2339    MAP. Comments begin with % and continue to the end of the line.  Each
2340    line of the file defines an entry: the first word is the real
2341    filename (e.g., `ptmr'), the second word is the alias (e.g.,
2342    `Times-Roman'), and any subsequent words are ignored.  .tfm is added
2343    if either the filename or the alias have no extension.  This is the
2344    same order as in Dvips' psfonts.map; unfortunately, we can't have TeX
2345    read that same file, since most of the real filenames start with an
2346    `r', because of the virtual fonts Dvips uses.  
2347    And what a load of bull! And who cares about DVIPS and VF files !*/
2348
2349 static void map_file_parse (map_type map, char *map_filename)
2350 {
2351   char *l;
2352   unsigned int map_lineno = 0;
2353   unsigned int entries = 0;
2354   FILE *f = fopen(map_filename, "r");
2355   
2356   if (f == NULL) {
2357     sprintf(logline, " ERROR: Can't open %s\n", map_filename);
2358     showline(logline, 1);
2359     perrormod(map_filename);
2360     return;
2361   }
2362
2363   while ((l = read_line(f)) != NULL) {
2364     char *filename;
2365     char *comment_loc;
2366
2367 /*    comment_loc = strrchr (l, '%'); */
2368     comment_loc = strchr(l, '%');         /* 96/Aug/20 */
2369 /*    if (comment_loc == NULL) comment_loc = strrchr (l, ';'); */
2370     if (comment_loc == NULL) comment_loc = strchr (l, ';');
2371       
2372 /*    Ignore anything after a % or ;  */
2373     if (comment_loc)  *comment_loc = 0;
2374       
2375     map_lineno++;
2376       
2377 /*    If we don't have any filename, that's ok, the line is blank.  */
2378     filename = strtok (l, " \t");
2379     if (filename) {
2380       char *alias = strtok (NULL, " \t");
2381           
2382       /* But if we have a filename and no alias, something's wrong.  */
2383       if (alias == NULL || *alias == 0) {
2384         sprintf(logline,
2385           " font name `%s', but no alias (line %u in `%s').\n",
2386             filename, map_lineno, map_filename);
2387         showline(logline, 1);
2388       }
2389       else {       /* We've got everything.  Insert the new entry.  */
2390         map_insert (map, alias, filename); /* alias is the key */
2391         entries++;
2392       }
2393     }
2394     free (l);
2395   }
2396 /*  xfclose (f, map_filename); */
2397   fclose (f);
2398 #ifdef DEBUGALIAS
2399   if (traceflag) {
2400     sprintf(logline, "%u entries\n", entries);
2401     showline(logline, 0);
2402   }
2403 #endif
2404 }
2405
2406 /* Look for the file `texfonts.map' in each of the directories in
2407    TEXFONTS.  Entries in earlier files override later files.  */
2408
2409 /* uses _searchenv ? */
2410
2411 /* map_type map_create (char *envvar) { old version
2412   char filename[_MAX_PATH];
2413   map_type map;
2414       
2415   _searchenv ("texfonts.map", envvar, filename);
2416   if (*filename == '\0') return NULL;
2417
2418   map = (map_type) xcalloc (MAP_SIZE, sizeof (map_element_type *));
2419   map_file_parse (map, filename);
2420 #ifdef DEBUG
2421   if (traceflag) map_show(map);
2422 #endif
2423   return map;
2424 } */
2425
2426 /* Look for the file `texfonts.map' in each of the directories in
2427    TEXFONTS.  Entries in earlier files override later files.  */
2428
2429 /* void oursearchenv (char *mapname, char *envvar, char *pathname) { */
2430 void oursearchenv (char *mapname, char *searchpath, char *pathname)
2431 {
2432 /*  char *searchpath; */          /* 97/May/10 */
2433   int foundfile=0;            /* set, but not used ? */
2434 #ifndef SUBDIRSEARCH
2435   FILE *input;
2436   char *s;
2437 #endif
2438
2439 /*  searchpath = _getenv(envvar); */
2440 /*  searchpath = grabenv(envvar); */    /* 97/May/10 */
2441   if (searchpath == NULL) {       /* 1996/July/30 */
2442     *pathname = '\0';         /* failed env var lookup */
2443     return;
2444   }                   /* new sanity check */
2445 #ifdef SUBDIRSEARCH
2446   if (searchalongpath(mapname, searchpath, pathname, 0) != 0)
2447     *pathname = '\0';
2448   else foundfile = 1;           /* 1994/Aug/18 */
2449 #else
2450   for (;;) {
2451     if ((searchpath = nextpathname(pathname, searchpath)) == NULL) {
2452 /*      foundfile = 0; */
2453       break;
2454     }
2455     s = pathname + strlen(pathname) - 1;
2456     if (*s != '\\' && *s != '/') strcat(pathname, "\\"); 
2457     strcat(pathname, mapname);
2458     if ((input = fopen(pathname, "r")) != NULL) {
2459       foundfile = 1;
2460       fclose (input);
2461       break;
2462     }
2463   }
2464 #endif
2465 }
2466
2467 /* Returns NULL if it failed for some reason */
2468
2469 /* map_type map_create (char *envvar) { */    /* 94/May/23 */
2470 map_type map_create (char *texfonts)      /* 97/May/10 */
2471 {
2472   char pathname[_MAX_PATH];
2473   map_type map;
2474       
2475 #ifdef DEBUGALIAS
2476   if (traceflag) showline("Creating alias table\n", 0);
2477 #endif
2478 /*  oursearchenv ("texfonts.map", envvar, pathname); */
2479   oursearchenv ("texfonts.map", texfonts, pathname);
2480   if (*pathname == '\0') {
2481 #ifdef DEBUGALIAS
2482     if (traceflag) {
2483       sprintf(logline, "Could not find %s in\n", "texfonts.map", texfonts);
2484       showline(logline, 0);
2485     }
2486 #endif
2487     return NULL;
2488   }
2489
2490   map = (map_type) xcalloc (MAP_SIZE, sizeof(map_element_type *));
2491   map_file_parse (map, pathname);
2492 #ifdef DEBUGALIAS
2493   if (traceflag) map_show(map);
2494 #endif
2495   return map;
2496 }
2497
2498 /* ************************************************************************* */
2499
2500 /*  if we didn't find the font, maybe its alias to be found in texfonts.map */
2501
2502 map_type fontmap = NULL;      /* static - keep around once set */
2503
2504 /*  returns NULL if failed to find an alias */
2505
2506 char *alias (char *name)
2507 {
2508 /*  static map_type fontmap = NULL; */  /* static - keep around once set */
2509   char *mapped_name;
2510       
2511   if (usefontmap == 0) return NULL; /* failed to find it before */
2512 /*  Now fault in the mapping if necessary.  */
2513   if (fontmap == NULL) {
2514 /*    fontmap = map_create ("TEXFONTS"); */
2515     fontmap = map_create (texfonts);    /* 97/May/10 */
2516     if (fontmap == NULL) {    /* check if it worked */
2517       usefontmap = 0;     /* don't try this again */
2518       return NULL;
2519     }
2520   }
2521       
2522 /*  Now look for our filename in the mapping.  */
2523   mapped_name = map_lookup(fontmap, name);
2524   return mapped_name;           /* possibly NULL */
2525 }
2526
2527 /* ************************************************************** */
2528
2529 #endif
2530
2531 /***************************************************************************/
2532
2533 #ifndef SUBDIRSEARCH
2534
2535 /* Moved from DVIPSONE.C since DVIPSLOG.C module is much smaller */
2536
2537 /* Extract next pathname from a searchpath - and write into pathname */
2538 /* return NULL if there are no more pathnames, */
2539 /* otherwise returns pointer to NEXT pathname in searchpath */
2540 /* searchpath = pathname1;pathname2; ... ;pathnamen */
2541
2542 /* used for pfb search path and eps search path */
2543 /* this version also allows space as separator */
2544
2545 char *nextpathname(char *pathname, char *searchpath)
2546 {
2547   int n;
2548   char *s;
2549
2550   if (*searchpath == '\0') return NULL; /* nothing left */
2551   else if (((s = strchr(searchpath, ';')) != NULL) ||
2552          ((s = strchr(searchpath, ' ')) != NULL)) {
2553     n = (s - searchpath);
2554     if (n >= MAXPATHLEN) {
2555       sprintf(logline, " Path too long %s\n", searchpath);
2556       showline(logline, 1);
2557       return NULL;
2558     }
2559     strncpy(pathname, searchpath, (unsigned int) n);
2560     *(pathname + n) = '\0';       /* terminate it */
2561     return(s + 1);            /* next pathname or NULL */
2562   }
2563   else {
2564     n = (int) strlen(searchpath);
2565     if (n >= MAXPATHLEN) {
2566       sprintf(logline, " Path too long %s\n", searchpath);
2567       showline(logline, 1);
2568       return NULL;
2569     }
2570     strcpy(pathname, searchpath);
2571     return(searchpath + n);
2572   }
2573 }
2574
2575 #endif
2576
2577 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2578
2579 /* struct _find_t {
2580     char reserved[21];
2581     char attrib;
2582     unsigned wr_time;
2583     unsigned wr_date;
2584     long size;
2585     char name[13];
2586     }; */ /* 16 bit world --- in dos.h */
2587
2588 /* struct _finddata_t {
2589     unsigned  attrib;
2590     time_t  time_create;  -1 for FAT file systems 
2591     time_t  time_access;  -1 for FAT file systems 
2592     time_t  time_write;
2593     _fsize_t  size;
2594     char  name[260];
2595 }; */ /* 32 bit world --- in io.h */
2596
2597 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2598
2599 #ifdef SUBDIRSEARCH
2600
2601 /* Code to implement (possibly recursive) sub-directory search 94/Aug/18 */
2602
2603 #define ACCESSCODE 4
2604
2605 #define SEPARATOR "\\"
2606
2607 /* This is the (possibly recursive) sub-directory searching code */
2608
2609 /* We come in here with the directory name in pathname */
2610 /* Which is also where we plan to return the result when we are done */
2611 /* We search in this directory first, */
2612 /* and we search one level subdirectories (if it ended in \), */
2613 /* or recursively if the flag is set (when it ends in \\). */
2614 /* File name searched for is in filename */
2615 /* Returns zero if successful --- return non-zero if not found */
2616
2617 /*  struct _finddata_t c_file; */
2618 /*  _finddata_t structure *can* be reused, unlike _find_t 95/Jan/31 */
2619 /*  so save on stack space, by having one copy, not one per expand_subdir */
2620 /*  possibly allocate this in the caller of findsubpath ? not static ? */
2621
2622 int findsubpath (char *filename, char *pathname, int recurse)
2623 {
2624   char *s;
2625   int code;
2626   int ret;
2627 /*  struct _finddata_t c_file; */ 
2628   static struct _finddata_t c_file;   /* structure can be reused (?) */
2629   long hFind;
2630 #endif
2631
2632   s = pathname + strlen(pathname);  /* remember the end of the dirpath */
2633   if (traceflag) {
2634     sprintf(logline, " Entering findsubpath: %s %s %d\n",
2635         filename, pathname, recurse);
2636     showline(logline, 0);
2637   }
2638
2639 /*  First try directly in this directory (may want this conditional) */
2640   strcat (pathname, SEPARATOR);   /* \ or / */
2641   strcat (pathname, filename);
2642
2643 /*  Try for match in this directory first - precedence over files in subdirs */
2644 /*  if (_access(pathname, ACCESSCODE) == 0) */    /* check for read access */
2645   code = _access(pathname, ACCESSCODE);
2646   if (code == 0) {
2647     if (traceflag) {
2648       sprintf(logline, " SUCCESS: %s\n", pathname);
2649       showline(logline, 0);
2650     }
2651     return 0;           /* success */
2652   }
2653   if (traceflag) {          /* debugging */
2654 /*    code = _access(pathname, ACCESSCODE); */
2655     sprintf(logline, " File %s Access %d\n", pathname, code);
2656     showline(logline, 0);
2657   }
2658
2659   *s = '\0';            /* strip off the filename again */
2660 /*  no luck, so try and find subdirectories */
2661   strcat (pathname, SEPARATOR); /* \ or / */
2662   strcat (pathname, "*.*");
2663 /*  if (_dos_findfirst (pathname, _A_NORMAL | _A_SUBDIR, &c_file) != 0) { */
2664 /*  if (_dos_findfirst (pathname,
2665     _A_NORMAL | _A_SUBDIR | _A_RDONLY, &c_file) != 0)  */
2666   hFind = _findfirst (pathname, &c_file);
2667   if (hFind > 0)  ret = 0;    /* found something */
2668   else ret = -1;          /* did not find path ? */
2669 /*  ret = _dos_findfirst (pathname, _A_NORMAL | _A_SUBDIR | _A_RDONLY, &c_file); */
2670
2671   if (ret) {            /* nothing found ? */
2672     if (badpathwarn++ == 0) {
2673       sprintf(logline, "WARNING: bad path `%s' for `%s':\n", pathname, filename);
2674       showline(logline, 1);
2675       perrormod(filename);    /* debugging only ? bad path given */
2676     }
2677     return -1;          /* failure */
2678   }
2679   *s = '\0';            /* strip off the \*.* again */
2680 /*  Step through sub-directories */
2681   for (;;) {
2682 /*    Ignore all but sub-directories here - also ignore . and .. */
2683     if ((c_file.attrib & _A_SUBDIR) == 0 || *c_file.name == '.') {
2684 /*      if (_dos_findnext (&c_file) != 0) break; */
2685       ret = _findnext (hFind, &c_file); /* success == TRUE ??? */
2686 /*      need to flip polarity of ret ? apparently not ... */
2687 /*      ret = _dos_findnext (&c_file);  */  /* success == 0 */
2688
2689       if (ret != 0) break;  /* give up, found nothing more */
2690       continue;       /* did find something else, go on */
2691     }
2692 /*    extend pathname with subdir name */
2693     strcat(pathname, SEPARATOR);
2694     strcat(pathname, c_file.name);
2695     if (traceflag) {
2696       sprintf(logline, " Checking subdir: %s\n", pathname);
2697       showline(logline, 0);
2698     }
2699 /*    OK, now try for match in this directory */
2700     if (recurse) {              /* recursive version */
2701       if (findsubpath(filename, pathname, recurse) == 0) {
2702         _findclose(hFind);
2703         hFind = 0;
2704         return 0;           /* succeeded */
2705       }
2706     }
2707     else {                  /* not recursive */
2708       strcat (pathname, SEPARATOR);
2709       strcat (pathname, filename);
2710       if (traceflag) {
2711         sprintf(logline, " Checking file: %s\n", pathname);
2712         showline(logline, 0);
2713       }
2714 /*      if (_access(pathname, ACCESSCODE) == 0)   */
2715       code = _access(pathname, ACCESSCODE); /* check read access */
2716       if (code == 0) { 
2717         if (traceflag) {
2718           sprintf(logline, " SUCCESS: %s\n", pathname);
2719           showline(logline, 0);
2720         }
2721         _findclose(hFind);
2722         hFind = 0;
2723         return 0;           /* success */
2724       }
2725       if (traceflag) {              /* debugging */
2726 /*        code = _access(pathname, ACCESSCODE); */
2727         sprintf(logline, " File %s Access %d\n", pathname, code);
2728         showline(logline, 0);
2729       }
2730     }
2731
2732 /*    No match in this directory, so continue */
2733     *s = '\0';
2734     if (traceflag) {
2735       sprintf(logline, "Ready for dos_findnext: %s %s %d\n",
2736           filename, pathname, recurse);
2737       showline(logline, 0);
2738     }
2739 /*    if (_dos_findnext (&c_file) != 0) break; */
2740     ret = _findnext (hFind, &c_file);   /* success == TRUE ??? */
2741 /*    need to flip polarity of ret ? apparently not ... */
2742 /*    ret = _dos_findnext (&c_file); */     /* success == 0 */
2743
2744     if (ret != 0) break;          /* found no more */
2745   } /* end of for{;;} loop */
2746   if (hFind > 0) {
2747     _findclose (hFind);
2748     hFind = 0;
2749   }
2750   return -1;                  /* failed */
2751 }
2752
2753 /* Our searchalongpath is (somewhat) analogous to DOS _searchenv */
2754 /* The name of the desired file is given in `filename' */
2755 /* The list of paths is given in `pathlist' */
2756 /* searchalongpath returns the full pathname of first match in `pathname' */
2757 /* (make sure there is enough space there!) */
2758 /* If the file is not found, then pathname contains "" */
2759 /* and it also returns non-zero if it fails. */
2760 /* It first searches in the current directory if currentflag > 0 */
2761 /* It also searches PFM subdirectories if currentflag < 0 97/June/1 */
2762 /* If a path in `pathlist' ends in \, then its sub-directories are searched, */
2763 /* (after the specified directory) */
2764 /* If a path in `pathlist' ends in \\, then this works recursively */
2765 /* (which may be slow and cause stack overflows ...) */
2766
2767 int searchalongpath (char *filename, char *pathlist, char *pathname, int current)
2768 {
2769 /*  struct _find_t c_file; */      /* need to preserve across calls to DOS */
2770   char *s, *t, *u, *send;
2771   int c, n;
2772   int recurse;
2773 #ifdef DEBUGSEARCHPATH
2774   int code;
2775 #endif
2776   
2777   if (current > 0) {  /*  Try for exact match in current directory first ? */
2778     strcpy(pathname, filename);
2779     if (_access(pathname, ACCESSCODE) == 0) { /* check for read access */
2780       if (traceflag) {
2781         sprintf(logline, " File %s SUCCESS\n", pathname);
2782         showline(logline, 0);
2783       }
2784       return 0;             /* success */
2785     }
2786 #ifdef DEBUGSEARCHPATH
2787     if (traceflag) {              /* debugging */
2788       code = _access(pathname, ACCESSCODE);
2789       sprintf(logline, " File %s Access %d\n",
2790         pathname, _access(pathname, ACCESSCODE));
2791       showline(logline, 0);
2792     }
2793 #endif
2794   }
2795
2796 /*  Now step through paths in pathlist */
2797   s = pathlist;
2798   for (;;) {
2799     if (*s == '\0') break;        /* sanity check */
2800     if ((t = strchr(s, ';')) == NULL)
2801       t = s + strlen(s);        /* if last path */
2802     n = t - s;
2803     strncpy(pathname, s, n);
2804     u = pathname + n;
2805     *u-- = '\0';            /* null terminate */
2806     c = *u;               /* check whether ends on \ */
2807     if (c == '\\' || c == '/') {    /* yes it does -> subdir search */
2808       *u-- = '\0';          /* remove it */
2809       c = *u;             /* check whether ends on \\ */
2810       if (c == '\\' || c == '/') {  /* yes it does */
2811         *u-- = '\0';        /* remove it */
2812         recurse = 1;        /* recursive subdir search */
2813       }
2814       else recurse = 0;
2815       if (traceflag) {
2816         sprintf(logline, " Trying subdir: %s\n", pathname);
2817         showline(logline, 0);
2818       }
2819       if (findsubpath (filename, pathname, recurse) == 0)
2820         return 0; /* success */
2821     }
2822     else {                  /* its just a directory */
2823       send = pathname + strlen(pathname); /* remember end for below */
2824       strcat (pathname, SEPARATOR);   /* \ or / */
2825       strcat (pathname, filename);
2826       if (_access (pathname, ACCESSCODE) == 0) {
2827         if (traceflag) {
2828           sprintf(logline, " File %s SUCCESS\n", pathname);
2829           showline(logline, 0);
2830         }
2831         return 0;           /* success */
2832       }
2833 #ifdef DEBUGSEARCHPATH
2834       if (traceflag) {          /* debugging */
2835         code = _access(pathname, ACCESSCODE);
2836         sprintf(logline, " File %s Access %d\n",
2837           pathname, _access(pathname, ACCESSCODE));
2838         showline(logline, 0);
2839       }
2840 #endif
2841       if (current < 0) {  /* try in PFM sub-directory also 97/June/1 */
2842         *send = '\0';         /* snip off file name again */
2843         strcat (pathname, SEPARATOR);   /* \ or / */
2844         strcat (pathname, "PFM");     /* splice in PFM */
2845         strcat (pathname, SEPARATOR);   /* \ or / */
2846         strcat (pathname, filename);
2847         if (_access (pathname, ACCESSCODE) == 0) {
2848           if (traceflag) {
2849             sprintf(logline, " File %s SUCCESS\n", pathname);
2850             showline(logline, 0);
2851           }
2852           return 0;           /* success */
2853         }
2854 #ifdef DEBUGSEARCHPATH
2855         if (traceflag) {          /* debugging */
2856           code = _access(pathname, ACCESSCODE);
2857           sprintf(logline, " File %s Access %d\n",
2858                pathname, _access(pathname, ACCESSCODE));
2859           showline(logline, 0);
2860         }
2861 #endif
2862       }
2863     }
2864
2865     s = t;            /* move on to next item in list */
2866     if (*s == ';') s++;     /* step over separator */
2867     else break;         /* we ran off the end */
2868   }
2869   strcpy(pathname, "");     /* failed to find it */
2870   return -1;
2871 }
2872
2873 /*  search for file in path list and open it if found */
2874 /*  return full path name in third arg unless third arg is NULL */
2875 /*  if third arg is NULL, a local temporary place is used for the name */
2876 /*  if current > 0, look in current directory first */
2877 /*  if current < 0, look in PFM sub directories also */
2878 //  only place we use _alloca ...
2879
2880 FILE *findandopen (char *filename, char *pathlist, char *pathname, char *mode, int current)
2881 {
2882   FILE *file;
2883
2884   if (pathname == NULL) {
2885     pathname = (char *) _alloca (FNAMELEN);
2886     if (pathname == NULL) checkexit(1);
2887   }
2888   if (searchalongpath(filename, pathlist, pathname, current) == 0) {
2889     file = fopen(pathname, mode);
2890     return file;
2891   }
2892   else return NULL;
2893 }
2894
2895 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
2896
2897 /* dviextra.c(5813) : fatal error C1001: internal compiler error */
2898 /*    (compiler file 'msc2.cpp', line 1011) */
2899
2900 /* dvipslog.c(2008) : fatal error C1001: internal compiler error
2901     (compiler file 'msc2.cpp', line 1011) */
2902
2903 /* stuff for reading .afm files */
2904
2905 int readafm(char *font, FILE *fp_afm, long widths[])
2906 {
2907   double fwidth;
2908   int chr, k=0;
2909
2910 /*  if (fp_afm == NULL) checkexit(5);  */
2911   (void) getrealline(fp_afm, line);
2912
2913   while (strstr(line, "StartCharMetrics") == NULL) {
2914     if(getrealline(fp_afm, line) == 0) {
2915       sprintf(logline, 
2916         " Can't find CharMetrics in AFM file for %s\n", font);
2917       showline(logline, 1);
2918       errcount(0);
2919       return 0;
2920     }
2921
2922 /* could extract UniqueID, BBox and FontInfo stuff at this point */
2923   }
2924   (void) getrealline(fp_afm, line);
2925   while(strstr(line, "EndCharMetrics") == NULL) {
2926     if(strstr(line, "EndCharMetrics") != NULL) break;
2927     if (sscanf(line," C %d ; WX %lg", &chr, &fwidth) < 2) {
2928       sprintf(logline, 
2929         " Parse error in line from AFM file for %s: %s", 
2930           font, line);
2931       showline(logline, 1);
2932       errcount(0);
2933       return 0;
2934     }
2935     if (chr >= 0 && chr < MAXCHRS) {
2936       if (chr > k) k = chr;
2937       widths[chr] = (long) ((fwidth/1000.0) * 1048576.0 + 0.5);
2938     }
2939     (void) getrealline(fp_afm, line);
2940   }
2941   return k;
2942 }
2943
2944 /* moved here from dviextra.c */
2945
2946 /* stuff for reading .tfm files */ /* OK for new form TFM files ? OK */
2947
2948 /* lf, lh, nw, nh, nd, ni, nl, nk, ne are numbers of words */
2949
2950 int readtfm(char *font, FILE *fp_tfm, long widths[])
2951 {
2952   static long qwidths[MAXCHRS];  /* 256 */
2953   int lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np;
2954   int k;
2955   int wdinx;
2956 /*  int chksum, dsgnsize;   */
2957 /*  int hdinx, itinx, rdinx;  */
2958
2959 /*  if (fp_tfm == NULL) checkexit(5);  */
2960     lf = sreadtwo(fp_tfm);  lh = sreadtwo(fp_tfm);
2961   bc = sreadtwo(fp_tfm);  ec = sreadtwo(fp_tfm);
2962   nw = sreadtwo(fp_tfm);  nh = sreadtwo(fp_tfm);
2963   nd = sreadtwo(fp_tfm);  ni = sreadtwo(fp_tfm);
2964   nl = sreadtwo(fp_tfm);  nk = sreadtwo(fp_tfm);
2965   ne = sreadtwo(fp_tfm);  np = sreadtwo(fp_tfm);
2966 /* first try and make sure this is a TFM file ! */
2967   if (lf < 0 || lh < 0 || nw < 0 || nw > 255 || 
2968     bc < 0 || ec < 0 || ec > 255 || bc > ec + 1 || 
2969     lf != 6 + lh + (ec - bc + 1) + nw + nh + nd + ni + nl + nk + ne + np)
2970     {
2971     sprintf(logline, " BAD TFM file for %s", font);
2972     showline(logline, 1);
2973     showline("\n", 0);
2974 /*    sprintf(logline, "Header: %d %d %d %d %d %d %d %d %d %d %d %d\n",
2975       lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np);
2976     showline(logline, 1); */
2977     errcount(0);
2978     return 0;
2979   }
2980 /* now for the header */
2981 /*  chksum = sreadtwo(fp_tfm); */   /* should we bother to verify ? */
2982   (void) sreadtwo(fp_tfm);    /* check sum */
2983 /*  dsgnsize = sreadtwo(fp_tfm);  */
2984   (void) sreadtwo(fp_tfm);  /* design size */
2985 /* discard rest of header */
2986   for (k = 2; k < lh; k++) {  
2987     (void) getc(fp_tfm); (void) getc(fp_tfm);
2988   }
2989 /* now read the actual widths */
2990   fseek(fp_tfm, (long) ((6 + lh + (ec - bc + 1)) << 2), SEEK_SET);
2991   for (k = 0; k < nw; k++) {
2992     qwidths[k] = sreadfour(fp_tfm);
2993 /* character width in design size units * 2^20 */
2994   }
2995   if (qwidths[0] != 0) {  /* qwidths[0] is supposed to be zero */
2996     sprintf(logline, " BAD TFM file for %s", font);
2997     showline(logline, 1);
2998     showline("- ", 0);
2999     showline("width[0] not zero", 0); /* qwidths[0] */
3000     errcount(0);
3001     return 0;
3002   }
3003 /* now go back and read character information */
3004   fseek(fp_tfm, (long) ((6 + lh) << 2), SEEK_SET);
3005   for (k = bc; k <= ec; k++) {
3006     wdinx = getc(fp_tfm); 
3007     (void) getc(fp_tfm);  /*    hdinx = getc(fp_tfm);  */
3008     (void) getc(fp_tfm);  /*    itinx = getc(fp_tfm);  */
3009     (void) getc(fp_tfm);  /*    rdinx = getc(fp_tfm);  */
3010     if (wdinx >= nw) {
3011       sprintf(logline, " BAD TFM file for %s", font);
3012       showline(logline, 1);
3013       showline(" - ", 0);
3014       sprintf(logline, "width index %d (char %d) > width table %d",
3015         wdinx, k, nw);
3016       showline(logline, 0);
3017       errcount(0);
3018       return 0;
3019     }
3020     widths[k] = qwidths[wdinx];
3021   }
3022   return (int) (ec + 1);
3023 }
3024
3025 /* stuff for reading widths from .pfm files */
3026
3027 int readpfm(char *font, FILE *fp_pfm, long widths[])
3028 {
3029   unsigned long length, offset;
3030 /*  double fwidth; */
3031   long lwidth;
3032   int bc, ec, c, k, n;
3033
3034 /*  if (fp_pfm == NULL) checkexit(5);   */
3035 /* first check that this is a PFM file - start with version number */
3036   if ((c = getc(fp_pfm)) != 0 || (c = getc(fp_pfm)) != 1)
3037   {
3038     sprintf(logline, " Not a proper PFM file %s\n", font);
3039     showline(logline, 1);
3040     errcount(0);
3041     return 0;
3042   }
3043   length = 0L;    /* read length of PFM file  */
3044   for (k = 0; k < 4; k++)         /* from byte 2 to byte 6 */
3045     length = length | (getc(fp_pfm) << (k * 8));
3046   for (k = 6; k < 66; k++) (void) getc(fp_pfm); /* ignore copyright */  
3047   for (k = 66; k < 95; k++) (void) getc(fp_pfm); /* ignore assorted */  
3048   bc = getc(fp_pfm); ec = getc(fp_pfm);  /* first and last character */
3049   for (k = 97; k < 117; k++) (void) getc(fp_pfm); /* skip to end header */
3050   for (k = 117; k < 119; k++) (void) getc(fp_pfm);  /* size PFMEXTENSION */
3051   for (k = 119; k < 123; k++) (void) getc(fp_pfm);  /* ptr EXTEXTMETRICS */
3052   offset = 0L;               /* offset of charwidth table */
3053   for (k = 0; k < 4; k++) offset = offset | (getc(fp_pfm) << (k * 8));
3054   if (offset > 8192) {
3055     sprintf(logline, " Offset too long in %s\n", font);
3056     showline(logline, 1);
3057     errcount(0);
3058     return 0;
3059   }
3060   n = (int) offset;
3061   for (k = 127; k < n; k++) c = getc(fp_pfm);
3062   if (c == EOF) {
3063     showline(" Premature EOF", 1);
3064     sprintf(logline, " in PFM file %s\n", font);
3065     showline(logline, 0);
3066     errcount(0);
3067     return 0;
3068   }
3069   for (k = bc; k <= ec; k++) {
3070 /*    fwidths = (double) (getc(fp_pfm) | (getc(fp_pfm) << 8));
3071     widths[k] = (long) ((fwidth/1000.0) * 1048576.0 + 0.5); */
3072     lwidth = (long) (getc(fp_pfm) | (getc(fp_pfm) << 8));
3073 /*    widths[k] = (long) (((lwidth << 20) + 500) / 1000);  */
3074     widths[k] = (long) (((lwidth << 17) + 62) / 125);  
3075 /*    if (lwidth != 0) showline(logline, "w[%d] %ld ", k, lwidth); */
3076 /*    if (widths[k] != 0) showline(logline, " %ld ", k, widths[k]); */
3077   }
3078   if (traceflag) {
3079     sprintf(logline, "bc = %d ec = %d ", bc, ec);
3080     showline(logline, 0);
3081   }
3082   return ec;
3083 }
3084
3085 #define DEBUGMMPFM
3086
3087 /* check PFM file for MM instance and extract PostScript FontName */
3088 /* WARNING: this writes back into second argument ! */
3089 /* make sure FontName has enough space for FontName ( > 32 ) 97/June/1 */
3090 /* In typical use, FaceName == NULL and nface == 0 */
3091 /* return 0 if fails in some way */
3092
3093 /* int pfminstance (FILE *input, char *FontName, int nlen) { */
3094 int NamesFromPFM (FILE *input, char *FaceName, int nface,
3095           char *FontName, int nfont, char *FileName)
3096 {
3097   short version;
3098   long length, offset;
3099   int n, ndrive;
3100   char DriverType[16];  /* space for "PostScript" */
3101   char *s;
3102   
3103 //  if (traceflag) {
3104 //    sprintf(logline, " NamesFromPFM nface %d nfont %d\n", nface, nfont);
3105 //    showline(logline, 0);     // debugging only
3106 //  }
3107
3108 #ifdef DEBUGMMPFM
3109   if (traceflag)  {
3110     sprintf(logline, " Read `%s' for MM instance info\n", FileName); /* debugging */
3111     showline(logline, 0);
3112   }
3113 #endif
3114   fread(&version, sizeof(version), 1, input);
3115   if (version != 256) {
3116 #ifdef DEBUGMMPFM
3117     sprintf(logline, " Bad version code (%d) in PFM %s ", version, FileName);
3118     showline(logline, 1);
3119 #endif
3120     return 0;       /* not PFM file */
3121   }
3122   fread(&length, sizeof(length), 1, input);
3123   if (fseek(input, 101, SEEK_SET) != 0) {
3124 #ifdef DEBUGMMPFM
3125     sprintf(logline, " Seek to %ld failed in PFM %s ", 101L, FileName);
3126     showline(logline, 1);
3127 #endif
3128     return 0;
3129   }
3130   fread(&offset, sizeof(offset), 1, input); /* offset to Driver Type */
3131   if (offset >= length || offset == 0) {
3132 #ifdef DEBUGMMPFM
3133     sprintf(logline, " Bad offset %ld (%d) in PFM %s ", offset, length, FileName);
3134     showline(logline, 1);
3135 #endif
3136     return 0; /* not PFM file */
3137   }
3138   if (fseek(input, offset, SEEK_SET) != 0) {
3139 #ifdef DEBUGMMPFM
3140     sprintf(logline, " Seek to %ld failed in PFM %s ", offset, FileName);
3141     showline(logline, 1);
3142 #endif
3143     return 0;
3144   }
3145   ndrive = sizeof(DriverType);
3146   s = DriverType;               /* temporary space */
3147   n = 0;
3148   while ((*s++ = (char) getc(input)) != '\0') { 
3149     if (n++ >= ndrive) {
3150 #ifdef DEBUGMMPFM
3151       sprintf(logline, " %s too long >= %ld in %s ", "DriverType", ndrive, FileName);
3152       showline(logline, 1);
3153 #endif
3154       return 0;
3155     }
3156   }
3157   *s = '\0';                  /* terminate */
3158   if (strcmp(DriverType, "PostScript") != 0) {
3159 #ifdef DEBUGMMPFM
3160     sprintf(logline, " Driver not %s in %s ", "PostScript", FileName);
3161     showline(logline, 1);
3162
3163 #endif
3164     return 0; /* Not PS font */
3165   }
3166   if (fseek(input, 105, SEEK_SET) != 0) {
3167 #ifdef DEBUGMMPFM
3168     sprintf(logline, " Seek to %ld failed in PFM %s ", 105L, FileName);
3169     showline(logline, 1);
3170 #endif
3171     return 0;
3172   }
3173   fread(&offset, sizeof(offset), 1, input); /* offset Windows Face Name */
3174   if (offset >= length || offset == 0) {
3175 #ifdef DEBUGMMPFM
3176     sprintf(logline, " Bad offset %ld (%ld) in PFM %s ", offset, length, FileName);
3177     showline(logline, 1);
3178 #endif
3179     return 0; /* not PFM file */
3180   }
3181   if (fseek(input, offset, SEEK_SET) != 0) {
3182 #ifdef DEBUGMMPFM
3183     sprintf(logline, " Seek to %ld failed in PFM %s ", offset, FileName);   
3184     showline(logline, 1);
3185 #endif
3186     return 0;
3187   }
3188   if (FaceName != NULL) {
3189     s = FaceName;
3190     n = 0;
3191     while ((*s++ = (char) getc(input)) != '\0')
3192       if (n++ >= nface) {
3193 #ifdef DEBUGMMPFM
3194       sprintf(logline, " %s too long >= %ld in %s ", "FaceName", nface, FileName);
3195       showline(logline, 1);
3196 #endif
3197       return 0;
3198     }
3199     *s = '\0';    /* terminate */
3200     if (strchr(FaceName, ' ') == NULL) {
3201 #ifdef DEBUGMMPFM
3202       sprintf(logline, " Not MM %s %s? ", "FaceName", FaceName);
3203       showline(logline, 1);
3204 #endif
3205 /*      return 0; */  /* not MM instance */
3206     }
3207   }
3208   if (fseek(input, 139, SEEK_SET) != 0) {
3209 #ifdef DEBUGMMPFM
3210     sprintf(logline, " Seek to %ld failed in PFM ", 139L);
3211     showline(logline, 1);
3212 #endif
3213     return 0;
3214   }
3215   fread(&offset, sizeof(offset), 1, input); /* offset to PS FontName */
3216   if (offset >= length || offset == 0) {
3217 #ifdef DEBUGMMPFM
3218     sprintf(logline, " Bad offset %ld (%ld) in PFM ", offset, length);
3219     showline(logline, 1);
3220 #endif
3221     return 0; /* not PFM file */
3222   }
3223   if (fseek(input, offset, SEEK_SET) != 0) {
3224 #ifdef DEBUGMMPFM
3225     sprintf(logline, " Seek to %ld failed in PFM ", offset);
3226     showline(logline, 1);
3227 #endif
3228     return 0;
3229   }
3230
3231 /*  write name back into second argument */
3232   if (FontName != NULL) {
3233     s = FontName;
3234     n = 0;
3235     while ((*s++ = (char) getc(input)) != '\0')
3236       if (n++ >= nfont) {
3237 #ifdef DEBUGMMPFM
3238       sprintf(logline, " %s too long >= %ld in %s ", "FontName", nfont, FileName);
3239       showline(logline, 1);
3240 #endif
3241       return 0;
3242     }
3243     *s = '\0';    /* terminate */
3244 /*    We assume FontName for MM instance must have underscores */
3245     if (strchr(FontName, '_') == NULL) {
3246 #ifdef DEBUGMMPFM
3247       sprintf(logline, " Not MM %s %s? ", "FontName", FontName);
3248       showline(logline, 1);
3249 #endif
3250       /* return 0; */ /* not MM instance */
3251     }
3252 #ifdef DEBUGMMPFM
3253     if (traceflag) {
3254       sprintf(logline, " FontName from PFM: %s\n", FontName);/* debugging output */
3255       showline(logline, 0);
3256     }
3257 #endif
3258   }
3259   return 1; /* OK, FaceName and FontName returned */
3260 }
3261
3262 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
3263
3264 /* stuff for reading ATMREG.ATM imported from winpslog.c 98/Jan/9 */
3265
3266 unsigned int xreadtwo (FILE *input)
3267 {
3268   unsigned int c, d, n;
3269   c = getc(input);
3270   d = getc(input);
3271   n = (d << 8) | c; 
3272   return n;
3273 }
3274
3275 unsigned long xreadfour (FILE *input)
3276 {
3277   unsigned int a, b, c, d;
3278   unsigned long n;
3279   a = getc(input);
3280   b = getc(input);
3281   c = getc(input);
3282   d = getc(input);
3283   n = (d << 8) | c;
3284   n = (n << 16) | (b << 8) | a;
3285   return n;
3286 }
3287
3288 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
3289
3290 int bATM41=0;     // needs to be set based on ATMREG.ATM header
3291
3292 /* read string from ATMREG.ATM up to null, string may be empty */
3293 /* returns -1 if hit EOF or name too long */
3294
3295 int ReadString (FILE *input, char *name, int nlen)
3296 {
3297   int c;
3298   int n=0;
3299   char *s=name;
3300
3301   *s = '\0';        /* in case we pop out early */
3302   for (;;) {        /* read string up to null */
3303     c = getc(input);
3304     if (bATM41)       // 2000 July 3 ATM 4.1 ???
3305       (void) getc(input); // discard second byte of UNICODE
3306     if (c == EOF) {   /* EOF */
3307       *s++ = '\0';
3308       return -1;
3309     }
3310     *s++ = (char) c;
3311     if (c == 0) break;
3312     n++;
3313     if (n >= nlen) {  /* too long */
3314       sprintf(logline, " String in ATMREG.ATM too long %d (> %d)\n", n, nlen);
3315       showline(logline, 1);
3316       *name = '\0'; /* flush the name */
3317         return -1;
3318     }
3319   }
3320   return 0;
3321 }
3322
3323 #define LF_FACENAME 32
3324 #define LF_FULLFACENAME 64
3325
3326 /* #define PFMName 16 */    /* >= 8+1+3+1 */
3327 /* #define PFBName 16 */    /* >= 8+1+3+1 */
3328
3329 /**************************************************************************/
3330
3331 /* New code for using ATMREG.ATM */
3332
3333 unsigned long startfontlist, endfontlist;
3334 unsigned long startdirlist, enddirlist;
3335 unsigned long startsetlist, endsetlist;
3336 int nDirs, nFonts, nSets;
3337
3338 typedef struct ATMRegRec {
3339   unsigned char nMMM;   // directory path index for MMMName
3340   unsigned char nPFB;   // directory path index for PFBName
3341   unsigned char nPFM;   // directory path index for PFMName
3342   unsigned char MMMflag;  // 0 => TTF, 1 => T1, 2 => MM Master, 4 => MM Instance
3343   char *FontName;     // PostScript FontName
3344   char *MMMName;      // File Name of PFM (T1 or MMM instance), MMM (for MM master)
3345   char *PFBName;      // File Name of PFB (blank for MM instance)
3346   char *PFMName;      // File Name of PFM (for MM master), MMM (for MM instance)
3347 };
3348
3349 struct ATMRegRec *ATMFonts=NULL;
3350
3351 int ATMfontindex=0;   // number of font entries
3352
3353 // char *DirPaths[MAXDIRS];
3354
3355 char **DirPaths=NULL;
3356
3357 int dirindex=0;
3358
3359 void FreeDirs (void)
3360 {
3361   int k;
3362   if (DirPaths == NULL) return;
3363   for (k = 0; k <= nDirs; k++) {
3364     if (DirPaths[k] != NULL) free(DirPaths[k]);
3365     DirPaths[k] = NULL;
3366   }
3367   dirindex=1;
3368   free(DirPaths);
3369   DirPaths = NULL;
3370 }
3371
3372 int AllocDirs (int nDirs)
3373 {
3374   int k, nlen;
3375   if (DirPaths != NULL) FreeDirs();
3376   nlen = (nDirs + 1) * sizeof(char *);
3377   DirPaths = (char **) malloc (nlen);
3378   if (DirPaths == NULL) {
3379     sprintf(logline,"ERROR: unable to allocate %d bytes for %d dir entries\n",
3380          nlen, nDirs);
3381     showline(logline, 1);
3382     return -1;
3383   }
3384   DirPaths[0] = _strdup("");
3385   for (k = 1; k <= nDirs; k++) DirPaths[k] = NULL;
3386   dirindex=1;
3387   return 0;
3388 }
3389
3390 void FreeFonts (void)
3391 {
3392   int k;
3393   if (ATMFonts == NULL) return;
3394   for (k = 0; k < ATMfontindex; k++) {
3395     if (ATMFonts[k].FontName != NULL) free(ATMFonts[k].FontName);
3396     if (ATMFonts[k].MMMName != NULL) free(ATMFonts[k].MMMName);
3397     if (ATMFonts[k].PFBName != NULL) free(ATMFonts[k].PFBName);
3398     if (ATMFonts[k].PFBName != NULL) free(ATMFonts[k].PFMName);
3399   }
3400   free(ATMFonts);
3401   ATMFonts = NULL;
3402 }
3403
3404 int AllocFonts (int nFonts)
3405 {
3406   int nlen;
3407   if (ATMFonts != NULL) FreeFonts();
3408   nlen = nFonts * sizeof(struct ATMRegRec);
3409   ATMFonts = (struct ATMRegRec *) malloc (nlen);
3410   if (ATMFonts == NULL) {
3411     sprintf(logline, " Unable to allocate %d bytes for %d fonts\n",
3412         nlen, nFonts);
3413     showline(logline, 1);
3414 //    checkexit(1);
3415     return -1;
3416   }
3417 //  sprintf(logline, "Allocated %d bytes for %d fonts\n", nlen, nFonts);  // debugging only
3418 //  showline(logline, 0);
3419   ATMfontindex=0;
3420   return 0;
3421 }
3422
3423 void ShowATMREG (void)
3424 {
3425   int k;
3426   char *szType;
3427   sprintf(logline, "ATMREG has %d T1 font entries (out of %d total):\n", ATMfontindex, nFonts);
3428   showline(logline, 0);
3429   for (k = 0; k < ATMfontindex; k++) {
3430     switch(ATMFonts[k].MMMflag) {
3431       case 0: szType = "TTF "; break;
3432       case 1: szType = "T1  "; break;
3433       case 2: szType = "MMM "; break;
3434       case 4: szType = "MMI "; break;
3435       default: szType = "ERR "; break;
3436     }
3437     sprintf(logline, "%s Fontname: `%s' MMMName: `%s%s' PFBName: `%s%s' PFMName: `%s%s'\n",
3438         szType, ATMFonts[k].FontName,
3439         DirPaths[ATMFonts[k].nMMM], ATMFonts[k].MMMName,
3440         DirPaths[ATMFonts[k].nPFB], ATMFonts[k].PFBName,
3441         DirPaths[ATMFonts[k].nPFM], ATMFonts[k].PFMName);
3442     showline(logline, 0);
3443   }
3444 }
3445
3446 /**********************************************************************************/
3447
3448 int SetupDirs (FILE *input, unsigned long startdirlist, unsigned long enddirlist)
3449 {
3450   int c, k, noff, nlen;
3451   int npath=0;
3452   unsigned long noffset;
3453   char pathname[ _MAX_PATH];
3454   char *s;
3455
3456 /*  if (fseek(input, 24, SEEK_SET) >= 0) noffset = xreadfour(input); */
3457
3458   noffset = startdirlist;     // 36
3459
3460   for (;;) {
3461     if (noffset >= enddirlist) break; /* normal exit from this */
3462     if (fseek(input, noffset, SEEK_SET) < 0) {
3463       if (traceflag) {
3464         sprintf(logline, " Seek to %ld failed\n", noffset);
3465         showline(logline, 0);
3466       }
3467       break;  /*        return -1; */
3468     }
3469     noff = xreadtwo(input);
3470     if (noff != 8) {
3471       if (traceflag) {
3472         sprintf(logline, " noff %lu != 8\n", noff);
3473         showline(logline, 0);
3474       }
3475 /*      break; */ /* new sanity check */
3476     }
3477     nlen = xreadtwo(input);
3478     if (nlen == 0) {
3479       if (traceflag) {
3480         sprintf(logline, " nlen == 0\n");
3481         showline(logline, 0);
3482       }
3483       break;    /* sanity check */
3484     }
3485     if (nlen > _MAX_PATH) {
3486       if (traceflag) {
3487         sprintf(logline, " nlen > %d\n", _MAX_PATH);
3488         showline(logline, 0);
3489       }
3490       break;    /* new sanity check */
3491     }
3492     noffset = xreadfour(input);
3493     if (noffset == 0) {
3494       if (traceflag) {
3495         sprintf(logline, " noffset == 0\n");
3496         showline(logline, 0);
3497       }
3498       break;  /* sanity check */
3499     }
3500     s = pathname;
3501     for (k = 0; k < nlen; k++) {
3502       c = getc(input);
3503       if (bATM41) (void) getc(input);
3504       if (c == EOF) {
3505         if (traceflag) {
3506           sprintf(logline, " Unexpected EOF (%s)\n", "setupdirs");
3507           showline(logline, 0);
3508         }
3509         return -1;
3510       }
3511       *s++ = (char) c;
3512       if (c == 0) break;
3513     }
3514     npath++;
3515 /*    if (noiseflag) printf("%d\t%s\n", npath, pathname); */
3516 //    if (dirindex >= MAXDIRS) {
3517     if (dirindex > nDirs) {
3518       if (traceflag) {
3519         sprintf(logline, " Too many paths (> %d)\n", nDirs);
3520         showline(logline, 0);
3521       }
3522       return -1;
3523     }
3524     DirPaths[dirindex] = xstrdup(pathname);
3525     dirindex++;
3526   }
3527   return 0;
3528 }
3529
3530 /* Look for given PS FontName in atmreg.atm and return file name of PFB */
3531 /* returns 0 if found, -1 if not found */
3532
3533 #ifdef IGNORED
3534 int SearchATMReg (FILE *input, unsigned long endfontlist,
3535           char *szPSFontName, char *szPFBFileName)
3536 {
3537   int c, k;
3538   unsigned int stroffset, nlen;
3539   unsigned long next;
3540   int boldflag, italicflag;   /* style bits */
3541   int ttfflag;
3542 /*  following just used for statistics - could remove to save time */
3543   int psflag, mmmflag, mmiflag, genflag;    /* font type bits */
3544   int nMMM, nPFB, nPFM;       /* index into dir path table */
3545   unsigned int flag[16];        /* 16 bytes of flags */
3546   char FaceName[LF_FACENAME+1];   /* Windows Face Name - not used */
3547   char StyleName[LF_FACENAME+1];    /* Style Name for TT font - not used */
3548   char FullName[LF_FULLFACENAME+1]; /* Full Name - not used */
3549   char FontName[LF_FULLFACENAME+1]; /* Font Name - used in comparison (T1 only) */
3550   char MMMName[LF_FACENAME+1];    /* PFM file or TTF file or MMM file */
3551   char PFBName[LF_FACENAME+1];    /* PFB file or PSS file - not used */
3552   char PFMName[LF_FACENAME+1];    /* PFM file of MMM font - not used */
3553 //  char *s;
3554
3555   *szPFBFileName = '\0';
3556   
3557   fseek(input, startfontlist, SEEK_SET);
3558
3559 /*   positioned at start of font list at this point */
3560
3561   for (;;) {
3562     c = getc(input);        /* check for end of file 99/Mar/1 */
3563     if (c == EOF) {
3564       break;
3565     }
3566     ungetc(c, input);
3567     stroffset = xreadtwo(input);  /* offset to first string == 44 */
3568     nlen = xreadtwo(input);     /* length of this record in bytes */
3569     next = xreadfour(input);    /* pointer to next record */
3570     for (k = 0; k < (28 - 8); k++) (void) getc(input);
3571     for (k = 0; k < 16; k++) flag[k] = getc(input);
3572     boldflag = flag[1];
3573     if (boldflag == 0 || boldflag > 2) {
3574       if (boldflag > 2) boldflag = 1; /* pretend it is OK */
3575 /*      break; */  /* impossible */ /* `fixed' 97/Sep/14 */
3576     }
3577     else boldflag = boldflag - 1;
3578     italicflag = flag[2];
3579     if (italicflag > 1) {
3580 /*      break; */ /* impossible */  /* `fixed' 97/Sep/14 */
3581     }
3582     ttfflag = psflag = mmmflag = mmiflag = genflag = 0;
3583 /*    ttfflag = flag[5]; */
3584     if (flag[4] == 0) ttfflag = 1;
3585     else if (flag[4] == 1) psflag = 1;
3586     else if (flag[4] == 2) mmmflag = 1;
3587     else if (flag[4] == 4) mmiflag = 1;
3588     if (flag[6] == 10) {
3589       genflag = 1;
3590       mmmflag = 0;
3591     }
3592     nMMM = flag[8] | (flag[9] << 8);  /* index into path name table */
3593     nPFB = flag[10] | (flag[11] << 8);  /* index into path name table */
3594     nPFM = flag[12] | (flag[13] << 8);  /* index into path name table */
3595 /*    mmflag = flag[12]; */
3596
3597 //    if (ttfflag) ttfcount++;
3598 //    else if (genflag) gencount++;
3599 //    else if (mmiflag) mmicount++;
3600 //    else if (mmmflag) mmmcount++;
3601 //    else pscount++;
3602
3603 /*    These used to all continue when they hit trouble */
3604 /*    Windows Face Name */
3605       if (ReadString(input, FaceName, sizeof(FaceName)) < 0) goto donext;
3606 /*    Style Name (will be empty string for PS SM or MM font) */
3607       if (ReadString(input, StyleName, sizeof(StyleName)) < 0) goto donext;
3608 /*    Full Name  (will be empty string for PS SM or MM font) */
3609       if (ReadString(input, FullName, sizeof(FullName)) < 0) goto donext;
3610 /*    Font Name  (may be empty if font file not yet read by ATM) */
3611       if (ReadString(input, FontName, sizeof(FontName)) < 0) goto donext;
3612 /*    Name of MMM file or PFM file or TTF file */ 
3613       if (ReadString(input, MMMName, sizeof(MMMName)) < 0) goto donext;
3614 /*    Name of PFB file or PSS file */ 
3615       if (ReadString(input, PFBName, sizeof(PFBName)) < 0) goto donext;
3616 /*    Name of PFM file in case of MMM font */ 
3617       if (ReadString(input, PFMName, sizeof(PFMName)) < 0) goto donext;
3618 /*    Flush extension from file name --- MMMName is file name */
3619 //    if ((s = strchr(MMMName, '.')) != NULL) *s = '\0';
3620 /*    Remove underscores from file name */
3621 /*    removeunderscores(MMMName); */
3622 /*    if (testflag == 0) removeunderscores (MMMName); */  /* ??? */
3623 /*    Make all uppercase ? It's a file name so its safe at least */
3624 /*    makeuppercase (MMMName); */ /* ??? */
3625 #ifdef DEBUGATM
3626     if (traceflag) {
3627 //      sprintf(logline, "%s %s %s%s %s (%d)\n", MMMName, FaceName,
3628 //          boldflag ? "BOLD" : "",
3629 //          italicflag ? "ITALIC" : "",
3630 //          ttfflag ? "(TT)" : "", pscount);
3631 //      showline(logline, 0);
3632       sprintf(logline, "Face: `%s' Style: `%s' Full: `%s' Font: `%s' MMM: `%s' PFB: `%s' PFM: `%s'",
3633           FaceName, StyleName, FullName, FontName, MMMName, PFBName, PFMName);
3634       showline(logline, 0);
3635     }
3636 #endif
3637 /*    if (strcmp(FontName, szPSFontName) == 0) */ /* ignore TrueType fonts */
3638     if (ttfflag == 0 && strcmp(FontName, szPSFontName) == 0 &&
3639         *PFBName != '\0') { // 2000 July 3
3640       if (DirPaths[nPFB] != NULL) strcpy(szPFBFileName, DirPaths[nPFB]);
3641       else *szPFBFileName = '\0';     // should not happen
3642       strcat(szPFBFileName, PFBName);
3643       if (traceflag) {
3644         sprintf(logline, " FOUND: %s for %s\n", szPFBFileName, szPSFontName);
3645         showline(logline, 0);
3646       }
3647       return 0;         /* success */
3648     }
3649 donext:     /* 1999/Mar/1 */
3650 /*    if (findfontstart(input) < 0) break; */
3651     if (next >= endfontlist) break;
3652     if (fseek(input, next, SEEK_SET) < 0) break;
3653   }
3654   *szPFBFileName = '\0';    /* wipe clean again */
3655   return -1;          /* failed to find */
3656 }
3657 #endif
3658
3659 /* New version uses ATMFonts structure */ /* First argument is PS FontName */
3660 /* WRITES BACK INTO SECOND ARGUMENT */
3661 /* returns 0 if found, -1 if not found */
3662
3663 int SearchATMReg (char *szPSFontName, char *szPFBFileName)
3664 {
3665   int k;
3666   for (k = 0; k < ATMfontindex; k++) {
3667     if (strcmp(szPSFontName, ATMFonts[k].FontName) == 0) {
3668       strcpy(szPFBFileName, DirPaths[ATMFonts[k].nPFB]);
3669       strcat(szPFBFileName, ATMFonts[k].PFBName);   // PFB file name
3670       return 0;
3671     }
3672   }
3673   *szPFBFileName = '\0';    /* wipe clean */
3674   return -1;          /* failed to find */
3675 }
3676
3677 /* Create new ATMFonts data structure 2000 July */
3678
3679 int ScanATMReg (FILE *input, unsigned long endfontlist)
3680 {
3681   int c, k;
3682   unsigned int stroffset, nlen;
3683   unsigned long next;
3684   int boldflag, italicflag;   /* style bits */
3685   int ttfflag;
3686 /*  following just used for statistics - could remove to save time */
3687   int psflag, mmmflag, mmiflag, genflag;    /* font type bits */
3688   int nMMM, nPFB, nPFM;       /* index into dir path table */
3689   unsigned int flag[16];        /* 16 bytes of flags */
3690   char FaceName[LF_FACENAME+1];   /* Windows Face Name - not used */
3691   char StyleName[LF_FACENAME+1];    /* Style Name for TT font - not used */
3692   char FullName[LF_FULLFACENAME+1]; /* Full Name - not used */
3693   char FontName[LF_FULLFACENAME+1]; /* Font Name - used in comparison (T1 only) */
3694   char MMMName[LF_FACENAME+1];    /* PFM file or TTF file or MMM file */
3695   char PFBName[LF_FACENAME+1];    /* PFB file or PSS file - not used */
3696   char PFMName[LF_FACENAME+1];    /* PFM file of MMM font - not used */
3697 //  char *s;
3698
3699   if (ATMFonts == NULL) {
3700     if (AllocFonts(nFonts)) return -1;
3701   }
3702   
3703   ATMfontindex = 0;
3704   
3705 //  sprintf(logline"SEEK TO %d\n", startfontlist);  // debugging only
3706 //  showline(logline, 0);
3707   fseek(input, startfontlist, SEEK_SET);
3708
3709 /*  positioned at start of font list at this point */
3710
3711   for (;;) {
3712     c = getc(input);        /* check for end of file 99/Mar/1 */
3713     if (c == EOF) {
3714       break;
3715     }
3716     ungetc(c, input);
3717     stroffset = xreadtwo(input);  /* offset to first string == 44 */
3718     nlen = xreadtwo(input);     /* length of this record in bytes */
3719     next = xreadfour(input);    /* pointer to next record */
3720     for (k = 0; k < (28 - 8); k++) (void) getc(input);
3721     for (k = 0; k < 16; k++) flag[k] = getc(input);
3722     boldflag = flag[1];
3723     if (boldflag == 0 || boldflag > 2) {
3724       if (boldflag > 2) boldflag = 1; /* pretend it is OK */
3725 /*      break; */  /* impossible */ /* `fixed' 97/Sep/14 */
3726     }
3727     else boldflag = boldflag - 1;
3728     italicflag = flag[2];
3729     if (italicflag > 1) {
3730 /*      break; */ /* impossible */  /* `fixed' 97/Sep/14 */
3731     }
3732     ttfflag = psflag = mmmflag = mmiflag = genflag = 0;
3733 /*    ttfflag = flag[5]; */
3734     if (flag[4] == 0) ttfflag = 1;
3735     else if (flag[4] == 1) psflag = 1;
3736     else if (flag[4] == 2) mmmflag = 1;
3737     else if (flag[4] == 4) mmiflag = 1;
3738     if (flag[6] == 10) {
3739       genflag = 1;
3740       mmmflag = 0;
3741     }
3742     nMMM = flag[8] | (flag[9] << 8);  /* index into path name table */
3743     nPFB = flag[10] | (flag[11] << 8);  /* index into path name table */
3744     nPFM = flag[12] | (flag[13] << 8);  /* index into path name table */
3745 /*    mmflag = flag[12]; */
3746
3747 //    if (ttfflag) ttfcount++;
3748 //    else if (genflag) gencount++;
3749 //    else if (mmiflag) mmicount++;
3750 //    else if (mmmflag) mmmcount++;
3751 //    else pscount++;
3752
3753 /*    These used to all continue when they hit trouble */
3754 /*    Windows Face Name */
3755     if (ReadString(input, FaceName, sizeof(FaceName)) < 0) goto donext;
3756 /*    Style Name (will be empty string for PS SM or MM font) */
3757     if (ReadString(input, StyleName, sizeof(StyleName)) < 0) goto donext;
3758 /*    Full Name  (will be empty string for PS SM or MM font) */
3759     if (ReadString(input, FullName, sizeof(FullName)) < 0) goto donext;
3760 /*    Font Name  (may be empty if font file not yet read by ATM) */
3761     if (ReadString(input, FontName, sizeof(FontName)) < 0) goto donext;
3762 /*    Name of MMM file or PFM file or TTF file */ 
3763     if (ReadString(input, MMMName, sizeof(MMMName)) < 0) goto donext;
3764 /*    Name of PFB file or PSS file */ 
3765     if (ReadString(input, PFBName, sizeof(PFBName)) < 0) goto donext;
3766 /*    Name of PFM file in case of MMM font */ 
3767     if (ReadString(input, PFMName, sizeof(PFMName)) < 0) goto donext;
3768 /*    Flush extension from file name --- MMMName is file name */
3769 //    if ((s = strchr(MMMName, '.')) != NULL) *s = '\0';
3770 /*    Remove underscores from file name */
3771 /*    removeunderscores(MMMName); */
3772 /*    if (testflag == 0) removeunderscores (MMMName); */  /* ??? */
3773 /*    Make all uppercase ? It's a file name so its safe at least */
3774 /*    makeuppercase (MMMName); */ /* ??? */
3775 #ifdef DEBUGATM
3776     if (traceflag) {
3777 //      sprintf(logline, "%s %s %s%s %s (%d)\n", MMMName, FaceName,
3778 //          boldflag ? "BOLD" : "",
3779 //          italicflag ? "ITALIC" : "",
3780 //          ttfflag ? "(TT)" : "", pscount);
3781 //      showline(logline, 0);
3782       sprintf(logline, "Face: `%s' Style: `%s' Full: `%s' Font: `%s' MMM: `%s' PFB: `%s' PFM: `%s'",
3783           FaceName, StyleName, FullName, FontName, MMMName, PFBName, PFMName);
3784       showline(logline, 0);
3785     }
3786 #endif
3787     if (ttfflag) goto donext;
3788     ATMFonts[ATMfontindex].nMMM = (unsigned char) nMMM;
3789     ATMFonts[ATMfontindex].nPFB = (unsigned char) nPFB;
3790     ATMFonts[ATMfontindex].nPFM = (unsigned char) nPFM;
3791     ATMFonts[ATMfontindex].MMMflag = (unsigned char) flag[4];
3792     ATMFonts[ATMfontindex].FontName = xstrdup(FontName);  // PS FontName
3793     ATMFonts[ATMfontindex].MMMName = xstrdup(MMMName);    // PFM/MMM File Name
3794     ATMFonts[ATMfontindex].PFBName = xstrdup(PFBName);    // PFB File Name
3795     ATMFonts[ATMfontindex].PFMName = xstrdup(PFMName);
3796     ATMfontindex++;
3797 donext:     /* 1999/Mar/1 */
3798     if (next >= endfontlist) break;
3799     if (fseek(input, next, SEEK_SET) < 0) break;
3800   }
3801   return ATMfontindex;
3802 }
3803
3804 /* sets up pointers to sections of ATMREG.ATM */
3805 /* also determines whether wide strings are used (ATM 4.1) */
3806 /* also reads in directory path table */
3807
3808 unsigned long ReadPointers (FILE *input)
3809 {
3810   (void) fseek(input, 6, SEEK_SET);
3811   nDirs = xreadtwo(input);      /* 6 number of directory paths */
3812   nFonts = xreadtwo(input);     /* 8 number of font entries */
3813   nSets = xreadtwo(input);      /* 10 number of font sets (?) */
3814 //  sprintf(logline, "%d Dir Paths %d Font Entries %d Font Sets\n", nDirs, nFonts, nSets);  // debugging only
3815 //  showline(logline, 0);
3816 //  (void) fseek(input, 12, SEEK_SET);  /* start of pointers into file */
3817   enddirlist = xreadfour(input);    /* 12 enddirlist */
3818   (void) xreadfour(input);      /* 16 mystery ??? */
3819   startfontlist = xreadfour(input); /* 20 startfontlist */
3820   startdirlist = xreadfour(input);  /* 24 startdirlist */
3821   startsetlist = xreadfour(input);  /* 28 endfontlist */
3822   endfontlist = startsetlist;
3823   endsetlist = xreadfour(input);    /* 32 endsetlist */
3824
3825 //  See whether strings in ATMREG.ATM are in UNICODE format
3826   (void) fseek(input, endsetlist, SEEK_SET);
3827   (void) getc(input);
3828   if (getc(input) == 0) bATM41 = 1;
3829   else bATM41 = 0;
3830   if (traceflag) {
3831     sprintf(logline, " bATM41 %d\n", bATM41);
3832     showline(logline, 0);
3833   }
3834   return endfontlist;
3835 }
3836
3837 int SetupATMReg (void)
3838 {
3839   char szFullFileName[FNAMELEN]="";
3840
3841   if (useatmreg == 0) return -1;    /* tried already and failed */
3842   if (szATMRegAtm == NULL) {
3843     setupinifilesub("atmreg.atm", szFullFileName);
3844     if (traceflag) {
3845       sprintf(logline, " atmreg.atm: %s ", szFullFileName);
3846       showline(logline, 0);
3847     }
3848     if (*szFullFileName == '\0') {
3849       useatmreg = 0;        /* don't try again */
3850       return -1;
3851     }
3852     szATMRegAtm = xstrdup(szFullFileName);
3853   }
3854   return 0;
3855 }
3856
3857 // LOAD information from ATMREG.ATM in convenient form 2000 July 6 
3858
3859 int LoadATMREG (void)
3860 {
3861   FILE *input;
3862   int count;
3863
3864   if (! useatmreg) return -1;     // tried before and failed
3865   if (szATMRegAtm == NULL) {
3866     if (SetupATMReg()) return -1; // failed to setup now
3867   }
3868   if (szATMRegAtm == NULL) return -1; // sanity check
3869   input = fopen(szATMRegAtm, "rb"); // open in binary mode for reading 
3870   if (input == NULL) {
3871     useatmreg = 0;
3872     return -1;    // probably because not found
3873   }
3874   if (traceflag) {
3875     sprintf(logline, "Scanning %s ", szATMRegAtm);
3876     showline(logline, 0);
3877   }
3878   (void) ReadPointers(input);
3879   if (AllocDirs(nDirs)) {
3880     useatmreg = 0;
3881     return -1;
3882   }
3883   SetupDirs(input, startdirlist, enddirlist);
3884   if (AllocFonts(nFonts)) {
3885     useatmreg = 0;
3886     return -1;
3887   }
3888   count = ScanATMReg(input, endfontlist);
3889   fclose(input);
3890   if (traceflag) ShowATMREG();    // debugging output
3891   return count;
3892 }
3893
3894
3895 /*  Look up specific font in ATMREG.ATM */
3896 /*  scan atmreg.atm in the windows directory for font info */
3897 /*  called with a single specific PS FontName */
3898 /*  returns -1 if it fails for one reason or another */
3899 /*  WRITES BACK INTO SECOND ARGUMENT */
3900
3901 #ifdef IGNORED
3902 int LookupATMReg (char *szPSFontName, char *szPSFileName)
3903 {
3904   FILE *input;
3905   int n=0;
3906
3907   if (! useatmreg) return -1;     // tried before and failed
3908   if (szATMRegAtm == NULL) {
3909     if (SetupATMReg()) return -1; // failed to setup now
3910   }
3911   input = fopen(szATMRegAtm, "rb"); // open in binary mode for reading 
3912   if (input == NULL) return -1;   // probably because not found
3913   if (traceflag) {
3914     sprintf(logline, "Scanning %s ", szATMRegAtm);
3915     showline(logline, 0);
3916   }
3917   (void) ReadPointers(input);
3918   if (AllocDirs(nDirs)) return -1;
3919   SetupDirs(input, startdirlist, enddirlist);
3920   (void) fseek (input, startfontlist, SEEK_SET);
3921   n = SearchATMReg(input, endfontlist, szPSFontName, szPSFileName);
3922 //  showline(" LookupATMReg ATTEMPT TO FREE DIRPATHS\n", 0);  // debugging only
3923 //  FreeDirs();
3924   fclose(input);
3925   return n;
3926 }
3927 #endif
3928
3929 /* First arg is PS FontName */ /* WRITES BACK INTO SECOND ARG */
3930
3931 int LookupATMReg (char *szPSFontName, char *szPSFileName)
3932 {
3933   int n;
3934   if (! useatmreg) return -1;   // tried before and failed
3935   if (szATMRegAtm == NULL) {    // create ATMFonts structure
3936     if (LoadATMREG() < 0) return -1;  // failed
3937   }
3938   n = SearchATMReg(szPSFontName, szPSFileName);
3939   if (traceflag) {
3940     sprintf(logline, " LookupATMReg %s %s %d\n",
3941         szPSFontName, szPSFileName, n);
3942     showline(logline, 0);   // debugging only
3943   }
3944   return n;
3945 }
3946
3947 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
3948
3949 /* could perhaps be speeded up slightly - using table of chars to skip */
3950
3951 /* check that fonts that have no characters used */
3952 /* (because of page limits) are NOT loaded in dviextra.c */
3953
3954 /* check that nothing but nop and font defs happen between eop and bop ? */
3955
3956 /* doesn't complain if pre not encountered ? IT DOES */
3957
3958 /* search for start of DVI in Textures file a bit crude ? */
3959
3960 /* try and avoid actually giving up if at all possible */
3961
3962 /* catch DVI commands before PRE - OK */
3963
3964 /* catch DVI commands after POST */
3965
3966 /* is TeX comment ever used later ? */  /* yes in PS file */
3967
3968 /* may also want to look 100 bytes into the file for start */
3969 /* some Mac files come that way... */
3970
3971 /* bRemapSpace remaps 32 => 195, 13 to 176, 10 => 173, 9 => 170, 0 => 161 */
3972 /* Rational is that text fonts reencoded to TeX 'n ANSI do not use 0 */
3973 /* or 9 or 10, and from now on text fonts will not use 13 for fl, */
3974 /* and TeX does not use 32 in text fonts */
3975 /* But math fonts do use 0, 9, 10, 13 and 32 */
3976 /* but math fonts always have the repetition of 0 - 32 higher up */
3977 /* And for some versions of Acrobat it may be best not to do this */
3978 /* for example transfer material to clipboard is null terminated */
3979 /* 9 is treated as tab, 10 as newline, 13 ignored and 32 ignored */