summaryrefslogtreecommitdiff
path: root/dviware/umddvi/dev/ip.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/umddvi/dev/ip.c')
-rw-r--r--dviware/umddvi/dev/ip.c696
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);
+ }
+ }
+}