Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!shadooby!samsung!uunet!crdgw1!montnaro From: montnaro@sprite.crd.ge.com (Skip Montanaro) Newsgroups: alt.sources Subject: dviselect (Part 1 of 6) Message-ID:Date: 13 Nov 89 21:19:34 GMT Sender: news@crdgw1.crd.ge.com Reply-To: (Skip Montanaro) Organization: GE Corporate Research & Development, Schenectady, NY Lines: 2250 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh Makefile <<'END_OF_Makefile' XDESTDIR= XCFLAGS= -O -I./h XMAKE= make X XBINDIR = $(HOME)/.commands XIPRBIN = /usr/local XMANDIR = $(HOME)/.man X XCSRCS = dviselect.c XSRCS = $(CSRCS) dviselect.1 X Xdefault: dviselect lib/lib.a X Xsrc: $(SRCS) X @echo Done X Xclean: X cd lib; $(MAKE) $(MFLAGS) clean X -rm -f core *.o dviselect imagen1 dviselect.shar* X Xinst-dviselect: dviselect dviselect.1 X install -s dviselect ${BINDIR}/dviselect X -install -c -m 444 dviselect.1 ${MANDIR}/man1/dviselect.1 X Xdviselect: dviselect.o lib/lib.a X ${CC} ${CFLAGS} -o dviselect dviselect.o lib/lib.a X Xlib/lib.a : X cd lib; $(MAKE) $(MFLAGS) X Xdvidvi: dvidvi.c X $(CC) $(CFLAGS) -o dvidvi dvidvi.c X Xdepend: X makedepend $(CFLAGS) $(CSRCS) X Xshar : X $(MAKE) $(MFLAGS) clean X shar -n1 -e6 -t "Now do 'make dviselect'" * >dviselect.shar.1 X shar -n2 -e6 -t "Now do 'make dviselect'" h/* >dviselect.shar.2 X shar -n3 -e6 -t "Now do 'make dviselect'" lib/[a-f]* >dviselect.shar.3 X shar -n4 -e6 -t "Now do 'make dviselect'" lib/[g-m]* >dviselect.shar.4 X shar -n5 -e6 -t "Now do 'make dviselect'" lib/[n-p]* >dviselect.shar.5 X shar -n6 -e6 -t "Now do 'make dviselect'" lib/[q-zM]* >dviselect.shar.6 X X# DO NOT DELETE THIS LINE -- make depend depends on it. X Xdviselect.o: ../h/types.h ../h/dvi.h ../h/dviclass.h ../h/dvicodes.h Xdviselect.o: ../h/fio.h ../h/search.h /usr/include/stdio.h Xdviselect.o: /usr/include/ctype.h END_OF_Makefile if test 1356 -ne `wc -c Makefile.orig <<'END_OF_Makefile.orig' XDESTDIR= XCFLAGS= -O -I../h XMAKE= make X XBINDIR = $(HOME)/.commands XIPRBIN = /usr/local XMANDIR = $(HOME)/.man X XCSRCS = dviselect.c XSRCS = $(CSRCS) dviselect.1 X Xdefault: all X X$(SRCS):; co -q $@ X Xsrc: $(SRCS) X @echo Done X Xclean: X -ci -q $(SRCS) X -rm core *.o dviselect imagen1 X Xinst-dviselect: dviselect dviselect.1 X install -s dviselect ${BINDIR}/dviselect X -install -c -m 444 dviselect.1 ${MANDIR}/man1/dviselect.1 X Xdviselect: dviselect.o ../lib/lib.a X ${CC} ${CFLAGS} -o dviselect dviselect.o ../lib/lib.a X Xdvidvi: dvidvi.c X $(CC) $(CFLAGS) -o dvidvi dvidvi.c X Xdepend: X makedepend $(CFLAGS) $(CSRCS) X X# DO NOT DELETE THIS LINE -- make depend depends on it. X Xdviselect.o: ../h/types.h ../h/dvi.h ../h/dviclass.h ../h/dvicodes.h Xdviselect.o: ../h/fio.h ../h/search.h /usr/include/stdio.h Xdviselect.o: /usr/include/ctype.h END_OF_Makefile.orig if test 820 -ne `wc -c dviselect.1 <<'END_OF_dviselect.1' X.TH DVISELECT 1 X.SH NAME Xdviselect \- extract pages from DVI files X.SH SYNOPSIS X.B dviselect X[ X.B \-s X] [ X.B \-i X.I infile X] [ X.B \-o X.I outfile X] X.I "list of pages" X[ X.I infile X[ X.I outfile X] ] X.SH DESCRIPTION X.I Dviselect Xselects pages from a DVI file produced by TeX, creating a new DVI Xfile usable by any of TeX's conversion program (e.g., iptex), or even Xby dviselect itself. X.PP XA X.I range Xis a string of the form X.I first:last Xwhere both X.I first Xand X.I last Xare optional numeric strings, with negative numbers indicated by Xa leading underscore character ``_''. If both X.I first Xand X.I last Xare omitted, the colon may also be omitted, or may be replaced Xwith an asterisk ``*''. A X.I page range Xis a list of ranges separated by periods. A X.I "list of pages" Xis described by a set of page ranges separated by commas and/or white space. X.PP X.I Dviselect Xactually looks at the ten X.I count Xvariables that TeX writes; the first of these (\ecount0) is the Xpage number, with \ecount1 through \ecount9 having varied uses Xdepending on which macro packages are in use. (Typically \ecount1 Xis a chapter or section number.) A page is included in X.IR dviselect 's Xoutput if all its \ecount values are within any one of the ranges Xlisted on the command line. For example, the command X``dviselect *.1,35:'' Xmight select everything in chapter 1, as well as pages 35 and up. X``dviselect 10:30'' would select pages 10 through 30 (inclusive). X``:43'' means everything up to and including page 43 (including Xnegative-numbered pages). XIf a Table of Contents has negative page numbers, ``:_1'' will select it. X``*.4 .........1'' might Xmean everything in every chapter 4 and an index, presuming \ecount9 Xwas set to 1 in the index. (``*'' must be quoted from the shell; Xthe null string is more convenient to use, if harder to read.) X.PP XInstead of \ecount values, X.I dviselect Xcan also select by ``absolute page number'', where the first page Xis page 1, the second page 2, and so forth. Absolute page numbers Xare indicated by a leading equal sign ``=''. Ranges of absolute Xpages are also allowed: ``dviselect =3:7'' will extract the third Xthrough seventh pages. Dot separators are not legal in absolute Xranges, and there are no negative absolute page numbers. X.PP XMore precisely, an asterisk or a null string implies no limit; Xan equal sign means absolute pages rather than \ecounts; Xa leading colon means everything up to and including the given page; a Xtrailing colon means everything from the given page on; and Xa period indicates that the next \ecount should be examined. XIf fewer than 10 ranges are specified, the remaining \ecounts Xare left unrestricted (that is, ``1:5'' and ``1:5.*'' are equivalent). XA single number \fIn\fP is treated as if it were the range \fIn:n\fP. XAn arbitrary number of page selectors may be given, separated by commas Xor whitespace; a page is selected if any of the selectors matches Xits \ecounts or absolute page number. X.PP XDviselect normally prints the page numbers of the pages selected; the X.I \-s Xoption suppresses this. X.SH AUTHOR XChris Torek, University of Maryland X.SH "SEE ALSO" Xdvipr(1), iptex(1), tex(1), \fIThe TeXbook\fP X.SH BUGS XA leading ``-'' ought to be allowed for negative numbers, but it Xis currently used as a synonym for ``:'', for backwards compatibility. X.PP XSection or subsection selection will sometimes fail, for the DVI Xfile lists only the \ecount values that were active when the page Xended. Clever macro packages can alleviate this by making use of Xother ``free'' \ecount registers. Chapters normally begin on new Xpages, and do not suffer from this particular problem. X.PP X.I Dviselect Xdoes not adjust the parameters in the postamble; however, since these Xvalues are normally used only to size certain structures in the output Xconversion programs, and the parameters never need to be adjusted upward, Xthis has not proven to be a problem. END_OF_dviselect.1 if test 3897 -ne `wc -c dviselect.c <<'END_OF_dviselect.c' X/* X * Copyright (c) 1987 University of Maryland Department of Computer Science. X * All rights reserved. Permission to copy for any purpose is hereby granted X * so long as this copyright notice remains intact. X */ X X#ifndef lint Xstatic char rcsid[] = "$Header: /home/reed/grunwald/Projects/Iptex/utilities/RCS/dviselect.c,v 1.3 87/12/06 12:27:33 grunwald Exp $"; X#endif X X/* X * DVI page selection program X * X * Reads DVI version 2 files and selects pages, writing a new DVI X * file. The new DVI file is technically correct, though we do not X * adjust the tallest and widest page values, nor the DVI stack size. X * This is all right since the values will never become too small, X * but it might be nice to fix them up. Perhaps someday . . . . X */ X X#include "types.h" X#include "dvi.h" X#include "dviclass.h" X#include "dvicodes.h" X#include "fio.h" X#include "search.h" X#include X#include X Xchar *ProgName; Xextern int errno; Xextern char *optarg; Xextern int optind; X X/* Globals */ Xchar serrbuf[BUFSIZ]; /* buffer for stderr */ X X/* X * We will try to keep output lines shorter than MAXCOL characters. X */ X#define MAXCOL 75 X X/* X * We use the following structure to keep track of fonts we have seen. X * The final DVI file lists only the fonts it uses. X */ Xstruct fontinfo { X i32 fi_newindex; /* font number in output file */ X int fi_reallyused; /* true => used on a page we copied */ X i32 fi_checksum; /* the checksum */ X i32 fi_mag; /* the magnification */ X i32 fi_designsize; /* the design size */ X short fi_n1; /* the name header length */ X short fi_n2; /* the name body length */ X char *fi_name; /* the name itself */ X}; X X/* X * We need to remember which pages the user would like. We build a linked X * list that allows us to decide (for any given page) whether it should X * be included in the output file. Each page has ten \count variables X * associated with it. We put a bound on the values allowed for each, and X * keep a linked list of alternatives should any be outside the allowed X * range. For example, `dviselect *.3,10-15' would generate a two-element X * page list, with the first allowing any value for \count0 (and \counts 2 to X * 9) but \count1 restricted to the range 3-3, and the second restricting X * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained. X * X * In case no bound is specified, the `nol' or `noh' flag is set (so that X * we need not fix some `large' number as a maximum value). X * X * We also allow `absolute' page references, where the first page is X * page 1, the second 2, and so forth. These are specified with an X * equal sign: `dviselect =4:10' picks up the fourth through tenth X * sequential pages, irrespective of \count values. X */ Xstruct pagesel { X i32 ps_low; /* lower bound */ X int ps_nol; /* true iff no lower bound */ X i32 ps_high; /* upper bound */ X int ps_noh; /* true iff no upper bound */ X}; Xstruct pagelist { X struct pagelist *pl_alt; /* next in a series of alternates */ X int pl_len; /* number of ranges to check */ X int pl_abs; /* true iff absolute page ref */ X struct pagesel pl_pages[10]; /* one for each \count variable */ X}; X Xint SFlag; /* true => -s, silent operation */ X Xstruct search *FontFinder; /* maps from input indicies to fontinfo */ Xi32 NextOutputFontIndex; /* generates output indicies */ Xi32 CurrentFontIndex; /* current (old) index in input */ Xi32 OutputFontIndex; /* current (new) index in ouput */ X Xstruct pagelist *PageList; /* the list of allowed pages */ X XFILE *inf; /* the input DVI file */ XFILE *outf; /* the output DVI file */ X Xint ExpectBOP; /* true => BOP ok */ Xint ExpectEOP; /* true => EOP ok */ X Xlong StartOfLastPage; /* The file position just before we started X the last page (this is later written to X the output file as the previous page X pointer). */ Xlong CurrentPosition; /* The current position of the file */ X Xint UseThisPage; /* true => current page is selected */ X Xi32 InputPageNumber; /* current absolute page in old DVI file */ Xint NumberOfOutputPages; /* number of pages in new DVI file */ X Xi32 Numerator; /* numerator from DVI file */ Xi32 Denominator; /* denominator from DVI file */ Xi32 DVIMag; /* magnification from DVI file */ X Xi32 Count[10]; /* the 10 \count variables */ X X/* save some string space: we use this a lot */ Xchar writeerr[] = "error writing DVI file"; X Xchar *malloc(), *realloc(), *sprintf(); X X/* X * lint gets rather confused with the current definitions of getc and putc, X * so we redefine them here (#if lint). This should really be in the X * standard I/O library, but I am not about to go change it now! X */ X#ifdef lint X#undef putc X#undef getc X#define putc(c,f) (*(f)->_ptr++ = (unsigned) (c)) X#define getc(f) (*(f)->_ptr++) X#endif X X/* X * Return true iff the 10 \counts are one of the desired output pages. X */ XDesiredPageP() X{ X register struct pagelist *pl; X X for (pl = PageList; pl != NULL; pl = pl->pl_alt) { X register struct pagesel *ps = pl->pl_pages; X register int i; X register i32 *pagep; X X pagep = pl->pl_abs ? &InputPageNumber : &Count[0]; X for (i = 0; i < pl->pl_len; i++, ps++, pagep++) X if (!ps->ps_nol && *pagep < ps->ps_low || X !ps->ps_noh && *pagep > ps->ps_high) X break; /* not within bounds */ X if (i >= pl->pl_len) X return (1); /* success */ X } X return (0); X} X X/* X * Print a message to stderr, with an optional leading space, and handling X * long line wraps. X */ Xmessage(space, str, len) X int space; X register char *str; X register int len; X{ X static int beenhere; X static int col; X X if (!beenhere) X space = 0, beenhere++; X if (len == 0) X len = strlen(str); X col += len; X if (space) { X if (col >= MAXCOL) X (void) putc('\n', stderr), col = len; X else X (void) putc(' ', stderr), col++; X } X while (--len >= 0) X (void) putc(*str++, stderr); X (void) fflush(stderr); X} X X/* X * Start a page (process a DVI_BOP). X */ XBeginPage() X{ X register i32 *i; X X if (!ExpectBOP) X GripeUnexpectedOp("BOP"); X ExpectBOP = 0; X ExpectEOP++; /* set the new "expect" state */ X X OutputFontIndex = -1; /* new page requires respecifying font */ X InputPageNumber++; /* count it */ X for (i = Count; i < &Count[10]; i++) X fGetLong(inf, *i); X (void) GetLong(inf); /* previous page pointer */ X X if ((UseThisPage = DesiredPageP()) == 0) X return; X X (void) putc(DVI_BOP, outf); X for (i = Count; i < &Count[10]; i++) X PutLong(outf, *i); X PutLong(outf, StartOfLastPage); X if (ferror(outf)) X error(1, errno, writeerr); X X StartOfLastPage = CurrentPosition; X CurrentPosition += 45; /* we just wrote this much */ X X if (!SFlag) { /* write nice page usage messages */ X register int z = 0; X register int mlen = 0; X char msg[80]; X X (void) sprintf(msg, "[%d", Count[0]); X mlen = strlen(msg); X for (i = &Count[1]; i < &Count[10]; i++) { X if (*i == 0) { X z++; X continue; X } X while (--z >= 0) X msg[mlen++] = '.', msg[mlen++] = '0'; X z = 0; X (void) sprintf(msg + mlen, ".%d", *i); X mlen += strlen(msg + mlen); X } X message(1, msg, mlen); X } X} X X/* X * End a page (process a DVI_EOP). X */ XEndPage() X{ X if (!ExpectEOP) X GripeUnexpectedOp("EOP"); X ExpectEOP = 0; X ExpectBOP++; X X if (!UseThisPage) X return; X X if (!SFlag) X message(0, "]", 1); X X putc(DVI_EOP, outf); X if (ferror(outf)) X error(1, errno, writeerr); X CurrentPosition++; X NumberOfOutputPages++; X} X X/* X * For each of the fonts used in the new DVI file, write out a definition. X */ X/* ARGSUSED */ XPostAmbleFontEnumerator(addr, key) X char *addr; X i32 key; X{ X X if (((struct fontinfo *) addr)->fi_reallyused) X WriteFont((struct fontinfo *) addr); X} X XHandlePostAmble() X{ X register i32 c; X X (void) GetLong(inf); /* previous page pointer */ X if (GetLong(inf) != Numerator) X GripeMismatchedValue("numerator"); X if (GetLong(inf) != Denominator) X GripeMismatchedValue("denominator"); X if (GetLong(inf) != DVIMag) X GripeMismatchedValue("\\magfactor"); X X putc(DVI_POST, outf); X PutLong(outf, StartOfLastPage); X PutLong(outf, Numerator); X PutLong(outf, Denominator); X PutLong(outf, DVIMag); X c = GetLong(inf); X PutLong(outf, c); /* tallest page height */ X c = GetLong(inf); X PutLong(outf, c); /* widest page width */ X c = GetWord(inf); X PutWord(outf, c); /* DVI stack size */ X PutWord(outf, NumberOfOutputPages); X StartOfLastPage = CurrentPosition; /* point at post */ X CurrentPosition += 29; /* count all those `put's */ X#ifdef notdef X (void) GetWord(inf); /* skip original number of pages */ X#endif X X /* X * just ignore all the incoming font definitions; we are done with X * input file X */ X X /* X * run through the FontFinder table and dump definitions for the X * fonts we have used. X */ X SEnumerate(FontFinder, PostAmbleFontEnumerator); X X putc(DVI_POSTPOST, outf); X PutLong(outf, StartOfLastPage); /* actually start of postamble */ X putc(DVI_VERSION, outf); X putc(DVI_FILLER, outf); X putc(DVI_FILLER, outf); X putc(DVI_FILLER, outf); X putc(DVI_FILLER, outf); X CurrentPosition += 10; X while (CurrentPosition & 3) X putc(DVI_FILLER, outf), CurrentPosition++; X if (ferror(outf)) X error(1, errno, writeerr); X} X X/* X * Write a font definition to the output file X */ XWriteFont(fi) X register struct fontinfo *fi; X{ X register int l; X register char *s; X X if (fi->fi_newindex < 256) { X putc(DVI_FNTDEF1, outf); X putc(fi->fi_newindex, outf); X CurrentPosition += 2; X } else if (fi->fi_newindex < 65536) { X putc(DVI_FNTDEF2, outf); X PutWord(outf, fi->fi_newindex); X CurrentPosition += 3; X } else if (fi->fi_newindex < 16777216) { X putc(DVI_FNTDEF3, outf); X Put3Byte(outf, fi->fi_newindex); X CurrentPosition += 4; X } else { X putc(DVI_FNTDEF4, outf); X PutLong(outf, fi->fi_newindex); X CurrentPosition += 5; X } X PutLong(outf, fi->fi_checksum); X PutLong(outf, fi->fi_mag); X PutLong(outf, fi->fi_designsize); X putc(fi->fi_n1, outf); X putc(fi->fi_n2, outf); X l = fi->fi_n1 + fi->fi_n2; X CurrentPosition += 14 + l; X s = fi->fi_name; X while (--l >= 0) X putc(*s, outf), s++; X} X X/* X * Handle the preamble. Someday we should update the comment field. X */ XHandlePreAmble() X{ X register int n, c; X X if (GetByte(inf) != Sign8(DVI_PRE)) X GripeMissingOp("PRE"); X if (GetByte(inf) != Sign8(DVI_VERSION)) X GripeMismatchedValue("DVI version number"); X Numerator = GetLong(inf); X Denominator = GetLong(inf); X DVIMag = GetLong(inf); X putc(DVI_PRE, outf); X putc(DVI_VERSION, outf); X PutLong(outf, Numerator); X PutLong(outf, Denominator); X PutLong(outf, DVIMag); X X n = UnSign8(GetByte(inf)); X CurrentPosition = 15 + n; /* well, almost */ X putc(n, outf); X while (--n >= 0) { X c = GetByte(inf); X putc(c, outf); /* never trust a macro, I always say */ X } X} X Xmain(argc, argv) X int argc; X register char **argv; X{ X register int c; X register char *s; X char *inname = NULL, *outname = NULL; X X ProgName = *argv; X setbuf(stderr, serrbuf); X X while ((c = getopt(argc, argv, "i:o:s")) != EOF) { X switch (c) { X X case 's': /* silent */ X SFlag++; X break; X X case 'i': X if (inname != NULL) X goto usage; X inname = optarg; X break; X X case 'o': X if (outname != NULL) X goto usage; X outname = optarg; X break; X X case '?': Xusage: X fprintf(stderr, "\ XUsage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n", X ProgName); X (void) fflush(stderr); X exit(1); X } X } X X while (optind < argc) { X s = argv[optind++]; X c = *s; X if (!isalpha(c) && c != '/') { X if (ParsePages(s)) X goto usage; X } else if (inname == NULL) X inname = s; X else if (outname == NULL) X outname = s; X else X goto usage; X } X if (PageList == NULL) X goto usage; X if (inname == NULL) X inf = stdin; X else if ((inf = fopen(inname, "r")) == 0) X error(1, errno, "cannot read %s", inname); X if (outname == NULL) X outf = stdout; X else if ((outf = fopen(outname, "w")) == 0) X error(1, errno, "cannot write %s", outname); X X if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0) X error(1, 0, "cannot create font finder (out of memory?)"); X X ExpectBOP++; X StartOfLastPage = -1; X HandlePreAmble(); X HandleDVIFile(); X HandlePostAmble(); X if (!SFlag) X fprintf(stderr, "\nWrote %d pages, %d bytes\n", X NumberOfOutputPages, CurrentPosition); X if (NumberOfOutputPages == 0) X exit(1); X else X exit(0); X} X Xstruct pagelist * XInstallPL(ps, n, absolute) X register struct pagesel *ps; X register int n; X int absolute; X{ X register struct pagelist *pl; X X pl = (struct pagelist *) malloc(sizeof *pl); X if (pl == NULL) X GripeOutOfMemory(sizeof *pl, "page list"); X pl->pl_alt = PageList; X PageList = pl; X pl->pl_len = n; X while (--n >= 0) X pl->pl_pages[n] = ps[n]; X pl->pl_abs = absolute; X} X X/* X * Parse a string representing a list of pages. Return 0 iff ok. As a X * side effect, the page selection(s) is (are) prepended to PageList. X */ XParsePages(s) X register char *s; X{ X register struct pagesel *ps; X register int c; /* current character */ X register i32 n; /* current numeric value */ X register int innumber; /* true => gathering a number */ X int i; /* next index in page select list */ X int range; /* true => saw a range indicator */ X int negative; /* true => number being built is negative */ X int absolute; /* true => absolute, not \count */ X struct pagesel pagesel[10]; X X#define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',') X X range = 0; X innumber = 0; X absolute = 0; X i = 0; X ps = pagesel; X /* X * Talk about ad hoc! (Not to mention convoluted.) X */ X for (;;) { X c = *s++; X if (i == 0 && !innumber && !range) { X /* nothing special going on */ X if (c == 0) X return 0; X if (white(c)) X continue; X } X if (c == '_') { X /* kludge: should be '-' for negatives */ X if (innumber || absolute) X return (-1); X innumber++; X negative = 1; X n = 0; X continue; X } X if (c == '=') { X /* absolute page */ X if (innumber || range || i > 0) X return (-1); X absolute++; X /* X * Setting innumber means that there is always X * a lower bound, but this is all right since X * `=:4' is treated as if it were `=0:4'. As X * there are no negative absolute page numbers, X * this selects pages 1:4, which is the proper X * action. X */ X innumber++; X negative = 0; X n = 0; X continue; X } X if (isdigit(c)) { X /* accumulate numeric value */ X if (!innumber) { X innumber++; X negative = 0; X n = c - '0'; X continue; X } X n *= 10; X n += negative ? '0' - c : c - '0'; X continue; X } X if (c == '-' || c == ':') { X /* here is a range */ X if (range) X return (-1); X if (innumber) { /* have a lower bound */ X ps->ps_low = n; X ps->ps_nol = 0; X } else X ps->ps_nol = 1; X range++; X innumber = 0; X continue; X } X if (c == '*') { X /* no lower bound, no upper bound */ X c = *s++; X if (innumber || range || i >= 10 || X (c && c != '.' && !white(c))) X return (-1); X ps->ps_nol = 1; X ps->ps_noh = 1; X goto finishnum; X } X if (c == 0 || c == '.' || white(c)) { X /* end of this range */ X if (i >= 10) X return (-1); X if (!innumber) { /* no upper bound */ X ps->ps_noh = 1; X if (!range) /* no lower bound either */ X ps->ps_nol = 1; X } else { /* have an upper bound */ X ps->ps_high = n; X ps->ps_noh = 0; X if (!range) { X /* no range => lower bound == upper */ X ps->ps_low = ps->ps_high; X ps->ps_nol = 0; X } X } Xfinishnum: X i++; X if (c == '.') { X if (absolute) X return (-1); X ps++; X } else { X InstallPL(pagesel, i, absolute); X ps = pagesel; X i = 0; X absolute = 0; X } X if (c == 0) X return (0); X range = 0; X innumber = 0; X continue; X } X /* illegal character */ X return (-1); X } X#undef white X} X X/* X * Handle a font definition. X */ XHandleFontDef(index) X i32 index; X{ X register struct fontinfo *fi; X register int i; X register char *s; X int def = S_CREATE | S_EXCL; X X if ((fi = (struct fontinfo *) SSearch(FontFinder, index, &def)) == 0) X if (def & S_COLL) X error(1, 0, "font %d already defined", index); X else X error(1, 0, "cannot stash font %d (out of memory?)", X index); X fi->fi_reallyused = 0; X fi->fi_checksum = GetLong(inf); X fi->fi_mag = GetLong(inf); X fi->fi_designsize = GetLong(inf); X fi->fi_n1 = UnSign8(GetByte(inf)); X fi->fi_n2 = UnSign8(GetByte(inf)); X i = fi->fi_n1 + fi->fi_n2; X if ((s = malloc((unsigned) i)) == 0) X GripeOutOfMemory(i, "font name"); X fi->fi_name = s; X while (--i >= 0) X *s++ = GetByte(inf); X} X X/* X * Handle a \special. X */ XHandleSpecial(c, l, p) X int c; X register int l; X register i32 p; X{ X register int i; X X if (UseThisPage) { X putc(c, outf); X switch (l) { X X case DPL_UNS1: X putc(p, outf); X CurrentPosition += 2; X break; X X case DPL_UNS2: X PutWord(outf, p); X CurrentPosition += 3; X break; X X case DPL_UNS3: X Put3Byte(outf, p); X CurrentPosition += 4; X break; X X case DPL_SGN4: X PutLong(outf, p); X CurrentPosition += 5; X break; X X default: X panic("HandleSpecial l=%d", l); X /* NOTREACHED */ X } X CurrentPosition += p; X while (--p >= 0) { X i = getc(inf); X putc(i, outf); X } X if (feof(inf)) X error(1, 0, "unexpected EOF"); X if (ferror(outf)) X error(1, errno, writeerr); X } else X while (--p >= 0) X (void) getc(inf); X} X XReallyUseFont() X{ X register struct fontinfo *fi; X int look = S_LOOKUP; X X fi = (struct fontinfo *) SSearch(FontFinder, CurrentFontIndex, &look); X if (fi == 0) X error(1, 0, "index %d not in font table!", CurrentFontIndex); X if (fi->fi_reallyused == 0) { X fi->fi_reallyused++; X fi->fi_newindex = NextOutputFontIndex++; X WriteFont(fi); X } X if (fi->fi_newindex != OutputFontIndex) { X PutFontSelector(fi->fi_newindex); X OutputFontIndex = fi->fi_newindex; X } X} X X/* X * Write a font selection command to the output file X */ XPutFontSelector(index) X i32 index; X{ X X if (index < 64) { X putc(index + DVI_FNTNUM0, outf); X CurrentPosition++; X } else if (index < 256) { X putc(DVI_FNT1, outf); X putc(index, outf); X CurrentPosition += 2; X } else if (index < 65536) { X putc(DVI_FNT2, outf); X PutWord(outf, index); X CurrentPosition += 3; X } else if (index < 16777216) { X putc(DVI_FNT3, outf); X Put3Byte(outf, index); X CurrentPosition += 4; X } else { X putc(DVI_FNT4, outf); X PutLong(outf, index); X CurrentPosition += 5; X } X} X X/* X * The following table describes the length (in bytes) of each of the DVI X * commands that we can simply copy, starting with DVI_SET1 (128). X */ Xchar oplen[128] = { X 0, 0, 0, 0, /* DVI_SET1 .. DVI_SET4 */ X 9, /* DVI_SETRULE */ X 0, 0, 0, 0, /* DVI_PUT1 .. DVI_PUT4 */ X 9, /* DVI_PUTRULE */ X 1, /* DVI_NOP */ X 0, /* DVI_BOP */ X 0, /* DVI_EOP */ X 1, /* DVI_PUSH */ X 1, /* DVI_POP */ X 2, 3, 4, 5, /* DVI_RIGHT1 .. DVI_RIGHT4 */ X 1, /* DVI_W0 */ X 2, 3, 4, 5, /* DVI_W1 .. DVI_W4 */ X 1, /* DVI_X0 */ X 2, 3, 4, 5, /* DVI_X1 .. DVI_X4 */ X 2, 3, 4, 5, /* DVI_DOWN1 .. DVI_DOWN4 */ X 1, /* DVI_Y0 */ X 2, 3, 4, 5, /* DVI_Y1 .. DVI_Y4 */ X 1, /* DVI_Z0 */ X 2, 3, 4, 5, /* DVI_Z1 .. DVI_Z4 */ X 0, /* DVI_FNTNUM0 (171) */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 172 .. 179 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 180 .. 187 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 188 .. 195 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 196 .. 203 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 204 .. 211 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 212 .. 219 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 220 .. 227 */ X 0, 0, 0, 0, 0, 0, 0, /* 228 .. 234 */ X 0, 0, 0, 0, /* DVI_FNT1 .. DVI_FNT4 */ X 0, 0, 0, 0, /* DVI_XXX1 .. DVI_XXX4 */ X 0, 0, 0, 0, /* DVI_FNTDEF1 .. DVI_FNTDEF4 */ X 0, /* DVI_PRE */ X 0, /* DVI_POST */ X 0, /* DVI_POSTPOST */ X 0, 0, 0, 0, 0, 0, /* 250 .. 255 */ X}; X X/* X * Here we read the input DVI file and write relevant pages to the X * output DVI file. We also keep track of font changes, handle font X * definitions, and perform some other housekeeping. X */ XHandleDVIFile() X{ X register int c, l; X register i32 p; X register int CurrentFontOK = 0; X X /* Only way out is via "return" statement */ X for (;;) { X c = getc(inf); /* getc() returns unsigned values */ X if (DVI_IsChar(c)) { X /* X * Copy chars, note font usage, but ignore if X * page is not interesting. X */ X if (!UseThisPage) X continue; X if (!CurrentFontOK) { X ReallyUseFont(); X CurrentFontOK++; X } X putc(c, outf); X CurrentPosition++; X continue; X } X if (DVI_IsFont(c)) { /* note font change */ X CurrentFontIndex = c - DVI_FNTNUM0; X CurrentFontOK = 0; X continue; X } X if ((l = (oplen - 128)[c]) != 0) { /* simple copy */ X if (!UseThisPage) { X while (--l > 0) X (void) getc(inf); X continue; X } X CurrentPosition += l; X putc(c, outf); X while (--l > 0) { X c = getc(inf); X putc(c, outf); X } X if (ferror(outf)) X error(1, errno, writeerr); X continue; X } X if ((l = DVI_OpLen(c)) != 0) { X /* X * Handle other generics. X * N.B.: there should only be unsigned parameters X * here (save SGN4), for commands with negative X * parameters have been taken care of above. X */ X switch (l) { X X case DPL_UNS1: X p = getc(inf); X break; X X case DPL_UNS2: X fGetWord(inf, p); X break; X X case DPL_UNS3: X fGet3Byte(inf, p); X break; X X case DPL_SGN4: X fGetLong(inf, p); X break; X X default: X panic("HandleDVIFile l=%d", l); X } X X /* X * Now that we have the parameter, perform the X * command. X */ X switch (DVI_DT(c)) { X X case DT_SET: X case DT_PUT: X if (!UseThisPage) X continue; X if (!CurrentFontOK) { X ReallyUseFont(); X CurrentFontOK++; X } X putc(c, outf); X switch (l) { X X case DPL_UNS1: X putc(p, outf); X CurrentPosition += 2; X continue; X X case DPL_UNS2: X PutWord(outf, p); X CurrentPosition += 3; X continue; X X case DPL_UNS3: X Put3Byte(outf, p); X CurrentPosition += 4; X continue; X X case DPL_SGN4: X PutLong(outf, p); X CurrentPosition += 5; X continue; X } X X case DT_FNT: X CurrentFontIndex = p; X CurrentFontOK = 0; X continue; X X case DT_XXX: X HandleSpecial(c, l, p); X continue; X X case DT_FNTDEF: X HandleFontDef(p); X continue; X X default: X panic("HandleDVIFile DVI_DT(%d)=%d", X c, DVI_DT(c)); X } X continue; X } X X switch (c) { /* handle the few remaining cases */ X X case DVI_BOP: X BeginPage(); X CurrentFontOK = 0; X break; X X case DVI_EOP: X EndPage(); X break; X X case DVI_PRE: X GripeUnexpectedOp("PRE"); X /* NOTREACHED */ X X case DVI_POST: X return; X X case DVI_POSTPOST: X GripeUnexpectedOp("POSTPOST"); X /* NOTREACHED */ X X default: X GripeUndefinedOp(c); X /* NOTREACHED */ X } X } X} END_OF_dviselect.c if test 22215 -ne `wc -c dviselect.c.orig <<'END_OF_dviselect.c.orig' X/* X * Copyright (c) 1987 University of Maryland Department of Computer Science. X * All rights reserved. Permission to copy for any purpose is hereby granted X * so long as this copyright notice remains intact. X */ X X#ifndef lint Xstatic char rcsid[] = "$Header: /home/reed/grunwald/Projects/Iptex/utilities/RCS/dviselect.c,v 1.3 87/12/06 12:27:33 grunwald Exp $"; X#endif X X/* X * DVI page selection program X * X * Reads DVI version 2 files and selects pages, writing a new DVI X * file. The new DVI file is technically correct, though we do not X * adjust the tallest and widest page values, nor the DVI stack size. X * This is all right since the values will never become too small, X * but it might be nice to fix them up. Perhaps someday . . . . X */ X X#include "types.h" X#include "dvi.h" X#include "dviclass.h" X#include "dvicodes.h" X#include "fio.h" X#include "search.h" X#include X#include X Xchar *ProgName; Xextern int errno; Xextern char *optarg; Xextern int optind; X X/* Globals */ Xchar serrbuf[BUFSIZ]; /* buffer for stderr */ X X/* X * We will try to keep output lines shorter than MAXCOL characters. X */ X#define MAXCOL 75 X X/* X * We use the following structure to keep track of fonts we have seen. X * The final DVI file lists only the fonts it uses. X */ Xstruct fontinfo { X i32 fi_newindex; /* font number in output file */ X int fi_reallyused; /* true => used on a page we copied */ X i32 fi_checksum; /* the checksum */ X i32 fi_mag; /* the magnification */ X i32 fi_designsize; /* the design size */ X short fi_n1; /* the name header length */ X short fi_n2; /* the name body length */ X char *fi_name; /* the name itself */ X}; X X/* X * We need to remember which pages the user would like. We build a linked X * list that allows us to decide (for any given page) whether it should X * be included in the output file. Each page has ten \count variables X * associated with it. We put a bound on the values allowed for each, and X * keep a linked list of alternatives should any be outside the allowed X * range. For example, `dviselect *.3,10-15' would generate a two-element X * page list, with the first allowing any value for \count0 (and \counts 2 to X * 9) but \count1 restricted to the range 3-3, and the second restricting X * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained. X * X * In case no bound is specified, the `nol' or `noh' flag is set (so that X * we need not fix some `large' number as a maximum value). X * X * We also allow `absolute' page references, where the first page is X * page 1, the second 2, and so forth. These are specified with an X * equal sign: `dviselect =4:10' picks up the fourth through tenth X * sequential pages, irrespective of \count values. X */ Xstruct pagesel { X i32 ps_low; /* lower bound */ X int ps_nol; /* true iff no lower bound */ X i32 ps_high; /* upper bound */ X int ps_noh; /* true iff no upper bound */ X}; Xstruct pagelist { X struct pagelist *pl_alt; /* next in a series of alternates */ X int pl_len; /* number of ranges to check */ X int pl_abs; /* true iff absolute page ref */ X struct pagesel pl_pages[10]; /* one for each \count variable */ X}; X Xint SFlag; /* true => -s, silent operation */ X Xstruct search *FontFinder; /* maps from input indicies to fontinfo */ Xi32 NextOutputFontIndex; /* generates output indicies */ Xi32 CurrentFontIndex; /* current (old) index in input */ Xi32 OutputFontIndex; /* current (new) index in ouput */ X Xstruct pagelist *PageList; /* the list of allowed pages */ X XFILE *inf; /* the input DVI file */ XFILE *outf; /* the output DVI file */ X Xint ExpectBOP; /* true => BOP ok */ Xint ExpectEOP; /* true => EOP ok */ X Xlong StartOfLastPage; /* The file position just before we started X the last page (this is later written to X the output file as the previous page X pointer). */ Xlong CurrentPosition; /* The current position of the file */ X Xint UseThisPage; /* true => current page is selected */ X Xi32 InputPageNumber; /* current absolute page in old DVI file */ Xint NumberOfOutputPages; /* number of pages in new DVI file */ X Xi32 Numerator; /* numerator from DVI file */ Xi32 Denominator; /* denominator from DVI file */ Xi32 DVIMag; /* magnification from DVI file */ X Xi32 Count[10]; /* the 10 \count variables */ X X/* save some string space: we use this a lot */ Xchar writeerr[] = "error writing DVI file"; X Xchar *malloc(), *realloc(), *sprintf(); X X/* X * lint gets rather confused with the current definitions of getc and putc, X * so we redefine them here (#if lint). This should really be in the X * standard I/O library, but I am not about to go change it now! X */ X#ifdef lint X#undef putc X#undef getc X#define putc(c,f) (*(f)->_ptr++ = (unsigned) (c)) X#define getc(f) (*(f)->_ptr++) X#endif X X/* X * Return true iff the 10 \counts are one of the desired output pages. X */ XDesiredPageP() X{ X register struct pagelist *pl; X X for (pl = PageList; pl != NULL; pl = pl->pl_alt) { X register struct pagesel *ps = pl->pl_pages; X register int i; X register i32 *pagep; X X pagep = pl->pl_abs ? &InputPageNumber : &Count[0]; X for (i = 0; i < pl->pl_len; i++, ps++, pagep++) X if (!ps->ps_nol && *pagep < ps->ps_low || X !ps->ps_noh && *pagep > ps->ps_high) X break; /* not within bounds */ X if (i >= pl->pl_len) X return (1); /* success */ X } X return (0); X} X X/* X * Print a message to stderr, with an optional leading space, and handling X * long line wraps. X */ Xmessage(space, str, len) X int space; X register char *str; X register int len; X{ X static int beenhere; X static int col; X X if (!beenhere) X space = 0, beenhere++; X if (len == 0) X len = strlen(str); X col += len; X if (space) { X if (col >= MAXCOL) X (void) putc('\n', stderr), col = len; X else X (void) putc(' ', stderr), col++; X } X while (--len >= 0) X (void) putc(*str++, stderr); X (void) fflush(stderr); X} X X/* X * Start a page (process a DVI_BOP). X */ XBeginPage() X{ X register i32 *i; X X if (!ExpectBOP) X GripeUnexpectedOp("BOP"); X ExpectBOP = 0; X ExpectEOP++; /* set the new "expect" state */ X X OutputFontIndex = -1; /* new page requires respecifying font */ X InputPageNumber++; /* count it */ X for (i = Count; i < &Count[10]; i++) X fGetLong(inf, *i); X (void) GetLong(inf); /* previous page pointer */ X X if ((UseThisPage = DesiredPageP()) == 0) X return; X X (void) putc(DVI_BOP, outf); X for (i = Count; i < &Count[10]; i++) X PutLong(outf, *i); X PutLong(outf, StartOfLastPage); X if (ferror(outf)) X error(1, errno, writeerr); X X StartOfLastPage = CurrentPosition; X CurrentPosition += 45; /* we just wrote this much */ X X if (!SFlag) { /* write nice page usage messages */ X register int z = 0; X register int mlen = 0; X char msg[80]; X X (void) sprintf(msg, "[%d", Count[0]); X mlen = strlen(msg); X for (i = &Count[1]; i < &Count[10]; i++) { X if (*i == 0) { X z++; X continue; X } X while (--z >= 0) X msg[mlen++] = '.', msg[mlen++] = '0'; X z = 0; X (void) sprintf(msg + mlen, ".%d", *i); X mlen += strlen(msg + mlen); X } X message(1, msg, mlen); X } X} X X/* X * End a page (process a DVI_EOP). X */ XEndPage() X{ X if (!ExpectEOP) X GripeUnexpectedOp("EOP"); X ExpectEOP = 0; X ExpectBOP++; X X if (!UseThisPage) X return; X X if (!SFlag) X message(0, "]", 1); X X putc(DVI_EOP, outf); X if (ferror(outf)) X error(1, errno, writeerr); X CurrentPosition++; X NumberOfOutputPages++; X} X X/* X * For each of the fonts used in the new DVI file, write out a definition. X */ X/* ARGSUSED */ XPostAmbleFontEnumerator(addr, key) X char *addr; X i32 key; X{ X X if (((struct fontinfo *) addr)->fi_reallyused) X WriteFont((struct fontinfo *) addr); X} X XHandlePostAmble() X{ X register i32 c; X X (void) GetLong(inf); /* previous page pointer */ X if (GetLong(inf) != Numerator) X GripeMismatchedValue("numerator"); X if (GetLong(inf) != Denominator) X GripeMismatchedValue("denominator"); X if (GetLong(inf) != DVIMag) X GripeMismatchedValue("\\magfactor"); X X putc(DVI_POST, outf); X PutLong(outf, StartOfLastPage); X PutLong(outf, Numerator); X PutLong(outf, Denominator); X PutLong(outf, DVIMag); X c = GetLong(inf); X PutLong(outf, c); /* tallest page height */ X c = GetLong(inf); X PutLong(outf, c); /* widest page width */ X c = GetWord(inf); X PutWord(outf, c); /* DVI stack size */ X PutWord(outf, NumberOfOutputPages); X StartOfLastPage = CurrentPosition; /* point at post */ X CurrentPosition += 29; /* count all those `put's */ X#ifdef notdef X (void) GetWord(inf); /* skip original number of pages */ X#endif X X /* X * just ignore all the incoming font definitions; we are done with X * input file X */ X X /* X * run through the FontFinder table and dump definitions for the X * fonts we have used. X */ X SEnumerate(FontFinder, PostAmbleFontEnumerator); X X putc(DVI_POSTPOST, outf); X PutLong(outf, StartOfLastPage); /* actually start of postamble */ X putc(DVI_VERSION, outf); X putc(DVI_FILLER, outf); X putc(DVI_FILLER, outf); X putc(DVI_FILLER, outf); X putc(DVI_FILLER, outf); X CurrentPosition += 10; X while (CurrentPosition & 3) X putc(DVI_FILLER, outf), CurrentPosition++; X if (ferror(outf)) X error(1, errno, writeerr); X} X X/* X * Write a font definition to the output file X */ XWriteFont(fi) X register struct fontinfo *fi; X{ X register int l; X register char *s; X X if (fi->fi_newindex < 256) { X putc(DVI_FNTDEF1, outf); X putc(fi->fi_newindex, outf); X CurrentPosition += 2; X } else if (fi->fi_newindex < 65536) { X putc(DVI_FNTDEF2, outf); X PutWord(outf, fi->fi_newindex); X CurrentPosition += 3; X } else if (fi->fi_newindex < 16777216) { X putc(DVI_FNTDEF3, outf); X Put3Byte(outf, fi->fi_newindex); X CurrentPosition += 4; X } else { X putc(DVI_FNTDEF4, outf); X PutLong(outf, fi->fi_newindex); X CurrentPosition += 5; X } X PutLong(outf, fi->fi_checksum); X PutLong(outf, fi->fi_mag); X PutLong(outf, fi->fi_designsize); X putc(fi->fi_n1, outf); X putc(fi->fi_n2, outf); X l = fi->fi_n1 + fi->fi_n2; X CurrentPosition += 14 + l; X s = fi->fi_name; X while (--l >= 0) X putc(*s, outf), s++; X} X X/* X * Handle the preamble. Someday we should update the comment field. X */ XHandlePreAmble() X{ X register int n, c; X X if (GetByte(inf) != Sign8(DVI_PRE)) X GripeMissingOp("PRE"); X if (GetByte(inf) != Sign8(DVI_VERSION)) X GripeMismatchedValue("DVI version number"); X Numerator = GetLong(inf); X Denominator = GetLong(inf); X DVIMag = GetLong(inf); X putc(DVI_PRE, outf); X putc(DVI_VERSION, outf); X PutLong(outf, Numerator); X PutLong(outf, Denominator); X PutLong(outf, DVIMag); X X n = UnSign8(GetByte(inf)); X CurrentPosition = 15 + n; /* well, almost */ X putc(n, outf); X while (--n >= 0) { X c = GetByte(inf); X putc(c, outf); /* never trust a macro, I always say */ X } X} X Xmain(argc, argv) X int argc; X register char **argv; X{ X register int c; X register char *s; X char *inname = NULL, *outname = NULL; X X ProgName = *argv; X setbuf(stderr, serrbuf); X X while ((c = getopt(argc, argv, "i:o:s")) != EOF) { X switch (c) { X X case 's': /* silent */ X SFlag++; X break; X X case 'i': X if (inname != NULL) X goto usage; X inname = optarg; X break; X X case 'o': X if (outname != NULL) X goto usage; X outname = optarg; X break; X X case '?': Xusage: X fprintf(stderr, "\ XUsage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n", X ProgName); X (void) fflush(stderr); X exit(1); X } X } X X while (optind < argc) { X s = argv[optind++]; X c = *s; X if (!isalpha(c) && c != '/') { X if (ParsePages(s)) X goto usage; X } else if (inname == NULL) X inname = s; X else if (outname == NULL) X outname = s; X else X goto usage; X } X if (PageList == NULL) X goto usage; X if (inname == NULL) X inf = stdin; X else if ((inf = fopen(inname, "r")) == 0) X error(1, errno, "cannot read %s", inname); X if (outname == NULL) X outf = stdout; X else if ((outf = fopen(outname, "w")) == 0) X error(1, errno, "cannot write %s", outname); X X if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0) X error(1, 0, "cannot create font finder (out of memory?)"); X X ExpectBOP++; X StartOfLastPage = -1; X HandlePreAmble(); X HandleDVIFile(); X HandlePostAmble(); X if (!SFlag) X fprintf(stderr, "\nWrote %d pages, %d bytes\n", X NumberOfOutputPages, CurrentPosition); X exit(0); X} X Xstruct pagelist * XInstallPL(ps, n, absolute) X register struct pagesel *ps; X register int n; X int absolute; X{ X register struct pagelist *pl; X X pl = (struct pagelist *) malloc(sizeof *pl); X if (pl == NULL) X GripeOutOfMemory(sizeof *pl, "page list"); X pl->pl_alt = PageList; X PageList = pl; X pl->pl_len = n; X while (--n >= 0) X pl->pl_pages[n] = ps[n]; X pl->pl_abs = absolute; X} X X/* X * Parse a string representing a list of pages. Return 0 iff ok. As a X * side effect, the page selection(s) is (are) prepended to PageList. X */ XParsePages(s) X register char *s; X{ X register struct pagesel *ps; X register int c; /* current character */ X register i32 n; /* current numeric value */ X register int innumber; /* true => gathering a number */ X int i; /* next index in page select list */ X int range; /* true => saw a range indicator */ X int negative; /* true => number being built is negative */ X int absolute; /* true => absolute, not \count */ X struct pagesel pagesel[10]; X X#define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',') X X range = 0; X innumber = 0; X absolute = 0; X i = 0; X ps = pagesel; X /* X * Talk about ad hoc! (Not to mention convoluted.) X */ X for (;;) { X c = *s++; X if (i == 0 && !innumber && !range) { X /* nothing special going on */ X if (c == 0) X return 0; X if (white(c)) X continue; X } X if (c == '_') { X /* kludge: should be '-' for negatives */ X if (innumber || absolute) X return (-1); X innumber++; X negative = 1; X n = 0; X continue; X } X if (c == '=') { X /* absolute page */ X if (innumber || range || i > 0) X return (-1); X absolute++; X /* X * Setting innumber means that there is always X * a lower bound, but this is all right since X * `=:4' is treated as if it were `=0:4'. As X * there are no negative absolute page numbers, X * this selects pages 1:4, which is the proper X * action. X */ X innumber++; X negative = 0; X n = 0; X continue; X } X if (isdigit(c)) { X /* accumulate numeric value */ X if (!innumber) { X innumber++; X negative = 0; X n = c - '0'; X continue; X } X n *= 10; X n += negative ? '0' - c : c - '0'; X continue; X } X if (c == '-' || c == ':') { X /* here is a range */ X if (range) X return (-1); X if (innumber) { /* have a lower bound */ X ps->ps_low = n; X ps->ps_nol = 0; X } else X ps->ps_nol = 1; X range++; X innumber = 0; X continue; X } X if (c == '*') { X /* no lower bound, no upper bound */ X c = *s++; X if (innumber || range || i >= 10 || X (c && c != '.' && !white(c))) X return (-1); X ps->ps_nol = 1; X ps->ps_noh = 1; X goto finishnum; X } X if (c == 0 || c == '.' || white(c)) { X /* end of this range */ X if (i >= 10) X return (-1); X if (!innumber) { /* no upper bound */ X ps->ps_noh = 1; X if (!range) /* no lower bound either */ X ps->ps_nol = 1; X } else { /* have an upper bound */ X ps->ps_high = n; X ps->ps_noh = 0; X if (!range) { X /* no range => lower bound == upper */ X ps->ps_low = ps->ps_high; X ps->ps_nol = 0; X } X } Xfinishnum: X i++; X if (c == '.') { X if (absolute) X return (-1); X ps++; X } else { X InstallPL(pagesel, i, absolute); X ps = pagesel; X i = 0; X absolute = 0; X } X if (c == 0) X return (0); X range = 0; X innumber = 0; X continue; X } X /* illegal character */ X return (-1); X } X#undef white X} X X/* X * Handle a font definition. X */ XHandleFontDef(index) X i32 index; X{ X register struct fontinfo *fi; X register int i; X register char *s; X int def = S_CREATE | S_EXCL; X X if ((fi = (struct fontinfo *) SSearch(FontFinder, index, &def)) == 0) X if (def & S_COLL) X error(1, 0, "font %d already defined", index); X else X error(1, 0, "cannot stash font %d (out of memory?)", X index); X fi->fi_reallyused = 0; X fi->fi_checksum = GetLong(inf); X fi->fi_mag = GetLong(inf); X fi->fi_designsize = GetLong(inf); X fi->fi_n1 = UnSign8(GetByte(inf)); X fi->fi_n2 = UnSign8(GetByte(inf)); X i = fi->fi_n1 + fi->fi_n2; X if ((s = malloc((unsigned) i)) == 0) X GripeOutOfMemory(i, "font name"); X fi->fi_name = s; X while (--i >= 0) X *s++ = GetByte(inf); X} X X/* X * Handle a \special. X */ XHandleSpecial(c, l, p) X int c; X register int l; X register i32 p; X{ X register int i; X X if (UseThisPage) { X putc(c, outf); X switch (l) { X X case DPL_UNS1: X putc(p, outf); X CurrentPosition += 2; X break; X X case DPL_UNS2: X PutWord(outf, p); X CurrentPosition += 3; X break; X X case DPL_UNS3: X Put3Byte(outf, p); X CurrentPosition += 4; X break; X X case DPL_SGN4: X PutLong(outf, p); X CurrentPosition += 5; X break; X X default: X panic("HandleSpecial l=%d", l); X /* NOTREACHED */ X } X CurrentPosition += p; X while (--p >= 0) { X i = getc(inf); X putc(i, outf); X } X if (feof(inf)) X error(1, 0, "unexpected EOF"); X if (ferror(outf)) X error(1, errno, writeerr); X } else X while (--p >= 0) X (void) getc(inf); X} X XReallyUseFont() X{ X register struct fontinfo *fi; X int look = S_LOOKUP; X X fi = (struct fontinfo *) SSearch(FontFinder, CurrentFontIndex, &look); X if (fi == 0) X error(1, 0, "index %d not in font table!", CurrentFontIndex); X if (fi->fi_reallyused == 0) { X fi->fi_reallyused++; X fi->fi_newindex = NextOutputFontIndex++; X WriteFont(fi); X } X if (fi->fi_newindex != OutputFontIndex) { X PutFontSelector(fi->fi_newindex); X OutputFontIndex = fi->fi_newindex; X } X} X X/* X * Write a font selection command to the output file X */ XPutFontSelector(index) X i32 index; X{ X X if (index < 64) { X putc(index + DVI_FNTNUM0, outf); X CurrentPosition++; X } else if (index < 256) { X putc(DVI_FNT1, outf); X putc(index, outf); X CurrentPosition += 2; X } else if (index < 65536) { X putc(DVI_FNT2, outf); X PutWord(outf, index); X CurrentPosition += 3; X } else if (index < 16777216) { X putc(DVI_FNT3, outf); X Put3Byte(outf, index); X CurrentPosition += 4; X } else { X putc(DVI_FNT4, outf); X PutLong(outf, index); X CurrentPosition += 5; X } X} X X/* X * The following table describes the length (in bytes) of each of the DVI X * commands that we can simply copy, starting with DVI_SET1 (128). X */ Xchar oplen[128] = { X 0, 0, 0, 0, /* DVI_SET1 .. DVI_SET4 */ X 9, /* DVI_SETRULE */ X 0, 0, 0, 0, /* DVI_PUT1 .. DVI_PUT4 */ X 9, /* DVI_PUTRULE */ X 1, /* DVI_NOP */ X 0, /* DVI_BOP */ X 0, /* DVI_EOP */ X 1, /* DVI_PUSH */ X 1, /* DVI_POP */ X 2, 3, 4, 5, /* DVI_RIGHT1 .. DVI_RIGHT4 */ X 1, /* DVI_W0 */ X 2, 3, 4, 5, /* DVI_W1 .. DVI_W4 */ X 1, /* DVI_X0 */ X 2, 3, 4, 5, /* DVI_X1 .. DVI_X4 */ X 2, 3, 4, 5, /* DVI_DOWN1 .. DVI_DOWN4 */ X 1, /* DVI_Y0 */ X 2, 3, 4, 5, /* DVI_Y1 .. DVI_Y4 */ X 1, /* DVI_Z0 */ X 2, 3, 4, 5, /* DVI_Z1 .. DVI_Z4 */ X 0, /* DVI_FNTNUM0 (171) */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 172 .. 179 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 180 .. 187 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 188 .. 195 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 196 .. 203 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 204 .. 211 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 212 .. 219 */ X 0, 0, 0, 0, 0, 0, 0, 0, /* 220 .. 227 */ X 0, 0, 0, 0, 0, 0, 0, /* 228 .. 234 */ X 0, 0, 0, 0, /* DVI_FNT1 .. DVI_FNT4 */ X 0, 0, 0, 0, /* DVI_XXX1 .. DVI_XXX4 */ X 0, 0, 0, 0, /* DVI_FNTDEF1 .. DVI_FNTDEF4 */ X 0, /* DVI_PRE */ X 0, /* DVI_POST */ X 0, /* DVI_POSTPOST */ X 0, 0, 0, 0, 0, 0, /* 250 .. 255 */ X}; X X/* X * Here we read the input DVI file and write relevant pages to the X * output DVI file. We also keep track of font changes, handle font X * definitions, and perform some other housekeeping. X */ XHandleDVIFile() X{ X register int c, l; X register i32 p; X register int CurrentFontOK = 0; X X /* Only way out is via "return" statement */ X for (;;) { X c = getc(inf); /* getc() returns unsigned values */ X if (DVI_IsChar(c)) { X /* X * Copy chars, note font usage, but ignore if X * page is not interesting. X */ X if (!UseThisPage) X continue; X if (!CurrentFontOK) { X ReallyUseFont(); X CurrentFontOK++; X } X putc(c, outf); X CurrentPosition++; X continue; X } X if (DVI_IsFont(c)) { /* note font change */ X CurrentFontIndex = c - DVI_FNTNUM0; X CurrentFontOK = 0; X continue; X } X if ((l = (oplen - 128)[c]) != 0) { /* simple copy */ X if (!UseThisPage) { X while (--l > 0) X (void) getc(inf); X continue; X } X CurrentPosition += l; X putc(c, outf); X while (--l > 0) { X c = getc(inf); X putc(c, outf); X } X if (ferror(outf)) X error(1, errno, writeerr); X continue; X } X if ((l = DVI_OpLen(c)) != 0) { X /* X * Handle other generics. X * N.B.: there should only be unsigned parameters X * here (save SGN4), for commands with negative X * parameters have been taken care of above. X */ X switch (l) { X X case DPL_UNS1: X p = getc(inf); X break; X X case DPL_UNS2: X fGetWord(inf, p); X break; X X case DPL_UNS3: X fGet3Byte(inf, p); X break; X X case DPL_SGN4: X fGetLong(inf, p); X break; X X default: X panic("HandleDVIFile l=%d", l); X } X X /* X * Now that we have the parameter, perform the X * command. X */ X switch (DVI_DT(c)) { X X case DT_SET: X case DT_PUT: X if (!UseThisPage) X continue; X if (!CurrentFontOK) { X ReallyUseFont(); X CurrentFontOK++; X } X putc(c, outf); X switch (l) { X X case DPL_UNS1: X putc(p, outf); X CurrentPosition += 2; X continue; X X case DPL_UNS2: X PutWord(outf, p); X CurrentPosition += 3; X continue; X X case DPL_UNS3: X Put3Byte(outf, p); X CurrentPosition += 4; X continue; X X case DPL_SGN4: X PutLong(outf, p); X CurrentPosition += 5; X continue; X } X X case DT_FNT: X CurrentFontIndex = p; X CurrentFontOK = 0; X continue; X X case DT_XXX: X HandleSpecial(c, l, p); X continue; X X case DT_FNTDEF: X HandleFontDef(p); X continue; X X default: X panic("HandleDVIFile DVI_DT(%d)=%d", X c, DVI_DT(c)); X } X continue; X } X X switch (c) { /* handle the few remaining cases */ X X case DVI_BOP: X BeginPage(); X CurrentFontOK = 0; X break; X X case DVI_EOP: X EndPage(); X break; X X case DVI_PRE: X GripeUnexpectedOp("PRE"); X /* NOTREACHED */ X X case DVI_POST: X return; X X case DVI_POSTPOST: X GripeUnexpectedOp("POSTPOST"); X /* NOTREACHED */ X X default: X GripeUndefinedOp(c); X /* NOTREACHED */ X } X } X} END_OF_dviselect.c.orig if test 22164 -ne `wc -c