1 /* Copyright (c) 1987, 1989, 2012 University of Maryland Department of
2    Computer Science.
3 
4    Permission is hereby granted, free of charge, to any person obtaining
5    a copy of this software and associated documentation files (the
6    "Software"), to deal in the Software without restriction, including
7    without limitation, the rights to use, copy, modify, merge, publish,
8    distribute, sublicense, and/or sell copies of the Software, and to
9    permit persons to whom the Software is furnished to do so, subject to
10    the following conditions: The above copyright notice, this permission
11    notice and the disclaimer statement shall be included in all copies
12    or substantial portions of the Software.
13 
14    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22 
23 /*
24  * DVI page rearrangement program
25  *
26  * Reads DVI version 2 files and rearranges pages into signatures,
27  * writing a new DVI file.
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 
34 #ifdef KPATHSEA
35 #include <kpathsea/config.h>
36 #include <kpathsea/c-fopen.h>
37 #include <kpathsea/getopt.h>
38 #else
39 #define FOPEN_RBIN_MODE  "rb"
40 #define FOPEN_WBIN_MODE  "wb"
41 #define SET_BINARY(x) (void)0
42 extern char *optarg;
43 extern int   optind;
44 #endif
45 
46 #include "types.h"
47 #include "dviclass.h"
48 #include "dvicodes.h"
49 #include "error.h"
50 #include "fio.h"
51 #include "gripes.h"
52 #include "search.h"
53 #include <stdio.h>
54 #include <ctype.h>
55 #include "seek.h"
56 
57 #define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
58 
59 #define MAXDVIPAGES 1000 /* max (absolute) pages in DVI file */
60 
61 char  *ProgName;
62 
63 /* Globals */
64 char	serrbuf[BUFSIZ];	/* buffer for stderr */
65 
66 /*
67  * We will try to keep output lines shorter than MAXCOL characters.
68  */
69 #define MAXCOL	75
70 
71 /*
72  * We use the following structure to keep track of fonts we have seen.
73  * The final DVI file lists only the fonts it uses.
74  */
75 struct fontinfo {
76 	i32	fi_newindex;	/* font number in output file */
77 	int	fi_reallyused;	/* true => used on a page we copied */
78 	i32	fi_checksum;	/* the checksum */
79 	i32	fi_mag;		/* the magnification */
80 	i32	fi_designsize;	/* the design size */
81 	short	fi_n1;		/* the name header length */
82 	short	fi_n2;		/* the name body length */
83 	char	*fi_name;	/* the name itself */
84 };
85 
86 int     Signature;              /* #pages per signature (multiple of 4) */
87 
88 int	SFlag;			/* true => -s, silent operation */
89 
90 struct	search *FontFinder;	/* maps from input indicies to fontinfo */
91 i32	NextOutputFontIndex;	/* generates output indicies */
92 i32	CurrentFontIndex;	/* current (old) index in input */
93 i32	OutputFontIndex;	/* current (new) index in ouput */
94 
95 const char	*DVIFileName;		/* name of input DVI file */
96 FILE	*inf;			/* the input file itself */
97 FILE	*outf;			/* the output DVI file */
98 
99 long	StartOfPage[MAXDVIPAGES];	/* The file positions of the
100 					   input pages */
101 
102 long	StartOfLastPage;	/* The file position just before we
103 				   started the last page */
104 long	CurrentPosition;	/* The current position of the file */
105 
106 int	UseThisPage;		/* true => current page is selected */
107 
108 i32	InputPageNumber;	/* current absolute page in old DVI file */
109 int	NumberOfOutputPages;	/* number of pages in new DVI file */
110 
111 i32	Numerator;		/* numerator from DVI file */
112 i32	Denominator;		/* denominator from DVI file */
113 i32	DVIMag;			/* magnification from DVI file */
114 
115 i32	Count[10];		/* the 10 \count variables */
116 
117 /* save some string space: we use this a lot */
118 char	writeerr[] = "error writing DVI file";
119 
120 #ifndef KPATHSEA
121 char *malloc(), *realloc();
122 #endif
123 /*
124  * You may get lint warnings about sprintf's return value.
125  * Older versions of 4BSD have `char *sprintf()'.  ANSI and
126  * SysV use `int sprintf()'; so ignore the warnings.
127  */
128 
129 /*
130  * Lint gets somewhat confused over putc.
131  */
132 #ifdef lint
133 #undef putc
134 #ifdef ultrix /* grr */
135 #define putc(c, f) fputc((char)(c), f)
136 #else
137 #define putc(c, f) fputc((int)(c), f)
138 #endif
139 #endif
140 
141 static void WriteFont(struct fontinfo *fi);
142 static void PutFontSelector(i32 index);
143 static void ScanDVIFile(void);
144 static void HandleDVIFile(void);
145 static int HandlePage(void);
146 static void PutEmptyPage(void);
147 
148 /*
149  * Print a message to stderr, with an optional leading space, and handling
150  * long line wraps.
151  */
152 static void
message(int space,const char * str,int len)153 message(int space, const char *str, int len)
154 {
155 	static int beenhere;
156 	static int col;
157 
158 	if (!beenhere)
159 		space = 0, beenhere++;
160 	if (len == 0)
161 		len = strlen(str);
162 	col += len;
163 	if (space) {
164 		if (col >= MAXCOL)
165 			(void) putc('\n', stderr), col = len;
166 		else
167 			(void) putc(' ', stderr), col++;
168 	}
169 	while (--len >= 0)
170 		(void) putc(*str++, stderr);
171 	(void) fflush(stderr);
172 }
173 
174 /*
175  * Start a page (process a DVI_BOP).
176  */
177 static void
BeginPage(void)178 BeginPage(void)
179 {
180 	register i32 *i;
181 
182 	OutputFontIndex = -1;	/* new page requires respecifying font */
183 	for (i = Count; i < &Count[10]; i++)
184 		fGetLong(inf, *i);
185 	(void) GetLong(inf);	/* previous page pointer */
186 
187 	if (!UseThisPage)
188 		return;
189 
190 	putbyte(outf, DVI_BOP);
191 	for (i = Count; i < &Count[10]; i++)
192 		PutLong(outf, *i);
193 	PutLong(outf, StartOfLastPage);
194 	if (ferror(outf))
195 		error(1, -1, writeerr);
196 
197 	StartOfLastPage = CurrentPosition;
198 	CurrentPosition += 45;	/* we just wrote this much */
199 
200 	if (!SFlag) {		/* write nice page usage messages */
201 		register int z = 0;
202 		register int mlen = 0;
203 		char msg[80];
204 
205 		(void) sprintf(msg, "[%ld", (long)Count[0]);
206 		mlen = strlen(msg);
207 		for (i = &Count[1]; i < &Count[10]; i++) {
208 			if (*i == 0) {
209 				z++;
210 				continue;
211 			}
212 			while (--z >= 0)
213 				msg[mlen++] = '.', msg[mlen++] = '0';
214 			z = 0;
215 			(void) sprintf(msg + mlen, ".%ld", (long)*i);
216 			mlen += strlen(msg + mlen);
217 		}
218 		message(1, msg, mlen);
219 	}
220 }
221 
222 /*
223  * End a page (process a DVI_EOP).
224  */
225 static void
EndPage(void)226 EndPage(void)
227 {
228 
229 	if (!UseThisPage)
230 		return;
231 	if (!SFlag)
232 		message(0, "]", 1);
233 	putbyte(outf, DVI_EOP);
234 	if (ferror(outf))
235 		error(1, -1, writeerr);
236 	CurrentPosition++;
237 	NumberOfOutputPages++;
238 }
239 
240 /*
241  * For each of the fonts used in the new DVI file, write out a definition.
242  */
243 /* ARGSUSED */
244 static void
PostAmbleFontEnumerator(char * addr,i32 key)245 PostAmbleFontEnumerator(char *addr, i32 key)
246 {
247 
248 	if (((struct fontinfo *)addr)->fi_reallyused)
249 		WriteFont((struct fontinfo *)addr);
250 }
251 
252 static void
HandlePostAmble(void)253 HandlePostAmble(void)
254 {
255 	register i32 c;
256 
257 	(void) GetLong(inf);	/* previous page pointer */
258 	if (GetLong(inf) != Numerator)
259 		GripeMismatchedValue("numerator");
260 	if (GetLong(inf) != Denominator)
261 		GripeMismatchedValue("denominator");
262 	if (GetLong(inf) != DVIMag)
263 		GripeMismatchedValue("\\magnification");
264 
265 	putbyte(outf, DVI_POST);
266 	PutLong(outf, StartOfLastPage);
267 	PutLong(outf, Numerator);
268 	PutLong(outf, Denominator);
269 	PutLong(outf, DVIMag);
270 	c = GetLong(inf);
271 	PutLong(outf, c);	/* tallest page height */
272 	c = GetLong(inf);
273 	PutLong(outf, c);	/* widest page width */
274 	c = GetWord(inf);
275 	PutWord(outf, c);	/* DVI stack size */
276 	PutWord(outf, NumberOfOutputPages);
277 	StartOfLastPage = CurrentPosition;	/* point at post */
278 	CurrentPosition += 29;	/* count all those `put's */
279 #ifdef notdef
280 	(void) GetWord(inf);	/* skip original number of pages */
281 #endif
282 
283 	/*
284 	 * just ignore all the incoming font definitions; we are done with
285 	 * input file
286 	 */
287 
288 	/*
289 	 * run through the FontFinder table and dump definitions for the
290 	 * fonts we have used.
291 	 */
292 	SEnumerate(FontFinder, PostAmbleFontEnumerator);
293 
294 	putbyte(outf, DVI_POSTPOST);
295 	PutLong(outf, StartOfLastPage);	/* actually start of postamble */
296 	putbyte(outf, DVI_VERSION);
297 	putbyte(outf, DVI_FILLER);
298 	putbyte(outf, DVI_FILLER);
299 	putbyte(outf, DVI_FILLER);
300 	putbyte(outf, DVI_FILLER);
301 	CurrentPosition += 10;
302 	while (CurrentPosition & 3) {
303 		putbyte(outf, DVI_FILLER);
304 		CurrentPosition++;
305 	}
306 	if (ferror(outf))
307 		error(1, -1, writeerr);
308 }
309 
310 /*
311  * Write a font definition to the output file
312  */
313 static void
WriteFont(struct fontinfo * fi)314 WriteFont(struct fontinfo *fi)
315 {
316 	register int l;
317 	register char *s;
318 
319 	if (fi->fi_newindex < 256) {
320 		putbyte(outf, DVI_FNTDEF1);
321 		putbyte(outf, fi->fi_newindex);
322 		CurrentPosition += 2;
323 	} else if (fi->fi_newindex < 65536) {
324 		putbyte(outf, DVI_FNTDEF2);
325 		PutWord(outf, fi->fi_newindex);
326 		CurrentPosition += 3;
327 	} else if (fi->fi_newindex < 16777216) {
328 		putbyte(outf, DVI_FNTDEF3);
329 		Put3Byte(outf, fi->fi_newindex);
330 		CurrentPosition += 4;
331 	} else {
332 		putbyte(outf, DVI_FNTDEF4);
333 		PutLong(outf, fi->fi_newindex);
334 		CurrentPosition += 5;
335 	}
336 	PutLong(outf, fi->fi_checksum);
337 	PutLong(outf, fi->fi_mag);
338 	PutLong(outf, fi->fi_designsize);
339 	putbyte(outf, fi->fi_n1);
340 	putbyte(outf, fi->fi_n2);
341 	l = fi->fi_n1 + fi->fi_n2;
342 	CurrentPosition += 14 + l;
343 	s = fi->fi_name;
344 	while (--l >= 0)
345 		putbyte(outf, *s++);
346 }
347 
348 /*
349  * Handle the preamble.  Someday we should update the comment field.
350  */
351 static void
HandlePreAmble(void)352 HandlePreAmble(void)
353 {
354 	register int n, c;
355 
356 	c = getc(inf);
357 	if (c == EOF)
358 		GripeUnexpectedDVIEOF();
359 	if (c != DVI_PRE)
360 		GripeMissingOp("PRE");
361 	if (getc(inf) != DVI_VERSION)
362 		error(1, 0, "%s is not a DVI version %d file",
363 		    DVIFileName, DVI_VERSION);
364 	Numerator = GetLong(inf);
365 	Denominator = GetLong(inf);
366 	DVIMag = GetLong(inf);
367 	putbyte(outf, DVI_PRE);
368 	putbyte(outf, DVI_VERSION);
369 	PutLong(outf, Numerator);
370 	PutLong(outf, Denominator);
371 	PutLong(outf, DVIMag);
372 
373 	n = UnSign8(GetByte(inf));
374 	CurrentPosition = 15 + n;	/* well, almost */
375 	putbyte(outf, n);
376 	while (--n >= 0) {
377 		c = GetByte(inf);
378 		putbyte(outf, c);
379 	}
380 }
381 
382 int
main(int argc,char ** argv)383 main(int argc, char **argv)
384 {
385 	register int c;
386 	register char *s;
387 	char *outname = NULL;
388 
389 	Signature = 0;
390 
391 	ProgName = *argv;
392 	setbuf(stderr, serrbuf);
393 
394 	while ((c = getopt(argc, argv, "i:o:s:q")) != EOF) {
395 		switch (c) {
396 
397 		case 'q':	/* silent */
398 			SFlag++;
399 			break;
400 
401 		case 'i':
402 			if (DVIFileName != NULL)
403 				goto usage;
404 			DVIFileName = optarg;
405 			break;
406 
407 		case 'o':
408 			if (outname != NULL)
409 				goto usage;
410 			outname = optarg;
411 			break;
412 
413 		case 's':
414 			if (Signature != 0)
415 				goto usage;
416 			Signature = atoi(optarg);
417 			if (Signature <= 0)
418 			   error(1, -1, "-s parameter must be > 0");
419 			if (Signature % 4 != 0)
420 			   error(1, -1,
421 				 "-s parameter must be a multiple of 4");
422 			break;
423 
424 		case '?':
425 usage:
426 			(void) fprintf(stderr, "\
427 Usage: %s [-s signature] [-q] [-i infile] [-o outfile] [infile [outfile]]\n",
428 				ProgName);
429 			(void) fflush(stderr);
430 			exit(1);
431 		}
432 	}
433 
434 	while (optind < argc) {
435 		s = argv[optind++];
436 		c = *s;
437 		if (DVIFileName == NULL)
438 			DVIFileName = s;
439 		else if (outname == NULL)
440 			outname = s;
441 		else
442 			goto usage;
443 	}
444 	if (DVIFileName == NULL) {
445 		DVIFileName = "`stdin'";
446 		inf = stdin;
447 		if (!isatty(fileno(inf)))
448 		  SET_BINARY(fileno(inf));
449 	} else if ((inf = fopen(DVIFileName, FOPEN_RBIN_MODE)) == 0)
450 		error(1, -1, "cannot read %s", DVIFileName);
451 	if (outname == NULL) {
452 		outf = stdout;
453 		if (!isatty(fileno(outf)))
454 		  SET_BINARY(fileno(outf));
455 	}
456 	else if ((outf = fopen(outname, FOPEN_WBIN_MODE)) == 0)
457 		error(1, -1, "cannot write %s", outname);
458 
459 	if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
460 		error(1, 0, "cannot create font finder (out of memory?)");
461 
462 	/* copy inf to TEMP file if not seekable */
463 	if ((inf = SeekFile(inf)) == NULL) {
464 	        error(1, 0, "can't seek file");
465 	}
466 	InputPageNumber = 0;
467 	StartOfLastPage = -1;
468 	HandlePreAmble();
469 	ScanDVIFile();
470 	HandleDVIFile();
471 	HandlePostAmble();
472 	if (!SFlag)
473 		(void) fprintf(stderr, "\nWrote %d page%s, %ld bytes\n",
474 		    NumberOfOutputPages, NumberOfOutputPages == 1 ? "" : "s",
475 		    (long)CurrentPosition);
476 	return 0;
477 }
478 
479 /*
480  * Handle a font definition.
481  */
482 static void
HandleFontDef(i32 index)483 HandleFontDef(i32 index)
484 {
485 	register struct fontinfo *fi;
486 	register int i;
487 	register char *s;
488 	int def = S_CREATE | S_EXCL;
489 
490 	if (!UseThisPage) {
491 		if ((fi = (struct fontinfo *)SSearch(FontFinder, index, &def)) == 0) {
492 			if (def & S_COLL)
493 				error(1, 0, "font %ld already defined", (long)index);
494 			else
495 				error(1, 0, "cannot stash font %ld (out of memory?)",
496 					(long)index);
497 		}
498 		fi->fi_reallyused = 0;
499 		fi->fi_checksum = GetLong(inf);
500 		fi->fi_mag = GetLong(inf);
501 		fi->fi_designsize = GetLong(inf);
502 		fi->fi_n1 = UnSign8(GetByte(inf));
503 		fi->fi_n2 = UnSign8(GetByte(inf));
504 		i = fi->fi_n1 + fi->fi_n2;
505 		if ((s = malloc((unsigned)i)) == 0)
506 			GripeOutOfMemory(i, "font name");
507 		fi->fi_name = s;
508 		while (--i >= 0)
509 			*s++ = GetByte(inf);
510 	} else {
511 	        (void) GetLong(inf);
512 	        (void) GetLong(inf);
513 	        (void) GetLong(inf);
514 		i = UnSign8(GetByte(inf));
515 		i += UnSign8(GetByte(inf));
516 		while (--i >= 0)
517 			(void) GetByte(inf);
518 	}
519 }
520 
521 /*
522  * Handle a \special.
523  */
524 static void
HandleSpecial(int c,int l,i32 p)525 HandleSpecial(int c, int l, i32 p)
526 {
527 	register int i;
528 
529 	if (UseThisPage) {
530 		putbyte(outf, c);
531 		switch (l) {
532 
533 		case DPL_UNS1:
534 			putbyte(outf, p);
535 			CurrentPosition += 2;
536 			break;
537 
538 		case DPL_UNS2:
539 			PutWord(outf, p);
540 			CurrentPosition += 3;
541 			break;
542 
543 		case DPL_UNS3:
544 			Put3Byte(outf, p);
545 			CurrentPosition += 4;
546 			break;
547 
548 		case DPL_SGN4:
549 			PutLong(outf, p);
550 			CurrentPosition += 5;
551 			break;
552 
553 		default:
554 			panic("HandleSpecial l=%d", l);
555 			/* NOTREACHED */
556 		}
557 		CurrentPosition += p;
558 		while (--p >= 0) {
559 			i = getc(inf);
560 			putbyte(outf, i);
561 		}
562 		if (feof(inf))
563 			GripeUnexpectedDVIEOF();
564 		if (ferror(outf))
565 			error(1, -1, writeerr);
566 	} else
567 		while (--p >= 0)
568 			(void) getc(inf);
569 }
570 
571 static void
ReallyUseFont(void)572 ReallyUseFont(void)
573 {
574 	register struct fontinfo *fi;
575 	int look = S_LOOKUP;
576 
577 	fi = (struct fontinfo *)SSearch(FontFinder, CurrentFontIndex, &look);
578 	if (fi == NULL)
579 		error(1, 0, "DVI file requested font %ld without defining it",
580 		    (long)CurrentFontIndex);
581 	if (fi->fi_reallyused == 0) {
582 		fi->fi_reallyused++;
583 		fi->fi_newindex = NextOutputFontIndex++;
584 		WriteFont(fi);
585 	}
586 	if (fi->fi_newindex != OutputFontIndex) {
587 		PutFontSelector(fi->fi_newindex);
588 		OutputFontIndex = fi->fi_newindex;
589 	}
590 }
591 
592 /*
593  * Write a font selection command to the output file
594  */
595 static void
PutFontSelector(i32 index)596 PutFontSelector(i32 index)
597 {
598 
599 	if (index < 64) {
600 		putbyte(outf, index + DVI_FNTNUM0);
601 		CurrentPosition++;
602 	} else if (index < 256) {
603 		putbyte(outf, DVI_FNT1);
604 		putbyte(outf, index);
605 		CurrentPosition += 2;
606 	} else if (index < 65536) {
607 		putbyte(outf, DVI_FNT2);
608 		PutWord(outf, index);
609 		CurrentPosition += 3;
610 	} else if (index < 16777216) {
611 		putbyte(outf, DVI_FNT3);
612 		Put3Byte(outf, index);
613 		CurrentPosition += 4;
614 	} else {
615 		putbyte(outf, DVI_FNT4);
616 		PutLong(outf, index);
617 		CurrentPosition += 5;
618 	}
619 }
620 
621 /*
622  * The following table describes the length (in bytes) of each of the DVI
623  * commands that we can simply copy, starting with DVI_SET1 (128).
624  */
625 char	oplen[128] = {
626 	0, 0, 0, 0,		/* DVI_SET1 .. DVI_SET4 */
627 	9,			/* DVI_SETRULE */
628 	0, 0, 0, 0,		/* DVI_PUT1 .. DVI_PUT4 */
629 	9,			/* DVI_PUTRULE */
630 	1,			/* DVI_NOP */
631 	0,			/* DVI_BOP */
632 	0,			/* DVI_EOP */
633 	1,			/* DVI_PUSH */
634 	1,			/* DVI_POP */
635 	2, 3, 4, 5,		/* DVI_RIGHT1 .. DVI_RIGHT4 */
636 	1,			/* DVI_W0 */
637 	2, 3, 4, 5,		/* DVI_W1 .. DVI_W4 */
638 	1,			/* DVI_X0 */
639 	2, 3, 4, 5,		/* DVI_X1 .. DVI_X4 */
640 	2, 3, 4, 5,		/* DVI_DOWN1 .. DVI_DOWN4 */
641 	1,			/* DVI_Y0 */
642 	2, 3, 4, 5,		/* DVI_Y1 .. DVI_Y4 */
643 	1,			/* DVI_Z0 */
644 	2, 3, 4, 5,		/* DVI_Z1 .. DVI_Z4 */
645 	0,			/* DVI_FNTNUM0 (171) */
646 	0, 0, 0, 0, 0, 0, 0, 0,	/* 172 .. 179 */
647 	0, 0, 0, 0, 0, 0, 0, 0,	/* 180 .. 187 */
648 	0, 0, 0, 0, 0, 0, 0, 0,	/* 188 .. 195 */
649 	0, 0, 0, 0, 0, 0, 0, 0,	/* 196 .. 203 */
650 	0, 0, 0, 0, 0, 0, 0, 0,	/* 204 .. 211 */
651 	0, 0, 0, 0, 0, 0, 0, 0,	/* 212 .. 219 */
652 	0, 0, 0, 0, 0, 0, 0, 0,	/* 220 .. 227 */
653 	0, 0, 0, 0, 0, 0, 0,	/* 228 .. 234 */
654 	0, 0, 0, 0,		/* DVI_FNT1 .. DVI_FNT4 */
655 	0, 0, 0, 0,		/* DVI_XXX1 .. DVI_XXX4 */
656 	0, 0, 0, 0,		/* DVI_FNTDEF1 .. DVI_FNTDEF4 */
657 	0,			/* DVI_PRE */
658 	0,			/* DVI_POST */
659 	0,			/* DVI_POSTPOST */
660 	0, 0, 0, 0, 0, 0,	/* 250 .. 255 */
661 };
662 
663 /*
664  * Here we scan the input DVI file and record pointers to the pages.
665  */
666 static void
ScanDVIFile(void)667 ScanDVIFile(void)
668 {
669 	UseThisPage = 0;
670 
671 	StartOfPage[InputPageNumber] = ftell(inf);
672 	while (HandlePage()) {  /* scan DVI file */
673 	        StartOfPage[++InputPageNumber] = ftell(inf);
674 	}
675 }
676 
677 /*
678  * Here we read the input DVI file and write relevant pages to the
679  * output DVI file. We also keep track of font changes, handle font
680  * definitions, and perform some other housekeeping.
681  */
682 static void
HandleDVIFile(void)683 HandleDVIFile(void)
684 {
685         int CurrentPage, ActualPage, MaxPage;
686 
687 	UseThisPage = 1;
688 
689 	MaxPage = InputPageNumber + (4-InputPageNumber%4)%4;
690 
691 	if (!Signature)
692 	        Signature = MaxPage;
693 	for (CurrentPage = 0; CurrentPage < MaxPage; CurrentPage++) {
694 	        ActualPage = CurrentPage - CurrentPage%Signature;
695 	        switch (CurrentPage%4) {
696 		case 0:
697 		case 3:
698 		   ActualPage += Signature-1-(CurrentPage%Signature)/2;
699 		   break;
700 		case 1:
701 		case 2:
702 		   ActualPage += (CurrentPage%Signature)/2;
703 		   break;
704 		}
705 	        if (ActualPage < InputPageNumber) {
706 		        if (fseek(inf, StartOfPage[ActualPage], 0) == -1)
707 		               error(1, -1,
708 				     "can't seek page %d", ActualPage+1);
709 		        HandlePage();
710 		} else
711     	                PutEmptyPage();
712 	}
713 	if (fseek(inf, StartOfPage[InputPageNumber]+1, 0) == -1)
714 	        error(1, -1, "can't seek last page");
715 }
716 
717 static int
HandlePage(void)718 HandlePage(void)
719 {
720 	register int c, l;
721 	register i32 p = 0;	/* avoid uninitialized warning */
722 	register int CurrentFontOK = 0;
723 	int doingpage = 0;
724 
725 	/* Only way out is via "return" statement */
726 	for (;;) {
727 		c = getc(inf);	/* getc() returns unsigned values */
728 		if (DVI_IsChar(c)) {
729 			/*
730 			 * Copy chars, note font usage, but ignore if
731 			 * page is not interesting.
732 			 */
733 			if (!UseThisPage)
734 				continue;
735 			if (!CurrentFontOK) {
736 				ReallyUseFont();
737 				CurrentFontOK++;
738 			}
739 			putbyte(outf, c);
740 			CurrentPosition++;
741 			continue;
742 		}
743 		if (DVI_IsFont(c)) {	/* note font change */
744 			CurrentFontIndex = c - DVI_FNTNUM0;
745 			CurrentFontOK = 0;
746 			continue;
747 		}
748 		if (c == EOF)
749 			GripeUnexpectedDVIEOF();
750 		if ((l = (oplen - 128)[c]) != 0) {	/* simple copy */
751 			if (!UseThisPage) {
752 				while (--l > 0)
753 					(void) getc(inf);
754 				continue;
755 			}
756 			CurrentPosition += l;
757 			putbyte(outf, c);
758 			while (--l > 0) {
759 				c = getc(inf);
760 				putbyte(outf, c);
761 			}
762 			if (ferror(outf))
763 				error(1, -1, writeerr);
764 			continue;
765 		}
766 		if ((l = DVI_OpLen(c)) != 0) {
767 			/*
768 			 * Handle other generics.
769 			 * N.B.: there should only be unsigned parameters
770 			 * here (save SGN4), for commands with negative
771 			 * parameters have been taken care of above.
772 			 */
773 			switch (l) {
774 
775 			case DPL_UNS1:
776 				p = getc(inf);
777 				break;
778 
779 			case DPL_UNS2:
780 				fGetWord(inf, p);
781 				break;
782 
783 			case DPL_UNS3:
784 				fGet3Byte(inf, p);
785 				break;
786 
787 			case DPL_SGN4:
788 				fGetLong(inf, p);
789 				break;
790 
791 			default:
792 				panic("HandleDVIFile l=%d", l);
793 			}
794 
795 			/*
796 			 * Now that we have the parameter, perform the
797 			 * command.
798 			 */
799 			switch (DVI_DT(c)) {
800 
801 			case DT_SET:
802 			case DT_PUT:
803 				if (!UseThisPage)
804 					continue;
805 				if (!CurrentFontOK) {
806 					ReallyUseFont();
807 					CurrentFontOK++;
808 				}
809 				putbyte(outf, c);
810 				switch (l) {
811 
812 				case DPL_UNS1:
813 					putbyte(outf, p);
814 					CurrentPosition += 2;
815 					continue;
816 
817 				case DPL_UNS2:
818 					PutWord(outf, p);
819 					CurrentPosition += 3;
820 					continue;
821 
822 				case DPL_UNS3:
823 					Put3Byte(outf, p);
824 					CurrentPosition += 4;
825 					continue;
826 
827 				case DPL_SGN4:
828 					PutLong(outf, p);
829 					CurrentPosition += 5;
830 					continue;
831 				}
832 
833 			case DT_FNT:
834 				CurrentFontIndex = p;
835 				CurrentFontOK = 0;
836 				continue;
837 
838 			case DT_XXX:
839 				HandleSpecial(c, l, p);
840 				continue;
841 
842 			case DT_FNTDEF:
843 				HandleFontDef(p);
844 				continue;
845 
846 			default:
847 				panic("HandleDVIFile DVI_DT(%d)=%d",
848 				      c, DVI_DT(c));
849 			}
850 			continue;
851 		}
852 
853 		switch (c) {	/* handle the few remaining cases */
854 
855 		case DVI_BOP:
856 			if (doingpage)
857 				GripeUnexpectedOp("BOP (during page)");
858 			BeginPage();
859 			doingpage = 1;
860 			break;
861 
862 		case DVI_EOP:
863 			if (!doingpage)
864 				GripeUnexpectedOp("EOP (outside page)");
865 			EndPage();
866 			doingpage = 0;
867 			return(1);
868 
869 		case DVI_PRE:
870 			GripeUnexpectedOp("PRE");
871 			/* NOTREACHED */
872 
873 		case DVI_POST:
874 			if (doingpage)
875 				GripeUnexpectedOp("POST (inside page)");
876 			return(0);
877 
878 		case DVI_POSTPOST:
879 			GripeUnexpectedOp("POSTPOST");
880 			/* NOTREACHED */
881 
882 		default:
883 			GripeUndefinedOp(c);
884 			/* NOTREACHED */
885 		}
886 	}
887 }
888 
889 /* write an empty page to fill out space */
890 static void
PutEmptyPage(void)891 PutEmptyPage(void)
892 {
893         int i;
894 
895 	putbyte(outf, DVI_BOP);
896 	PutLong(outf, -1L);
897 	for (i = 1; i < 10; i++)     /* set all sub counts to 0 */
898 		PutLong(outf, 0L);
899 	PutLong(outf, StartOfLastPage);
900 	putbyte(outf, DVI_EOP);
901 	if (!SFlag) {		/* write nice page usage messages */
902 		const char *msg = "[*]";
903 		message(1, msg, strlen(msg));
904 	}
905 	if (ferror(outf))
906 		error(1, -1, writeerr);
907 
908 	StartOfLastPage = CurrentPosition;
909 	CurrentPosition += 46;	/* we just wrote this much */
910 	NumberOfOutputPages++;
911 }
912