OSDN Git Service

d6b63311ce1bf3dc1bb9eee9e5bd67212314758d
[putex/putex.git] / src / dvisourc / dvianal.c
1 /* Copyright 1990,1991,1992,1993,1994,1995,1996,1997,1998,1999 Y&Y, Inc.
2    Copyright 2007 TeX Users Group
3    Copyright 2014 Clerk Ma
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301 USA.  */
19
20
21 /**********************************************************************
22 *
23 * DVI to PS convertor for Adobe Type 1 (ATM compatible) fonts
24 * This is the part that actually converts DVI commands to PS
25 *
26 **********************************************************************/
27
28 #include "dvipsone.h"
29
30 /* NOTE: S = s w, T = s x, W = w<n>, X = x<n>, Y = y<n>, Z = z<n> */
31 /* bp = bop, ep = eop, pr = put_rule, sr = set_rule */
32
33 int firstpage = 0;    /* non-zero when nothing has been output yet */
34 /* int evenlast = 0;  */    /* last non-skipped page was even */
35 /* int oddlast = 0; */    /* last non-skipped page was odd */
36 int skiptoend = 0;    /* non-zero => still need to skip to last page */
37 int finish = 0;     /* non-zero => have hit end of DVI file */
38 int showcount = 0;    /* on when last sent out "set" or "put" */
39 int freshflag = 0;    /* on after fresh line is started (\n) */
40
41 int stinx;        /* stack index - to avoid overflow */ 
42 int maxstinx;     /* max stack index seen  - not used here */
43
44 long currentpagestart;    /* 95/Aug/27 */
45
46 /* int escapecode[14] = {'b', 't', 'n', 'v', 'f', 'r'}; */
47
48 char *escapecode = "btnvfr";  /* special codes for 8, 9, 10, 12, and 13 */
49
50 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
51
52 /* we don't have to worry about sign extension here - no need for short int */
53
54 /* static unsigned int ureadone (FILE *input) {
55   return getc(input);
56 } */
57
58 static unsigned int ureadtwo (FILE *input)
59 {
60   return (getc(input) << 8) | getc(input);
61 }
62
63 static unsigned long ureadthree (FILE *input)
64 {
65   int c, d, e;
66   c = getc(input);
67   d = getc(input);
68   e = getc(input);
69   return ((((unsigned long) c << 8) | d) << 8) | e;
70 }
71
72 static unsigned long ureadfour (FILE *input)
73 {
74   int c, d, e, f;
75   c = getc(input);
76   d = getc(input);
77   e = getc(input);
78   f = getc(input);
79   return ((((((unsigned long) c << 8) | (unsigned long) d) << 8) | e) << 8) | f;
80 }
81
82 /* we do have to worry about sign extension here - use short int if needed */
83
84 static int sreadone (FILE *input)
85 {
86   int c;
87
88   c = getc(input);
89   if (c > 127)
90     return (c - 256);
91   else
92     return c;
93 }
94
95 #ifdef IGNORED
96 static int sreadtwo (FILE *input)
97 {
98   short int result;
99 /*  return (getc(input) << 8) | getc(input); */ /* 1995/Nov/15 */
100 /*  result = (getc(input) << 8) | getc(input); */
101   result = ((short int) getc(input) << 8) | (short int) getc(input);
102   return result;
103 }
104 #endif
105
106 /* possible compiler optimization bug worked around 98/Feb/8 */
107
108 static int sreadtwo (FILE *input)
109 {
110   int c, d;
111   c = getc(input);
112   d = getc(input);
113   if (c > 127) c = c - 256;
114   return c << 8 | d;
115 }
116
117 static long sreadthree (FILE *input)
118 {
119   int c, d, e;
120   c = getc(input);
121   d = getc(input);
122   e = getc(input);
123   if (c > 127) c = c - 256;
124   return ((((long) c << 8) | d) << 8) | e;
125 }
126
127 static long sreadfour (FILE *input)
128 {
129   int c, d, e, f;
130   c = getc(input);
131   d = getc(input);
132   e = getc(input);
133   f = getc(input);
134   return ((((((long) c << 8) | (long) d) << 8) | e) << 8) | f;
135 }
136
137 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
138
139 /* don't need to optimize `push pop' since doesn't happen ever? */
140
141 void do_push(FILE *output, FILE *input)
142 {
143   int c;
144
145   if (skipflag == 0)
146   {
147     stinx++;
148
149     if (stinx % 64 == 0)    /* see if stack is getting full */
150     {
151       PSputs(" pushstack\n", output);
152       showcount = 0;
153       return;
154     }
155
156     c = getc(input);
157
158     if (c == (int) push && ((stinx + 1) % 64 != 0))
159     {
160       stinx++;
161       PSputs(" U", output); /* u u */
162     }
163     else
164     {
165       (void) ungetc(c, input);
166       PSputs(" u", output);   /* statepush */
167     }
168     showcount = 0;
169   }
170 }
171
172 /* Are we sure the `O' = `o o' works when at edge of 64 size stack ? */
173
174 void do_pop(FILE *output, FILE *input)
175 {
176   int c;
177
178   if (skipflag == 0)
179   {
180     if (stinx % 64 == 0)    /* time to retrieve saved stack ? */
181     {
182       stinx--;
183       PSputs(" popstack\n", output);
184       showcount = 0; 
185       return;
186     }
187
188     stinx--;
189     c = getc(input);
190
191     if (c == (int) pop && (stinx % 64 != 0))
192     {
193       stinx--;
194       PSputs(" O", output);   /* o o */
195     }
196     else
197     {
198       if (c == (int) push)
199       {
200         stinx++;
201         PSputs(" M", output);
202       }   /* o u - OK if M defined as `o u' */
203       else
204       {
205         (void) ungetc(c, input);
206         PSputs(" o", output); /* statepop */
207       }
208     }
209     showcount = 0;
210   }
211 }
212
213 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
214
215 void complaincharcode(unsigned long c)    /* 1993/Dec/11 */
216 {
217   sprintf(logline, " Character code %lu > 255\n", c);
218   showline(logline, 1);
219 }
220
221 /* come here either with character code 0 - 127 --- or from set1 */
222 /* in the case of set1 we need to read the next byte, which likely is > 127 */
223
224 void normalchar (FILE *output, FILE *input, int c)
225 {
226   int d;
227
228   if (skipflag == 0)
229   {
230     if (showcount > MAXSHOWONLINE)    /* too much on one line ? */
231     {
232       PSputc('\n', output);
233       showcount = 0;  /* first go to new line */
234     } 
235     PSputc('(', output);
236   }
237
238   while (c < 128 || c == (int) set1)    /* changed ! */
239   {
240     if (c == (int) set1)
241       c = getc(input); /* new ! read next byte */
242
243     if (skipflag == 0)
244     {
245       if (bRemapControl || bRemapFont)
246       {
247         if (c < MAXREMAP)
248           c = remaptable[c];
249 #if MAXREMAP < 128
250         else if (c == 32)
251           c = 195;
252         else if (c == 127)
253           c = 196;
254 #endif
255       }
256 /* NOTE: this must match corresponding code in DVIPSLOG.C */
257       else if (bRemapSpace && c <= 32)  /* 1995/Oct/17 */
258       {
259         if (c == 32) c = 195;   /* not 160 */
260         else if (c == 13) c = 176;  /* 1996/June/4 */
261         else if (c == 10) c = 173;  /* 1996/June/4 */
262         else if (c == 9) c = 170;   /* 1996/June/4 */
263         else if (c == 0) c = 161;
264       }
265 /*      if (c < 32 || c >= 127) { */    /* control characters */
266 /* added test for percent 1992/Dec/21 to avoid % in string ... */
267       if (c < 32 || c >= 127 || c == 37)  { /* control chars and % */
268 /*        if (bForwardFlag != 0 && c <= 13 && c >= 8 && c != 11)  */
269         if (c <= 13 && c >= 8 && c != 11 && bForwardFlag != 0) {
270 /* use special escape \b \t \n ... \f \r for 8 ... 13 1993/Sep/29 */
271           PSputc('\\', output);
272           PSputc(escapecode[c-8], output);
273         }
274 /*        if (backwardflag == 1)  */ /* backward compatible with old ALW */
275         else if (bBackWardFlag == 1) { /* compatibility with old ALW */
276           d = getc(input); (void) ungetc(d, input); /* peek  */
277           if ((d >= 32 && d <= 127) || d == (int) set1) {
278 //            fprintf(output, "\\%03o", c);  /* just to be safe */
279             sprintf(logline, "\\%03o", c);  /* just to be safe */
280           }
281           else {
282             sprintf(logline, "\\%o", c);
283           }
284           PSputs(logline, output);
285         }
286         else {    /* following not always safe for old ALW ... */
287           d = getc(input); (void) ungetc(d, input); /* peek  */
288           if ((d >= '0' && d <= '7') || d == (int) set1) {
289 //            fprintf(output, "\\%03o", c);  /* just to be safe */
290             sprintf(logline, "\\%03o", c);  /* just to be safe */
291           }
292           else {
293             sprintf(logline, "\\%o", c);
294           }
295           PSputs(logline, output);
296         }
297       }
298       else {              /* not control characters */
299         if (c == '\\' || c == '(' || c == ')')
300         {
301 //          putc('\\', output);
302           PSputc('\\', output);
303         }
304 /*        if (c == '%') fprintf(output, "\045"); */
305 /*        else putc(c, output); */
306 //        putc(c, output);
307         PSputc(c, output);
308       }
309     }
310     c = getc(input);    /* get the next byte in DVI file */
311     if (c < 0) break;   /* trap EOF - avoid loop */
312   } /* end of while (c < 128 ... ) loop */
313
314 /* analyze next DVI command to see whether can combine with above */
315   if (skipflag != 0) (void) ungetc(c, input);
316   else {
317     if (c == (int) w0) {
318 //      fputs(")S", output);
319       PSputs(")S", output);
320     }
321     else if (c == (int) x0) {
322 //      fputs(")T", output);
323       PSputs(")T", output);
324     }
325     else {
326 //      fputs(")s", output);
327       PSputs(")s", output);
328       (void) ungetc(c, input);  /* can't use it, put it back */
329     }
330     showcount++;
331   }
332 /*  also need to increase h by total width */
333 /*  fprintf(output, "currentpoint pop /h exch def\n"); */
334 }
335
336 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
337
338 /* Following need *not* be efficient since it is rarely used */
339 /* Put single character - called by put1/put2/put3/put4 */
340 /* Set single character - also called by set2/set3/set4 */
341 /* duplicates a lot of code form normalchar() above */
342
343 /* separated out 1995/June/30 */  /* third arg is `s' or `p' */
344
345 void do_charsub (FILE *output, unsigned long c, char code)
346 {
347   if (skipflag == 0)
348   {
349 /*    if (bRemapControl && c < MAXREMAP) c = remaptable[c]; */
350     if (bRemapControl || bRemapFont)
351     {
352       if (c < MAXREMAP) c = remaptable[c];
353 #if MAXREMAP < 128
354       else if (c == 32) c = 195;
355       else if (c == 127) c = 196;
356 #endif
357     }
358     else if (bRemapSpace && c <= 32) {        /* 1995/Oct/17 */
359       if (c == 32) c = 195;   /* not 160 */
360       else if (c == 13) c = 176;  /* 1996/June/4 */
361       else if (c == 10) c = 173;  /* 1996/June/4 */
362       else if (c == 9) c = 170;   /* 1996/June/4 */
363       else if (c == 0) c = 161;
364     }
365     if (c >= 256) {
366       complaincharcode(c);
367       return;       /* ignore it - should never happen */
368     }
369 /*    if (f < 0) {
370       showline("Setting char %d without font", c);
371       tellwhere(1);   errcount(0);
372     } */
373 //    putc('(', output); 
374     PSputc('(', output); 
375 /*    the following code copied from normachar() --- 1995/June/30 */
376 /*    if (bRemapControl && c < MAXREMAP)
377       c = remaptable[c];  */        /* 1994/Jun/20 */
378 /*    if (c < 32 || c >= 127) */
379     if (c < 32 || c >= 127 || c == 37) {  /* 1995/June/30 fix */
380 /*      fprintf(output, "(\\%o)p", c); */   /* put1 */
381       if (c <= 13 && c >= 8 && c != 11 && bForwardFlag != 0) {
382 /* use special escape \b \t \n ... \f \r for 8 ... 13 1993/Sep/29 */
383 //        putc('\\', output);
384         PSputc('\\', output);
385 //        putc(escapecode[c-8], output);
386         PSputc(escapecode[c-8], output);
387       }
388       else if (bBackWardFlag == 1) {  /* compatibility with old ALW */
389         sprintf(logline, "\\%03o", (unsigned int) c);
390         PSputs(logline, output);
391       }
392       else {    /* following not always safe for old ALW ... */
393         sprintf(logline, "\\%o", (unsigned int) c);
394         PSputs(logline, output);
395       }
396     }
397 /*    else fprintf(output, "(%c)p", c); */  /* 1995/June/30 fixed */
398     else {
399         if (c == '\\' || c == '(' || c == ')') {
400 //          putc('\\', output);
401           PSputc('\\', output);
402         }
403 /*        if (c == '%') fprintf(output, "\045"); */
404 /*        else putc(c, output); */
405 //        putc((unsigned int) c, output);
406         PSputc((unsigned int) c, output);
407     }
408 //    putc(')', output); 
409     PSputc(')', output); 
410 //    putc(code, output);     /* 'p' or 's' */
411     PSputc(code, output);     /* 'p' or 's' */
412     showcount++;
413   }
414 }
415
416 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
417
418 /* could be more efficient here if we ever see several in a row OK */
419 /* model on "normalchar" if needed OK */
420     
421 void do_set1(FILE *output, FILE *input)
422 {
423   if (skipflag == 0)
424   {
425     normalchar(output, input, (int) set1);
426   }
427   else
428     (void) getc(input);
429
430 /* read following byte and throw it away */
431 /* set character c and increase h by width of character */
432 /* used (normally only) for characters in range 128 to 255 */
433 }
434
435 void do_set2(FILE *output, FILE *input)
436 {
437   do_charsub(output, ureadtwo(input), 's');
438 }
439
440 void do_set3(FILE *output, FILE *input)
441 {
442   do_charsub(output, ureadthree(input), 's');
443 }
444
445 void do_set4(FILE *output, FILE *input)
446 {
447   do_charsub(output, ureadfour(input), 's');
448 }
449
450 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
451
452 /* set character c and DO NOT increase h by width of character */
453
454 void do_put1(FILE *output, FILE *input)
455 {
456   do_charsub(output, getc(input), 'p');
457 }
458
459 void do_put2(FILE *output, FILE *input)
460 {
461   do_charsub(output, ureadtwo(input), 'p');
462 }
463
464 void do_put3(FILE *output, FILE *input)
465 {
466   do_charsub(output, ureadthree(input), 'p');
467 }
468
469 void do_put4(FILE *output, FILE *input)
470 {
471   do_charsub(output, ureadfour(input), 'p');
472 }
473
474 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
475
476 /* For PDF problems we adjust height of horizontal rule 95/Oct/15 */
477 /* but we don't adjust the position of the rule ... and */
478 /* if we were to adjust width of vertical rules we'd need to adjust position */
479
480 void do_common_rule (FILE *output, FILE *input, char *s)
481 {
482   long a, b; /* height, width */
483
484   a = sreadfour(input);
485   b = sreadfour(input);
486
487   if (skipflag == 0)
488   {
489     if (nMinRule != 0 && a > 0)       /* 1995/Oct/10 */
490     {
491       /* Make sure we don't get zero width rules in PDF output... */
492       /* ... compensate for truncating down instead of rounding in pdf */
493       if (a < nMinRule)
494         a = nMinRule;
495       else if (a > nMinRule)
496         a = a + nMinRule / 2;
497     }
498
499     if (bRuleColor)
500     {
501       if (! freshflag)
502         PSputc('\n', output);
503
504       sprintf(logline, "%lg %lg %lg rgb ", rulered, rulegreen, ruleblue);
505       PSputs(logline, output);
506       freshflag = 0;
507     }
508     else
509       if (bTextColor)
510       {
511         if (! freshflag) PSputc('\n', output);
512         PSputs("black ", output);
513         freshflag = 0;
514       }
515
516     /* some silly nonsense about using a height = -2^31 in set_rule */
517     /* if (bDVICopyReduce && -a == 2147483648L) a = 0; */  /* 1995/Sep/16 */
518     if (bDVICopyReduce && -a == 2147483648L) /* 1995/Sep/16 */
519     {
520       /* need to do nothing for pr, no output, no motion */
521       if (strcmp (s, "sr") == 0)
522       {
523         if (! freshflag) PSputc('\n', output);
524 #ifdef ALLOWSCALE
525         if (outscaleflag)
526         {
527           sprintf(logline, "%.9lg r", (double) b / outscale);
528         }
529         else
530 #endif
531         {
532           sprintf(logline, "%ld r", b); /* setrule => right */
533         }
534         PSputs(logline, output);
535         freshflag = 0;
536       }
537     }
538     else
539     {
540       if (! freshflag) PSputc('\n', output);
541 #ifdef ALLOWSCALE
542       if (outscaleflag)
543       {
544         sprintf(logline, "%.9lg %.9lg %s",
545             (double) a / outscale, (double) b / outscale, s);
546       }
547       else
548 #endif
549       {
550         sprintf(logline, "%ld %ld %s", a, b, s); /* setrule or putrule */
551       }
552       PSputs(logline, output);
553       freshflag = 0;
554     }
555
556     if (bTextColor)
557     {
558       if (! freshflag) PSputc('\n', output);
559       sprintf(logline, "%lg %lg %lg rgb ", textred, textgreen, textblue);/* 1993/Oct/22 */
560       PSputs(logline, output);
561       freshflag = 0;
562     }
563     else
564       if (bRuleColor)
565       {
566         if (! freshflag) PSputc('\n', output);
567         PSputs("black ", output);
568         freshflag = 0;
569       }
570     showcount = 0;
571   }
572 }
573
574 void do_set_rule(FILE *output, FILE *input)
575 {
576   do_common_rule (output, input, "sr");
577 }
578
579 void do_put_rule(FILE *output, FILE *input)
580 {
581   do_common_rule (output, input, "pr");
582 }
583
584 /* write TeX /counter's */
585 char *showcounters(char *s)
586 {
587   int k;
588   int kmax = 0;
589
590   sprintf(s, "%ld", counter[0]);   /* *always* write first one */
591   s += strlen(s);
592
593   for (k = 10-1; k > 0; k--)
594   {
595     if (counter[k] != 0)
596     {
597       kmax = k;
598       break;
599     }
600   }
601
602   for (k = 1; k <= kmax; k++) /* write others if non-zero */
603   {
604     sprintf(s, " %ld", counter[k]);
605     s += strlen(s);
606   }
607
608   return s;
609 }
610
611 /*** code for working way into back end of file looking for post ***/
612
613 #define BUFSIZE  128 /* buffer size to read in at one time */
614 #define NUMSTEPS 32  /* number of buffers to try from end of file */
615 #define MAGIC    223 /* magic code used by TeX at end of DVI file */
616
617 /* This does some things to work around possible crap at end of file */
618 /* The way to loose is get garbage at end that comes from other DVI file ! */
619
620 /* search for post at end of file */
621 long gotopost(FILE *input)
622 {
623   unsigned long n;
624   int c, d, e, f, k, i, j, count;
625   int buffer[BUFSIZE];
626   long nlen;
627
628   if (fseek(input, - (long) BUFSIZE, SEEK_END) < 0)
629   {
630     rewind(input);      /* possibly because file shorter than BUFSIZE ? */
631   }
632
633   for (j=0; j < NUMSTEPS; j++) /* let's not go on forever ! */
634   {
635     for (k = 0; k < BUFSIZE; k++)
636     {
637       buffer[k] =  getc(input);
638     }
639
640     k = BUFSIZE - 1;
641
642     while (k > 10)
643     {
644       count=0;            /* count MAGIC codes seen */
645
646       for (i = k; i >= 5; i--)    /* need at least seq of four */
647       {
648         if (buffer[i] == MAGIC)
649         {
650           count++;
651
652           if (count == 4)
653             break;
654         }
655         else
656           count = 0;
657       }
658
659       k = i;
660
661       if (count == 4) {    /* found sequence of four */
662         for (i = k; i >= 5; i--)   /* but there can be many more */
663           if (buffer[i] != MAGIC) break;
664         k = i;             /* first non MAGIC - ID_BYTE ? */
665         if (buffer[k] != MAGIC) {  /* did see end of MAGIC stuff */
666           if (buffer[k-5] == (int) post_post) { /* is it valid ? */
667 /*            if (buffer[k] != ID_BYTE) { 
668               showline( 
669             "File is DVI version %d - program designed for %d\n",
670                 i, ID_BYTE);
671               errcount(0);
672             } */
673             k = k - 5;    /* step back to post_post */
674             c = buffer[k+1];  d = buffer[k+2];
675             e = buffer[k+3];  f = buffer[k+4];
676             n = ((((((unsigned long) c << 8) | (unsigned long) d) << 8) | e) << 8) | f;
677             fseek(input, (long) n, SEEK_SET); /* go to post ! */
678             c = getc(input); (void) ungetc(c, input);
679             if (c != (int) post) {        /* check it ! */
680               showline("ERROR: Unable to find pointer to POST", 1);
681               giveup(5);
682               return 0;
683             }
684             else {
685               if (traceflag) {
686                 sprintf(logline, "Found POST at %ld\n", n);
687                 showline(logline, 0);
688               }
689               return n;   /* seem to be in good shape */
690             }
691           }
692         }
693       }
694     }
695     if (fseek(input, - (long) (BUFSIZE * 2 - 10), SEEK_CUR) != 0) {
696 /*      showline("Can't find proper ending of DVI file", 1); */
697 /*      giveup(15); */
698       break;
699     }
700   }
701
702   sprintf(logline, "ERROR: Can't find proper ending of DVI file `%s'\n",
703       filenamex);
704   showline(logline, 1);
705   fseek(input, 0, SEEK_END);
706   nlen = ftell(input);        /* get length of file 99/Mar/21 */
707   sprintf(logline, "Searched near end of file of %ld bytes\n", nlen);
708   showline(logline, 0);
709   giveup(5);
710   return 0;
711 }
712
713 void insertblank(FILE *output, long page)
714 {
715   PSputs("dvidict begin\n", output);
716
717   if (newbopflag)
718   {
719     sprintf(logline, "%ld %ld bop eop end ",
720        counter[0], page); /* 1995/Mar/25 */
721     PSputs(logline, output);
722   }
723   else
724   {
725     PSputs("bp ep end ", output);
726   }
727
728   PSputs("% blank page\n", output);
729 }
730
731 void docountercomment (FILE *output)
732 {
733   char *s;
734
735   s = logline;
736   strcpy(s, "% [");
737   s += strlen(s);
738   s = showcounters(s);
739   strcat(s, "]");
740   PSputs(logline, output);
741 }
742
743 /* beginning of page */
744 void do_bop(FILE *output, FILE *input)
745 {
746   int k;
747   long pageno;        /* page number logical or physical */
748   long page;          /* always dvi page count from start of file */
749   double xoffset, yoffset;  /* 1992/July/11 */
750   COLORSPEC SavedColor;   /* 1999/Apr/06 */
751 //  char *s;
752
753   if (skiptoend != 0)
754   {
755     gotopost(input);
756     skiptoend = 0;
757     return;
758   }
759
760 /*  Normally bRepeatMode == 0 */       /* 1995/Aug/27 */
761   if (nRepeatCount > 1)
762   {
763     if (nRepeatIndex == 0)          /* first time */
764       currentpagestart = ftell(input)-1;  /* right at bop */
765     else
766       pagenumber--;            /* compensate */
767   }
768
769   pagenumber++;       /* DVI page count from start of job */
770
771   if (reverseflag)
772     page = dvi_t - pagenumber + 1;
773   else
774     page = pagenumber;
775
776   stinx = 0;          /* reset stack counter */
777 /*  h = 0; v = 0; w = 0; x = 0; y = 0; z = 0;  */
778   ff = -1;          /* undefined font */
779 /*  fnt = finx[0];  */    /* just in case - not clear could be -1 ! */
780 /*  currentfont = fontchar[0]; */ /* ? */
781 /*  reset_stack();    */  /* empty the stack */
782   pagetpic = 0;     /* 1992/Nov/17 */
783   complainedaboutj=0;   /* 1993/Oct/17 */
784
785   if (bCarryColor == 0)
786     colorindex=0;   /* reset color stack index */
787
788   if (bCarryColor && bColorUsed) {    /* 98/Jul/18 */
789     RestoreColorStack(page);      /* right page number ? */
790 /*    if (colorindex > 0) {
791       doColorPop(page);
792       doColorSet(output, -1);
793     } */ /* done down below */
794   }
795
796   clipstackindex = 0;     /* reset push pop stack 98/Sep/12 */
797
798   CTMstackindex= 0;   /* reset CTM stack pointer in dvispeci.c */
799
800   for (k = 0; k < 10; k++) counter[k] = sreadfour(input); 
801   previous = sreadfour(input);
802   showcount = 0;
803 /*  skipflag = 0; */
804
805 /*  if (reverseflag) page = dvi_t - pagenumber + 1;
806   else page = pagenumber; */  /* already done */
807
808   if (countzeroflag != 0) pageno = counter[0];
809 /*  else pageno = (long) pagenumber; */
810   else pageno = (long) page;        /* 1993/Aug/28 */
811
812   skipflag = skip_this_page(pageno);
813 /*  following is the logic for two-sided printing */
814 /*  if (skipflag != 0) evenlast = 1; oddlast = 1; */
815   if (skipflag != 0) firstpage = -1;    /* reset for next group */
816   else if (skipflag == 0) {       /* page in valid range */
817     if (oddpageflag != 0) {       /* if printing only odd pages */
818       if ((counter[0] & 1) == 0) {  /* seen even numbered page */
819         if (firstpage != 0)
820           insertblank(output, page);    /* matching blank */
821         skipflag++; 
822       }
823       firstpage = 0;      
824     }
825     if (evenpageflag != 0) {      /* if printing only even pages */
826       if ((counter[0] & 1) == 1) {  /* seen odd numbered page */
827         if (firstpage != 0)
828           insertblank(output, page);  /* matching blank */
829         skipflag++;
830       }
831       firstpage = 0;
832     }
833   }
834   if (skipflag != 0) {    /* skipping this page */
835     if (reverseflag != 0) {
836       if (previous > 0) fseek(input, previous, SEEK_SET);
837       else finish = -1; 
838     }
839     return;
840   }
841   else {            /* not skipping this page */
842     if (verboseflag) { 
843 //      putc('[', stdout); 
844 //      if (logfileflag) putc('[', logfile); 
845       showline("[", 0);
846       showcounters(logline);
847       showline(logline, 0);
848 //      if (logfileflag) showcounters(logfile); 
849     } 
850     else {
851 //      putc('.', stdout);
852 //      if (logfileflag) putc('.', logfile);
853       showline(".", 0);
854     }
855 /*    note: first item after Page: is a page label - here counter[0] */
856 /*    (or counter[1]-counter[2]) 1996/Jan/28 */
857 /*    note: first item after Page: need not be a number */
858 /*    note: second item after Page: is sequential page number */
859 /*    An experiment 1995/Aug/27 */
860 /*    page = numpages + 1; */
861     if (stripcomment == 0) {
862 //      fputs("%%Page: ", output);
863       PSputs("%%Page: ", output);
864       if (bUseCounters) {
865         sprintf(logline, "%ld-%ld %ld\n",
866           counter[1], counter[2], numpages+1);  /* 1996/Jan/20 */
867       }
868       else {
869         sprintf(logline, "%ld %ld\n", counter[0], numpages+1);
870       }
871       PSputs(logline, output);
872     }
873 //    fputs("dvidict begin ", output);
874     PSputs("dvidict begin ", output);
875     if (evenoddoff != 0) {
876       if ((counter[0] & 1) == 1) {  /* seen odd numbered page */
877         xoffset = xoffseto; yoffset = yoffseto;
878       }
879       else {              /* seen even numbered page */
880         xoffset = xoffsete; yoffset = yoffsete;
881       }
882       sprintf(logline, 
883         "/xoffset %lg def /yoffset %lg def\n", xoffset, yoffset);
884       PSputs(logline, output);
885     }
886     PSputc('\n', output);   // always start new line for this
887     if (newbopflag) {
888       sprintf(logline, "%ld %ld bop ", counter[0], numpages+1);
889       PSputs(logline, output);
890     }
891     else PSputs("bp ", output);
892
893     if (stripcomment == 0) docountercomment (output);
894
895 /*    sure use of pageno ??? is OK even with countzeroflag ??? use page instead ??? */
896     if (bBackGroundFlag && bBackUsed) {   /* 98/Jun/30 */
897       if (BackColors[page].A != -1.0 ||
898         BackColors[page].B != -1.0 ||
899         BackColors[page].C != -1.0) {
900 //        putc('\n', output);
901         PSputc('\n', output);
902 //        fputs("gsave clippath ", output);
903         PSputs("gsave clippath ", output);
904         SavedColor = CurrColor;     /* save around following */
905         CurrColor = BackColors[page];
906         doColorSet(output, 3);      /* background - in dvispeci.c */
907 //        fputs("fill grestore ", output);            
908         PSputs("fill grestore ", output);
909         CurrColor = SavedColor;     /* restore after 99/Apr/06 */
910 /*        putc('\n', output); */
911 /*        CurrColor.A = CurrColor.B = CurrColor.C = 0.0F;
912         CurrColor.D = 0.0F; */    /* initial color on page ? */
913       }
914     }
915 /*    now pop color pushed at bottom of previous page (restored stack up above) */
916     if (bColorUsed && (colorindex > 0)) {   /* 98/Feb/14 */
917       doColorPop(page); 
918       doColorSet(output, 2);      /* bop - in dvispeci.c */
919     }
920     else {
921       PSputc('\n', output); /* omission slightly risky ... */
922 //      freshflag = 1;      // maybe not, keep blank line in PS
923     }
924
925   }
926 /*  maybe also do "structuring conventions" stuff ? */
927 }
928
929 /* end of page */
930 void do_eop(FILE *output, FILE *input)
931 {
932   int c;
933 //  char *s;
934
935   if (bAbort) abortjob();         /* 1992/Nov/24 */
936   if (abortflag) return;
937
938 /*  check_stack(pageno); */ /*  check that stack is empty */
939   
940   showcount = 0;
941
942   if (colorindex > 0) checkColorStack(output);  /* 1996/Nov/3 */
943 /*  do this only if color was used ??? */
944   if (bCarryColor && bColorUsed) {
945 /*    doColorPush(); *//* NO - do in dvipslog.c */
946 /*    UGH! This only makes sense if we page sequentially */
947   }
948
949   if (clipstackindex > 0)
950     doClipBoxPopAll(output);
951
952   if (skipflag == 0)
953   {
954     if (CTMstackindex != 0)
955       checkCTM(output);   /* 1996/Nov/3 */
956
957     PSputc('\n', output);     // always start new line
958
959     if (newbopflag)
960       PSputs("eop ", output);
961     else
962       PSputs("ep ", output);
963
964     if (stripcomment == 0)
965       docountercomment(output);
966
967     PSputc('\n', output);
968     PSputs("end", output);
969
970     if (stripcomment == 0)
971       PSputs(" % dvidict", output);
972
973     PSputc('\n', output);
974 /*    %%PageTrailer comments highly optional ... */
975     if (bOptionalDSC) {           /* 1994/Mar/3 */
976       if (stripcomment == 0) {
977 //        fputs("%%PageTrailer\n", output);
978         PSputs("%%PageTrailer\n", output);
979       }
980     }
981     if (verboseflag) showline("] ", 0);
982
983 /* maybe also do "structuring conventions" stuff ? */
984     numpages++;   /* update number of pages actually processed */
985   }
986 //  if (ferror(output) != 0) 
987   if (output != NULL && ferror(output)) {
988     showline("\n", 0);
989 //    sprintf(logline, " ERROR in output file %s\n", outputfile);
990     showline("ERROR in output file", 1);
991     perrormod((outputfile != NULL) ? outputfile : "");
992     giveup(7);
993     return;
994   }
995
996 /*  Normally bRepeatMode == 0 */       /* 1995/Aug/27 */
997   if (nRepeatCount > 1) {
998     nRepeatIndex++;
999     if (nRepeatIndex == nRepeatCount) nRepeatIndex = 0;
1000     else {
1001       fseek (input, currentpagestart, SEEK_SET);
1002       return;
1003     }
1004   }
1005
1006   skipflag = 0;
1007
1008   if (reverseflag != 0) { /* go back if reading in reverse */
1009     if (previous > 0) fseek(input, previous, SEEK_SET);
1010     else finish = -1;
1011   }
1012   if (textures != 0) (void) ureadfour(input); /* skip over length code */
1013 /*  may also want to check whether length is something reasonable ? */
1014   c = getc(input); (void) ungetc(c, input);   /* peek ahead */
1015 /*  here we expect to see bop, nop or fnt_def's ONLY */
1016 /*  if (c >= 0 && c <= 127) {
1017     showline( "Invalid code %d between EOP and BOP\n", c);
1018     tellwhere(1);
1019     errcount(0); 
1020     finish = -1;
1021   } */
1022   if (c >= 0 && c <= 127) { /* this should normally not happen: */
1023     sprintf(logline, " invalid code (%d)\n", c); /* DEBUG */
1024     showline(logline, 1);
1025     finish = -1;
1026   }
1027 }
1028
1029 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
1030
1031 /* rare */
1032 void do_right1(FILE *output, FILE *input)
1033 {
1034   int b;
1035
1036   b = sreadone(input);
1037
1038   if (skipflag == 0)
1039   {
1040     if (! freshflag) PSputc('\n', output);
1041 #ifdef ALLOWSCALE
1042     if (outscaleflag)
1043     {
1044       sprintf(logline, "%.9lg r", (double) b / outscale);
1045     }
1046     else
1047 #endif
1048     {
1049       sprintf(logline, "%d r", b); /* right */
1050     }
1051
1052     PSputs(logline, output);
1053     freshflag = 0;
1054     showcount = 0;
1055 /*  h = h + b; */
1056   }
1057 }
1058
1059 void do_right2(FILE *output, FILE *input)
1060 {
1061   int b;
1062
1063   b = sreadtwo(input);
1064
1065   if (skipflag == 0)
1066   {
1067     if (! freshflag) PSputc('\n', output);
1068 #ifdef ALLOWSCALE
1069     if (outscaleflag)
1070     {
1071       sprintf(logline, "%.9lg r", (double) b / outscale);
1072     }
1073     else
1074 #endif
1075     {
1076       sprintf(logline, "%d r", b);  /* right */
1077     }
1078
1079     PSputs(logline, output);
1080     freshflag = 0;
1081     showcount = 0;
1082 /*  h = h + b; */
1083   }
1084
1085
1086 void do_rightsub(FILE *output, long b)
1087 {
1088   if (skipflag == 0)
1089   {
1090     if (! freshflag) PSputc('\n', output);
1091 #ifdef ALLOWSCALE
1092     if (outscaleflag)
1093     {
1094       sprintf(logline, "%.9lg r", (double) b / outscale);
1095     }
1096     else
1097 #endif
1098     {
1099       sprintf(logline, "%ld r", b); /* right */
1100     }
1101
1102     PSputs(logline, output);
1103     freshflag = 0;
1104     showcount = 0;
1105 /*  h = h + b; */
1106   }
1107 }
1108
1109 void do_right3(FILE *output, FILE *input)
1110 {
1111   do_rightsub(output, sreadthree(input));
1112 }
1113
1114 void do_right4(FILE *output, FILE *input)
1115 {
1116   do_rightsub(output, sreadfour(input));
1117 }
1118
1119 void do_w0(FILE * output)
1120 {
1121   if (skipflag == 0)
1122   {
1123     PSputs(" w", output); /* wright */
1124     showcount = 0;
1125 /*    h = h + w; */
1126   }
1127 }
1128
1129 /* rare */
1130 void do_w1(FILE *output, FILE *input)
1131 {
1132   long w; /* trial */
1133
1134   w = sreadone(input);
1135
1136   if (skipflag == 0)
1137   {
1138     if (! freshflag) PSputc('\n', output);
1139 #ifdef ALLOWSCALE
1140     if (outscaleflag)
1141     {
1142       sprintf(logline, "%.9lg W", (double) w / outscale);
1143     }
1144     else
1145 #endif
1146     {
1147       sprintf(logline, "%ld W", w); /* wsetright */
1148     }
1149     PSputs(logline, output);
1150     freshflag = 0;
1151     showcount = 0;
1152 /*  h = h + w; */
1153   }
1154 }
1155
1156 void do_w2(FILE *output, FILE *input)
1157 {
1158   long w; /* trial */
1159
1160   w = sreadtwo(input);
1161
1162   if (skipflag == 0)
1163   {
1164     if (! freshflag) PSputc('\n', output);
1165 #ifdef ALLOWSCALE
1166     if (outscaleflag)
1167     {
1168       sprintf(logline, "%.9lg W", (double) w / outscale);
1169     }
1170     else
1171 #endif
1172     {
1173       sprintf(logline, "%ld W", w); /* wsetright */
1174     }
1175
1176     PSputs(logline, output);
1177     freshflag = 0;
1178     showcount = 0;
1179 /*  h = h + w; */
1180   }
1181 }
1182
1183 void do_wsub(FILE *output, long w)
1184 {
1185   if (skipflag == 0)
1186   {
1187     if (! freshflag) PSputc('\n', output);
1188 #ifdef ALLOWSCALE
1189     if (outscaleflag)
1190     {
1191       sprintf(logline, "%.9lg W", (double) w / outscale);
1192     }
1193     else
1194 #endif
1195     {
1196       sprintf(logline, "%ld W", w); /* wsetright */
1197     }
1198
1199     PSputs(logline, output);
1200     freshflag = 0;
1201     showcount = 0;
1202 /*  h = h + w; */
1203   }
1204 }
1205
1206 void do_w3(FILE *output, FILE *input)
1207 {
1208   do_wsub(output, sreadthree(input));
1209 }
1210
1211 void do_w4(FILE *output, FILE *input)
1212 {
1213   do_wsub(output, sreadfour(input));
1214 }
1215
1216 void do_x0(FILE *output)
1217 {
1218   if (skipflag == 0)
1219   {
1220     PSputs(" x", output); /* xright */
1221     showcount = 0;
1222 /*    h = h + x; */
1223   }
1224 }
1225
1226 /* rare */
1227 void do_x1(FILE *output, FILE *input)
1228 {
1229   long x; /* trial */
1230
1231   x = sreadone(input);
1232
1233   if (skipflag == 0)
1234   {
1235     if (! freshflag) PSputc('\n', output);
1236 #ifdef ALLOWSCALE
1237     if (outscaleflag)
1238     {
1239       sprintf(logline, "%.9lg X", (double) x / outscale);
1240     }
1241     else
1242 #endif
1243     {
1244       sprintf(logline, "%ld X", x); /*  xsetright */
1245     }
1246
1247     PSputs(logline, output);
1248     freshflag = 0;
1249     showcount = 0;
1250 /*  h = h + x; */
1251   }
1252 }
1253
1254 void do_x2(FILE *output, FILE *input)
1255 {
1256   long x; /* trial */
1257
1258   x = sreadtwo(input);
1259
1260   if (skipflag == 0)
1261   {
1262     if (! freshflag) PSputc('\n', output);
1263 #ifdef ALLOWSCALE
1264     if (outscaleflag)
1265     {
1266       sprintf(logline, "%.9lg X", (double) x / outscale);
1267     }
1268     else
1269 #endif
1270     {
1271       sprintf(logline, "%ld X", x); /* xsetright */
1272     }
1273     PSputs(logline, output);
1274     freshflag = 0;
1275     showcount = 0;
1276 /*  h = h + x; */
1277   }
1278 }
1279
1280 void do_xsub(FILE *output, long x)
1281 {
1282   if (skipflag == 0)
1283   {
1284     if (! freshflag) PSputc('\n', output);
1285 #ifdef ALLOWSCALE
1286     if (outscaleflag)
1287     {
1288       sprintf(logline, "%.9lg X", (double) x / outscale);
1289     }
1290     else
1291 #endif
1292     {
1293       sprintf(logline, "%ld X", x); /* xsetright */
1294     }
1295
1296     PSputs(logline, output);
1297     freshflag = 0;
1298     showcount = 0;
1299 /*  h = h + x; */
1300   }
1301 }
1302
1303 void do_x3(FILE *output, FILE *input)
1304 {
1305   do_xsub(output, sreadthree(input));
1306 }
1307
1308 void do_x4(FILE *output, FILE *input)
1309 {
1310   do_xsub(output, sreadfour(input));
1311 }
1312
1313 /* rare */
1314 void do_down1(FILE *output, FILE *input)
1315 {
1316   int a;
1317
1318   a = sreadone(input);
1319
1320   if (skipflag == 0)
1321   {
1322     if (! freshflag) PSputc('\n', output);
1323 #ifdef ALLOWSCALE
1324     if (outscaleflag)
1325     {
1326       sprintf(logline, "%.9lg d", (double) a / outscale);
1327     }
1328     else
1329 #endif
1330     {
1331       sprintf(logline, "%d d", a); /* down */
1332     }
1333
1334     PSputs(logline, output);
1335     freshflag = 0;
1336     showcount = 0;
1337 /*  v = v + a; */
1338   }
1339 }
1340
1341 /* rare */
1342 void do_down2(FILE *output, FILE *input)
1343 {
1344   int a;
1345
1346   a = sreadtwo(input);
1347
1348   if (skipflag == 0)
1349   {
1350     if (! freshflag) PSputc('\n', output);
1351 #ifdef ALLOWSCALE
1352     if (outscaleflag)
1353     {
1354       sprintf(logline, "%.9lg d", (double) a / outscale);
1355     }
1356     else
1357 #endif
1358     {
1359       sprintf(logline, "%d d", a); /* down */
1360     }
1361
1362     PSputs(logline, output);
1363     freshflag = 0;
1364     showcount = 0;
1365 /*  v = v + a; */
1366   }
1367 }
1368
1369 void do_downsub(FILE *output, long a)
1370 {
1371   if (skipflag == 0)
1372   {
1373     if (! freshflag) PSputc('\n', output);
1374 #ifdef ALLOWSCALE
1375     if (outscaleflag)
1376     {
1377       sprintf(logline, "%.9lg d", (double) a / outscale);
1378     }
1379     else
1380 #endif
1381     {
1382       sprintf(logline, "%ld d", a); /* down */
1383     }
1384
1385     PSputs(logline, output);
1386     freshflag = 0;
1387     showcount = 0;
1388 /*  v = v + a; */
1389   }
1390 }
1391
1392 void do_down3(FILE *output, FILE *input)
1393 {
1394   do_downsub(output, sreadthree(input));
1395 }
1396
1397 void do_down4(FILE *output, FILE *input)
1398 {
1399   do_downsub(output, sreadfour(input));
1400 }
1401
1402 void do_y0(FILE *output)
1403 {
1404   if (skipflag == 0)
1405   {
1406     PSputs(" y", output);
1407     showcount = 0;
1408 /*    v = v + y; */
1409   }
1410 }
1411
1412 /* rare */
1413 void do_y1(FILE *output, FILE *input)
1414 {
1415   long y; /* trial */
1416
1417   y = sreadone(input);
1418
1419   if (skipflag == 0)
1420   {
1421     if (! freshflag) PSputc('\n', output);
1422 #ifdef ALLOWSCALE
1423     if (outscaleflag)
1424     {
1425       sprintf(logline, "%.9lg Y", (double) y / outscale);
1426     }
1427     else
1428 #endif
1429     {
1430       sprintf(logline, "%ld Y", y); /* ysetdown */
1431     }
1432
1433     PSputs(logline, output);
1434     freshflag = 0;
1435     showcount = 0;
1436 /*  v = v + y; */
1437   }
1438 }
1439
1440 void do_y2(FILE *output, FILE *input)
1441 {
1442   long y; /* trial */
1443
1444   y = sreadtwo(input);
1445
1446   if (skipflag == 0)
1447   {
1448     if (! freshflag) PSputc('\n', output);
1449 #ifdef ALLOWSCALE
1450     if (outscaleflag)
1451     {
1452       sprintf(logline, "%.9lg Y", (double) y / outscale);
1453     }
1454     else
1455 #endif
1456     {
1457       sprintf(logline, "%ld Y", y); /*  ysetdown */
1458     }
1459     PSputs(logline, output);
1460     freshflag = 0;
1461     showcount = 0;
1462 /*  v = v + y; */
1463   }
1464 }
1465
1466 void do_ysub(FILE *output, long y)
1467 {
1468   if (skipflag == 0)
1469   {
1470     if (! freshflag) PSputc('\n', output);
1471 #ifdef ALLOWSCALE
1472     if (outscaleflag)
1473     {
1474       sprintf(logline, "%.9lg Y", (double) y / outscale);
1475     }
1476     else
1477 #endif
1478     {
1479       sprintf(logline, "%ld Y", y); /* ysetdown */
1480     }
1481
1482     PSputs(logline, output);
1483     freshflag = 0;
1484     showcount = 0;
1485 /*  v = v + y; */
1486   }
1487 }
1488
1489 void do_y3(FILE *output, FILE *input)
1490 {
1491   do_ysub(output, sreadthree(input));
1492 }
1493
1494 /* not used */
1495 void do_y4(FILE *output, FILE *input)
1496 {
1497   do_ysub(output, sreadfour(input));
1498
1499
1500 void do_z0(FILE *output)
1501 {
1502   if (skipflag == 0)
1503   {
1504     PSputs(" z", output);
1505     showcount = 0;
1506 /*    v = v + z; */
1507   }
1508 }
1509
1510 /* rare */
1511 void do_z1(FILE *output, FILE *input)
1512 {
1513   long z; /* trial */
1514
1515   z = sreadone(input);
1516
1517   if (skipflag == 0)
1518   {
1519     if (! freshflag) PSputc('\n', output);
1520 #ifdef ALLOWSCALE
1521     if (outscaleflag)
1522     {
1523       sprintf(logline, "%.9lg Z", (double) z / outscale);
1524     }
1525     else
1526 #endif
1527     {
1528       sprintf(logline, "%ld Z", z); /* zsetdown */
1529     }
1530
1531     PSputs(logline, output);
1532     freshflag = 0;
1533     showcount = 0;
1534 /*  v = v + z; */
1535   }
1536 }
1537
1538 void do_z2(FILE *output, FILE *input)
1539 {
1540   long z; /* trial */
1541
1542   z = sreadtwo(input);
1543
1544   if (skipflag == 0)
1545   {
1546     if (! freshflag) PSputc('\n', output);
1547 #ifdef ALLOWSCALE
1548     if (outscaleflag)
1549     {
1550       sprintf(logline, "%.9lg Z", (double) z / outscale);
1551     }
1552     else
1553 #endif
1554     {
1555       sprintf(logline, "%ld Z", z); /* zsetdown */
1556     }
1557
1558     PSputs(logline, output);
1559     freshflag = 0;
1560     showcount = 0;
1561 /*  v = v + z; */
1562   }
1563 }
1564
1565 void do_zsub(FILE *output, long z)
1566 {
1567   if (skipflag == 0)
1568   {
1569     if (! freshflag) PSputc('\n', output);
1570 #ifdef ALLOWSCALE
1571     if (outscaleflag)
1572     {
1573       sprintf(logline, "%.9lg Z", (double) z / outscale);
1574     }
1575     else
1576 #endif
1577     {
1578       sprintf(logline, "%ld Z", z); /* zsetdown */
1579     }
1580
1581     PSputs(logline, output);
1582     freshflag = 0;
1583     showcount = 0;
1584 /*  v = v + z; */
1585   }
1586 }
1587
1588 void do_z3(FILE *output, FILE *input)
1589 {
1590   do_zsub(output, sreadthree(input));
1591 }
1592
1593 void do_z4(FILE *output, FILE *input)
1594 {
1595   do_zsub(output, sreadfour(input));
1596 }
1597
1598 /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
1599
1600 void complainfontcode(unsigned long fs)
1601 {
1602   sprintf(logline, " Bad font code %lu (> %u)\n", fs, MAXFONTNUMBERS-1);
1603   showline(logline, 1);
1604 }
1605 /* switching to other font */
1606 void switchfont(FILE *output, int fs)
1607 {
1608   int fn;
1609
1610   if (fs < 0)
1611   {
1612     sprintf(logline, "Negative font number %d\n", fs);
1613     showline(logline, 1);
1614   }
1615
1616   if (fs >= MAXFONTNUMBERS)
1617     complainfontcode(fs);
1618
1619   ff = fs;                /* set state */
1620
1621   if (skipflag == 0)
1622   {
1623     if (bShortFont != 0)
1624       fn = finx[ff];
1625     else
1626       fn = fs;
1627
1628     PSputc('\n', output);   // always on new line
1629     sprintf(logline, "f%d", fn);
1630     PSputs(logline, output);
1631   }
1632
1633 /*  if (fnt < 0) fnt = 0; */  /* for safety sake */
1634   showcount = 0;
1635 }
1636 /* switch fonts */
1637 void do_fnt1(FILE *output, FILE *input)
1638 {
1639   unsigned int fs;
1640
1641   fs = getc(input);
1642   switchfont(output, (int) fs);
1643 }
1644 /* switch fonts */
1645 void do_fnt2(FILE *output, FILE *input)
1646 {
1647   unsigned int fs;
1648
1649   fs = ureadtwo(input);
1650
1651   if (fs >= MAXFONTNUMBERS)
1652   {
1653     complainfontcode (fs);
1654     fs = MAXFONTNUMBERS-1;
1655   }
1656
1657   switchfont(output, (int) fs);
1658 }
1659
1660 void do_fntsub(FILE *output, unsigned long fs)
1661 {
1662   if (fs >= MAXFONTNUMBERS)
1663   {
1664     complainfontcode (fs);
1665     fs = MAXFONTNUMBERS-1;
1666   }
1667   switchfont(output, (int) fs);
1668 }
1669 /* switch fonts */
1670 void do_fnt3(FILE *output, FILE *input)
1671 {
1672   do_fntsub(output, ureadthree(input));
1673 }
1674
1675 /* switch fonts */
1676 void do_fnt4(FILE *output, FILE *input)
1677 {
1678   long fs;
1679
1680   fs = sreadfour(input);
1681
1682   if (fs < 0)
1683   {
1684     sprintf(logline, "Font code %ld < 0\n", fs);
1685     showline(logline, 1);
1686     fs = 0;
1687   }
1688
1689   do_fntsub(output, (unsigned long) fs);
1690 }
1691
1692 /**************************************************************************/
1693
1694 void do_xxxi (FILE *output, FILE *input, unsigned int n)
1695 {
1696 /*  int c; */
1697   unsigned int k;
1698
1699   if (skipflag)
1700   {
1701     if (bCarryColor)
1702       prereadspecial(input, n);
1703     else for(k = 0; k < n; k++) (void) getc(input);
1704   }
1705   else
1706     readspecial(output, input, (unsigned long) n);
1707
1708   showcount = 0;
1709 }
1710 /* for /special */
1711 void do_xxx1 (FILE *output, FILE *input)
1712 {
1713   unsigned n;
1714
1715   n = getc(input);
1716   do_xxxi(output, input, n);
1717 }
1718
1719 /* for /special */
1720 void do_xxx2 (FILE *output, FILE *input)
1721 {
1722   unsigned int n;
1723
1724   n = ureadtwo(input);
1725   do_xxxi(output, input, n);
1726 }
1727
1728 void do_xxxl (FILE *output, FILE *input, unsigned long n)
1729 {
1730   unsigned long k;
1731
1732   if (skipflag)
1733   {
1734     if (bCarryColor)
1735       prereadspecial(input, n);
1736     else for(k = 0; k < n; k++) (void) getc(input);
1737   }
1738   else
1739     readspecial(output, input, n);
1740
1741   showcount = 0;
1742 }
1743
1744 void do_xxx3 (FILE *output, FILE *input)
1745 {
1746   unsigned long n;
1747
1748   n = ureadthree(input);
1749   do_xxxl(output, input, n);
1750 }
1751
1752 void do_xxx4 (FILE *output, FILE *input)
1753 {
1754   unsigned long n;
1755
1756   n = ureadfour(input);
1757   do_xxxl(output, input, n);
1758 }
1759
1760 /**************************************************************************/
1761
1762 /* need to do this even if skipping pages */
1763
1764 /* nothing much should actually happen here !!! */
1765
1766 void fnt_def (FILE *output, FILE *input, unsigned int k)
1767 {
1768   unsigned int na, nl, i;
1769   int f, newfont = 1;
1770   char namebuffer[FNAMELEN];
1771   char *fp;
1772
1773   if (finx[k] != BLANKFONT)
1774   {
1775     newfont = 0;
1776     f = finx[k];
1777   }
1778   else
1779   {
1780     f = fnext;
1781
1782     if (finx[k] != (short) f)
1783     {
1784       showline(" ERROR: Inconsistency between passes\n", 1);
1785       errcount(0);
1786     }
1787
1788     fnext++;
1789   }
1790
1791   for (k = 0; k < 12; k++)
1792     (void) getc(input);
1793
1794   na = getc(input);
1795   nl = getc(input);
1796
1797   if (newfont == 0)
1798   {
1799     for (i = 0; i < na + nl; i++)
1800       (void) getc(input);
1801   }
1802   else
1803   {
1804     sprintf(logline, " ERROR: Redefining font %d\n", f);
1805     showline(logline, 1);
1806 /*    fp = fontname[f]; */
1807     fp = namebuffer;
1808
1809     if (na + nl >= sizeof(namebuffer)-1)
1810     {
1811       sprintf(logline, "Font name too long: %d (> %d) ",
1812           na + nl, sizeof(namebuffer)-1);
1813       showline(logline, 1);
1814       showline("\n", 0);
1815       errcount(0);
1816       tellwhere(input, 1);
1817
1818       for (i = 0; i < na + nl; i++)
1819         (void) getc(input);
1820     }
1821     else
1822     {
1823       for (i = 0; i < na + nl; i++)
1824         *fp++ = (char) getc(input);
1825     }
1826
1827     *fp++ = '\0';
1828
1829     if (fontname[f] != NULL)
1830       free(fontname[f]);
1831
1832     fontname[f] = zstrdup(namebuffer);
1833     fontsubflag[f] = -1; /* all this goes to extract */
1834   }
1835 }
1836
1837 /* define font */
1838 void do_fnt_def1 (FILE *output, FILE *input)
1839 {
1840   unsigned int k;
1841
1842   k = getc(input);
1843   fnt_def(output, input, k);
1844 }
1845 /* define font */
1846 void do_fnt_def2 (FILE *output, FILE *input)
1847 {
1848   unsigned int k;
1849
1850   k = ureadtwo(input);
1851
1852   if (k >= MAXFONTNUMBERS)
1853   {
1854     complainfontcode (k);
1855     k = MAXFONTNUMBERS-1;
1856   }
1857
1858   fnt_def(output, input, (unsigned int) k);
1859 }
1860
1861 void do_fnt_defsub (FILE *output, FILE *input, unsigned long k)
1862 {
1863   if (k >= MAXFONTNUMBERS)
1864   {
1865     complainfontcode (k);
1866     k = MAXFONTNUMBERS-1;
1867   }
1868
1869   fnt_def(output, input, (unsigned int) k);
1870 }
1871
1872 /* define font */
1873 void do_fnt_def3 (FILE *output, FILE *input)
1874 {
1875   do_fnt_defsub(output, input, ureadthree(input));
1876 }
1877
1878 /* define font */
1879 void do_fnt_def4(FILE *output, FILE *input)
1880 {
1881   long k;
1882
1883   k = sreadfour(input);
1884
1885   if (k < 0)
1886   {
1887     sprintf(logline, "Font code %ld < 0\n", k);
1888     showline(logline, 1);
1889     k = 0;
1890   }
1891
1892   do_fnt_defsub(output, input, (unsigned long) k);
1893 }
1894
1895 /* need to do this even if skipping pages */
1896 /* doesn't do output */
1897 void do_pre (FILE *output, FILE *input)
1898 {
1899   unsigned int k, j;
1900
1901   (void) getc(input);
1902
1903   for (j = 0; j < 12; j++)
1904     (void) getc(input);
1905
1906   k = getc(input);
1907
1908   for (j = 0; j < k; j++)
1909     (void) getc(input);
1910
1911   if (textures != 0)
1912     (void) ureadfour(input); /* skip over length code */
1913 }
1914
1915 /* need to do this even if skipping pages */
1916 /* doesn't do output */
1917 void do_post (FILE *output, FILE *input)
1918 {
1919   int k;
1920
1921   previous = sreadfour(input);  /* was ureadfour ... */
1922
1923   if (traceflag)
1924     showline("Hit POST!\n", 0);
1925
1926   for (k = 0; k < 12; k++)
1927     (void) getc(input);
1928
1929   for (k = 0; k < 8; k++)
1930     (void) getc(input);
1931
1932   for (k = 0; k < 4; k++)
1933     (void) getc(input);
1934
1935   if (reverseflag == 0)
1936     finish = -1;
1937
1938   if (reverseflag != 0)
1939     fseek(input, previous, SEEK_SET); /* 98/Jul/20 ??? */
1940 }
1941
1942 /* only in reverse ? */
1943 void do_post_post (FILE *output, FILE *input)
1944 {
1945   unsigned long previous;
1946   unsigned int id;
1947
1948   if (traceflag)
1949     showline("Hit POSTPOST!\n", 0);  /* never ? */
1950
1951   previous = ureadfour(input);
1952   id = getc(input);
1953
1954   if (reverseflag != 0)
1955     fseek(input, previous, SEEK_SET); /* go to POST? */
1956   else
1957   {
1958     PSputs("% This is really the end !\n", output); // never!
1959   }
1960
1961   if (reverseflag == 0)
1962     finish = -1;  /* 98/Jul/20 */
1963
1964   showcount = 0;
1965 }
1966
1967 // main entry point to this part of the program
1968 // lastflag indicates last in set of copies of same page
1969
1970 int scandvifile (FILE *output, FILE *input, int lastflag)
1971 {
1972   int c, fs;
1973   long filptr;
1974
1975 #ifdef DEBUGGING
1976   if (output == NULL)
1977   {
1978     sprintf(logline, " NULL %s file\n", "output"); /* debug */
1979     showline(logline, 1);
1980   }
1981
1982   if (input == NULL)
1983   {
1984     sprintf(logline, " NULL %s file\n", "input"); /* debug */
1985     showline(logline, 1);
1986   }
1987 #endif
1988
1989   if (countzeroflag)
1990     resetpagerangehit (0);
1991
1992   numpages = 0;   /* number of pages actually processed */
1993   firstpage = -1;   /* flag for two sided printing case */
1994 /*  evenlast = -1; oddlast = -1; */
1995
1996   if (textures != 0)
1997     fseek(input, dvistart, SEEK_SET);
1998
1999   if (reverseflag != 0)
2000     skiptoend = -1;
2001   else
2002     skiptoend = 0;
2003
2004   pagenumber = 0;     /* value from earlier scan already used */
2005
2006   finish = 0;
2007   stinx = 0;    /* maxstinx = 0;  */  /* redundant, hopefully */
2008 /*  if (reverseflag != 0) pageorder = -1; else pageorder = +1; */
2009
2010 /*  if (wanthistogram != 0) for(k = 0; k < 256; k++) histogram[k] = 0; */
2011
2012   if (nRepeatCount > 1)
2013     nRepeatIndex = 0; /* 95/Aug/27 */
2014
2015   for(;;) {
2016 /*    if (output == NULL) showline("NULL output file\n", 1); */
2017     c = getc(input);
2018
2019     if (c == EOF)
2020     {
2021       sprintf(logline, " Unexpected EOF (%s)\n", "scandvi");
2022       showline(logline, 1);
2023
2024       {
2025         long current = ftell(input);
2026         sprintf(logline, " at byte %d\n", current);
2027         showline(logline, 1);
2028       }
2029
2030       finish = -1;
2031 /*      increase error count here ? */
2032       break;      /* NEW ??? */
2033 /*      giveup(13); */
2034     }
2035
2036     if (c < 128)
2037     {
2038       normalchar(output, input, c);
2039     }
2040     else if (c >= 171 && c <= 234)
2041     {
2042       fs = (c - 171);
2043       switchfont(output, fs);
2044     }
2045     else
2046     {
2047       switch(c)
2048       {
2049         case set1:
2050           do_set1(output, input);
2051           break;
2052
2053         case set2:
2054           do_set2(output, input);
2055           break;
2056
2057         case set3:
2058           do_set3(output, input);
2059           break;
2060
2061         case set4:
2062           do_set4(output, input);
2063           break;
2064
2065         case set_rule:
2066           do_set_rule(output, input);
2067           break;
2068
2069         case put1:
2070           do_put1(output, input);
2071           break;
2072
2073         case put2:
2074           do_put2(output, input);
2075           break;
2076
2077         case put3:
2078           do_put3(output, input);
2079           break;
2080
2081         case put4:
2082           do_put4(output, input);
2083           break;
2084
2085         case put_rule:
2086           do_put_rule(output, input);
2087           break;
2088
2089         case nop:
2090           break;
2091
2092         case bop:
2093           do_bop(output, input);
2094           break;
2095
2096         case eop:
2097           do_eop(output, input);
2098           break;
2099
2100         case push:
2101           do_push(output, input);
2102           break;
2103
2104         case pop:
2105           do_pop(output, input);
2106           break;
2107
2108         case right1:
2109           do_right1(output, input);
2110           break;
2111
2112         case right2:
2113           do_right2(output, input);
2114           break;
2115
2116         case right3:
2117           do_right3(output, input);
2118           break;
2119
2120         case right4:
2121           do_right4(output, input);
2122           break;
2123
2124         case w0:
2125           do_w0(output);
2126           break;
2127
2128         case w1:
2129           do_w1(output, input);
2130           break;
2131
2132         case w2:
2133           do_w2(output, input);
2134           break;
2135
2136         case w3:
2137           do_w3(output, input);
2138           break;
2139
2140         case w4:
2141           do_w4(output, input);
2142           break;
2143
2144         case x0:
2145           do_x0(output);
2146           break;
2147
2148         case x1:
2149           do_x1(output, input);
2150           break;
2151
2152         case x2:
2153           do_x2(output, input);
2154           break;
2155
2156         case x3:
2157           do_x3(output, input);
2158           break;
2159
2160         case x4:
2161           do_x4(output, input);
2162           break;
2163
2164         case down1:
2165           do_down1(output, input);
2166           break;
2167
2168         case down2:
2169           do_down2(output, input);
2170           break;
2171
2172         case down3:
2173           do_down3(output, input);
2174           break;
2175
2176         case down4:
2177           do_down4(output, input);
2178           break;
2179
2180         case y0:
2181           do_y0(output);
2182           break;
2183
2184         case y1:
2185           do_y1(output, input);
2186           break;
2187
2188         case y2:
2189           do_y2(output, input);
2190           break;
2191
2192         case y3:
2193           do_y3(output, input);
2194           break;
2195
2196         case y4:
2197           do_y4(output, input);
2198           break;
2199
2200         case z0:
2201           do_z0(output);
2202           break;
2203
2204         case z1:
2205           do_z1(output, input);
2206           break;
2207
2208         case z2:
2209           do_z2(output, input);
2210           break;
2211
2212         case z3:
2213           do_z3(output, input);
2214           break;
2215
2216         case z4:
2217           do_z4(output, input);
2218           break;
2219
2220         case fnt1:
2221           do_fnt1(output, input);
2222           break;
2223
2224         case fnt2:
2225           do_fnt2(output, input);
2226           break;
2227
2228         case fnt3:
2229           do_fnt3(output, input);
2230           break;
2231
2232         case fnt4:
2233           do_fnt4(output, input);
2234           break;
2235
2236         case xxx1:
2237           do_xxx1(output, input);
2238           break;
2239
2240         case xxx2:
2241           do_xxx2(output, input);
2242           break;
2243
2244         case xxx3:
2245           do_xxx3(output, input);
2246           break;
2247
2248         case xxx4:
2249           do_xxx4(output, input);
2250           break;
2251
2252         case fnt_def1:
2253           do_fnt_def1(output, input);
2254           break;
2255
2256         case fnt_def2:
2257           do_fnt_def2(output, input);
2258           break;
2259
2260         case fnt_def3:
2261           do_fnt_def3(output, input);
2262           break;
2263
2264         case fnt_def4:
2265           do_fnt_def4(output, input);
2266           break;
2267
2268         case post:
2269           do_post(output, input);
2270           break;
2271
2272         case pre:
2273           do_pre(output, input);
2274           break;
2275
2276         case post_post:
2277           do_post_post(output, input);
2278           break;
2279   
2280         default:
2281         {
2282           finish = -1;
2283           sprintf(logline, " ERROR: Unrecognized DVI command: %d", c);
2284           showline(logline, 1);
2285           filptr = ftell(input);
2286
2287           if (filptr > 0)
2288           {
2289             sprintf(logline, " at byte %ld in DVI file", filptr-1);
2290             showline(logline, 0);
2291           }
2292
2293           errcount(0);
2294         }
2295         break;
2296       }
2297     }
2298
2299     if (c < xxx1 || c > xxx4)
2300       freshflag = 0;    // 99/Dec/19
2301
2302     if (finish != 0)
2303       break;
2304
2305     if (bAbort)
2306       abortjob();       // fine grained
2307
2308     if (abortflag)
2309       break;       // in DLL version
2310   }
2311
2312   if (abortflag)
2313     return -1;
2314
2315   if (verboseflag && lastflag)
2316   {
2317     char *s;
2318     showline("\n", 0);
2319     s = logline;
2320
2321     if (statisticsflag)
2322     {
2323       sprintf(s, "Max stack depth %d - ", dvi_s);
2324       s += strlen(s);
2325       sprintf(s, "%d font slot%s used - ",
2326         fnext, (fnext == 1) ? "" : "s");  /* 1994/Feb/1 */
2327       s += strlen(s);
2328     }
2329 //    we have a problem if there are more than 65535 pages
2330     sprintf(s, "DVI file contains %d page%s\n", dvi_t,
2331       (dvi_t == 1) ? "" : "s");       /* 1994/Feb/1 */
2332     showline(logline, 0);
2333   }
2334   return 0;
2335 }
2336
2337 /* deal with CMINCH */ /* deal with MANFNT */
2338
2339 /* add in PostScript 2.0 structuring convention bullshit */
2340
2341 /* can use either box or line to draw rules - don't need both */
2342
2343 /* combine /font9 def and /f9 def ? what ? */
2344
2345 /* reduce size of scanfile to allow optimize */
2346
2347 /* deal with other page formats ? A4 ? portrait ? */
2348
2349 /* precompute the scale factor used on each BOP - don't recompute it */
2350
2351 /* quick way to get fonts: go to end of file - NOT NEEDED */
2352
2353 /* alternate way of specifying pages (actual pages versus counter[0] ? */
2354 /* OK use upper case B and E instead of lower case b and e */
2355
2356 /* maybe control how much goes on one output line ? */
2357 /* presently somewhat kludgy in allowing MAXSHOWONLINE items */
2358 /* rather count character columns and check before output if it will fit */
2359
2360 /* avoid bind def in some cases to allow redefinition via special ? */
2361
2362 /* may need to align lower left of rule to underlying grid... */
2363 /* do tests with rules spaced along page to see effect */
2364
2365 /* shorten code for set_rule and put_rule and bp and ep */
2366 /* set up scale constant to use at top of page */
2367 /* improve mf  & set font */
2368
2369 /* should bop include "dvidict begin" and eop include "end" ? */
2370 /* but watch out, fnt_def1 and xxx1 can appear between eop and bop */
2371
2372 /* further compression coding to exploit common sequences ? */
2373 /* d u u u - s o y u - s o o o o - s o o u - s o o o o o */
2374 /* exploit - o u - o o u u - sequences ? - u o already is absent */
2375 /* o o => O,  u u => U,  o u => K,  d u => D */
2376 /* s o y u => M, s o z u => N */
2377 /* also helps make undecypherable ! have under control of flag ? */
2378 /* write as post-processing rules ? use output line buffer ? */
2379 /* also s o y u <n> r is common pattern with fixed <n> */
2380
2381 /* note also common patterns like r(char)s and r(char)S */
2382
2383 /* keep convention that lower case letters are straight DVI command trans */
2384 /* while upper case letters are combinations of sorts */
2385
2386 /* access w, x, y, z off stack (i.e. keep in stack not register) ? */
2387
2388 /* consider sequences of set1 commands - treat like normalchar ? */
2389
2390 /* check on fonthit even when font switch on page that is not printed ? */
2391
2392 /* check on redundant operations that dvipslog already does anyway */
2393
2394 /* for set1 and put1, use number, not string! then use =string ? */
2395
2396 /* check that nothing but nop and font defs happen between eop and bop ? */
2397
2398 /* Implement %%PageTable: ? */
2399
2400 /* avoid shortening octal codes for old interpretors maybe */
2401
2402 /* try and avoid actually giving up if at all possible */
2403
2404 /* when print even pages only, print a blank at first if last page is odd */
2405 /* when print odd pages only, print a blank at first if first is even */
2406
2407 /* when stack gets too deep insert a savestack  - and matching restorestack */
2408
2409 /* bRemapSpace remaps 32 => 195, 13 to 176, 10 => 173, 9 => 170, 0 => 161 */
2410 /* Rational is that text fonts reencoded to TeX 'n ANSI do not use 0 */
2411 /* or 9 or 10, and from now on text fonts will not use 13 for fl, */
2412 /* and TeX does not use 32 in text fonts */
2413 /* But math fonts do use 0, 9, 10, 13 and 32 */
2414 /* but math fonts always have the repetition of 0 - 32 higher up */
2415 /* And for some versions of Acrobat it may be best not to do this */
2416 /* for example transfer material to clipboard is null terminated */
2417 /* 9 is treated as tab, 10 as newline, 13 ignored and 32 ignored */
2418
2419 /* Bytes 250 and 251 are used for left to right typesetting. For instance,
2420    what follows is the definition of these commands in omega:
2421
2422    250. Begin a (possibly recursive) reflected segment.
2423    251. End a (possibly recursive) reflected segment.
2424
2425    When a DVI-IVD driver encounters a \\{begin\_reflect} command, it should
2426    skim ahead (as previously described) until finding the matching
2427    \\{end\_reflect}; these will be properly nested with respect to each
2428    other and with respect to \\{push} and \\{pop}.  After skimming has
2429    located a segment of material to be reflected, that segment should be
2430    re-scanned and obeyed in mirror-image mode as described earlier.  The
2431    reflected segment might recursively involve
2432    $\\{begin\_reflect}/\\{end\_reflect}$ pairs that need to be reflected
2433    again. */
2434