/* * 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 #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<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; }