diff options
Diffstat (limited to 'dviware/umddvi/dev/verser1.c')
-rw-r--r-- | dviware/umddvi/dev/verser1.c | 1047 |
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; +} |