summaryrefslogtreecommitdiff
path: root/dviware/umddvi/dev/verser1.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/umddvi/dev/verser1.c')
-rw-r--r--dviware/umddvi/dev/verser1.c1047
1 files changed, 1047 insertions, 0 deletions
diff --git a/dviware/umddvi/dev/verser1.c b/dviware/umddvi/dev/verser1.c
new file mode 100644
index 0000000000..9c8faf0bf6
--- /dev/null
+++ b/dviware/umddvi/dev/verser1.c
@@ -0,0 +1,1047 @@
+/*
+ * Copyright (c) 1987 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: verser1.c,v 2.4 87/06/16 17:14:51 chris Exp $";
+#endif
+
+/*
+ * Verser1 -- First half of DVI to Versatec driver
+ *
+ * Reads DVI version 2 files and converts to an intermediate form that
+ * is read by verser2. Most of the work consists of converting DVI units
+ * to Versatec units, sorting pages, and rotating positions if the -h
+ * flag is given.
+ *
+ * TODO:
+ * think about fonts with characters outside [0..127]
+ */
+
+#include <stdio.h>
+#include "types.h"
+#include "conv.h"
+#include "dvi.h"
+#include "dviclass.h"
+#include "dvicodes.h"
+#include "fio.h"
+#include "font.h"
+#include "postamble.h"
+#include "search.h"
+#include "verser.h"
+
+char *ProgName;
+extern char *optarg;
+extern int optind;
+
+/* Globals */
+char serrbuf[BUFSIZ]; /* buffer for stderr */
+
+/*
+ * According to DVItype, we have to plot characters using two simultaneous
+ * pieces of information: the character's TFM width modified by the scale
+ * factor from the DVI file (this is the width in scaled points), and the
+ * character's width in pixels (converted from scaled points). The former
+ * is obtained by the glyph routines; the latter we put in the g_pixwidth
+ * field of each glyph.
+ *
+ * Whenever we move horizontally by a DVI distance >= `space', we
+ * are to recompute horizontal position from DVI units; otherwise, we are to
+ * use device resolution units to keep track of horizontal position. A
+ * similar scheme must be followed for vertical positioning.
+ */
+struct fontinfo {
+ struct font *f; /* the font */
+ int index; /* our index number */
+ i32 pspace; /* boundary between `small' & `large' spaces
+ (for positive horizontal motion) */
+ i32 nspace; /* -4 * pspace, for negative motion */
+ i32 vspace; /* 5 * pspace, for vertical motion */
+};
+
+/*
+ * However, there's an exception to the rule (natch!): certain fonts
+ * tend to produce a constant "drift" away from the "correct" position
+ * which eventually builds up to an intolerable amount. So, if hh and
+ * fromSP(dvi_h) become more than MaxDrift units apart, hh must be adjusted
+ * by the smallest amount that will preserve the invariant. (The same
+ * applies to vv and dvi_v.)
+ */
+int MaxDrift; /* the maximum allowable difference between
+ hh and fromSP(dvi_h) */
+
+struct fontinfo *CurrentFont; /* the current font (if any) */
+int NextFont; /* during font definition, we assign
+ sequential indicies; verser2 knows this */
+
+struct fontinfo NoFont; /* a fake font, to help get things started */
+
+char *TeXFontDesc; /* getenv(CONFENV) */
+
+/* arrays containing page info */
+int Chars; /* number of chars {left,} on page */
+int MaxChars; /* total space for chars */
+int *yx; /* contains (y<<16|x) for each char */
+int *fcp; /* contains (font<<14|char<<7|part) */
+int *nextyx; /* pointer to next yx area */
+int *nextfcp; /* pointer to next fcp area */
+
+/*
+ * A few experiments showed that the typical job uses less than 3200
+ * characters per page. This is an extensible array, so the initial value
+ * affects only efficiency.
+ */
+#ifndef InitialChars
+#define InitialChars 4000 /* initial number of chars to allocate */
+#endif
+
+int ExpectBOP; /* true => BOP ok */
+int ExpectEOP; /* true => EOP ok */
+
+/*
+ * If there are lots of characters and rules that don't fit on a page,
+ * these flags help reduce error output.
+ */
+int TopEMsg; /* true => gave error message about top */
+int BottomEMsg; /* true => gave error message about bottom */
+int LeftEMsg; /* true => gave error message about left */
+int RightEMsg; /* true => gave error message about right */
+int RuleEMsg; /* true => gave error message about rule */
+
+int CFlag; /* -c => center output */
+int HFlag; /* -h => horizontal (sideways) output */
+int SFlag; /* -s => silent (no page #s) */
+int Debug; /* -D => debug flag */
+
+int hh; /* current horizontal position, in DEVs */
+int vv; /* current vertical position, in DEVs */
+
+/*
+ * Similar to dvi_stack, but includes `hh' and `vv', which are usually
+ * but not always the same as fromSP(h) and fromSP(v):
+ */
+struct localstack {
+ int stack_hh;
+ int stack_vv;
+ struct dvi_stack stack_dvi;
+};
+
+struct localstack *dvi_stack; /* base of stack */
+struct localstack *dvi_stackp; /* current place in stack */
+
+int BottomMargin; /* bottom margin (in DEVs) */
+int TopMargin; /* top margin (in DEVs) */
+int WidestPageWidth; /* width of widest page (in DEVs) */
+int TallestPageHeight; /* height of tallest page (in DEVs) */
+int HHMargin; /* horizontal margin (in DEVs) */
+int VVMargin; /* vertical margin (in DEVs) */
+
+i32 Numerator; /* numerator from DVI file */
+i32 Denominator; /* denominator from DVI file */
+i32 DVIMag; /* magnification from the DVI file */
+int UserMag; /* user specified magnification */
+
+struct search *FontFinder; /* maps from DVI index to internal info */
+int FontErrors; /* true => error(s) occurred during font
+ definitions from DVI postamble */
+
+char *malloc(), *realloc(), *getenv();
+
+/* Absolute value */
+#define ABS(n) ((n) >= 0 ? (n) : -(n))
+
+/* Correct devpos (the actual device position) to be within MaxDrift pixels
+ of dvipos (the virtual DVI position). */
+#define FIXDRIFT(devpos, dvipos) \
+ if (ABS((devpos) - (dvipos)) <= MaxDrift) \
+ /* void */; \
+ else \
+ if ((devpos) < (dvipos)) \
+ (devpos) = (dvipos) - MaxDrift; \
+ else \
+ (devpos) = (dvipos) + MaxDrift
+
+/*
+ * Compute the DEV widths of the characters in the given font.
+ */
+ComputeCWidths(fi)
+ struct fontinfo *fi;
+{
+ register struct font *f;
+ register struct glyph *g;
+ register int i;
+
+ f = fi->f;
+ for (i = 0; i < 128; i++) {
+ g = GLYPH(f, i);
+ if (GVALID(g))
+ g->g_pixwidth = fromSP(g->g_tfmwidth);
+ }
+}
+
+SelectFont(n)
+ i32 n;
+{
+ int x = S_LOOKUP;
+
+ if ((CurrentFont = (struct fontinfo *)SSearch(FontFinder, n, &x)) == 0)
+ error(1, 0, "font %d not in finder table", n);
+}
+
+/*
+ * Have run out of room in the current yx and fcp arrays, so expand them.
+ */
+ExpandArrays()
+{
+ register unsigned newsize;
+
+ MaxChars <<= 1;
+ newsize = MaxChars * sizeof *yx;
+ if ((yx = (int *) realloc((char *) yx, newsize)) == NULL)
+ GripeOutOfMemory(newsize, "yx array");
+ if ((fcp = (int *) realloc((char *) fcp, newsize)) == NULL)
+ GripeOutOfMemory(newsize, "fcp array");
+ Chars = MaxChars >> 1;
+ nextyx = &yx[Chars];
+ nextfcp = &fcp[Chars];
+ --Chars; /* because we're about to use one */
+}
+
+/*
+ * Sort the page arrays so that the values in yx are in ascending order. We
+ * use a Shell sort.
+ */
+SortPage()
+{
+ register int i, j, k, delta, *y, *f;
+
+ /*
+ * Chars is currently the number of chars on the page, not the number
+ * of chars left in the array.
+ */
+ y = yx;
+ f = fcp;
+ delta = 1;
+ while (9 * delta + 4 < Chars)
+ delta = 3 * delta + 1;
+ while (delta > 0) {
+ for (i = delta; i < Chars; i++) {
+ if (y[j = i - delta] > y[i]) {
+ register int t1 = y[i];
+ register int t2 = f[i];
+
+ k = i;
+ do {
+ y[k] = y[j];
+ f[k] = f[j];
+ k = j;
+ j -= delta;
+ } while (j >= 0 && y[j] > t1);
+ y[k] = t1;
+ f[k] = t2;
+ }
+ }
+ delta /= 3;
+ }
+}
+
+/*
+ * Start a page (process a DVI_BOP).
+ * NOTE: I'm depending on getting a BOP before any characters or rules on a
+ * page!
+ */
+BeginPage()
+{
+ register int *i;
+ static int count[11]; /* the 10 counters, plus the previous page
+ pointer (which we ignore anyway) */
+
+ if (!ExpectBOP)
+ GripeUnexpectedOp("BOP");
+
+ if (nextyx && !SFlag)
+ putc(' ', stderr);
+
+ /* Chars now becomes "number of characters left" */
+ Chars = MaxChars; /* empty the arrays */
+ nextyx = yx;
+ nextfcp = fcp;
+
+ dvi_stackp = dvi_stack;
+
+ ExpectBOP = 0;
+ ExpectEOP++; /* set the new "expect" state */
+
+ TopEMsg = 0;
+ BottomEMsg = 0;
+ LeftEMsg = 0;
+ RightEMsg = 0;
+ RuleEMsg = 0;
+
+ for (i = count; i < &count[sizeof count / sizeof *count]; i++)
+ fGetLong(stdin, *i);
+
+ if (!SFlag) {
+ (void) fprintf(stderr, "[%d", count[0]);
+ (void) fflush(stderr);
+ }
+ hh = HHMargin;
+ vv = VVMargin;
+ dvi_h = toSP(hh); /* `0' */
+ dvi_v = toSP(vv); /* `0' */
+ dvi_w = 0;
+ dvi_x = 0;
+ dvi_y = 0;
+ dvi_z = 0;
+}
+
+/*
+ * End a page (process a DVI_EOP).
+ */
+EndPage()
+{
+ register int i, *y, *f, t, v, oldv;
+
+ if (!ExpectEOP)
+ GripeUnexpectedOp("EOP");
+
+ /* Chars now becomes "number of characters on page" */
+ i = Chars = MaxChars - Chars;
+
+ ExpectBOP++;
+ ExpectEOP = 0; /* set the new "expect" state */
+
+ SortPage();
+
+ if (!SFlag) {
+ putc(']', stderr);
+ (void) fflush(stderr);
+ }
+ y = yx;
+ f = fcp;
+ oldv = 0;
+ while (--i >= 0) {
+ v = *y >> 16;
+ t = v - oldv;
+ if (*f >= 0) { /* setting a character */
+ t = (t << 16) | (*y++ & 0xffff);
+ PutLong(stdout, t);
+ t = *f++;
+ PutLong(stdout, t); /* move down & place char */
+ } else { /* setting a rule */
+ y++;
+ if (t > 0) { /* need to move down first */
+ t = -t;
+ PutLong(stdout, -1);
+ PutLong(stdout, t);
+ }
+ t = *f++ & 0x7fffffff;
+ PutLong(stdout, -1);
+ PutLong(stdout, t); /* place rule */
+ }
+ oldv = v;
+ }
+
+ /* Make all pages the same length */
+ if (HFlag)
+ t = -WidestPageWidth;
+ else
+ t = -TallestPageHeight;
+ t -= BottomMargin + TopMargin;
+ if (t) {
+ PutLong(stdout, -1); /* move down */
+ PutLong(stdout, t);
+ }
+ PutLong(stdout, -1);
+ PutLong(stdout, 0); /* end of page */
+}
+
+/*
+ * Store the relevant information from the DVI postamble, copying some of it
+ * to stdout for verser2, and set up variables.
+ */
+PostAmbleHeader(p)
+ register struct PostAmbleInfo *p;
+{
+ register int n;
+
+ Numerator = p->pai_Numerator;
+ Denominator = p->pai_Denominator;
+ DVIMag = p->pai_DVIMag;
+
+ /*
+ * Set the conversion factor.
+ */
+ SetConversion(200, UserMag, Numerator, Denominator, DVIMag);
+
+ TallestPageHeight = fromSP(p->pai_TallestPageHeight);
+ WidestPageWidth = fromSP(p->pai_WidestPageWidth);
+
+ n = p->pai_DVIStackSize * sizeof *dvi_stack;
+ dvi_stack = (struct localstack *) malloc((unsigned) n);
+ if ((dvi_stackp = dvi_stack) == 0)
+ GripeOutOfMemory(n, "DVI stack");
+
+ /* verser2 needs to set the conversion factor too */
+ PutLong(stdout, 200); /* keep raster density knowledge all here */
+ PutLong(stdout, UserMag);
+ PutLong(stdout, Numerator);
+ PutLong(stdout, Denominator);
+ PutLong(stdout, DVIMag);
+}
+
+/*
+ * Handle one of the font definitions from the DVI postamble.
+ */
+PostAmbleFontDef(p)
+ register struct PostAmbleFont *p;
+{
+ register struct fontinfo *fi;
+ register struct font *f;
+ register char *s;
+ register int n;
+ char *fname;
+ int def = S_CREATE | S_EXCL;
+
+ if (NextFont >= NFONTS) /* fix this later */
+ error(1, 0, "too many fonts (%d) used", NextFont);
+
+ fi = (struct fontinfo *) SSearch(FontFinder, p->paf_DVIFontIndex,
+ &def);
+ if (fi == NULL) {
+ if (def & S_COLL)
+ GripeFontAlreadyDefined(p->paf_DVIFontIndex);
+ else
+ error(1, 0, "can't stash font %ld (out of memory?)",
+ p->paf_DVIFontIndex);
+ /* NOTREACHED */
+ }
+ f = GetRasterlessFont(p->paf_name, p->paf_DVIMag,
+ p->paf_DVIDesignSize, "versatec", &fname);
+ if ((fi->f = f) == NULL) {
+ GripeCannotGetFont(p->paf_name, p->paf_DVIMag,
+ p->paf_DVIDesignSize, "versatec", fname);
+ FontErrors++;
+ return;
+ }
+ if (Debug) {
+ (void) fprintf(stderr, "[%s -> %s]\n",
+ Font_TeXName(f), fname);
+ (void) fflush(stderr);
+ }
+ /* match checksums, if not zero */
+ if (p->paf_DVIChecksum && f->f_checksum &&
+ p->paf_DVIChecksum != f->f_checksum)
+ GripeDifferentChecksums(fname, p->paf_DVIChecksum,
+ f->f_checksum);
+
+ putchar(1); /* signal another font */
+ PutLong(stdout, p->paf_DVIChecksum);
+ PutLong(stdout, p->paf_DVIMag);
+ PutLong(stdout, p->paf_DVIDesignSize);
+ n = p->paf_n1 + p->paf_n2;
+ PutLong(stdout, n);
+ fputs(p->paf_name, stdout);
+
+ ComputeCWidths(fi);
+
+ fi->index = NextFont++;
+ fi->pspace = p->paf_DVIMag / 6; /* a three-unit "thin space" */
+ fi->nspace = -4 * fi->pspace;
+ fi->vspace = 5 * fi->pspace;
+}
+
+/*
+ * Read the postamble.
+ */
+ReadPostAmble()
+{
+
+ if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
+ error(1, 0, "can't create FontFinder (out of memory?)");
+ ScanPostAmble(stdin, PostAmbleHeader, PostAmbleFontDef);
+ if (FontErrors)
+ GripeMissingFontsPreventOutput(FontErrors);
+ putchar(0); /* mark end of fonts */
+}
+
+/*
+ * Read the preamble and do a few sanity checks.
+ */
+ReadPreAmble()
+{
+ register int n;
+
+ rewind(stdin);
+ if (GetByte(stdin) != Sign8(DVI_PRE))
+ GripeMissingOp("PRE");
+ if (GetByte(stdin) != Sign8(DVI_VERSION))
+ GripeMismatchedValue("version numbers");
+ if (GetLong(stdin) != Numerator)
+ GripeMismatchedValue("numerator");
+ if (GetLong(stdin) != Denominator)
+ GripeMismatchedValue("denominator");
+ if (GetLong(stdin) != DVIMag)
+ GripeMismatchedValue("\\magfactor");
+ n = UnSign8(GetByte(stdin));
+ while (--n >= 0)
+ (void) GetByte(stdin);
+}
+
+main(argc, argv)
+ int argc;
+ register char **argv;
+{
+ register int c;
+ register char *s;
+ int lmargin;
+
+ setbuf(stderr, serrbuf);
+
+ ProgName = *argv;
+ UserMag = 1000;
+ MaxDrift = DefaultMaxDrift;
+
+ while ((c = getopt(argc, argv, "cd:hm:sD")) != EOF) {
+ switch (c) {
+
+ case 'c':
+ CFlag++;/* centered output */
+ break;
+
+ case 'd': /* max drift value */
+ MaxDrift = atoi(optarg);
+ break;
+
+ case 'h': /* horizontal output */
+ HFlag++;
+ break;
+
+ case 'm': /* magnification */
+ UserMag = atoi(optarg);
+ break;
+
+ case 's': /* silent */
+ SFlag++;
+ break;
+
+ case 'D':
+ Debug++;
+ break;
+
+ case '?':
+ (void) fprintf(stderr, "\
+Usage: %s [-c] [-h] [-m mag] [-s] [file]\n",
+ ProgName);
+ (void) fflush(stderr);
+ exit(1);
+ }
+ }
+ if (optind < argc)
+ if (freopen(argv[optind], "r", stdin) == NULL)
+ error(1, -1, "can't open %s", argv[optind]);
+
+ if (MakeSeekable(stdin))
+ error(1, 0,
+ "unable to copy input to temp file (see the manual)");
+
+ if ((TeXFontDesc = getenv(CONFENV)) == NULL)
+ TeXFontDesc = "";
+
+ c = (VERSION << 1) + (HFlag ? 1 : 0);
+ putchar(c);
+ c = strlen(s = TeXFontDesc);
+ PutLong(stdout, c);
+ while (--c >= 0)
+ putchar(*s++);
+
+ ReadPostAmble();
+
+ /*
+ * The character plotter must check each character to ensure it
+ * is on the page, because the widest and tallest page values from
+ * the DVI file are not always accurate; so these tests do little
+ * save to keep one from finding the offending object. Accordingly,
+ * I have disabled them. 20 May 1984 ACT.
+ */
+#ifdef notdef
+ if (HFlag) {
+ if (MaxPageWidth - MinimumLeftMargin < TallestPageHeight)
+ error(1, 0, "text object too high!");
+ if (MaxPageHeight - MinimumTopMargin < WidestPageWidth)
+ error(1, 0, "text object too wide!");
+ } else { /* page height can be safely ignored */
+ if (MaxPageWidth - MinimumLeftMargin < WidestPageWidth)
+ error(1, 0, "text object too wide!");
+ }
+#endif
+
+ /* Determine margins */
+ /* THIS CODE NEEDS WORK */
+ if (CFlag) {
+ lmargin = HFlag ? TallestPageHeight : WidestPageWidth;
+ lmargin = (MaxPageWidth - lmargin) >> 1;
+ if (lmargin < MinimumLeftMargin) {
+ lmargin = MinimumLeftMargin;
+ error(0, 0, "\
+cannot center (page too wide); flush left instead");
+ }
+ } else
+ lmargin = HFlag ? DefaultTopMargin : DefaultLeftMargin;
+
+ if (HFlag) {
+ TopMargin = (MaxPageHeight - WidestPageWidth) >> 1;
+ if (TopMargin < 0)
+ TopMargin = 0;
+ BottomMargin = MaxPageHeight - TopMargin - WidestPageWidth;
+ if (BottomMargin < 0)
+ BottomMargin = 0;
+ } else {
+ TopMargin = DefaultTopMargin;
+ BottomMargin = DefaultBottomMargin;
+ }
+
+ HHMargin = lmargin;
+ VVMargin = TopMargin;
+
+ ReadPreAmble();
+ ExpectBOP++;
+
+ /* Allocate arrays */
+ MaxChars = InitialChars;
+ if ((yx = (int *) malloc(InitialChars * sizeof *yx)) == NULL)
+ GripeOutOfMemory(InitialChars * sizeof *yx, "yx array");
+ if ((fcp = (int *) malloc(InitialChars * sizeof *fcp)) == NULL)
+ GripeOutOfMemory(InitialChars * sizeof *fcp, "fcp array");
+
+ /*
+ * If the first command in the DVI file involves motion, we will need
+ * to compare it to the current font `space' parameter; so start with
+ * a fake current font of all zeros.
+ */
+ CurrentFont = &NoFont;
+ ReadDVIFile();
+
+ exit(0);
+}
+
+/*
+ * Skip a font definition (since we are using those from the postamble).
+ */
+/*ARGSUSED*/
+SkipFontDef(font)
+ i32 font;
+{
+ register int i;
+
+ (void) GetLong(stdin);
+ (void) GetLong(stdin);
+ (void) GetLong(stdin);
+ i = UnSign8(GetByte(stdin)) + UnSign8(GetByte(stdin));
+ while (--i >= 0)
+ (void) GetByte(stdin);
+}
+
+/*
+ * Perform a \special - right now ignore all of them.
+ */
+DoSpecial(len)
+ i32 len; /* length of the \special string */
+{
+
+ error(0, 0, "warning: ignoring \\special");
+ (void) fseek (stdin, (long) len, 1);
+}
+
+#ifndef lint
+#define maxysize min(MaxCharHeight, 255)
+#else
+#define maxysize 255
+#endif
+
+/*
+ * Draw a rule at the current (hh,vv) position. There are two 4 byte
+ * parameters. The first is the height of the rule, and the second is
+ * the width. (hh,vv) is the lower left corner of the rule.
+ */
+SetRule(advance)
+ int advance;
+{
+ i32 rwidth; /* rule width from DVI file */
+ i32 rheight; /* rule height from DVI file */
+ register int y; /* temporary y value */
+ register int x; /* temporary x value */
+ register int h, w; /* temporaries */
+ register int ymax; /* bottommost (versatec-wise) y coord */
+ register int xmax; /* rightmost (versatec-wise) x coord */
+ register int ymin; /* topmost y coord */
+ register int xmin; /* leftmost x coord */
+ int anybad = 0;
+
+ fGetLong(stdin, rheight);
+ fGetLong(stdin, rwidth);
+
+ h = ConvRule(rheight);
+ w = ConvRule(rwidth);
+
+ if (!HFlag) {
+ xmin = hh;
+ ymax = vv;
+ ymin = ymax - h;
+ xmax = xmin + w;
+ } else {
+ ymin = hh - FFMargin;
+ xmin = MaxPageWidth - vv - 1; /* ???DO I NEED -1 ANYMORE?? */
+ xmax = xmin + h;
+ ymax = ymin + w;
+ if (ymax > MaxPageHeight - FFMargin)
+ ymax = MaxPageHeight - FFMargin, anybad++;
+ }
+ if (ymin < 0)
+ ymin = 0, anybad++;
+ if (xmin < 0)
+ xmin = 0, anybad++;
+ if (xmax > MaxPageWidth)
+ xmax = MaxPageWidth, anybad++;
+ if (anybad && !RuleEMsg) {
+ error(0, 0, "WARNING: rule(s) off page edge; clipped to fit");
+ RuleEMsg++;
+ }
+ if (advance) {
+ hh += w;
+ dvi_h += rwidth;
+ x = fromSP(dvi_h);
+ FIXDRIFT(hh, x);
+ }
+ for (y = ymin; y < ymax; y += h) {
+ for (x = xmin; x < xmax; x += w) {
+ h = ymax - y;
+ h = min(h, maxysize);
+ w = xmax - x;
+ w = min(w, 255);
+ if (--Chars < 0)
+ ExpandArrays();
+ *nextyx++ = (y << 16) | x;
+ *nextfcp++ = (1 << 31) | (x << 16) | (h << 8) | w;
+ }
+ }
+}
+
+/* this driver needs work for codes > 127 */
+char chartoobig[] = "Character code %d is too big; ignored";
+
+/*
+ * Used inside the dump-char code to ensure chars are within page limits:
+ */
+#define CHECK(cond, msg, flag) \
+ if (cond) { \
+ if (!flag) { \
+ error(0, 0, warn, msg); \
+ flag++; \
+ } \
+ goto ignore; \
+ }
+
+/*
+ * This rather large routine reads the DVI file and calls on other routines
+ * to do anything moderately difficult (except put characters: there is
+ * a bunch of ugly code with `goto's which makes things much faster).
+ */
+ReadDVIFile()
+{
+ register int c;
+ register struct glyph *g;
+ register i32 p;
+ int advance;
+ static char warn[] = "\
+WARNING: text object(s) run off %s of page; ignored";
+
+ /*
+ * Only way out is via "return" statement. I had a `for (;;)' here,
+ * but everything crawled off the right.
+ */
+loop:
+ /*
+ * Get the DVI byte, and switch on its parameter length and type.
+ * Note that getchar() returns unsigned values.
+ */
+ c = getchar();
+
+ /*
+ * Handling characters (the most common case) early makes hte
+ * program run a bit faster.
+ */
+ if (DVI_IsChar(c)) {
+ advance = 1;
+do_char:
+ {
+ register struct font *f = CurrentFont->f;
+
+ g = GLYPH(f, c);
+ if (!GVALID(g)) {
+ error(0, 0, "there is no character %d in %s",
+ c, f->f_path);
+ goto loop;
+ }
+ }
+ {
+ register int ulcx, ulcy, height;
+
+ if (!HFlag) {
+ ulcy = vv - g->g_yorigin;
+ ulcx = hh - g->g_xorigin;
+ height = g->g_height;
+ CHECK(ulcy < 0, "top", TopEMsg);
+ CHECK(ulcx < 0, "left", LeftEMsg);
+ CHECK(ulcx + g->g_width >= MaxPageWidth,
+ "right", RightEMsg);
+ } else {/* rotate & translate */
+ ulcy = hh - g->g_xorigin - FFMargin;
+ ulcx = MaxPageWidth -
+ (vv + g->g_height - g->g_yorigin);
+ height = g->g_width;
+ CHECK(ulcy < 0, "left", LeftEMsg);
+ CHECK(ulcy+height >= MaxPageHeight-FFMargin,
+ "right", RightEMsg);
+ CHECK(ulcx < 0, "bottom", BottomEMsg);
+ CHECK(ulcx + g->g_height >= MaxPageWidth,
+ "top", TopEMsg);
+ }
+ p = 0;
+ while (height > 0) {
+ if (--Chars < 0)
+ ExpandArrays();
+ *nextyx++ = (ulcy << 16) | ulcx;
+ *nextfcp++ = (CurrentFont->index<<FONTSHIFT) |
+ ((c & CHARMASK) << CHARSHIFT) | p;
+ height -= MaxCharHeight;
+ ulcy += MaxCharHeight;
+ p++;
+ }
+ }
+ignore:
+ if (advance) {
+ hh += g->g_pixwidth;
+ dvi_h += g->g_tfmwidth;
+ p = fromSP(dvi_h);
+ FIXDRIFT(hh, p);
+ }
+ goto loop;
+ }
+
+ switch (DVI_OpLen(c)) {
+
+ case DPL_NONE:
+ break;
+
+ case DPL_SGN1:
+ p = getchar();
+ p = Sign8(p);
+ break;
+
+ case DPL_SGN2:
+ fGetWord(stdin, p);
+ p = Sign16(p);
+ break;
+
+ case DPL_SGN3:
+ fGet3Byte(stdin, p);
+ p = Sign24(p);
+ break;
+
+ case DPL_SGN4:
+ fGetLong(stdin, p);
+ break;
+
+ case DPL_UNS1:
+ p = UnSign8(getchar());
+ break;
+
+ case DPL_UNS2:
+ fGetWord(stdin, p);
+ p = UnSign16(p);
+ break;
+
+ case DPL_UNS3:
+ fGet3Byte(stdin, p);
+ p = UnSign24(p);
+ break;
+
+ default:
+ panic("DVI_OpLen(%d) = %d", c, DVI_OpLen(c));
+ /* NOTREACHED */
+ }
+
+ /*
+ * Now that we have the parameter, perform the
+ * command.
+ */
+ switch (DVI_DT(c)) {
+
+ case DT_SET:
+ advance = 1;
+ c = p;
+ if (c > 127) {
+ error(0, 0, chartoobig, c);
+ break;
+ }
+ goto do_char;
+
+ case DT_PUT:
+ advance = 0;
+ c = p;
+ if (c > 127) {
+ error(0, 0, chartoobig, c);
+ break;
+ }
+ advance = 0;
+ goto do_char;
+
+ case DT_SETRULE:
+ SetRule(1);
+ break;
+
+ case DT_PUTRULE:
+ SetRule(0);
+ break;
+
+ case DT_NOP:
+ break;
+
+ case DT_BOP:
+ BeginPage();
+ break;
+
+ case DT_EOP:
+ EndPage();
+ break;
+
+ case DT_PUSH:
+ dvi_stackp->stack_hh = hh;
+ dvi_stackp->stack_vv = vv;
+ dvi_stackp->stack_dvi = dvi_current;
+ dvi_stackp++;
+ break;
+
+ case DT_POP:
+ dvi_stackp--;
+ hh = dvi_stackp->stack_hh;
+ vv = dvi_stackp->stack_vv;
+ dvi_current = dvi_stackp->stack_dvi;
+ break;
+
+ case DT_W0: /* there should be a way to make these pretty */
+ p = dvi_w;
+ goto move_right;
+
+ case DT_W:
+ dvi_w = p;
+ goto move_right;
+
+ case DT_X0:
+ p = dvi_x;
+ goto move_right;
+
+ case DT_X:
+ dvi_x = p;
+ goto move_right;
+
+ case DT_RIGHT:
+move_right:
+ dvi_h += p;
+ /*
+ * DVItype tells us that we must round motions in this way:
+ * `When the horizontal motion is small, like a kern, hh
+ * changes by rounding the kern; but when the motion is
+ * large, hh changes by rounding the true position so that
+ * accumulated rounding errors disappear.'
+ */
+ if (p >= CurrentFont->pspace || p <= CurrentFont->nspace)
+ hh = fromSP(dvi_h);
+ else {
+ hh += fromSP(p);
+ p = fromSP(dvi_h);
+ FIXDRIFT(hh, p);
+ }
+ break;
+
+ case DT_Y0:
+ p = dvi_y;
+ goto move_down;
+
+ case DT_Y:
+ dvi_y = p;
+ goto move_down;
+
+ case DT_Z0:
+ p = dvi_z;
+ goto move_down;
+
+ case DT_Z:
+ dvi_z = p;
+ goto move_down;
+
+ case DT_DOWN:
+move_down:
+ dvi_v += p;
+ /*
+ * `Vertical motion is done similarly, but with the threshold
+ * between ``small'' and ``large'' increased by a factor of
+ * 5. The idea is to make fractions like $1\over2$ round
+ * consistently, but to absorb accumulated rounding errors in
+ * the baseline-skip moves.'
+ */
+ if (ABS(p) >= CurrentFont->vspace)
+ vv = fromSP(dvi_v);
+ else {
+ vv += fromSP(p);
+ p = fromSP(dvi_v);
+ FIXDRIFT(vv, p);
+ }
+ break;
+
+ case DT_FNTNUM:
+ SelectFont((i32) (c - DVI_FNTNUM0));
+ break;
+
+ case DT_FNT:
+ SelectFont(p);
+ break;
+
+ case DT_XXX:
+ DoSpecial(p);
+ break;
+
+ case DT_FNTDEF:
+ SkipFontDef(p);
+ break;
+
+ case DT_PRE:
+ GripeUnexpectedOp("PRE");
+ /* NOTREACHED */
+
+ case DT_POST:
+ if (!ExpectBOP)
+ GripeUnexpectedOp("POST");
+ if (!SFlag) {
+ (void) fprintf(stderr, "\n");
+ (void) fflush(stderr);
+ }
+ return;
+
+ case DT_POSTPOST:
+ GripeUnexpectedOp("POSTPOST");
+ /* NOTREACHED */
+
+ case DT_UNDEF:
+ GripeUndefinedOp(c);
+ /* NOTREACHED */
+
+ default:
+ panic("DVI_DT(%d) = %d", c, DVI_DT(c));
+ /* NOTREACHED */
+ }
+ goto loop;
+}