diff options
Diffstat (limited to 'dviware/umddvi/dev/ip.c')
-rw-r--r-- | dviware/umddvi/dev/ip.c | 696 |
1 files changed, 696 insertions, 0 deletions
diff --git a/dviware/umddvi/dev/ip.c b/dviware/umddvi/dev/ip.c new file mode 100644 index 0000000000..a97ffbd7ad --- /dev/null +++ b/dviware/umddvi/dev/ip.c @@ -0,0 +1,696 @@ +/* + * 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$"; +#endif + +/* + * DVI to Interpress driver + * + * Reads DVI version 2 files and converts to Xerox Interpress format. + */ + +#include "types.h" +#include "dvi.h" +#include "dviclass.h" +#include "dvicodes.h" +#include "fio.h" +#include "pxl.h" +#include "search.h" +#include "interpress.h" +#include <stdio.h> + +char *ProgName; +extern int errno; +extern char *optarg; +extern int optind; + +/* Globals */ +char serrbuf[BUFSIZ]; /* buffer for stderr */ + +/* DVI style arithmetic: when moving 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 used for vertical + positioning. */ +struct fontinfo { + struct pxltail *px; /* pxl file info */ + int ipfont; /* Interpress font index */ + 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 */ + int cwidth[128]; /* width (in DEVs) of each char */ + char cload[128]; /* flag for ``char loaded into Imagen'' */ +}; + +int MaxDrift; /* the maximum allowable difference between + hh and SPtoDEV(dvi_h), and vv and.... */ + +struct search *FontFinder; /* search table for DVI index => fontinfo */ +struct fontinfo *CurrentFont; /* the current font (if any) */ +int NextIPFont; /* during font definition, the next ip font + index */ +int FontErrors; /* true => error(s) during font definition */ + +char *TeXfonts; /* getenv("TEXFONTS") */ + +int ExpectBOP; /* true => BOP ok */ +int ExpectEOP; /* true => EOP ok */ + +int DPI; /* -d => device resolution (dots/inch) */ +/* int LFlag; /* -l => landscape mode (eventually...) */ +int SFlag; /* -s => silent (no page #s) */ +int XFlag; /* -x => debug (undocumented) */ + +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 SPtoDEV(h) and SPtoDEV(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 HHMargin; /* horizontal margin (in DEVs) */ +int VVMargin; /* vertical margin (in DEVs) */ + +int Numerator; /* numerator from DVI file */ +int Denominator; /* denominator from DVI file */ +int DVIMag; /* magnification from DVI file */ + +double UserMag; /* user specified magnification */ +double GlobalMag; /* overall magnification (UserMag*DVIMag) */ +double conv; /* conversion factor for magnified DVI units */ + +double OneHalf = 0.5; /* .5, so compiler can generate constant only + once */ +double Zero = 0.0; /* likewise */ +double _d_; /* Used to store intermediate results. The + compiler should do this for us, but it's + too stupid. */ + +int IpHH; /* Interpress horizontal position */ +int IpVV; /* Interpress vertical position */ +int IpFont; /* Interpress current-font number */ + +char *getenv (), *malloc (); + +/* Absolute value */ +#define ABS(n) ((n) >= 0 ? (n) : -(n)) + +/* Round a floating point number to integer */ +#define ROUND(f) ((int) (_d_ = (f), \ + _d_ < Zero ? _d_ - OneHalf : _d_ + OneHalf) + +/* Convert to floating point */ +#define FLOAT(i) ((double) (i)) + +/* Convert a value in sp's to dev's, and vice versa */ +#define SPtoDEV(sp) (ROUND ((sp) * conv)) +#define DEVtoSP(dev) (ROUND ((dev) / conv)) + +/* Put a two-byte (word) value */ +#define putword(w) (putchar ((w) >> 8), putchar (w)) + +/* Correct devpos (the virtual device position) to be within MaxDrift pixels + of dvipos (the virtual DVI position). */ +#define FIXDRIFT(devpos, dvipos) \ + if (ABS ((devpos) - (dvipos)) <= MaxDrift); \ + 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 int i; + register struct chinfo *ch; + register int *cw; + + ch = fi -> px -> px_info; + cw = fi -> cwidth; + i = 128; + while (--i >= 0) { + *cw++ = SPtoDEV (ch -> ch_TFMwidth); + ch++; + } +} + +SelectFont (n) +int n; +{ + register struct fontinfo *f; + + CurrentFont = f = FindFont ((i32) n, (struct fontinfo *) 0); + CurrentFontIndex = f - FontInfo; +} + +/* 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[10]; /* the 10 counters */ + static int beenhere; + + if (!ExpectBOP) + error (1, 0, "unexpected BOP"); + if (beenhere) { + if (!SFlag) + putc (' ', stderr); + } + else + beenhere++; + + dvi_stackp = dvi_stack; + + ExpectBOP = 0; + ExpectEOP++; /* set the new "expect" state */ + + for (i = count; i < &count[sizeof count / sizeof *count]; i++) + fGetLong (stdin, *i); + fGetLong (stdin, i); /* previous page pointer */ + + if (!SFlag) { + fprintf (stderr, "[%d", count[0]); + (void) fflush (stderr); + } + + putchar (imP_Page); /* XXX */ + IpHH = 0; + IpVV = 0; + + hh = HHMargin; + vv = VVMargin; + dvi_h = DEVtoSP (hh); + dvi_v = DEVtoSP (vv); + dvi_w = 0; + dvi_x = 0; + dvi_y = 0; + dvi_z = 0; +} + +/* End a page (process a DVI_EOP) */ +EndPage () { + if (!ExpectEOP) + error (1, 0, "unexpected EOP"); + + if (!SFlag) { + putc (']', stderr); + (void) fflush (stderr); + } + + ExpectEOP = 0; + ExpectBOP++; + + putchar (imP_EndPage); /* XXX */ +} + +/* Begin XXX */ +/* Store the relevant information from the DVI postamble, and set up + various internal things. */ +PosotAmbleHeader (p) +register struct PostAmbleInfo *p; { + register int n; + + PrevPagePointer = p -> pai_PrevPagePointer; + Numerator = p -> pai_Numerator; + Denominator = p -> pai_Denominator; + DVIMag = p -> pai_DVIMag; + + /* Here we sneakily correct for the actual device resolution, so that we can + pretend that it's 200 dots per inch. */ + UserMag *= FLOAT (DPI) / 200.0; + + GlobalMag = DMagFactor (DVIMag) * UserMag; + + /* The conversion factor is figured as follows: there are exactly n/d DVI + units per decimicron, and 254000 decimicrons per inch, and 200 pixels per + inch. Then we have to adjust this by the stated magnification. */ + conv = (Numerator / 254000.0) * (200.0 / Denominator) * GlobalMag; + + n = p -> pai_DVIStackSize * sizeof *dvi_stack; + dvi_stack = (struct localstack *) malloc ((unsigned) n); + if ((dvi_stackp = dvi_stack) == 0) + error (1, errno, "can't allocate %d DVI stack bytes", n); + IntGlobalMag = ROUND (GlobalMag * 1000.0); +} + +/* Handle one of the font definitions from the DVI postamble. */ +PostAmbleFontDef (p) +register struct PostAmbleFont *p; { + register struct fontinfo *f; + register char *s; + int def = S_CREATE | S_EXCL; + + f = (struct fontinfo *) SSearch (FontFinder, p -> paf_DVIFontIndex, &def); + if (f == 0) + if (def & S_COLL) + error (1, 0, "font %d already defined", p -> paf_DVIFontIndex); + else + error (1, 0, "can't stash font %d (out of memory?)", + p -> paf_DVIFontIndex); + + f -> ipfont = NextIPFont++; + s = GenPXLFileName (p -> paf_name, p -> paf_DVIMag, + p -> paf_DVIDesignSize, IntGlobalMag, TeXfonts); + if ((f -> px = ReadPXLFile (s, 1)) == 0) { + error (0, errno, "can't find font \"%s\"", s); + FontErrors++; + return; + } + if (p -> paf_DVIChecksum != f -> px -> px_checksum) + error (0, 0, "\ +WARNING: width tables and raster tables have different\n\ +\tchecksums for font \"%s\"\n\ +\tPlease notify your TeX maintainer\n\ +\t(TFM checksum = 0%o, PXL checksum = 0%o)", + s, dvi_checksum, f -> px -> px_checksum); + + ScaleTFMWidths (f -> px, dvi_mag); + ComputeCWidths (f); + f -> pspace = p -> paf_DVIMag / 6; /* a three-unit ``thin space'' */ + f -> nspace = -4 * f -> pspace; + f -> vspace = 5 * f -> pspace; +} + +/* Read the postamble. */ +ReadPostAmble () { + static char s[2] = { 's', 0 }; + + if ((FontFinder = SCreate (sizeof (struct fontinfo))) == 0) + error (1, 0, "can't create FontFinder (out of memory?)"); + ScanPostAmble (stdin, PostAmbleHeader, PostAmbleFontDef); + if (FontErrors) + error (1, 0, "missing font%s prevent%s output (sorry)", + FontErrors > 1 ? s : &s[1], FontErrors == 1 ? s : &s[1]); +} +/* End XXX */ + +/* Read the preamble and do a few sanity checks */ +ReadPreAmble () { + register int n; + + rewind (stdin); + if (GetByte (stdin) != Sign8 (DVI_PRE)) + error (1, 0, "missing PRE"); + if (GetByte (stdin) != Sign8 (DVI_VERSION)) + error (1, 0, "mismatched version numbers"); + if (GetLong (stdin) != Numerator) + error (1, 0, "mismatched numerator"); + if (GetLong (stdin) != Denominator) + error (1, 0, "mismatched denominator"); + if (GetLong (stdin) != DVIMag) + error (1, 0, "mismatched \\magfactor"); + n = UnSign8 (GetByte (stdin)); + while (--n >= 0) + (void) GetByte (stdin); +} + +main (argc, argv) +int argc; +register char **argv; +{ + register int c; + char *inname; + + setbuf (stderr, serrbuf); + + ProgName = *argv; + UserMag = 1.0; + MaxDrift = DefaultMaxDrift; + DPI = DefaultDPI; + inname = "stdin"; + + while ((c = getopt (argc, argv, "d:m:r:s")) != EOF) { + switch (c) { + case 'd': /* max drift value */ + MaxDrift = atoi (optarg); + break; +/* case 'l': /* landscape mode */ +/* LFlag++; */ +/* break; */ + case 'm': /* magnification */ + UserMag = DMagFactor (atoi (optarg)); + break; + case 'r': /* resolution */ + DPI = atoi (optarg); + break; + case 's': /* silent */ + SFlag++; + break; + case 'x': /* enable debugging */ + XFlag++; + break; + case '?': + fprintf (stderr, "\ +Usage: %s [-d drift] [-m mag] [-s] [-r resolution] [file]\n", + ProgName); + (void) fflush (stderr); + exit (1); + } + } + if (optind < argc) + if (freopen (inname = argv[optind], "r", stdin) == NULL) + error (1, errno, "can't open %s", inname); + + /* ReadPostAmble does an fseek which, if performed on a tty, tends to make + the shell log one out, thus the following kludge: */ + if (isatty (fileno (stdin))) + error (1, 0, "input from ttys is expressly forbidden!"); + + TeXfonts = getenv ("TEXFONTS"); + if (TeXfonts == 0) + TeXfonts = ""; + + ReadPostAmble (); + + /* Margins -- needs work! */ + HHMargin = DefaultLeftMargin;/* XXX */ + VVMargin = DefaultTopMargin;/* XXX */ + + ReadPreAmble (); + ExpectBOP++; + (void) fseek (stdin, PrevPagePointer, 0); + + /* All set! */ + printf ("Interpress/Xerox/2.1 "); + PutInstructionsBody (inname); + PutPreamble (); + ReadDVIFile (); + /* EOF is implicit (?) */ + + exit (0); +} + +/* Skip a font definition (since we are using those from the postamble) */ +/* ARGSUSED */ +SkipFontDef (font) +int 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) +int len; /* length of the \special string */ +{ + error (0, 0, "warning: ignoring \\special"); + (void) fseek (stdin, (long) len, 1); +} + +/* 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 */ + rheight; /* rule height from DVI file */ + register int h, + w; + + fGetLong (stdin, rheight); + fGetLong (stdin, rwidth); + + /* Rule sizes must be computed in this manner: */ + h = conv * rheight; + if (FLOAT (h) < (conv * rheight)) + h++; + w = conv * rwidth; + if (FLOAT (w) < (conv * rwidth)) + w++; + + /* put the rule out */ + if (IpHH != hh || IpVV != vv) + SetPosition (hh, vv); + putchar (imP_Rule); /* XXX */ + putword (w); /* XXX */ + putword (h); /* XXX */ + putword (-h + 1); /* XXX */ + if (advance) { + hh += w; + dvi_h += rwidth; + if (ABS (hh - (w = SPtoDEV (dvi_h))) > MaxDrift) + hh = w + (hh < w ? -MaxDrift : MaxDrift); + } +} + +/* FIXME (kerns, etc, etc) */ +/* resume XXX */ +/* 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, + p; + int advance; + + IpFamily = -1; + + /* Only way out is via "return" statement */ + for (;;) { + /* Get the DVI byte, and if it's a character, put it */ +/* c = UnSign8 (getchar ()); */ + c = getchar (); /* getchar() returns unsigned values */ + + if (DVI_IsChar (c)) { /* I know, ugly, but ... no function call + overhead this way */ + register struct chinfo *ch; + register struct fontinfo *cf; + +set: + advance = 1; +put: + cf = CurrentFont; + ch = &cf -> px -> px_info[c]; + if (ch -> ch_width == 0) + goto ignore; /* not a real character, just advance */ + /* BEGIN INLINE EXPANSION OF IpSetPosition (the things we do in + the name of efficency! ;-) ) */ + if (ImHH != hh) { + if (ImHH == hh - 1) + putchar (imP_Forw); + else if (ImHH == hh + 1) + putchar (imP_Backw); + else { + putchar (imP_SetHAbs); + putword (hh); + } + ImHH = hh; + } + if (ImVV != vv) { + putchar (imP_SetVAbs); + putword (vv); + ImVV = vv; + } + /* END INLINE EXPANSION OF ImSetPosition */ + if (ImFamily != CurrentFontIndex) { + putchar (imP_SetFamily); + putchar (CurrentFontIndex); + ImFamily = CurrentFontIndex; + } + putchar (c); + ImHH += cf -> cwidth[c]; +ignore: + if (advance) { +#ifdef DEBUG + if (XFlag) { + fprintf (stderr, "setchar%d h:=%d+%d=%d, hh:=%d\n", + c, dvi_h - DEVtoSP (HHMargin), ch->ch_TFMwidth, + dvi_h - DEVtoSP (HHMargin) + ch->ch_TFMwidth, + hh + CurrentFont->cwidth[c] - HHMargin); + fflush (stderr); + } +#endif DEBUG + hh += cf -> cwidth[c]; + dvi_h += ch -> ch_TFMwidth; + p = SPtoDEV (dvi_h); + FIXDRIFT (hh, p); + } + continue; + } + /* Wasn't a character, maybe a font? */ + if (DVI_IsFont (c)) { + SelectFont ((i32) (c - DVI_FNTNUM0)); + continue; + } + /* Wasn't a font, see if it's a generic one */ + if (p = DVI_OpLen (c)) { + /* It's generic, get its parameter */ + switch (p) { + case 1: + p = Sign8 (getchar ()); + break; + case 2: + fGetWord (stdin, p); + p = Sign16 (p); + break; + case 3: + fGet3Byte (stdin, p); + p = Sign24 (p); + break; + case 4: + fGetLong (stdin, p); + break; + case 5: + p = UnSign8 (getchar ()); + break; + case 6: + fGetWord (stdin, p); + p = UnSign16 (p); + break; + case 7: + fGet3Byte (stdin, p); + p = UnSign24 (p); + break; + } + /* Now that we have the parameter, perform the command */ + switch (DVI_DT (c)) { + case DT_SET: + c = p; + goto set; + case DT_PUT: + c = p; + advance = 0; + goto put; + 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 = SPtoDEV (dvi_h); + else { + hh += SPtoDEV (p); + p = SPtoDEV (dvi_h); + FIXDRIFT (hh, p); + } + break; + case DT_W: + dvi_w = p; + goto move_right; + case DT_X: + dvi_x = p; + goto move_right; + 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 baeline-skip moves.'' */ + if (ABS (p) >= CurrentFont -> vspace) + vv = SPtoDEV (dvi_v); + else { + vv += SPtoDEV (p); + p = SPtoDEV (dvi_v); + FIXDRIFT (vv, p); + } + break; + case DT_Y: + dvi_y = p; + goto move_down; + case DT_Z: + dvi_z = p; + goto move_down; + case DT_FNT: + SelectFont (p); + break; + case DT_XXX: + DoSpecial (p); + break; + case DT_FNTDEF: + SkipFontDef (p); + break; +#ifdef PARANOID + default: + error (1, 0, "bad DVI_DT(%d): (%d)", c, DVI_DT (c)); +#endif PARANOID + } + continue; + } + /* Wasn't a char, wasn't a generic command, just pick it out from the + whole mess */ + switch (c) { + case DVI_SETRULE: + SetRule (1); + break; + case DVI_PUTRULE: + SetRule (0); + break; + case DVI_NOP: + break; + case DVI_BOP: + BeginPage (); + break; + case DVI_EOP: + EndPage (); + if (PrevPagePointer == -1) { + if (!SFlag) { + fprintf (stderr, "\n"); + (void) fflush (stderr); + } + return; + } + break; + case DVI_PUSH: + dvi_stackp -> stack_hh = hh; + dvi_stackp -> stack_vv = vv; + dvi_stackp -> stack_dvi = dvi_current; + dvi_stackp++; + break; + case DVI_POP: + dvi_stackp--; + hh = dvi_stackp -> stack_hh; + vv = dvi_stackp -> stack_vv; + dvi_current = dvi_stackp -> stack_dvi; + break; + case DVI_W0: + p = dvi_w; + goto move_right; + case DVI_X0: + p = dvi_x; + goto move_right; + case DVI_Y0: + p = dvi_y; + goto move_down; + case DVI_Z0: + p = dvi_z; + goto move_down; + case DVI_PRE: + error (1, 0, "unexpected PRE"); + case DVI_POST: /* shouldn't get this, reading backwards */ + error (1, 0, "unexpected POST"); + case DVI_POSTPOST: + error (1, 0, "unexpected POSTPOST"); + default: + error (1, 0, "undefined DVI opcode (%d)", c); + } + } +} |