summaryrefslogtreecommitdiff
path: root/Build/source/texk/seetexk/dviselect.c
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-17 21:41:51 +0000
committerKarl Berry <karl@freefriends.org>2006-01-17 21:41:51 +0000
commit487ca4806cc046076293cf6cc5fbba0db282bac7 (patch)
tree847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/seetexk/dviselect.c
parenta3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff)
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/seetexk/dviselect.c')
-rw-r--r--Build/source/texk/seetexk/dviselect.c1088
1 files changed, 1088 insertions, 0 deletions
diff --git a/Build/source/texk/seetexk/dviselect.c b/Build/source/texk/seetexk/dviselect.c
new file mode 100644
index 00000000000..1d9296cca6c
--- /dev/null
+++ b/Build/source/texk/seetexk/dviselect.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (c) 1987, 1989 University of Maryland
+ * Department of Computer Science. All rights reserved.
+ * Permission to copy for any purpose is hereby granted
+ * so long as this copyright notice remains intact.
+ */
+
+#ifndef lint
+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 $";
+#endif
+
+/*
+ * DVI page selection program
+ *
+ * Reads DVI version 2 files and selects pages, writing a new DVI
+ * file. The new DVI file is technically correct, though we do not
+ * adjust the tallest and widest page values, nor the DVI stack size.
+ * This is all right since the values will never become too small,
+ * but it might be nice to fix them up. Perhaps someday . . . .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef KPATHSEA
+#include <kpathsea/c-fopen.h>
+#include <kpathsea/getopt.h>
+#else
+#define FOPEN_RBIN_MODE "rb"
+#define FOPEN_RBIN_MODE "wb"
+#define SET_BINARY(x)
+extern char *optarg;
+extern int optind;
+#endif
+
+#include "types.h"
+#include "dviclass.h"
+#include "dvicodes.h"
+#include "error.h"
+#include "fio.h"
+#include "gripes.h"
+#include "search.h"
+#include <stdio.h>
+#include <ctype.h>
+
+#define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
+
+char *ProgName;
+/* Globals */
+char serrbuf[BUFSIZ]; /* buffer for stderr */
+
+/*
+ * We will try to keep output lines shorter than MAXCOL characters.
+ */
+#define MAXCOL 75
+
+/*
+ * We use the following structure to keep track of fonts we have seen.
+ * The final DVI file lists only the fonts it uses.
+ */
+struct fontinfo {
+ i32 fi_newindex; /* font number in output file */
+ int fi_reallyused; /* true => used on a page we copied */
+ i32 fi_checksum; /* the checksum */
+ i32 fi_mag; /* the magnification */
+ i32 fi_designsize; /* the design size */
+ short fi_n1; /* the name header length */
+ short fi_n2; /* the name body length */
+ char *fi_name; /* the name itself */
+};
+
+/*
+ * We need to remember which pages the user would like. We build a linked
+ * list that allows us to decide (for any given page) whether it should
+ * be included in the output file. Each page has ten \count variables
+ * associated with it. We put a bound on the values allowed for each, and
+ * keep a linked list of alternatives should any be outside the allowed
+ * range. For example, `dviselect *.3,10-15' would generate a two-element
+ * page list, with the first allowing any value for \count0 (and \counts 2 to
+ * 9) but \count1 restricted to the range 3-3, and the second restricting
+ * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained.
+ *
+ * We remember whether a bound is specified, so that we need not fix
+ * some `large' number as a maximum value.
+ *
+ * We also allow `absolute' page references, where the first page is
+ * page 1, the second 2, and so forth. These are specified with an
+ * equal sign: `dviselect =4:10' picks up the fourth through tenth
+ * sequential pages, irrespective of \count values.
+ *
+ * There is also an even/odd switch (which can be applied to absolute
+ * or relative pages): dviselect =even, even.3, etc.
+ */
+enum pstype {
+ pt_lu, /* have both lower and upper bounds */
+ pt_l, /* lower bound only */
+ pt_u, /* upper bound only */
+ pt_unbounded, /* any value at all */
+ pt_even, /* even values only */
+ pt_odd /* odd values only */
+};
+struct pagesel {
+ enum pstype ps_type; /* type of selector */
+ i32 ps_low; /* lower bound */
+ i32 ps_high; /* upper bound */
+};
+struct pagelist {
+ struct pagelist *pl_alt; /* next in a series of alternates */
+ int pl_len; /* number of ranges to check */
+ int pl_abs; /* true iff absolute page ref */
+ struct pagesel pl_pages[10]; /* one for each \count variable */
+};
+
+int SFlag; /* true => -s, silent operation */
+
+struct search *FontFinder; /* maps from input indicies to fontinfo */
+i32 NextOutputFontIndex; /* generates output indicies */
+i32 CurrentFontIndex; /* current (old) index in input */
+i32 OutputFontIndex; /* current (new) index in ouput */
+
+struct pagelist *PageList; /* the list of allowed pages */
+
+char *DVIFileName; /* name of input DVI file */
+FILE *inf; /* the input file itself */
+FILE *outf; /* the output DVI file */
+
+long StartOfLastPage; /* The file position just before we started
+ the last page (this is later written to
+ the output file as the previous page
+ pointer). */
+long CurrentPosition; /* The current position of the file */
+
+int UseThisPage; /* true => current page is selected */
+
+i32 InputPageNumber; /* current absolute page in old DVI file */
+int NumberOfOutputPages; /* number of pages in new DVI file */
+
+i32 Numerator; /* numerator from DVI file */
+i32 Denominator; /* denominator from DVI file */
+i32 DVIMag; /* magnification from DVI file */
+
+i32 Count[10]; /* the 10 \count variables */
+
+/* save some string space: we use this a lot */
+char writeerr[] = "error writing DVI file";
+
+#ifdef NeedFunctionPrototypes
+#include <string.h>
+void WriteFont(struct fontinfo *);
+int evenodd(char *);
+int ParsePages(char *);
+void HandleDVIFile();
+void PutFontSelector(i32);
+
+#ifdef _AMIGA
+#define bcmp(s1, s2, len) memcmp(s1, s2, len)
+#define bzero(s, len) memset(s, '\0', len)
+#define index(s, c) strchr(s, c)
+#endif /* _AMIGA */
+
+#ifndef KPATHSEA
+char *malloc(), *realloc();
+#endif /* not WIN32 */
+#endif
+/*
+ * You may get lint warnings about sprintf's return value.
+ * Older versions of 4BSD have `char *sprintf()'. ANSI and
+ * SysV use `int sprintf()'; so ignore the warnings.
+ */
+
+/*
+ * Lint gets somewhat confused over putc.
+ */
+#ifdef lint
+#undef putc
+#ifdef ultrix /* grr */
+#define putc(c, f) fputc((char)(c), f)
+#else
+#define putc(c, f) fputc((int)(c), f)
+#endif
+#endif
+
+/*
+ * Return true iff the 10 \counts are one of the desired output pages.
+ */
+DesiredPageP()
+{
+ register struct pagelist *pl;
+
+ for (pl = PageList; pl != NULL; pl = pl->pl_alt) {
+ register struct pagesel *ps = pl->pl_pages;
+ register int i;
+ register i32 *pagep;
+
+ pagep = pl->pl_abs ? &InputPageNumber : &Count[0];
+ for (i = 0; i < pl->pl_len; i++, ps++, pagep++) {
+ switch (ps->ps_type) {
+
+ case pt_lu: /* check upper, fall through */
+ if (*pagep > ps->ps_high)
+ goto no_good;
+ /* FALLTHROUGH */
+
+ case pt_l: /* only if not too low */
+ if (*pagep < ps->ps_low)
+ goto no_good;
+ break;
+
+ case pt_u: /* only if not too high */
+ if (*pagep > ps->ps_high)
+ goto no_good;
+ break;
+
+ case pt_unbounded:
+ break;
+
+ case pt_even: /* only if even */
+ if (*pagep & 1)
+ goto no_good;
+ break;
+
+ case pt_odd: /* only if odd */
+ if ((*pagep & 1) == 0)
+ goto no_good;
+ break;
+ }
+ }
+ return (1); /* success */
+ no_good:
+ continue;
+ }
+ return (0);
+}
+
+/*
+ * Print a message to stderr, with an optional leading space, and handling
+ * long line wraps.
+ */
+void message(space, str, len)
+ int space;
+ register char *str;
+ register int len;
+{
+ static int beenhere;
+ static int col;
+
+ if (!beenhere)
+ space = 0, beenhere++;
+ if (len == 0)
+ len = strlen(str);
+ col += len;
+ if (space) {
+ if (col >= MAXCOL)
+ (void) putc('\n', stderr), col = len;
+ else
+ (void) putc(' ', stderr), col++;
+ }
+ while (--len >= 0)
+ (void) putc(*str++, stderr);
+ (void) fflush(stderr);
+}
+
+/*
+ * Start a page (process a DVI_BOP).
+ */
+void BeginPage()
+{
+ register i32 *i;
+
+ OutputFontIndex = -1; /* new page requires respecifying font */
+ InputPageNumber++; /* count it */
+ for (i = Count; i < &Count[10]; i++)
+ fGetLong(inf, *i);
+ (void) GetLong(inf); /* previous page pointer */
+
+ if ((UseThisPage = DesiredPageP()) == 0)
+ return;
+
+ putbyte(outf, DVI_BOP);
+ for (i = Count; i < &Count[10]; i++)
+ PutLong(outf, *i);
+ PutLong(outf, StartOfLastPage);
+ if (ferror(outf))
+ error(1, -1, writeerr);
+
+ StartOfLastPage = CurrentPosition;
+ CurrentPosition += 45; /* we just wrote this much */
+
+ if (!SFlag) { /* write nice page usage messages */
+ register int z = 0;
+ register int mlen = 0;
+ char msg[80];
+
+ (void) sprintf(msg, "[%ld", (long)Count[0]);
+ mlen = strlen(msg);
+ for (i = &Count[1]; i < &Count[10]; i++) {
+ if (*i == 0) {
+ z++;
+ continue;
+ }
+ while (--z >= 0)
+ msg[mlen++] = '.', msg[mlen++] = '0';
+ z = 0;
+ (void) sprintf(msg + mlen, ".%ld", (long)*i);
+ mlen += strlen(msg + mlen);
+ }
+ message(1, msg, mlen);
+ }
+}
+
+/*
+ * End a page (process a DVI_EOP).
+ */
+void EndPage()
+{
+
+ if (!UseThisPage)
+ return;
+ if (!SFlag)
+ message(0, "]", 1);
+ putbyte(outf, DVI_EOP);
+ if (ferror(outf))
+ error(1, -1, writeerr);
+ CurrentPosition++;
+ NumberOfOutputPages++;
+}
+
+/*
+ * For each of the fonts used in the new DVI file, write out a definition.
+ */
+/* ARGSUSED */
+void
+PostAmbleFontEnumerator(addr, key)
+ char *addr;
+ i32 key;
+{
+
+ if (((struct fontinfo *)addr)->fi_reallyused)
+ WriteFont((struct fontinfo *)addr);
+}
+
+void HandlePostAmble()
+{
+ register i32 c;
+
+ (void) GetLong(inf); /* previous page pointer */
+ if (GetLong(inf) != Numerator)
+ GripeMismatchedValue("numerator");
+ if (GetLong(inf) != Denominator)
+ GripeMismatchedValue("denominator");
+ if (GetLong(inf) != DVIMag)
+ GripeMismatchedValue("\\magnification");
+
+ putbyte(outf, DVI_POST);
+ PutLong(outf, StartOfLastPage);
+ PutLong(outf, Numerator);
+ PutLong(outf, Denominator);
+ PutLong(outf, DVIMag);
+ c = GetLong(inf);
+ PutLong(outf, c); /* tallest page height */
+ c = GetLong(inf);
+ PutLong(outf, c); /* widest page width */
+ c = GetWord(inf);
+ PutWord(outf, c); /* DVI stack size */
+ PutWord(outf, NumberOfOutputPages);
+ StartOfLastPage = CurrentPosition; /* point at post */
+ CurrentPosition += 29; /* count all those `put's */
+#ifdef notdef
+ (void) GetWord(inf); /* skip original number of pages */
+#endif
+
+ /*
+ * just ignore all the incoming font definitions; we are done with
+ * input file
+ */
+
+ /*
+ * run through the FontFinder table and dump definitions for the
+ * fonts we have used.
+ */
+ SEnumerate(FontFinder, PostAmbleFontEnumerator);
+
+ putbyte(outf, DVI_POSTPOST);
+ PutLong(outf, StartOfLastPage); /* actually start of postamble */
+ putbyte(outf, DVI_VERSION);
+ putbyte(outf, DVI_FILLER);
+ putbyte(outf, DVI_FILLER);
+ putbyte(outf, DVI_FILLER);
+ putbyte(outf, DVI_FILLER);
+ CurrentPosition += 10;
+ while (CurrentPosition & 3) {
+ putbyte(outf, DVI_FILLER);
+ CurrentPosition++;
+ }
+ if (ferror(outf))
+ error(1, -1, writeerr);
+}
+
+/*
+ * Write a font definition to the output file
+ */
+void WriteFont(fi)
+ register struct fontinfo *fi;
+{
+ register int l;
+ register char *s;
+
+ if (fi->fi_newindex < 256) {
+ putbyte(outf, DVI_FNTDEF1);
+ putbyte(outf, fi->fi_newindex);
+ CurrentPosition += 2;
+ } else if (fi->fi_newindex < 65536) {
+ putbyte(outf, DVI_FNTDEF2);
+ PutWord(outf, fi->fi_newindex);
+ CurrentPosition += 3;
+ } else if (fi->fi_newindex < 16777216) {
+ putbyte(outf, DVI_FNTDEF3);
+ Put3Byte(outf, fi->fi_newindex);
+ CurrentPosition += 4;
+ } else {
+ putbyte(outf, DVI_FNTDEF4);
+ PutLong(outf, fi->fi_newindex);
+ CurrentPosition += 5;
+ }
+ PutLong(outf, fi->fi_checksum);
+ PutLong(outf, fi->fi_mag);
+ PutLong(outf, fi->fi_designsize);
+ putbyte(outf, fi->fi_n1);
+ putbyte(outf, fi->fi_n2);
+ l = fi->fi_n1 + fi->fi_n2;
+ CurrentPosition += 14 + l;
+ s = fi->fi_name;
+ while (--l >= 0)
+ putbyte(outf, *s++);
+}
+
+/*
+ * Handle the preamble. Someday we should update the comment field.
+ */
+void HandlePreAmble()
+{
+ register int n, c;
+
+ c = getc(inf);
+ if (c == EOF)
+ GripeUnexpectedDVIEOF();
+ if (c != DVI_PRE)
+ GripeMissingOp("PRE");
+ if (getc(inf) != DVI_VERSION)
+ error(1, 0, "%s is not a DVI version %d file",
+ DVIFileName, DVI_VERSION);
+ Numerator = GetLong(inf);
+ Denominator = GetLong(inf);
+ DVIMag = GetLong(inf);
+ putbyte(outf, DVI_PRE);
+ putbyte(outf, DVI_VERSION);
+ PutLong(outf, Numerator);
+ PutLong(outf, Denominator);
+ PutLong(outf, DVIMag);
+
+ n = UnSign8(GetByte(inf));
+ CurrentPosition = 15 + n; /* well, almost */
+ putbyte(outf, n);
+ while (--n >= 0) {
+ c = GetByte(inf);
+ putbyte(outf, c);
+ }
+}
+
+int
+main(argc, argv)
+ int argc;
+ register char **argv;
+{
+ register int c;
+ register char *s;
+ char *outname = NULL;
+
+ ProgName = *argv;
+ setbuf(stderr, serrbuf);
+
+ while ((c = getopt(argc, argv, "i:o:s")) != EOF) {
+ switch (c) {
+
+ case 's': /* silent */
+ SFlag++;
+ break;
+
+ case 'i':
+ if (DVIFileName != NULL)
+ goto usage;
+ DVIFileName = optarg;
+ break;
+
+ case 'o':
+ if (outname != NULL)
+ goto usage;
+ outname = optarg;
+ break;
+
+ case '?':
+usage:
+ (void) fprintf(stderr, "\
+Usage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n",
+ ProgName);
+ (void) fflush(stderr);
+ exit(1);
+ }
+ }
+
+ while (optind < argc) {
+ s = argv[optind++];
+ c = *s;
+ if (!isalpha(c) && c != '/' ||
+ (c == 'e' || c == 'o') && evenodd(s)) {
+ if (ParsePages(s))
+ goto usage;
+ } else if (DVIFileName == NULL)
+ DVIFileName = s;
+ else if (outname == NULL)
+ outname = s;
+ else
+ goto usage;
+ }
+ if (PageList == NULL)
+ goto usage;
+ if (DVIFileName == NULL) {
+ DVIFileName = "`stdin'";
+ inf = stdin;
+ if (!isatty(fileno(inf)))
+ SET_BINARY(fileno(inf));
+ } else if ((inf = fopen(DVIFileName, FOPEN_RBIN_MODE)) == 0)
+ error(1, -1, "cannot read %s", DVIFileName);
+ if (outname == NULL) {
+ outf = stdout;
+ if (!isatty(fileno(outf)))
+ SET_BINARY(fileno(outf));
+ } else if ((outf = fopen(outname, FOPEN_WBIN_MODE)) == 0)
+ error(1, -1, "cannot write %s", outname);
+
+ if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
+ error(1, 0, "cannot create font finder (out of memory?)");
+
+ StartOfLastPage = -1;
+ HandlePreAmble();
+ HandleDVIFile();
+ HandlePostAmble();
+ if (!SFlag)
+ (void) fprintf(stderr, "\nWrote %d page%s, %ld bytes\n",
+ NumberOfOutputPages, NumberOfOutputPages == 1 ? "" : "s",
+ (long)CurrentPosition);
+ return 0;
+}
+
+struct pagelist *
+InstallPL(ps, n, absolute)
+ register struct pagesel *ps;
+ register int n;
+ int absolute;
+{
+ register struct pagelist *pl;
+
+ pl = (struct pagelist *)malloc(sizeof *pl);
+ if (pl == NULL)
+ GripeOutOfMemory(sizeof *pl, "page list");
+ pl->pl_alt = PageList;
+ PageList = pl;
+ pl->pl_len = n;
+ while (--n >= 0)
+ pl->pl_pages[n] = ps[n];
+ pl->pl_abs = absolute;
+ return pl;
+}
+
+/*
+ * Return true iff the string `s' is the word `even' or `odd',
+ * followed by `.' or `white' characters.
+ */
+int
+evenodd(s)
+ char *s;
+{
+ register int c;
+
+ if (strncmp(s, "even", 4) == 0)
+ c = s[4];
+ else if (strncmp(s, "odd", 3) == 0)
+ c = s[3];
+ else
+ return (0);
+ if (c == 0 || c == '.' || white(c))
+ return (1);
+ return (0);
+}
+
+/*
+ * Parse a string representing a list of pages. Return 0 iff ok. As a
+ * side effect, the page selection(s) is (are) prepended to PageList.
+ */
+int ParsePages(s)
+ register char *s;
+{
+ register struct pagesel *ps;
+ register int c; /* current character */
+ register i32 n; /* current numeric value */
+ register int innumber; /* true => gathering a number */
+ int i; /* next index in page select list */
+ int range; /* true => saw a range indicator */
+ int negative; /* true => number being built is negative */
+ int absolute; /* true => absolute, not \count */
+ int lb, ub, even, odd; /* flags for lower,upper,even,odd */
+ struct pagesel pagesel[10];
+
+ range = 0;
+ innumber = 0;
+ absolute = 0;
+ i = 0;
+ ps = pagesel;
+ lb = ub = even = odd = 0;
+ /*
+ * Talk about ad hoc! (Not to mention convoluted.)
+ */
+ for (;;) {
+ c = *s++;
+ if (i == 0 && !innumber && !range) {
+ /* nothing special going on */
+ if (c == 0)
+ return 0;
+ if (white(c))
+ continue;
+ }
+ if ((c == 'e' || c == 'o') && evenodd(s - 1)) {
+ if (innumber || range)
+ return (-1);
+ if (c == 'e') {
+ s += 3;
+ even = 1;
+ } else {
+ s += 2;
+ odd = 1;
+ }
+ c = *s++;
+ goto finishnum;
+ }
+ if (c == '_') {
+ /* kludge: should be '-' for negatives */
+ if (innumber || absolute)
+ return (-1);
+ innumber = 1;
+ negative = 1;
+ n = 0;
+ continue;
+ }
+ if (c == '=') {
+ /* absolute page */
+ if (innumber || range || i > 0)
+ return (-1);
+ absolute = 1;
+ negative = 0;
+ n = 0;
+ continue;
+ }
+ if (isdigit(c)) {
+ /* accumulate numeric value */
+ if (!innumber) {
+ innumber = 1;
+ negative = 0;
+ n = c - '0';
+ continue;
+ }
+ n *= 10;
+ n += negative ? '0' - c : c - '0';
+ continue;
+ }
+ if (c == '-' || c == ':') {
+ /* here is a range */
+ if (range)
+ return (-1);
+ if (innumber) { /* have a lower bound */
+ ps->ps_low = n;
+ lb = 1;
+ }
+ range = 1;
+ innumber = 0;
+ continue;
+ }
+ if (c == '*') {
+ /* no lower bound, no upper bound */
+ c = *s++;
+ if (innumber || range || (c && c != '.' && !white(c)))
+ return (-1);
+ goto finishnum;
+ }
+ if (c == 0 || c == '.' || white(c)) {
+ /* end of this range */
+ if (innumber) { /* have an upper bound */
+ ps->ps_high = n;
+ ub = 1;
+ if (!range) {
+ /* no range => lower bound == upper */
+ ps->ps_low = ps->ps_high;
+ lb = 1;
+ }
+ }
+finishnum:
+ if (even)
+ ps->ps_type = pt_even;
+ else if (odd)
+ ps->ps_type = pt_odd;
+ else if (lb)
+ ps->ps_type = ub ? pt_lu : pt_l;
+ else
+ ps->ps_type = ub ? pt_u : pt_unbounded;
+ if (c == '.') {
+ if (absolute)
+ return (-1);
+ if (++i >= 10) /* too many specifiers */
+ return (-1);
+ ps++;
+ } else {
+ InstallPL(pagesel, i + 1, absolute);
+ ps = pagesel;
+ i = 0;
+ absolute = 0;
+ }
+ if (c == 0)
+ return (0);
+ range = 0;
+ innumber = 0;
+ lb = ub = even = odd = 0;
+ continue;
+ }
+ /* illegal character */
+ return (-1);
+ }
+}
+
+/*
+ * Handle a font definition.
+ */
+void HandleFontDef(index)
+ i32 index;
+{
+ register struct fontinfo *fi;
+ register int i;
+ register char *s;
+ int def = S_CREATE | S_EXCL;
+
+ if ((fi = (struct fontinfo *)SSearch(FontFinder, index, &def)) == 0)
+ if (def & S_COLL)
+ error(1, 0, "font %ld already defined", (long)index);
+ else
+ error(1, 0, "cannot stash font %ld (out of memory?)",
+ (long)index);
+ fi->fi_reallyused = 0;
+ fi->fi_checksum = GetLong(inf);
+ fi->fi_mag = GetLong(inf);
+ fi->fi_designsize = GetLong(inf);
+ fi->fi_n1 = UnSign8(GetByte(inf));
+ fi->fi_n2 = UnSign8(GetByte(inf));
+ i = fi->fi_n1 + fi->fi_n2;
+ if ((s = malloc((unsigned)i)) == 0)
+ GripeOutOfMemory(i, "font name");
+ fi->fi_name = s;
+ while (--i >= 0)
+ *s++ = GetByte(inf);
+}
+
+/*
+ * Handle a \special.
+ */
+void HandleSpecial(c, l, p)
+ int c;
+ register int l;
+ register i32 p;
+{
+ register int i;
+
+ if (UseThisPage) {
+ putbyte(outf, c);
+ switch (l) {
+
+ case DPL_UNS1:
+ putbyte(outf, p);
+ CurrentPosition += 2;
+ break;
+
+ case DPL_UNS2:
+ PutWord(outf, p);
+ CurrentPosition += 3;
+ break;
+
+ case DPL_UNS3:
+ Put3Byte(outf, p);
+ CurrentPosition += 4;
+ break;
+
+ case DPL_SGN4:
+ PutLong(outf, p);
+ CurrentPosition += 5;
+ break;
+
+ default:
+ panic("HandleSpecial l=%d", l);
+ /* NOTREACHED */
+ }
+ CurrentPosition += p;
+ while (--p >= 0) {
+ i = getc(inf);
+ putbyte(outf, i);
+ }
+ if (feof(inf))
+ GripeUnexpectedDVIEOF();
+ if (ferror(outf))
+ error(1, -1, writeerr);
+ } else
+ while (--p >= 0)
+ (void) getc(inf);
+}
+
+void ReallyUseFont()
+{
+ register struct fontinfo *fi;
+ int look = S_LOOKUP;
+
+ fi = (struct fontinfo *)SSearch(FontFinder, CurrentFontIndex, &look);
+ if (fi == NULL)
+ error(1, 0, "DVI file requested font %ld without defining it",
+ (long)CurrentFontIndex);
+ if (fi->fi_reallyused == 0) {
+ fi->fi_reallyused++;
+ fi->fi_newindex = NextOutputFontIndex++;
+ WriteFont(fi);
+ }
+ if (fi->fi_newindex != OutputFontIndex) {
+ PutFontSelector(fi->fi_newindex);
+ OutputFontIndex = fi->fi_newindex;
+ }
+}
+
+/*
+ * Write a font selection command to the output file
+ */
+void PutFontSelector(index)
+ i32 index;
+{
+
+ if (index < 64) {
+ putbyte(outf, index + DVI_FNTNUM0);
+ CurrentPosition++;
+ } else if (index < 256) {
+ putbyte(outf, DVI_FNT1);
+ putbyte(outf, index);
+ CurrentPosition += 2;
+ } else if (index < 65536) {
+ putbyte(outf, DVI_FNT2);
+ PutWord(outf, index);
+ CurrentPosition += 3;
+ } else if (index < 16777216) {
+ putbyte(outf, DVI_FNT3);
+ Put3Byte(outf, index);
+ CurrentPosition += 4;
+ } else {
+ putbyte(outf, DVI_FNT4);
+ PutLong(outf, index);
+ CurrentPosition += 5;
+ }
+}
+
+/*
+ * The following table describes the length (in bytes) of each of the DVI
+ * commands that we can simply copy, starting with DVI_SET1 (128).
+ */
+char oplen[128] = {
+ 0, 0, 0, 0, /* DVI_SET1 .. DVI_SET4 */
+ 9, /* DVI_SETRULE */
+ 0, 0, 0, 0, /* DVI_PUT1 .. DVI_PUT4 */
+ 9, /* DVI_PUTRULE */
+ 1, /* DVI_NOP */
+ 0, /* DVI_BOP */
+ 0, /* DVI_EOP */
+ 1, /* DVI_PUSH */
+ 1, /* DVI_POP */
+ 2, 3, 4, 5, /* DVI_RIGHT1 .. DVI_RIGHT4 */
+ 1, /* DVI_W0 */
+ 2, 3, 4, 5, /* DVI_W1 .. DVI_W4 */
+ 1, /* DVI_X0 */
+ 2, 3, 4, 5, /* DVI_X1 .. DVI_X4 */
+ 2, 3, 4, 5, /* DVI_DOWN1 .. DVI_DOWN4 */
+ 1, /* DVI_Y0 */
+ 2, 3, 4, 5, /* DVI_Y1 .. DVI_Y4 */
+ 1, /* DVI_Z0 */
+ 2, 3, 4, 5, /* DVI_Z1 .. DVI_Z4 */
+ 0, /* DVI_FNTNUM0 (171) */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 172 .. 179 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 180 .. 187 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 188 .. 195 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 196 .. 203 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 204 .. 211 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 212 .. 219 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 220 .. 227 */
+ 0, 0, 0, 0, 0, 0, 0, /* 228 .. 234 */
+ 0, 0, 0, 0, /* DVI_FNT1 .. DVI_FNT4 */
+ 0, 0, 0, 0, /* DVI_XXX1 .. DVI_XXX4 */
+ 0, 0, 0, 0, /* DVI_FNTDEF1 .. DVI_FNTDEF4 */
+ 0, /* DVI_PRE */
+ 0, /* DVI_POST */
+ 0, /* DVI_POSTPOST */
+ 0, 0, 0, 0, 0, 0, /* 250 .. 255 */
+};
+
+/*
+ * Here we read the input DVI file and write relevant pages to the
+ * output DVI file. We also keep track of font changes, handle font
+ * definitions, and perform some other housekeeping.
+ */
+void HandleDVIFile()
+{
+ register int c, l;
+ register i32 p;
+ register int CurrentFontOK = 0;
+ int doingpage = 0;
+
+ /* Only way out is via "return" statement */
+ for (;;) {
+ c = getc(inf); /* getc() returns unsigned values */
+ if (DVI_IsChar(c)) {
+ /*
+ * Copy chars, note font usage, but ignore if
+ * page is not interesting.
+ */
+ if (!UseThisPage)
+ continue;
+ if (!CurrentFontOK) {
+ ReallyUseFont();
+ CurrentFontOK++;
+ }
+ putbyte(outf, c);
+ CurrentPosition++;
+ continue;
+ }
+ if (DVI_IsFont(c)) { /* note font change */
+ CurrentFontIndex = c - DVI_FNTNUM0;
+ CurrentFontOK = 0;
+ continue;
+ }
+ if (c == EOF)
+ GripeUnexpectedDVIEOF();
+ if ((l = (oplen - 128)[c]) != 0) { /* simple copy */
+ if (!UseThisPage) {
+ while (--l > 0)
+ (void) getc(inf);
+ continue;
+ }
+ CurrentPosition += l;
+ putbyte(outf, c);
+ while (--l > 0) {
+ c = getc(inf);
+ putbyte(outf, c);
+ }
+ if (ferror(outf))
+ error(1, -1, writeerr);
+ continue;
+ }
+ if ((l = DVI_OpLen(c)) != 0) {
+ /*
+ * Handle other generics.
+ * N.B.: there should only be unsigned parameters
+ * here (save SGN4), for commands with negative
+ * parameters have been taken care of above.
+ */
+ switch (l) {
+
+ case DPL_UNS1:
+ p = getc(inf);
+ break;
+
+ case DPL_UNS2:
+ fGetWord(inf, p);
+ break;
+
+ case DPL_UNS3:
+ fGet3Byte(inf, p);
+ break;
+
+ case DPL_SGN4:
+ fGetLong(inf, p);
+ break;
+
+ default:
+ panic("HandleDVIFile l=%d", l);
+ }
+
+ /*
+ * Now that we have the parameter, perform the
+ * command.
+ */
+ switch (DVI_DT(c)) {
+
+ case DT_SET:
+ case DT_PUT:
+ if (!UseThisPage)
+ continue;
+ if (!CurrentFontOK) {
+ ReallyUseFont();
+ CurrentFontOK++;
+ }
+ putbyte(outf, c);
+ switch (l) {
+
+ case DPL_UNS1:
+ putbyte(outf, p);
+ CurrentPosition += 2;
+ continue;
+
+ case DPL_UNS2:
+ PutWord(outf, p);
+ CurrentPosition += 3;
+ continue;
+
+ case DPL_UNS3:
+ Put3Byte(outf, p);
+ CurrentPosition += 4;
+ continue;
+
+ case DPL_SGN4:
+ PutLong(outf, p);
+ CurrentPosition += 5;
+ continue;
+ }
+
+ case DT_FNT:
+ CurrentFontIndex = p;
+ CurrentFontOK = 0;
+ continue;
+
+ case DT_XXX:
+ HandleSpecial(c, l, p);
+ continue;
+
+ case DT_FNTDEF:
+ HandleFontDef(p);
+ continue;
+
+ default:
+ panic("HandleDVIFile DVI_DT(%d)=%d",
+ c, DVI_DT(c));
+ }
+ continue;
+ }
+
+ switch (c) { /* handle the few remaining cases */
+
+ case DVI_BOP:
+ if (doingpage)
+ GripeUnexpectedOp("BOP (during page)");
+ BeginPage();
+ doingpage = 1;
+ CurrentFontOK = 0;
+ break;
+
+ case DVI_EOP:
+ if (!doingpage)
+ GripeUnexpectedOp("EOP (outside page)");
+ EndPage();
+ doingpage = 0;
+ break;
+
+ case DVI_PRE:
+ GripeUnexpectedOp("PRE");
+ /* NOTREACHED */
+
+ case DVI_POST:
+ if (doingpage)
+ GripeUnexpectedOp("POST (inside page)");
+ return;
+
+ case DVI_POSTPOST:
+ GripeUnexpectedOp("POSTPOST");
+ /* NOTREACHED */
+
+ default:
+ GripeUndefinedOp(c);
+ /* NOTREACHED */
+ }
+ }
+}