2
* Copyright (c) 1987, 1989 University of Maryland
3
* Department of Computer Science. All rights reserved.
4
* Permission to copy for any purpose is hereby granted
5
* so long as this copyright notice remains intact.
9
static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/dvi/RCS/dviselect.c,v 3.1 89/08/22 17:16:13 chris Exp $";
13
* DVI page selection program
15
* Reads DVI version 2 files and selects pages, writing a new DVI
16
* file. The new DVI file is technically correct, though we do not
17
* adjust the tallest and widest page values, nor the DVI stack size.
18
* This is all right since the values will never become too small,
19
* but it might be nice to fix them up. Perhaps someday . . . .
27
#include <kpathsea/c-fopen.h>
28
#include <kpathsea/getopt.h>
30
#define FOPEN_RBIN_MODE "rb"
31
#define FOPEN_RBIN_MODE "wb"
47
#define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
51
char serrbuf[BUFSIZ]; /* buffer for stderr */
54
* We will try to keep output lines shorter than MAXCOL characters.
59
* We use the following structure to keep track of fonts we have seen.
60
* The final DVI file lists only the fonts it uses.
63
i32 fi_newindex; /* font number in output file */
64
int fi_reallyused; /* true => used on a page we copied */
65
i32 fi_checksum; /* the checksum */
66
i32 fi_mag; /* the magnification */
67
i32 fi_designsize; /* the design size */
68
short fi_n1; /* the name header length */
69
short fi_n2; /* the name body length */
70
char *fi_name; /* the name itself */
74
* We need to remember which pages the user would like. We build a linked
75
* list that allows us to decide (for any given page) whether it should
76
* be included in the output file. Each page has ten \count variables
77
* associated with it. We put a bound on the values allowed for each, and
78
* keep a linked list of alternatives should any be outside the allowed
79
* range. For example, `dviselect *.3,10-15' would generate a two-element
80
* page list, with the first allowing any value for \count0 (and \counts 2 to
81
* 9) but \count1 restricted to the range 3-3, and the second restricting
82
* \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained.
84
* We remember whether a bound is specified, so that we need not fix
85
* some `large' number as a maximum value.
87
* We also allow `absolute' page references, where the first page is
88
* page 1, the second 2, and so forth. These are specified with an
89
* equal sign: `dviselect =4:10' picks up the fourth through tenth
90
* sequential pages, irrespective of \count values.
92
* There is also an even/odd switch (which can be applied to absolute
93
* or relative pages): dviselect =even, even.3, etc.
96
pt_lu, /* have both lower and upper bounds */
97
pt_l, /* lower bound only */
98
pt_u, /* upper bound only */
99
pt_unbounded, /* any value at all */
100
pt_even, /* even values only */
101
pt_odd /* odd values only */
104
enum pstype ps_type; /* type of selector */
105
i32 ps_low; /* lower bound */
106
i32 ps_high; /* upper bound */
109
struct pagelist *pl_alt; /* next in a series of alternates */
110
int pl_len; /* number of ranges to check */
111
int pl_abs; /* true iff absolute page ref */
112
struct pagesel pl_pages[10]; /* one for each \count variable */
115
int SFlag; /* true => -s, silent operation */
117
struct search *FontFinder; /* maps from input indicies to fontinfo */
118
i32 NextOutputFontIndex; /* generates output indicies */
119
i32 CurrentFontIndex; /* current (old) index in input */
120
i32 OutputFontIndex; /* current (new) index in ouput */
122
struct pagelist *PageList; /* the list of allowed pages */
124
char *DVIFileName; /* name of input DVI file */
125
FILE *inf; /* the input file itself */
126
FILE *outf; /* the output DVI file */
128
long StartOfLastPage; /* The file position just before we started
129
the last page (this is later written to
130
the output file as the previous page
132
long CurrentPosition; /* The current position of the file */
134
int UseThisPage; /* true => current page is selected */
136
i32 InputPageNumber; /* current absolute page in old DVI file */
137
int NumberOfOutputPages; /* number of pages in new DVI file */
139
i32 Numerator; /* numerator from DVI file */
140
i32 Denominator; /* denominator from DVI file */
141
i32 DVIMag; /* magnification from DVI file */
143
i32 Count[10]; /* the 10 \count variables */
145
/* save some string space: we use this a lot */
146
char writeerr[] = "error writing DVI file";
148
#ifdef NeedFunctionPrototypes
150
void WriteFont(struct fontinfo *);
152
int ParsePages(char *);
153
void HandleDVIFile();
154
void PutFontSelector(i32);
157
#define bcmp(s1, s2, len) memcmp(s1, s2, len)
158
#define bzero(s, len) memset(s, '\0', len)
159
#define index(s, c) strchr(s, c)
163
char *malloc(), *realloc();
164
#endif /* not WIN32 */
167
* You may get lint warnings about sprintf's return value.
168
* Older versions of 4BSD have `char *sprintf()'. ANSI and
169
* SysV use `int sprintf()'; so ignore the warnings.
173
* Lint gets somewhat confused over putc.
177
#ifdef ultrix /* grr */
178
#define putc(c, f) fputc((char)(c), f)
180
#define putc(c, f) fputc((int)(c), f)
185
* Return true iff the 10 \counts are one of the desired output pages.
189
register struct pagelist *pl;
191
for (pl = PageList; pl != NULL; pl = pl->pl_alt) {
192
register struct pagesel *ps = pl->pl_pages;
196
pagep = pl->pl_abs ? &InputPageNumber : &Count[0];
197
for (i = 0; i < pl->pl_len; i++, ps++, pagep++) {
198
switch (ps->ps_type) {
200
case pt_lu: /* check upper, fall through */
201
if (*pagep > ps->ps_high)
205
case pt_l: /* only if not too low */
206
if (*pagep < ps->ps_low)
210
case pt_u: /* only if not too high */
211
if (*pagep > ps->ps_high)
218
case pt_even: /* only if even */
223
case pt_odd: /* only if odd */
224
if ((*pagep & 1) == 0)
229
return (1); /* success */
237
* Print a message to stderr, with an optional leading space, and handling
240
void message(space, str, len)
249
space = 0, beenhere++;
255
(void) putc('\n', stderr), col = len;
257
(void) putc(' ', stderr), col++;
260
(void) putc(*str++, stderr);
261
(void) fflush(stderr);
265
* Start a page (process a DVI_BOP).
271
OutputFontIndex = -1; /* new page requires respecifying font */
272
InputPageNumber++; /* count it */
273
for (i = Count; i < &Count[10]; i++)
275
(void) GetLong(inf); /* previous page pointer */
277
if ((UseThisPage = DesiredPageP()) == 0)
280
putbyte(outf, DVI_BOP);
281
for (i = Count; i < &Count[10]; i++)
283
PutLong(outf, StartOfLastPage);
285
error(1, -1, writeerr);
287
StartOfLastPage = CurrentPosition;
288
CurrentPosition += 45; /* we just wrote this much */
290
if (!SFlag) { /* write nice page usage messages */
292
register int mlen = 0;
295
(void) sprintf(msg, "[%ld", (long)Count[0]);
297
for (i = &Count[1]; i < &Count[10]; i++) {
303
msg[mlen++] = '.', msg[mlen++] = '0';
305
(void) sprintf(msg + mlen, ".%ld", (long)*i);
306
mlen += strlen(msg + mlen);
308
message(1, msg, mlen);
313
* End a page (process a DVI_EOP).
322
putbyte(outf, DVI_EOP);
324
error(1, -1, writeerr);
326
NumberOfOutputPages++;
330
* For each of the fonts used in the new DVI file, write out a definition.
334
PostAmbleFontEnumerator(addr, key)
339
if (((struct fontinfo *)addr)->fi_reallyused)
340
WriteFont((struct fontinfo *)addr);
343
void HandlePostAmble()
347
(void) GetLong(inf); /* previous page pointer */
348
if (GetLong(inf) != Numerator)
349
GripeMismatchedValue("numerator");
350
if (GetLong(inf) != Denominator)
351
GripeMismatchedValue("denominator");
352
if (GetLong(inf) != DVIMag)
353
GripeMismatchedValue("\\magnification");
355
putbyte(outf, DVI_POST);
356
PutLong(outf, StartOfLastPage);
357
PutLong(outf, Numerator);
358
PutLong(outf, Denominator);
359
PutLong(outf, DVIMag);
361
PutLong(outf, c); /* tallest page height */
363
PutLong(outf, c); /* widest page width */
365
PutWord(outf, c); /* DVI stack size */
366
PutWord(outf, NumberOfOutputPages);
367
StartOfLastPage = CurrentPosition; /* point at post */
368
CurrentPosition += 29; /* count all those `put's */
370
(void) GetWord(inf); /* skip original number of pages */
374
* just ignore all the incoming font definitions; we are done with
379
* run through the FontFinder table and dump definitions for the
380
* fonts we have used.
382
SEnumerate(FontFinder, PostAmbleFontEnumerator);
384
putbyte(outf, DVI_POSTPOST);
385
PutLong(outf, StartOfLastPage); /* actually start of postamble */
386
putbyte(outf, DVI_VERSION);
387
putbyte(outf, DVI_FILLER);
388
putbyte(outf, DVI_FILLER);
389
putbyte(outf, DVI_FILLER);
390
putbyte(outf, DVI_FILLER);
391
CurrentPosition += 10;
392
while (CurrentPosition & 3) {
393
putbyte(outf, DVI_FILLER);
397
error(1, -1, writeerr);
401
* Write a font definition to the output file
404
register struct fontinfo *fi;
409
if (fi->fi_newindex < 256) {
410
putbyte(outf, DVI_FNTDEF1);
411
putbyte(outf, fi->fi_newindex);
412
CurrentPosition += 2;
413
} else if (fi->fi_newindex < 65536) {
414
putbyte(outf, DVI_FNTDEF2);
415
PutWord(outf, fi->fi_newindex);
416
CurrentPosition += 3;
417
} else if (fi->fi_newindex < 16777216) {
418
putbyte(outf, DVI_FNTDEF3);
419
Put3Byte(outf, fi->fi_newindex);
420
CurrentPosition += 4;
422
putbyte(outf, DVI_FNTDEF4);
423
PutLong(outf, fi->fi_newindex);
424
CurrentPosition += 5;
426
PutLong(outf, fi->fi_checksum);
427
PutLong(outf, fi->fi_mag);
428
PutLong(outf, fi->fi_designsize);
429
putbyte(outf, fi->fi_n1);
430
putbyte(outf, fi->fi_n2);
431
l = fi->fi_n1 + fi->fi_n2;
432
CurrentPosition += 14 + l;
439
* Handle the preamble. Someday we should update the comment field.
441
void HandlePreAmble()
447
GripeUnexpectedDVIEOF();
449
GripeMissingOp("PRE");
450
if (getc(inf) != DVI_VERSION)
451
error(1, 0, "%s is not a DVI version %d file",
452
DVIFileName, DVI_VERSION);
453
Numerator = GetLong(inf);
454
Denominator = GetLong(inf);
455
DVIMag = GetLong(inf);
456
putbyte(outf, DVI_PRE);
457
putbyte(outf, DVI_VERSION);
458
PutLong(outf, Numerator);
459
PutLong(outf, Denominator);
460
PutLong(outf, DVIMag);
462
n = UnSign8(GetByte(inf));
463
CurrentPosition = 15 + n; /* well, almost */
474
register char **argv;
478
char *outname = NULL;
481
setbuf(stderr, serrbuf);
483
while ((c = getopt(argc, argv, "i:o:s")) != EOF) {
486
case 's': /* silent */
491
if (DVIFileName != NULL)
493
DVIFileName = optarg;
504
(void) fprintf(stderr, "\
505
Usage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n",
507
(void) fflush(stderr);
512
while (optind < argc) {
515
if (!isalpha(c) && c != '/' ||
516
(c == 'e' || c == 'o') && evenodd(s)) {
519
} else if (DVIFileName == NULL)
521
else if (outname == NULL)
526
if (PageList == NULL)
528
if (DVIFileName == NULL) {
529
DVIFileName = "`stdin'";
531
if (!isatty(fileno(inf)))
532
SET_BINARY(fileno(inf));
533
} else if ((inf = fopen(DVIFileName, FOPEN_RBIN_MODE)) == 0)
534
error(1, -1, "cannot read %s", DVIFileName);
535
if (outname == NULL) {
537
if (!isatty(fileno(outf)))
538
SET_BINARY(fileno(outf));
539
} else if ((outf = fopen(outname, FOPEN_WBIN_MODE)) == 0)
540
error(1, -1, "cannot write %s", outname);
542
if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
543
error(1, 0, "cannot create font finder (out of memory?)");
545
StartOfLastPage = -1;
550
(void) fprintf(stderr, "\nWrote %d page%s, %ld bytes\n",
551
NumberOfOutputPages, NumberOfOutputPages == 1 ? "" : "s",
552
(long)CurrentPosition);
557
InstallPL(ps, n, absolute)
558
register struct pagesel *ps;
562
register struct pagelist *pl;
564
pl = (struct pagelist *)malloc(sizeof *pl);
566
GripeOutOfMemory(sizeof *pl, "page list");
567
pl->pl_alt = PageList;
571
pl->pl_pages[n] = ps[n];
572
pl->pl_abs = absolute;
577
* Return true iff the string `s' is the word `even' or `odd',
578
* followed by `.' or `white' characters.
586
if (strncmp(s, "even", 4) == 0)
588
else if (strncmp(s, "odd", 3) == 0)
592
if (c == 0 || c == '.' || white(c))
598
* Parse a string representing a list of pages. Return 0 iff ok. As a
599
* side effect, the page selection(s) is (are) prepended to PageList.
604
register struct pagesel *ps;
605
register int c; /* current character */
606
register i32 n; /* current numeric value */
607
register int innumber; /* true => gathering a number */
608
int i; /* next index in page select list */
609
int range; /* true => saw a range indicator */
610
int negative; /* true => number being built is negative */
611
int absolute; /* true => absolute, not \count */
612
int lb, ub, even, odd; /* flags for lower,upper,even,odd */
613
struct pagesel pagesel[10];
620
lb = ub = even = odd = 0;
622
* Talk about ad hoc! (Not to mention convoluted.)
626
if (i == 0 && !innumber && !range) {
627
/* nothing special going on */
633
if ((c == 'e' || c == 'o') && evenodd(s - 1)) {
634
if (innumber || range)
647
/* kludge: should be '-' for negatives */
648
if (innumber || absolute)
657
if (innumber || range || i > 0)
665
/* accumulate numeric value */
673
n += negative ? '0' - c : c - '0';
676
if (c == '-' || c == ':') {
677
/* here is a range */
680
if (innumber) { /* have a lower bound */
689
/* no lower bound, no upper bound */
691
if (innumber || range || (c && c != '.' && !white(c)))
695
if (c == 0 || c == '.' || white(c)) {
696
/* end of this range */
697
if (innumber) { /* have an upper bound */
701
/* no range => lower bound == upper */
702
ps->ps_low = ps->ps_high;
708
ps->ps_type = pt_even;
710
ps->ps_type = pt_odd;
712
ps->ps_type = ub ? pt_lu : pt_l;
714
ps->ps_type = ub ? pt_u : pt_unbounded;
718
if (++i >= 10) /* too many specifiers */
722
InstallPL(pagesel, i + 1, absolute);
731
lb = ub = even = odd = 0;
734
/* illegal character */
740
* Handle a font definition.
742
void HandleFontDef(index)
745
register struct fontinfo *fi;
748
int def = S_CREATE | S_EXCL;
750
if ((fi = (struct fontinfo *)SSearch(FontFinder, index, &def)) == 0)
752
error(1, 0, "font %ld already defined", (long)index);
754
error(1, 0, "cannot stash font %ld (out of memory?)",
756
fi->fi_reallyused = 0;
757
fi->fi_checksum = GetLong(inf);
758
fi->fi_mag = GetLong(inf);
759
fi->fi_designsize = GetLong(inf);
760
fi->fi_n1 = UnSign8(GetByte(inf));
761
fi->fi_n2 = UnSign8(GetByte(inf));
762
i = fi->fi_n1 + fi->fi_n2;
763
if ((s = malloc((unsigned)i)) == 0)
764
GripeOutOfMemory(i, "font name");
773
void HandleSpecial(c, l, p)
786
CurrentPosition += 2;
791
CurrentPosition += 3;
796
CurrentPosition += 4;
801
CurrentPosition += 5;
805
panic("HandleSpecial l=%d", l);
808
CurrentPosition += p;
814
GripeUnexpectedDVIEOF();
816
error(1, -1, writeerr);
824
register struct fontinfo *fi;
827
fi = (struct fontinfo *)SSearch(FontFinder, CurrentFontIndex, &look);
829
error(1, 0, "DVI file requested font %ld without defining it",
830
(long)CurrentFontIndex);
831
if (fi->fi_reallyused == 0) {
833
fi->fi_newindex = NextOutputFontIndex++;
836
if (fi->fi_newindex != OutputFontIndex) {
837
PutFontSelector(fi->fi_newindex);
838
OutputFontIndex = fi->fi_newindex;
843
* Write a font selection command to the output file
845
void PutFontSelector(index)
850
putbyte(outf, index + DVI_FNTNUM0);
852
} else if (index < 256) {
853
putbyte(outf, DVI_FNT1);
854
putbyte(outf, index);
855
CurrentPosition += 2;
856
} else if (index < 65536) {
857
putbyte(outf, DVI_FNT2);
858
PutWord(outf, index);
859
CurrentPosition += 3;
860
} else if (index < 16777216) {
861
putbyte(outf, DVI_FNT3);
862
Put3Byte(outf, index);
863
CurrentPosition += 4;
865
putbyte(outf, DVI_FNT4);
866
PutLong(outf, index);
867
CurrentPosition += 5;
872
* The following table describes the length (in bytes) of each of the DVI
873
* commands that we can simply copy, starting with DVI_SET1 (128).
876
0, 0, 0, 0, /* DVI_SET1 .. DVI_SET4 */
878
0, 0, 0, 0, /* DVI_PUT1 .. DVI_PUT4 */
885
2, 3, 4, 5, /* DVI_RIGHT1 .. DVI_RIGHT4 */
887
2, 3, 4, 5, /* DVI_W1 .. DVI_W4 */
889
2, 3, 4, 5, /* DVI_X1 .. DVI_X4 */
890
2, 3, 4, 5, /* DVI_DOWN1 .. DVI_DOWN4 */
892
2, 3, 4, 5, /* DVI_Y1 .. DVI_Y4 */
894
2, 3, 4, 5, /* DVI_Z1 .. DVI_Z4 */
895
0, /* DVI_FNTNUM0 (171) */
896
0, 0, 0, 0, 0, 0, 0, 0, /* 172 .. 179 */
897
0, 0, 0, 0, 0, 0, 0, 0, /* 180 .. 187 */
898
0, 0, 0, 0, 0, 0, 0, 0, /* 188 .. 195 */
899
0, 0, 0, 0, 0, 0, 0, 0, /* 196 .. 203 */
900
0, 0, 0, 0, 0, 0, 0, 0, /* 204 .. 211 */
901
0, 0, 0, 0, 0, 0, 0, 0, /* 212 .. 219 */
902
0, 0, 0, 0, 0, 0, 0, 0, /* 220 .. 227 */
903
0, 0, 0, 0, 0, 0, 0, /* 228 .. 234 */
904
0, 0, 0, 0, /* DVI_FNT1 .. DVI_FNT4 */
905
0, 0, 0, 0, /* DVI_XXX1 .. DVI_XXX4 */
906
0, 0, 0, 0, /* DVI_FNTDEF1 .. DVI_FNTDEF4 */
909
0, /* DVI_POSTPOST */
910
0, 0, 0, 0, 0, 0, /* 250 .. 255 */
914
* Here we read the input DVI file and write relevant pages to the
915
* output DVI file. We also keep track of font changes, handle font
916
* definitions, and perform some other housekeeping.
922
register int CurrentFontOK = 0;
925
/* Only way out is via "return" statement */
927
c = getc(inf); /* getc() returns unsigned values */
930
* Copy chars, note font usage, but ignore if
931
* page is not interesting.
935
if (!CurrentFontOK) {
943
if (DVI_IsFont(c)) { /* note font change */
944
CurrentFontIndex = c - DVI_FNTNUM0;
949
GripeUnexpectedDVIEOF();
950
if ((l = (oplen - 128)[c]) != 0) { /* simple copy */
956
CurrentPosition += l;
963
error(1, -1, writeerr);
966
if ((l = DVI_OpLen(c)) != 0) {
968
* Handle other generics.
969
* N.B.: there should only be unsigned parameters
970
* here (save SGN4), for commands with negative
971
* parameters have been taken care of above.
992
panic("HandleDVIFile l=%d", l);
996
* Now that we have the parameter, perform the
1005
if (!CurrentFontOK) {
1014
CurrentPosition += 2;
1019
CurrentPosition += 3;
1024
CurrentPosition += 4;
1029
CurrentPosition += 5;
1034
CurrentFontIndex = p;
1039
HandleSpecial(c, l, p);
1047
panic("HandleDVIFile DVI_DT(%d)=%d",
1053
switch (c) { /* handle the few remaining cases */
1057
GripeUnexpectedOp("BOP (during page)");
1065
GripeUnexpectedOp("EOP (outside page)");
1071
GripeUnexpectedOp("PRE");
1076
GripeUnexpectedOp("POST (inside page)");
1080
GripeUnexpectedOp("POSTPOST");
1084
GripeUndefinedOp(c);