summaryrefslogtreecommitdiff
path: root/dviware/umddvi/dev
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/umddvi/dev
Initial commit
Diffstat (limited to 'dviware/umddvi/dev')
-rw-r--r--dviware/umddvi/dev/conf.sh113
-rw-r--r--dviware/umddvi/dev/config3
-rw-r--r--dviware/umddvi/dev/dmd-sp.c568
-rw-r--r--dviware/umddvi/dev/dmd.c920
-rw-r--r--dviware/umddvi/dev/dmdcodes.h39
-rw-r--r--dviware/umddvi/dev/dmdhost.c236
-rw-r--r--dviware/umddvi/dev/dmdslave.c1176
-rw-r--r--dviware/umddvi/dev/dvipr.sh71
-rw-r--r--dviware/umddvi/dev/fontdesc1
-rw-r--r--dviware/umddvi/dev/imagen1-special.c718
-rw-r--r--dviware/umddvi/dev/imagen1.c867
-rw-r--r--dviware/umddvi/dev/interpress.h29
-rw-r--r--dviware/umddvi/dev/ip.c696
-rw-r--r--dviware/umddvi/dev/iptex.sh61
-rw-r--r--dviware/umddvi/dev/makefile143
-rw-r--r--dviware/umddvi/dev/makefile.3b149
-rw-r--r--dviware/umddvi/dev/makefile.local143
-rw-r--r--dviware/umddvi/dev/readme7
-rw-r--r--dviware/umddvi/dev/verser1.c1047
-rw-r--r--dviware/umddvi/dev/verser2.c758
20 files changed, 7745 insertions, 0 deletions
diff --git a/dviware/umddvi/dev/conf.sh b/dviware/umddvi/dev/conf.sh
new file mode 100644
index 0000000000..d10d74e484
--- /dev/null
+++ b/dviware/umddvi/dev/conf.sh
@@ -0,0 +1,113 @@
+#! /bin/sh
+#
+# conf - dynamically configure a makefile
+#
+# uses lines of the form "# conf" ... "# endconf" to figure out what
+# to do.
+#
+# This script uses the file `Makefile' as a base and creates a
+# new `Makefile.local'. It is assumed that the first thing the
+# original makefile does is run make on the local Makefile.
+
+PATH=/bin:/usr/bin:/usr/ucb:"$PATH"; export PATH
+
+# saved configuration file
+conf=Config
+
+# temp files
+t1=/tmp/conf1.$$
+t2=/tmp/conf2.$$
+
+# clean up if interrupted
+trap "rm -f $t1 $t2; exit 1" 1 2 3 15
+
+# Step 1: find the "# conf" lines, gripe if none. (But if $1 is
+# "update", we will just read the saved configuration.)
+case $1 in
+update)
+ if [ ! -f $conf ]; then
+ echo "Your saved configuration file \`$conf' is gone!"
+ echo "(Try \`make conf' again.)"
+ exit 1
+ fi;;
+*)
+ grep "^#[ ][ ]*conf[ ][ ]*" Makefile |
+ sort | uniq >$t1
+ case $? in
+ 0) ;;
+ *) echo "Something is seriously wrong with \`Makefile': there are
+no \`# conf' lines in it. You'll have to fix it by hand (sorry)."
+ rm -f $t1; exit 1;;
+ esac;;
+esac
+
+# Step 2: collect list of entries, and remember for later.
+# If $1 is "update", take the remembered entries; if "all", take all entries.
+case "$1" in
+update)
+ # N.B.: The following depends on the fact that the first two
+ # lines of $conf are comments, the third the configuration.
+ list="`awk 'NR==3 {print}' $conf`";;
+all)
+ list=`awk '{if ($3 != "none") printf ("%s ", $3)}' <$t1`
+ echo "# This file contains the default \`all' configuration.
+# Do not edit it yourself: use \`make conf' instead.
+$list" >$conf;;
+*)
+ list=
+ for i in `awk '{if ($3 != "none") printf ("%s ", $3)}' <$t1`; do
+ echo -n "Do you have a(n) $i? "
+ read answer
+ case "$answer" in
+ y|Y|yes|Yes|YES) list="$list $i";;
+ esac;
+ done
+ echo "# This file contains your configuration.
+# Do not edit it yourself: use \`make conf' instead.
+$list" >$conf;;
+esac
+
+# Step 3: edit the Makefile so that the things that are configured
+# in are on, and those that are not are commented out. Put the result
+# in Makefile.local.
+# This `if' is for 4.3beta machines, where `mv -f' is botched
+if [ -f Makefile.local ]; then
+ mv -f Makefile.local Makefile.l.bak
+fi
+awk "
+BEGIN {
+ want = 0; # 0 => normal
+ # 1 => uncomment, -1 => comment
+ split(\"$list\", list);
+}
+/^#[ ][ ]*conf[ ][ ]*/ { # a conf item
+ want = -1; # assume we do not want it
+ for (i in list)
+ if (list[i] == \$3)
+ want = 1; # we do want it after all
+ print; # in any case, echo it
+ next;
+}
+/^#[ ][ ]*endconf/ { # end of conf item
+ want = 0; # back to normal
+}
+/^# / { # something that was commented out
+ if (want <= 0) { # do not really want it
+ print;
+ next;
+ }
+ for (i = 2; i < NF; i++) # want it: uncomment
+ printf(\"%s \", \$i);
+ print \$NF;
+ next;
+}
+{ # anything else
+ if (want >= 0) # take it as is
+ print;
+ else # comment it out
+ printf(\"# %s\n\", \$0);
+}" <Makefile >$t2
+(trap '' 1 2 3 15; mv -f $t2 Makefile.local)
+
+# Clean up and exit
+rm -f $t1 $t2; exit 0
diff --git a/dviware/umddvi/dev/config b/dviware/umddvi/dev/config
new file mode 100644
index 0000000000..64650ecd58
--- /dev/null
+++ b/dviware/umddvi/dev/config
@@ -0,0 +1,3 @@
+# This file contains the default `all' configuration.
+# Do not edit it yourself: use `make conf' instead.
+imagen versatec
diff --git a/dviware/umddvi/dev/dmd-sp.c b/dviware/umddvi/dev/dmd-sp.c
new file mode 100644
index 0000000000..40bf02424b
--- /dev/null
+++ b/dviware/umddvi/dev/dmd-sp.c
@@ -0,0 +1,568 @@
+/*
+ * Support drawing routines for Chris Torek's DVI->ImPress program.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "types.h"
+#include "dmdcodes.h"
+
+/* Put a two-byte (word) value to the Imagen */
+#define putword(w) (putchar((w) >> 8), putchar(w))
+
+extern char *malloc();
+
+
+#define TRUE 1
+#define FALSE 0
+
+#define PI 3.14157926536
+#define TWOPI (PI*2.0)
+#define MAXPOINTS 300 /* Most number of points in a path */
+
+
+/* Graphics operations */
+#define WHITE 0
+#define SHADE 3
+#define OR 7
+#define BLACK 15
+
+extern double cos(), sin(), sqrt();
+extern int DPI; /* Resolution of device */
+#define PixPerInX DPI
+#define PixPerInY DPI
+
+extern int UserMag;
+#define fconv(x, f)\
+ (((double)(x)/1000.0) * ((double)(f)) * ((double)UserMag/1000.0))
+#define conv(x, f)\
+ ((int) ((((double)(x)/1000.0) * ((double)(f)) * ((double)UserMag/1000.0)) + 0.5))
+#define xconv(x) conv(x, PixPerInX)
+#define yconv(y) conv(y, PixPerInY)
+
+extern int ImHH; /* Imagen horizontal position */
+extern int ImVV; /* Imagen vertical position */
+extern int hh; /* current horizontal position, in DEVs */
+extern int vv; /* current vertical position, in DEVs */
+
+
+static int xx[MAXPOINTS], yy[MAXPOINTS], pathlen,
+ pensize = 1; /* Size we want Imagen to draw at, default 2 pixels */
+
+#define MAXPENSIZE 20 /* Imagen restriction */
+
+static int
+ family_defined = FALSE, /* Have we chosen family yet? */
+ texture_defined = FALSE,/* Have we done a set_texture yet? */
+ whiten_next = FALSE, /* Should next object be whitened? */
+ blacken_next = FALSE, /* Should next object be blackened? */
+ shade_next = FALSE; /* Should next object be shaded? */
+
+/* Predefined shading (texture) glyph */
+/* First, define size of glyph */
+#define THEIGHT 32 /* bits high */
+#define TWIDTH 4 /* bytes wide */
+/* Next, declare the bit map for the glyph */
+static char stexture[THEIGHT][TWIDTH]={
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}};
+
+/*
+ * Copy a default texture into the stexture array
+ */
+static void glyph_init()
+{
+ static char btexture[THEIGHT][TWIDTH]={
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}};
+
+ int i;
+ for (i=0; i<THEIGHT; i++)
+ bcopy(btexture[i],stexture[i],TWIDTH);
+
+}
+
+#define push_location()
+#define pop_location()
+
+#ifdef notdef
+/*
+ * Push the state of the Imagen and set up a new virtual coord system
+ */
+static void push_location()
+{
+ putchar(imP_Push);
+ putchar(imP_SetHVSystem);
+ putchar(0140);
+}
+
+
+/*
+ * Create the pushed virtual page, and pop the state of the printer
+ */
+static void pop_location()
+{
+ putchar(imP_Pop);
+}
+#endif
+
+
+/*
+ * Set the pen size
+ * Called as \special{pn size}
+ * eg: \special{pn 8}
+ * The size is the number of milli-inches for the diameter of the pen.
+ * This routine converts that value to device-dependent pixels, and makes
+ * sure that the resulting value is within legal bounds.
+ */
+static void im_pensize(cp)
+char *cp;
+{
+ int size;
+
+ if (sscanf(cp, " %d ", &size) != 1) return;
+ pensize = yconv(size);
+ if (pensize < 1) pensize = 1;
+ else if (pensize > MAXPENSIZE) pensize = MAXPENSIZE;
+}
+
+
+/*
+ * Make sure the pen size is set. Since we push and pop the state,
+ * this has to be sent for each different object (I think).
+ */
+static void set_pen_size()
+{
+ putchar(DMD_PENSIZE);
+ putchar(pensize);
+}
+
+
+/*
+ * Actually apply the attributes (shade, whiten, or blacken) to the currently
+ * defined path/figure.
+ */
+static void do_attributes()
+{
+ static int family; /* Family of downloaded texture glyph */
+ static int member; /* Member of family */
+ int i,j; /* Loop through glyph array */
+
+ if (shade_next) {
+ shade_next = FALSE;
+#ifdef notdef
+ if (!family_defined) {
+ family_defined = TRUE;
+ family = fnum++;
+ member = -1;
+ }
+ if (!texture_defined) {
+ texture_defined = TRUE;
+ member++;
+ putchar(imP_DefGlyph);
+ putchar((family & 0x7e) >> 1);
+ putchar((family & 0x01) << 7 | (member & 0x7f));
+ /*putword(0); */ /* Advance width */
+ putword(32);
+ putword(TWIDTH*8); /* pixel width (8 x number of bytes) */
+ /*putword(0); */ /* left offset */
+ putword(32);
+ putword(THEIGHT); /* and height of glyph */
+ /*putword(0); */ /* top offset */
+ putword(32);
+ for (i=0; i<THEIGHT; i++)/* Do rows */
+ for (j=0; j<TWIDTH; j++) putchar(stexture[i][j]);
+ }
+ putchar(imP_SetTexture);
+ putchar((family & 0x7e) >> 1);
+ putchar((family & 0x01) << 7 | (member & 0x7f));
+#endif
+ putchar(DMD_FILLPATH);
+ putchar(SHADE);
+ glyph_init(); /* reinitialize the array */
+ }
+ else if (whiten_next) {
+ whiten_next = FALSE;
+ putchar(DMD_FILLPATH);
+ putchar(WHITE);
+ }
+ else if (blacken_next) {
+ blacken_next = FALSE;
+ putchar(DMD_FILLPATH);
+ putchar(BLACK);
+ }
+}
+
+
+/*
+ * Flush the path that we've built up with im_drawto()
+ * Called as \special{fp}
+ */
+static void im_flushpath()
+{
+ register int i;
+
+ push_location();
+ if (pathlen <= 0) return;
+ set_pen_size();
+ putchar(DMD_SEGMENT);
+ putword(pathlen);
+ for (i=1; i<=pathlen; i++) {
+ putword(xx[i]);
+ putword(yy[i]);
+ }
+ pathlen = 0;
+ putchar(DMD_DRAWPATH);
+ putchar(BLACK);
+ do_attributes();
+ pop_location();
+}
+
+
+/* Helper routine for dashed_line() */
+static void connect(x0, y0, x1, y1)
+int x0, y0, x1, y1;
+{
+ set_pen_size();
+ putchar(DMD_SEGMENT);
+ putword(2); /* Path length */
+ putword(x0); putword(y0);/* The path */
+ putword(x1); putword(y1);
+ putchar(DMD_DRAWPATH);
+ putchar(BLACK);
+}
+
+
+/* Another helper. Draw a dot at the indicated point */
+static void dot_at(x, y)
+int x,y;
+{
+ set_pen_size();
+ putchar(DMD_SEGMENT);
+ putword(1); /* Path length */
+ putword(x); putword(y); /* The path */
+ putchar(DMD_DRAWPATH);
+ putchar(BLACK);
+}
+
+
+/*
+ * Draw a dashed or dotted line between the first pair of points in the array
+ * Called as \special{da <inchesperdash>} (dashed line)
+ * or \special{dt <inchesperdot>} (dotted line)
+ * eg: \special{da 0.05}
+ */
+static void dashed_line(cp, dotted)
+char *cp;
+int dotted; /* boolean */
+{
+ int i, numdots, x0, y0, x1, y1;
+ double cx0, cy0, cx1, cy1;
+ double d, spacesize, a, b, dx, dy, pixperdash;
+ float inchesperdash;
+
+ if (sscanf(cp, " %f ", &inchesperdash) != 1) return;
+ if (pathlen <= 1) return;
+ pixperdash = inchesperdash * ((float) PixPerInY);
+ if (pixperdash < 2.)
+ pixperdash = 2.;
+ x0 = xx[1]; x1 = xx[2];
+ y0 = yy[1]; y1 = yy[2];
+ dx = x1 - x0;
+ dy = y1 - y0;
+ push_location();
+ if (dotted) {
+ numdots = sqrt(dx*dx + dy*dy) / pixperdash + 0.5;
+ if (numdots > 0)
+ for (i = 0; i <= numdots; i++) {
+ a = (float) i / (float) numdots;
+ cx0 = ((float) x0) + (a*dx) + 0.5;
+ cy0 = ((float) y0) + (a*dy) + 0.5;
+ dot_at((int) cx0, (int) cy0);
+ }
+ }
+ else {
+ d = sqrt(dx*dx + dy*dy);
+ if (d <= 2 * pixperdash) {
+ connect(x0, y0, x1, y1);
+ pathlen = 0;
+ pop_location();
+ return;
+ }
+ numdots = d / (2 * pixperdash) + 1;
+ spacesize = (d - numdots * pixperdash) / (numdots - 1);
+ for (i=0; i<numdots-1; i++) {
+ a = i * (pixperdash + spacesize) / d;
+ b = a + pixperdash / d;
+ cx0 = ((float) x0) + (a*dx) + 0.5;
+ cy0 = ((float) y0) + (a*dy) + 0.5;
+ cx1 = ((float) x0) + (b*dx) + 0.5;
+ cy1 = ((float) y0) + (b*dy) + 0.5;
+ connect((int) cx0, (int) cy0, (int) cx1, (int) cy1);
+ b += spacesize / d;
+ }
+ cx0 = ((float) x0) + (b*dx) + 0.5;
+ cy0 = ((float) y0) + (b*dy) + 0.5;
+ connect((int) cx0, (int) cy0, x1, y1);
+ }
+ pathlen = 0;
+ pop_location();
+}
+
+
+/*
+ * Virtually draw to a given x,y position on the virtual page.
+ * X and Y are expressed in thousandths of an inch, and this
+ * routine converts them to pixels.
+ *
+ * Called as \special{pa <x> <y>}
+ * eg: \special{pa 0 1200}
+ */
+static void im_drawto(cp)
+char *cp;
+{
+ int x,y;
+
+ if (sscanf(cp, " %d %d ", &x, &y) != 2) return;
+
+ if (++pathlen >= MAXPOINTS)
+ error(1, 0, "Too many points specified");
+ xx[pathlen] = xconv(x) + ImHH;
+ yy[pathlen] = yconv(y) + ImVV;
+}
+
+/* Same routine as above, but it uses the special graphics primitives */
+static void im_arc(cp)
+char *cp;
+{
+ int xc, yc, xrad, yrad;
+ float start_angle, end_angle, fxrad, fyrad;
+ int xp, yp;
+
+ if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
+ &end_angle) != 6) return;
+ push_location();
+ set_pen_size();
+ xc = xconv(xc) + ImHH;
+ yc = yconv(yc) + ImVV;
+ {
+ double temp;
+ temp = start_angle;
+ start_angle = end_angle;
+ end_angle = temp;
+ }
+ if (xrad >= yrad-1 && xrad <= yrad+1) { /* Circle or arc */
+ putchar(DMD_CIRCLE);
+ putword(xc); putword(yc);
+ /* starting point */
+ fyrad = fconv(yrad, PixPerInY);
+ xp = fyrad * cos(start_angle) + xc + .5;
+ yp = fyrad * sin(start_angle) + yc + .5;
+ putword(xp); putword(yp);
+ /* finishing point */
+ xp = fyrad * cos(end_angle) + xc + .5;
+ yp = fyrad * sin(end_angle) + yc + .5;
+ putword(xp); putword(yp);
+ }
+ else { /* Ellipse */
+ putchar(DMD_ELLIPSE);
+ putword(xc); putword(yc);
+ /* starting point */
+ fxrad = fconv(xrad, PixPerInX);
+ fyrad = fconv(yrad, PixPerInY);
+ xp = fxrad * cos(start_angle) + xc + .5;
+ yp = fyrad * sin(start_angle) + yc + .5;
+ putword(xp); putword(yp);
+ /* finishing point */
+ xp = fxrad * cos(end_angle) + xc + .5;
+ yp = fyrad * sin(end_angle) + yc + .5;
+ putword(xp); putword(yp);
+ putword(xconv(xrad));
+ putword(yconv(yrad));
+ }
+ putchar(DMD_DRAWPATH);
+ putchar(BLACK);
+ do_attributes();
+ pop_location();
+}
+
+
+/*
+ * Create a spline through the points in the array.
+ * Called like flush path (fp) command, after points
+ * have been defined via pa command(s).
+ *
+ * eg: \special{sp}
+ */
+static void flush_spline()
+{
+ register int i;
+
+ push_location();
+ if (pathlen <= 0) return;
+ set_pen_size();
+ putchar(DMD_SPLINE);
+ putword(pathlen);
+ for (i=1; i<=pathlen; i++) {
+ putword(xx[i]);
+ putword(yy[i]);
+ }
+ pathlen = 0;
+ putchar(DMD_DRAWPATH);
+ putchar(BLACK);
+ do_attributes();
+ pop_location();
+}
+
+
+/*
+ * Whiten the interior of the next figure (path). Command is:
+ * \special{wh}
+ */
+static void im_whiten()
+{
+ whiten_next = TRUE;
+}
+
+
+/*
+ * Blacken the interior of the next figure (path). Command is:
+ * \special{bk}
+ */
+static void im_blacken()
+{
+ blacken_next = TRUE;
+}
+
+
+/*
+ * Shade the interior of the next figure (path) with the predefined
+ * texture. Command is:
+ * \special{sh}
+ */
+static void im_shade()
+{
+ shade_next = TRUE;
+}
+
+
+/*
+ * Define the texture array. Command is:
+ * \special{tx 32bits 32bits ....}
+ */
+static void im_texture(pcount,bitpattern)
+int pcount, bitpattern[32];
+{
+ int i,j,k;
+ unsigned long ul_one;
+
+#ifdef notdef
+#ifdef DEBUG
+ if (sizeof ul_one != TWIDTH)
+ error(1, 0, "pointer/size mismatch");
+#endif
+ j = 0;
+ for (k=0; k < THEIGHT/pcount; k++) {
+ for (i=0; i<pcount; i++) {
+ ul_one = htonl((unsigned long) bitpattern[i]);
+ bcopy((char *) &ul_one, stexture[j++], TWIDTH);
+ }
+ }
+ texture_defined = FALSE;
+#endif
+}
+
+
+/*
+ * This routine takes the string argument for a tx command and
+ * parses out the separate bitpatterns to call im_texture with.
+ * Written by Tinh Tang
+ */
+static void do_texture(t)
+char *t;
+{
+ int bitpattern[32];
+ int pcount = 0;
+
+ while (isspace (*t)) t++;
+ while (*t) {
+ if (sscanf(t, "%x", &bitpattern[pcount++]) != 1) {
+ error(0, 0, "malformed tx command");
+ return;
+ }
+ while (*t && !isspace(*t)) t++;/* Skip to space */
+ while (*t && isspace(*t)) t++;/* Skip to nonspace */
+ }
+ if (pcount != 4 && pcount != 8 && pcount != 16 && pcount != 32) {
+ error(0, 0, "malformed tx command");
+ return;
+ }
+ im_texture(pcount, bitpattern);
+}
+
+
+#define COMLEN 3 /* Length of a tpic command plus one */
+
+DoSpecial(k)
+ i32 k;
+{
+ char *spstring, *cp, command[COMLEN];
+ register int len;
+
+ spstring = malloc((unsigned) (k+1));
+ if (spstring == NULL) error(2, 0, "Out of memory");
+ len = 0;
+ while (k--) spstring[len++] = GetByte(stdin);
+ spstring[len] = '\0';
+ cp = spstring;
+ while (isspace(*cp)) ++cp;
+ len = 0;
+ while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
+ command[len] = '\0';
+
+ if (ImHH != hh || ImVV != vv)
+ ImSetPosition(hh, vv);
+
+ if (strcmp(command, "pn") == 0) im_pensize(cp);
+ else if (strcmp(command, "fp") == 0) im_flushpath();
+ else if (strcmp(command, "da") == 0) dashed_line(cp, 0);
+ else if (strcmp(command, "dt") == 0) dashed_line(cp, 1);
+ else if (strcmp(command, "pa") == 0) im_drawto(cp);
+ else if (strcmp(command, "ar") == 0) im_arc(cp);
+ else if (strcmp(command, "sp") == 0) flush_spline();
+ else if (strcmp(command, "sh") == 0) im_shade();
+ else if (strcmp(command, "wh") == 0) im_whiten();
+ else if (strcmp(command, "bk") == 0) im_blacken();
+ else if (strcmp(command, "tx") == 0) im_texture(cp);
+ else error(0, 0, "warning: ignoring \\special");
+
+ free(spstring);
+}
diff --git a/dviware/umddvi/dev/dmd.c b/dviware/umddvi/dev/dmd.c
new file mode 100644
index 0000000000..bc194b989e
--- /dev/null
+++ b/dviware/umddvi/dev/dmd.c
@@ -0,0 +1,920 @@
+#ifndef lint
+static char rcsid[] = "$Header: imagen1.c,v 2.4 86/11/18 02:26:18 chris Exp $";
+#endif
+
+/*
+ * DVI to Imagen driver
+ *
+ * Reads DVI version 2 files and converts to imPRESS commands for spooling to
+ * the Imagen (via ipr).
+ *
+ * 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 "dmddev.h"
+#include "dmdcodes.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 font *f; /* the font */
+ 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 family; /* DMD family number (we get one) */
+#ifdef notyet
+ int UseTime; /* cache info: flush fonts on LRU basis */
+#endif
+};
+
+/*
+ * We use one of the per-glyph user flags to keep track of whether a
+ * glyph has been loaded into the Imagen.
+ */
+#define GF_LOADED GF_USR0
+
+/*
+ * The exception that proves the rule is that hh and fromSP(dvi_h) are not
+ * allowed to get more than MaxDrift units apart.
+ */
+int MaxDrift; /* the maximum allowable difference between
+ hh and fromSP(dvi_h) */
+
+struct fontinfo *CurrentFont; /* the current font */
+
+int ExpectBOP; /* true => BOP ok */
+int ExpectEOP; /* true => EOP ok */
+
+int DPI; /* -d => device resolution (dots/inch) */
+int PFlag = 1; /* -p => no page reversal */
+int LFlag; /* -l => landscape mode (eventually...) */
+int SFlag = 1; /* -s => silent (no page numbers) */
+int Exflag; /* -x => exit emulator */
+int Debug; /* -D => debug flag */
+
+int XOffset;
+int YOffset; /* offsets for margins */
+
+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 HHMargin; /* horizontal margin (in DEVs) */
+int VVMargin; /* vertical margin (in DEVs) */
+
+long CurrentPagePointer; /* current page we are processing */
+long PrevPagePointer; /* The previous page pointer from the DVI
+ file. This allows us to read the file
+ backwards, which obviates the need for
+ page reversal (reversal is unsupported
+ on the 8/300). */
+
+int Numerator; /* numerator from DVI file */
+int Denominator; /* denominator from DVI file */
+int DVIMag; /* magnification from DVI file */
+int UserMag; /* user-specified magnification */
+
+int ImHH; /* Imagen horizontal position */
+int ImVV; /* Imagen vertical position */
+int ImFamily; /* Imagen current-font number */
+
+char *PrintEngine; /* e.g., canon, ricoh */
+struct search *FontFinder; /* maps from DVI index to internal fontinfo */
+int FontErrors; /* true => error(s) occurred during font
+ definitions from DVI postamble */
+
+struct fontinfo NoFont; /* a fake font to help get things started */
+
+char *getenv(), *malloc();
+
+/* Absolute value */
+#define ABS(n) ((n) >= 0 ? (n) : -(n))
+
+/* Put a two-byte (word) value to the Imagen */
+#define putword(w) (putchar((w) >> 8), putchar(w))
+
+/*
+ * Correct devpos (the actual device position) to be within MaxDrift pixels
+ * of dvipos (the virtual DVI position).
+ */
+#define FIXDRIFT(devpos, dvipos) \
+ if ((devpos) < (dvipos)) \
+ if ((dvipos) - (devpos) <= MaxDrift) \
+ /* void */; \
+ else \
+ (devpos) = (dvipos) - MaxDrift; \
+ else \
+ if ((devpos) - (dvipos) <= MaxDrift) \
+ /* void */; \
+ else \
+ (devpos) = (dvipos) + MaxDrift
+
+SelectFont(n)
+ i32 n;
+{
+ int x = S_LOOKUP;
+
+ if ((CurrentFont = (struct fontinfo *)SSearch(FontFinder, n, &x)) == 0)
+ GripeNoSuchFont(n);
+}
+
+/*
+ * Start a page (process a DVI_BOP).
+ */
+BeginPage()
+{
+ register int *i;
+ static int count[10]; /* the 10 counters */
+ static int beenhere;
+
+ if (!ExpectBOP)
+ GripeUnexpectedOp("BOP");
+ if (beenhere) {
+ if (!SFlag)
+ putc(' ', stderr);
+ } else
+ beenhere++;
+ CurrentPagePointer = ftell(stdin) - 1;
+
+ 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, PrevPagePointer);
+
+ if (!SFlag) {
+ (void) fprintf(stderr, "[%d", count[0]);
+ (void) fflush(stderr);
+ }
+ putchar(DMD_PAGE);
+ ImHH = 0;
+ ImVV = 0;
+
+ hh = HHMargin;
+ vv = VVMargin;
+ dvi_h = toSP(hh);
+ dvi_v = toSP(vv);
+ dvi_w = 0;
+ dvi_x = 0;
+ dvi_y = 0;
+ dvi_z = 0;
+}
+
+/*
+ * End a page (process a DVI_EOP)
+ */
+EndPage()
+{
+ int newpage;
+
+ if (!ExpectEOP)
+ GripeUnexpectedOp("EOP");
+
+ if (!SFlag) {
+ putc(']', stderr);
+ (void) fflush(stderr);
+ }
+ ExpectEOP = 0;
+ ExpectBOP++;
+
+again:
+ putchar(DMD_ENDPAGE);
+ newpage = pagecmd();
+ switch (newpage) {
+ case -1:
+ if (PrevPagePointer != -1)
+ fseek(stdin, PrevPagePointer, 0);
+ else
+ goto again;
+ break;
+ case 0:
+ fseek(stdin, CurrentPagePointer, 0);
+ break;
+ case 1:
+ default:
+ break;
+ }
+}
+
+/*
+ * Store the relevant information from the DVI postamble, and set up
+ * various internal things.
+ */
+PostAmbleHeader(p)
+ register struct PostAmbleInfo *p;
+{
+ register int n;
+
+ PrevPagePointer = p->pai_PrevPagePointer;
+ Numerator = p->pai_Numerator;
+ Denominator = p->pai_Denominator;
+ DVIMag = p->pai_DVIMag;
+
+ /*
+ * Set the conversion factor. This must be done before using
+ * any fonts.
+ */
+ SetConversion(DPI, UserMag, Numerator, Denominator, DVIMag);
+
+ n = p->pai_DVIStackSize * sizeof *dvi_stack;
+ dvi_stack = (struct localstack *) malloc((unsigned) n);
+ if ((dvi_stackp = dvi_stack) == NULL)
+ GripeOutOfMemory(n, "DVI stack");
+}
+
+/* Handle one of the font definitions from the DVI postamble. */
+PostAmbleFontDef(p)
+ register struct PostAmbleFont *p;
+{
+ register int i;
+ register struct glyph *g;
+ register struct fontinfo *fi;
+ register struct font *f;
+ register char *s;
+ char *fname;
+ int def = S_CREATE | S_EXCL;
+ char loaded[16];
+ char *rindex(), *strsave();
+
+ 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 = GetFont(p->paf_name, p->paf_DVIMag, p->paf_DVIDesignSize,
+ PrintEngine, &fname);
+ if ((fi->f = f) == NULL) {
+ GripeCannotGetFont(p->paf_name, p->paf_DVIMag,
+ p->paf_DVIDesignSize, PrintEngine, 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);
+
+ fi->pspace = p->paf_DVIMag / 6; /* a three-unit "thin space" */
+ fi->nspace = -4 * fi->pspace;
+ fi->vspace = 5 * fi->pspace;
+ putchar(DMD_MKFONT);
+ if (s = rindex(fname, '/'))
+ s++;
+ else
+ s = fname;
+ while (*s)
+ putchar(*s++);
+ putchar(0);
+ fi->family = inkbd();
+ if (fi->family == 255)
+ error(1, 0, "out of space in remote dmd");
+ s = loaded;
+ for (i = 0; i < sizeof loaded; i++)
+ *s++ = inkbd();
+#define bitset(a, i) (a[i>>3] & (1 << ((~i) & 07)))
+ for (i = 0; i < 128; i++) {
+ if (bitset(loaded, i)) {
+ g = GLYPH(f, i);
+ g->g_pixwidth = fromSP(g->g_tfmwidth);
+ g->g_flags |= GF_LOADED;
+ }
+ }
+}
+
+/* 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);
+}
+
+/* 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;
+ char *inname;
+
+ setbuf(stderr, serrbuf);
+
+ ProgName = *argv;
+ UserMag = 1000;
+ MaxDrift = DefaultMaxDrift;
+ DPI = DefaultDPI;
+ inname = "stdin";
+ PrintEngine = "dmd";
+
+ while ((c = getopt(argc, argv, "d:e:lm:pr:sxDX:Y:")) != EOF) {
+ switch (c) {
+
+ case 'd': /* max drift value */
+ MaxDrift = atoi(optarg);
+ break;
+
+ case 'e': /* engine */
+ PrintEngine = optarg;
+ break;
+
+ case 'l': /* landscape mode */
+ LFlag++;
+ break;
+
+ case 'm': /* magnification */
+ UserMag = atoi(optarg);
+ break;
+
+ case 'p': /* no page reversal */
+ PFlag++;
+ break;
+
+ case 'r': /* resolution */
+ DPI = atoi(optarg);
+ break;
+
+ case 's': /* silent */
+ SFlag++;
+ break;
+
+ case 'x': /* Exit */
+ Exflag++;
+ break;
+
+ case 'D':
+ Debug++;
+ break;
+
+ case 'X': /* x offset, in 1/10 inch increments */
+ XOffset = atoi(optarg);
+ break;
+
+ case 'Y': /* y offset */
+ YOffset = atoi(optarg);
+ break;
+
+ case '?':
+ (void) fprintf(stderr, "\
+Usage: %s [-d drift] [-m mag] [-x] [more options, see manual] [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);
+
+ dmdstart();
+ if (isatty(fileno(stdin))) {
+ putchar(Exflag ? DMD_EXIT : DMD_TERM);
+ exit(0);
+ }
+
+
+/* fontinit((char *) NULL); */
+
+ ReadPostAmble();
+
+ /* Margins -- needs work! */
+ HHMargin = DefaultLeftMargin + XOffset * DPI / 10;
+ VVMargin = DefaultTopMargin + YOffset * DPI / 10;
+
+ ReadPreAmble();
+ ExpectBOP++;
+ if (!PFlag)
+ (void) fseek(stdin, PrevPagePointer, 0);
+
+ /* All set! */
+
+ /*
+ * 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();
+ if (!SFlag) {
+ (void) fprintf(stderr, "\n");
+ (void) fflush(stderr);
+ }
+ putchar(DMD_TERM);
+ 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);
+}
+
+/*
+ * 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;
+{
+ register i32 h, w, rw;
+
+ fGetLong(stdin, h);
+ fGetLong(stdin, rw);
+
+ h = ConvRule(h);
+ w = ConvRule(rw);
+
+ /* put the rule out */
+ if (ImHH != hh || ImVV != vv)
+ ImSetPosition(hh, vv);
+ putchar(DMD_RULE);
+ putword(w);
+ putword(h);
+ if (advance) {
+ hh += w;
+ dvi_h += rw;
+ w = fromSP(dvi_h);
+ FIXDRIFT(hh, w);
+ }
+}
+
+/* if anyone ever uses character codes > 127, this driver will need work */
+char chartoobig[] = "Warning: character code %d too big for Imagen!";
+
+/*
+ * This rather large routine reads the DVI file and calls on other routines
+ * to do anything moderately difficult (except put characters: there is
+ * some ugly code with `goto's which makes things faster).
+ */
+
+ReadDVIFile()
+{
+ register int c;
+ register struct glyph *g;
+ register struct font *f;
+ register i32 p;
+ int advance;
+
+ ImFamily = -1; /* force DMD_SETFONT command */
+
+ /*
+ * 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 the
+ * program run a bit faster.
+ */
+ if (DVI_IsChar(c)) {
+ advance = 1;
+do_char:
+ 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;
+ }
+ if ((g->g_flags & GF_LOADED) == 0)
+ DownLoadGlyph(c, g);
+ if (HASRASTER(g)) { /* workaround for Imagen bug */
+
+ /* BEGIN INLINE EXPANSION OF ImSetPosition */
+ register int delta;
+
+ if (ImHH != hh) {
+ delta = hh - ImHH;
+ if (delta == 1)
+ putchar(DMD_FORW);
+ else if (delta == -1)
+ putchar(DMD_BACK);
+ else if (-128 <= delta && delta <= 127) {
+ putchar(DMD_HREL);
+ putchar(delta);
+ } else {
+ putchar(DMD_HABS);
+ putword(hh);
+ }
+ ImHH = hh;
+ }
+ if (ImVV != vv) {
+ delta = vv - ImVV;
+ if (-128 <= delta && delta <= 127) {
+ putchar(DMD_VREL);
+ putchar(delta);
+ } else {
+ putchar(DMD_VABS);
+ putword(vv);
+ }
+ ImVV = vv;
+ }
+ /* END INLINE EXPANSION OF ImSetPosition */
+ if (ImFamily != CurrentFont->family) {
+ putchar(DMD_SETFONT);
+ putchar(CurrentFont->family);
+ ImFamily = CurrentFont->family;
+ }
+ putchar(c);
+ ImHH += g->g_pixwidth;
+ }
+ 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 */
+ }
+
+ switch (DVI_DT(c)) {
+
+ case DT_SET:
+ advance = 1;
+ c = p;
+ if (c > 127)
+ error(0, 0, chartoobig, c);
+ goto do_char;
+
+ case DT_PUT:
+ advance = 0;
+ c = p;
+ if (c > 127)
+ error(0, 0, chartoobig, c);
+ 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 (PFlag)
+ return;
+ GripeUnexpectedOp("POST");
+ /* NOTREACHED */
+
+ 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;
+}
+
+/*
+ * Download the character c/g in the current font.
+ */
+DownLoadGlyph(c, g)
+ int c;
+ register struct glyph *g;
+{
+ register char *p;
+ register int i, j, w;
+
+ g->g_pixwidth = fromSP(g->g_tfmwidth);
+ g->g_flags |= GF_LOADED;
+ if (!HASRASTER(g)) /* never load dull glyphs */
+ return;
+
+ if (!LFlag) {
+ w = 0;
+ p = RASTER(g, CurrentFont->f, ROT_NORM);
+ } else {
+ w = 1 << 14;
+ p = RASTER(g, CurrentFont->f, ROT_RIGHT);
+ }
+
+ w |= (CurrentFont->family << 7) | c;
+
+ /* Define the character */
+ if (-128 <= g->g_pixwidth && g->g_pixwidth <= 127 &&
+ g->g_width <= 255 && g->g_height <= 255 &&
+ -128 <= g->g_xorigin && g->g_xorigin <= 127 &&
+ -128 <= g->g_yorigin && g->g_yorigin <= 127) {
+ putchar(DMD_SGLYPH); /* a.k.a. SGLY */
+ putword(w); /* rotation, family, member */
+ putchar(g->g_pixwidth); /* advance */
+ putchar(g->g_width); /* width */
+ putchar(g->g_xorigin); /* left offset */
+ putchar(g->g_height); /* height */
+ putchar(g->g_yorigin); /* top-offset */
+ } else {
+ putchar(DMD_BGLYPH); /* a.k.a. BGLY */
+ putword(w); /* rotation, family, member */
+ putchar(g->g_pixwidth); /* advance */
+ putchar(g->g_width); /* width */
+ putchar(g->g_xorigin); /* left offset */
+ putchar(g->g_height); /* height */
+ putchar(g->g_yorigin); /* top-offset */
+ }
+
+ /*
+ * Now put out the bitmap.
+ */
+ w = (g->g_width + 7) >> 3;
+ for (i = g->g_height; --i >= 0;)
+ for (j = w; --j >= 0;)
+ (void) putchar(*p++);
+
+ if (g->g_raster) { /* XXX */
+ free(g->g_raster);
+ g->g_raster = NULL;
+ }
+
+}
+
+/*
+ * Set the Imagen's h & v positions. It is currently at ImHH, ImVV.
+ */
+ImSetPosition(h, v)
+ register int h, v;
+{
+
+ register int delta;
+ if (ImHH != h) {
+ delta = h - ImHH;
+ if (delta == 1)
+ putchar(DMD_FORW);
+ else if (delta == -1)
+ putchar(DMD_BACK);
+ else if (-128 <= delta && delta <= 127) {
+ putchar(DMD_HREL);
+ putchar(delta);
+ } else {
+ putchar(DMD_HABS);
+ putword(h);
+ }
+ ImHH = h;
+ }
+ if (ImVV != v) {
+ delta = v - ImVV;
+ if (-128 <= delta && delta <= 127) {
+ putchar(DMD_VREL);
+ putchar(delta);
+ } else {
+ putchar(DMD_VABS);
+ putword(v);
+ }
+ ImVV = v;
+ }
+}
diff --git a/dviware/umddvi/dev/dmdcodes.h b/dviware/umddvi/dev/dmdcodes.h
new file mode 100644
index 0000000000..78b134e37a
--- /dev/null
+++ b/dviware/umddvi/dev/dmdcodes.h
@@ -0,0 +1,39 @@
+/* DMD command codes */
+
+#define DMD_FORW 131 /* one pixel forward */
+#define DMD_BACK 132 /* one pixel backward */
+#define DMD_HABS 135 /* + short, set absolute H pos */
+#define DMD_HREL 136 /* + schar, set relative H pos */
+#define DMD_VABS 137 /* + short, set absolute V pos */
+#define DMD_VREL 138 /* + schar, set relative V pos */
+
+#define DMD_EXIT 140
+#define DMD_ASCII 141
+#define DMD_TERM 142
+#define DMD_CLEAR 143
+#define DMD_TYPESET 144
+#define DMD_ACK 145
+#define DMD_NAK 146
+#define DMD_WIND 147
+#define DMD_NEXT 149
+
+#define DMD_RULE 193 /* print a rule */
+
+#define DMD_SGLYPH 198 /* define a small glyph */
+#define DMD_BGLYPH 199 /* define a big glyph */
+
+#define DMD_MKFONT 205 /* create a downloaded font */
+#define DMD_SETFONT 206 /* specify font number */
+
+#define DMD_PAGE 218 /* start a new page */
+#define DMD_ENDPAGE 219 /* request next action */
+
+#define DMD_SEGMENT 221 /* define path with lines */
+#define DMD_SPLINE 222 /* define path with spline */
+#define DMD_CIRCLE 223 /* define circular path */
+#define DMD_ELLIPSE 224 /* define elliptical path */
+#define DMD_DRAWPATH 225 /* draw a path */
+#define DMD_FILLPATH 226 /* fill a path */
+#define DMD_PENSIZE 227 /* set pen size */
+
+#define imP_ForceDel 240 /* force glyph deletion */
diff --git a/dviware/umddvi/dev/dmdhost.c b/dviware/umddvi/dev/dmdhost.c
new file mode 100644
index 0000000000..344b5d02b1
--- /dev/null
+++ b/dviware/umddvi/dev/dmdhost.c
@@ -0,0 +1,236 @@
+
+#include <stdio.h>
+#ifdef sys5
+#include <sys/termio.h>
+#else
+#include <sgtty.h>
+#endif
+#include <signal.h>
+#include <sys/jioctl.h>
+#include <setjmp.h>
+#include "dmdcodes.h"
+
+static jmp_buf jenv;
+int jerq;
+static char prooftty[] = "/dev/tty";
+#ifdef sys5
+static struct termio sttybuf, sttysave;
+#else
+static struct sgttyb modes, savetty;
+#endif
+static int termraw;
+
+void
+sighup()
+{
+ putchar(DMD_EXIT);
+ exit(1);
+}
+
+dmdstart()
+{
+ char command[256];
+ int ismpx;
+
+ signal(SIGHUP, sighup);
+
+ if ((jerq = open(prooftty, 2)) < 0) {
+ error(1, 0, prooftty);
+ exit(1);
+ }
+ if (ioctl(jerq, JMPX, 0) == -1)
+ ismpx = 0;
+ else
+ ismpx = 1;
+
+#ifdef sys5
+ ioctl(jerq, TCGETA, &sttysave);
+ sttybuf.c_iflag = IGNBRK;
+ sttybuf.c_cflag = (sttysave.c_cflag & (CBAUD | CLOCAL)) | CS8 | CREAD;
+ sttybuf.c_cc[VMIN] = 1;
+ (void)ioctl(jerq, TCSETAW, &sttybuf);
+#else
+ ioctl(jerq, TIOCGETP, &modes);
+ savetty = modes;
+ modes.sg_flags |= RAW;
+ modes.sg_flags &= ~ECHO;
+ ioctl(jerq, TIOCSETP, &modes);
+#endif
+ termraw++;
+#define Proofm "/usr/local/lib/dvidmd.m"
+#define Proofj "/usr/local/lib/dvidmd.j"
+#define X32ld "32ld"
+ if (!isatty(1) || !verify()) {
+ sprintf(command, "%s %s < %s > %s", X32ld,
+ ismpx ? Proofm : Proofj, prooftty, prooftty);
+ if (system(command) != 0)
+ error(1, 0, "%s failed", X32ld);
+ if (!verify())
+ error(1, 0, "could not sync display");
+ }
+}
+
+void
+alarmcatch(sig)
+{
+ longjmp(jenv, 1);
+}
+
+verify()
+{
+ char c;
+
+ signal(SIGALRM, alarmcatch);
+ c = DMD_TYPESET;
+ write(jerq, &c, 1);
+ if (setjmp(jenv))
+ return(0);
+ alarm(2);
+ read(jerq, &c, 1);
+ alarm(0);
+ return (c == DMD_ACK);
+}
+
+pagecmd()
+{
+ int i, c;
+
+ switch (c = inkbd()) {
+ case DMD_EXIT:
+ exit(0);
+ case DMD_PAGE:
+ i = inkbd();
+ if (i > 127)
+ i -= 256;
+ return(i);
+ default:
+ error(1, 0, "bad pagecmd response 0%o", c);
+ }
+ /*NOTREACHED*/
+}
+
+inkbd()
+{
+ char c;
+ register i;
+
+ fflush(stdout);
+ if (read(jerq, &c, 1) != 1)
+ c = 4; /* ^D, looks like EOF */
+ i = c & 0377;
+ return(i);
+}
+
+exit(n)
+{
+ fflush(stdout);
+ fflush(stderr);
+ if (termraw) {
+#ifdef sys5
+ (void)ioctl(jerq, TCSETAW, &sttysave);
+#else
+ ioctl(jerq, TIOCSETP, &savetty);
+#endif
+ }
+ _exit(n);
+}
+
+#ifndef lint
+static char rcsid[] = "$Header: error.c,v 2.5 86/11/08 17:09:39 chris Exp $";
+#endif
+
+/*
+ * Print an error message with an optional system error number, and
+ * optionally quit.
+ *
+ * THIS CODE IS SYSTEM DEPENDENT UNLESS varargs WORKS WITH vprintf
+ * OR _doprnt. It should work properly under System V using vprintf.
+ * (If you have vprintf, define HAVE_VPRINTF.)
+ */
+
+#include <varargs.h>
+
+#ifdef lint
+
+/* VARARGS3 ARGSUSED */
+error(quit, e, fmt) int quit, e; char *fmt; {;}
+
+/* VARARGS1 ARGSUSED */
+panic(fmt) char *fmt; { exit(1); /* NOTREACHED */ }
+
+#else lint
+
+extern char *ProgName;
+extern int errno;
+extern char *sys_errlist[];
+extern int sys_nerr;
+
+/*
+ * We can be civlised by calling legitimate routines.
+ */
+error(va_alist)
+ va_dcl
+{
+ va_list l;
+ int quit, e;
+ char *fmt;
+
+ if (termraw)
+ putchar(DMD_ASCII);
+ (void) fflush(stdout); /* sync error messages */
+ (void) fprintf(stderr, "%s: ", ProgName);
+ va_start(l);
+ /* pick up the constant arguments: quit, errno, printf format */
+ quit = va_arg(l, int);
+ e = va_arg(l, int);
+ if (e < 0)
+ e = errno;
+ fmt = va_arg(l, char *);
+#if defined(sys5) || defined(HAVE_VPRINTF)
+ (void) vfprintf(stderr, fmt, l);
+#else
+ _doprnt(fmt, l, stderr);
+#endif
+ va_end(l);
+ if (e) {
+ if (e < sys_nerr)
+ (void) fprintf(stderr, ": %s", sys_errlist[e]);
+ else
+ (void) fprintf(stderr, ": Unknown error code %d", e);
+ }
+ (void) putc('\n', stderr);
+ (void) fflush(stderr); /* just in case */
+ if (termraw)
+ putchar(0);
+ if (quit) {
+ if (termraw)
+ putchar(DMD_TERM);
+ exit(quit);
+ }
+}
+
+panic(va_alist)
+ va_dcl
+{
+ va_list l;
+ char *fmt;
+
+ if (termraw)
+ putchar(DMD_TERM);
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "%s: panic: ", ProgName);
+ va_start(l);
+ /* pick up the constant argument: printf format */
+ fmt = va_arg(l, char *);
+#if defined(sys5) || defined(HAVE_VPRINTF)
+ (void) vfprintf(stderr, fmt, l);
+#else
+ _doprnt(fmt, l, stderr);
+#endif
+ va_end(l);
+ (void) putc('\n', stderr);
+ (void) fflush(stderr);
+ abort();
+}
+
+#endif /* lint */
diff --git a/dviware/umddvi/dev/dmdslave.c b/dviware/umddvi/dev/dmdslave.c
new file mode 100644
index 0000000000..ac1988379c
--- /dev/null
+++ b/dviware/umddvi/dev/dmdslave.c
@@ -0,0 +1,1176 @@
+/*
+ * Typesetter/Terminal Emulator for the DMD 5620
+ *
+ * Lou Salkind
+ * New York University
+ * Thu Apr 2 01:21:09 EST 1987
+ *
+ * This program was inspired by the DMD proof program
+ * and the Impress typesetting language. It is used by
+ * the TeX DVIDMD driver.
+ */
+
+#include <jerq.h>
+#include "layer.h"
+#include "font.h"
+#include "dmdcodes.h"
+
+#define MAXFAMILY 128 /* number of different fonts */
+#define MAXFONTNAME 16 /* maximum font string */
+#define PAGECHAR 8192 /* buffered characters to save */
+#define MAXPAGE 127
+
+#define SCROLLSIZE 20 /* scrolling border */
+#define PAGEPIXELS 1010 /* XXX - length of page (should be an argument) */
+#define NEWLINESIZE 16
+#define CURSOR '\01' /* cursor char in font */
+#define LINEBUFSIZE 100
+
+#define MOVED 256
+
+#ifdef PAGECHAR
+/* treatment of input characters */
+#define CHAR_DISCARD 0
+#define CHAR_STORE 1
+#define CHAR_FETCH 2
+
+int savechars;
+char savebuf[PAGECHAR];
+char *saveptr;
+#endif
+
+#define RoundUp(a, b) (((a) + (b) - 1) & ~((b) - 1))
+
+#ifdef MPX
+#undef cursinhibit
+#undef cursallow
+#define cursinhibit() {}
+#define cursallow() {}
+#endif
+
+static Texture16 prompt = {
+ 0x0000, 0x0000, 0x0000, 0x322E, 0x4B69, 0x4369, 0x42A9, 0x42A9,
+ 0x42A9, 0x4229, 0x4229, 0x4229, 0x322E, 0x0000, 0x0000, 0x0000
+};
+
+Point fudge = {5, 3}; /* DAG - offsets from corners */
+
+int dotypeset; /* 1==typesetter, 0==terminal */
+int cursvis; /* is cursor visible */
+Point org; /* current origin */
+Point typeorg; /* current typesetter origin */
+Point curpt; /* current typesetter point relative to origin */
+Point curpos; /* current ascii terminal position */
+
+struct line {
+ char buf[LINEBUFSIZE];
+ char *bufp;
+};
+
+struct line line;
+
+struct glyph {
+ Bitmap g_bitmap;
+ short g_pxwidth;
+ short g_xoffset;
+ short g_yoffset;
+};
+
+struct fontinfo {
+ char f_name[MAXFONTNAME];
+ struct glyph f_glyph[128];
+};
+
+struct fontinfo *ftbl[MAXFAMILY];
+struct fontinfo *curfont;
+Point inpoint();
+
+
+main()
+{
+ register int c;
+
+ resetmode(DMD_TERM);
+#ifdef MPX
+ P->state |= RESHAPED; /* set window parameters */
+#else
+ Drect = inset(Drect, 2);
+#endif /* MPX */
+ windowupdate();
+ for(;;) {
+ c = inchar();
+ if (dotypeset)
+ typeset(c);
+ else {
+ if(cursvis)
+ term(CURSOR, 0); /* undraw cursor */
+ term(c, 1);
+ while (own()&RCV)
+ term(inchar(), 1);
+ term(CURSOR, 0); /* draw at new spot */
+ cursvis = 1;
+ }
+ }
+}
+
+/* terminal emulation */
+term(c, advance)
+ register int c;
+{
+ register struct line *linep = &line;
+ register Point *pp = &curpos;
+ register Fontchar *fp;
+ Rectangle r;
+ Point p;
+
+ if (c & 0x80) {
+ if (c == DMD_TYPESET) {
+ resetmode(DMD_TYPESET);
+ send(DMD_ACK);
+ return;
+ }
+ c &= 0x7F;
+ }
+ switch(c) {
+ default:
+ fp = defont.info+c;
+ if (fp->width+pp->x >= Drect.corner.x)
+ newline(linep, pp);
+ p = *pp;
+ r.origin.x = fp->x;
+ r.corner.x = (fp+1)->x;
+ if (advance) {
+ r.origin.y = 0;
+ r.corner.y = defont.height;
+ bitblt(defont.bits, r, &display, p, F_STORE);
+ pp->x += fp->width;
+ if (linep->bufp < linep->buf+LINEBUFSIZE)
+ *linep->bufp++ = c;
+ } else {
+ r.origin.y = fp->top;
+ r.corner.y = fp->bottom;
+ p.y += fp->top;
+ bitblt(defont.bits, r, &display, p, F_XOR);
+ }
+ break;
+ case '\n':
+ newline(linep, pp);
+ break;
+ case '\7':
+ ringbell(); /* DAG -- should work? */
+ case 0:
+ break;
+ case '\r':
+ pp->x=Drect.origin.x+fudge.x; /* DAG -- changed 5 to fudge.x */
+ linep->bufp = linep->buf;
+ break;
+ case '\013': /* ^K: reverse linefeed */
+ if(pp->y>Drect.origin.y+fudge.y+defont.height)
+ pp->y-=NEWLINESIZE;
+ break;
+ case '\b':
+ backspace(linep, pp);
+ break;
+ case '\014':
+ formfeed(linep, pp);
+ break;
+ case '\t':
+ pp->x=nexttab(pp->x);
+ if(pp->x>=Drect.corner.x)
+ newline(linep, pp);
+ if(linep->bufp<linep->buf+LINEBUFSIZE)
+ *linep->bufp++=c;
+ break;
+ }
+}
+
+/*int eightspaces=8*dispatch[' '].c_wid;*/
+int eightspaces=72;
+
+nexttab(x)
+{
+ register int xx = x-Drect.origin.x-fudge.x;
+
+ return(xx-(xx%eightspaces)+eightspaces+Drect.origin.x+fudge.x);
+}
+
+backspace(linep, pp)
+ register struct line *linep;
+ register Point *pp;
+{
+ register char *p;
+ register int x = Drect.origin.x+fudge.x;
+
+ if (linep->bufp>linep->buf) {
+ for (p=linep->buf; p<linep->bufp-1; p++)
+ if (*p=='\t')
+ x = nexttab(x);
+ else
+ x += defont.info[*p].width;
+ pp->x = x;
+ --linep->bufp;
+ if (*p!='\t')
+ term(*p, 0);
+ }
+}
+
+newline(linep, pp)
+ struct line *linep;
+ register Point *pp;
+{
+ register cursoff=0;
+
+ if (pp->y+2*NEWLINESIZE > Drect.corner.y-fudge.y+1) {
+ /* weirdness is because the tail of the arrow may be anywhere */
+ if (rectXrect(Rect(mouse.xy.x-16, mouse.xy.y-16, mouse.xy.x+16,
+ mouse.xy.y+16), Drect)){
+ cursinhibit();
+ cursoff++;
+ }
+ lscroll();
+ if(cursoff)
+ cursallow();
+ } else
+ pp->y += NEWLINESIZE;
+ pp->x = Drect.origin.x+fudge.x;
+ linep->bufp = linep->buf;
+}
+
+lscroll()
+{
+ Rectangle r;
+
+ r = Drect;
+ r.origin.y += NEWLINESIZE;
+ bitblt(&display, r, &display, Pt(r.origin.x, r.origin.y-NEWLINESIZE), F_STORE);
+ stipple(Rpt(Pt(Drect.origin.x, Drect.corner.y-NEWLINESIZE), Drect.corner));
+}
+
+formfeed(linep, pp)
+ struct line *linep;
+ Point *pp;
+{
+ cursinhibit();
+ stipple(Drect);
+ cursallow();
+ *pp=add(Drect.origin, fudge);
+ linep->bufp=linep->buf;
+}
+
+stipple(r)
+ Rectangle r;
+{
+ cursinhibit();
+ rectf(&display, r, F_CLR);
+ cursallow();
+}
+
+/* routines to handle command input */
+
+inchar()
+{
+ register int c;
+
+#ifdef PAGECHAR
+ if (savechars == CHAR_FETCH)
+ return(*saveptr++ & 0377);
+#endif
+#ifdef MPX
+ wait(RCV);
+ if (P->state&(RESHAPED|MOVED))
+ windowupdate();
+ c = rcvchar();
+#else
+ for ( ; ; ) {
+ wait(RCV|KBD);
+ if (own() & RCV) {
+ c = rcvchar();
+ break;
+ }
+ if (!dotypeset)
+ send(kbdchar());
+ }
+#endif MPX
+#ifdef PAGECHAR
+ if (savechars == CHAR_STORE) {
+ if (saveptr < &savebuf[PAGECHAR])
+ *saveptr++ = c;
+ else
+ savechars = CHAR_DISCARD;
+ }
+#endif
+ return(c&0377);
+}
+
+insignchar()
+{
+ register int c;
+
+ c = inchar();
+ if (c > 127)
+ c -= 256;
+ return(c);
+}
+
+inshort()
+{
+ register short i;
+
+ i = inchar() << 8;
+ i |= inchar();
+ return(i);
+}
+
+Point
+inpoint()
+{
+ Point p;
+
+ p.x = inshort() + typeorg.x;
+ p.y = inshort() + typeorg.y;
+ return(p);
+}
+
+send(c)
+{
+ char cc = c;
+
+ sendnchars(1, &cc);
+}
+
+/* typesetter emulation */
+typeset(c)
+ register int c;
+{
+ register struct glyph *g;
+ register Bitmap *b;
+ Point pprime;
+ int old;
+
+ if (c <= 127) {
+ if (curfont == 0)
+ return;
+ g = &curfont->f_glyph[c];
+ b = &g->g_bitmap;
+ if (b->base == 0) {
+ curpt.x += g->g_pxwidth;
+ return;
+ }
+ pprime = add(curpt, typeorg);
+ pprime.x -= g->g_xoffset;
+ pprime.y -= g->g_yoffset;
+ bitblt(b, b->rect, &display, pprime, F_OR);
+ curpt.x += g->g_pxwidth;
+ return;
+ }
+
+ switch (c) {
+ case DMD_EXIT:
+ bye();
+ break;
+ case DMD_TERM:
+#ifdef PAGECHAR
+ savechars = CHAR_DISCARD;
+#endif
+ resetmode(DMD_TERM);
+ break;
+ case DMD_CLEAR:
+ stipple(Drect);
+ curpos = add(org, fudge);
+ break;
+ case DMD_TYPESET:
+ send(DMD_ACK);
+ break;
+ case DMD_ASCII:
+#ifdef PAGECHAR
+ if (savechars == CHAR_STORE)
+ saveptr--;
+ old = savechars;
+ savechars = CHAR_DISCARD;
+#endif
+ while (c = inchar())
+ term(c, 1);
+#ifdef PAGECHAR
+ savechars = old;
+#endif
+ break;
+ case DMD_RULE: {
+ short w, h;
+ Rectangle r;
+
+ w = inshort();
+ h = inshort();
+ pprime = add(curpt, typeorg);
+ pprime.y++;
+ r.origin = pprime;
+ r.origin.y = pprime.y - h;
+ r.corner = pprime;
+ r.corner.x = pprime.x + w;
+ rectf(&display, r, F_STORE);
+ break;
+ }
+ case DMD_FORW:
+ curpt.x++;
+ break;
+ case DMD_BACK:
+ curpt.x--;
+ break;
+ case DMD_HABS:
+ curpt.x = inshort();
+ break;
+ case DMD_HREL:
+ curpt.x += insignchar();
+ break;
+ case DMD_VABS:
+ curpt.y = inshort();
+ break;
+ case DMD_VREL:
+ curpt.y += insignchar();
+ break;
+ case DMD_PAGE:
+#ifdef PAGECHAR
+ saveptr = savebuf;
+ savechars = CHAR_STORE;
+#endif
+ stipple(Drect);
+ curpos = add(org, fudge);
+ curpt.x = curpt.y = 0;
+ break;
+ case DMD_ENDPAGE:
+ pagecmd();
+ break;
+ case DMD_SETFONT: {
+ int i;
+
+ i = inchar();
+ if (i < MAXFAMILY)
+ curfont = ftbl[i];
+ break;
+ }
+ case DMD_MKFONT:
+ case DMD_SGLYPH:
+ case DMD_BGLYPH:
+#ifdef PAGECHAR
+ if (savechars == CHAR_STORE)
+ saveptr--;
+ old = savechars;
+ savechars = CHAR_DISCARD;
+#endif
+ if (c == DMD_MKFONT)
+ ldfont();
+ else
+ ldglyph(c);
+#ifdef PAGECHAR
+ savechars = old;
+#endif
+ break;
+ case DMD_SEGMENT:
+ case DMD_SPLINE:
+ define_path(c);
+ break;
+ case DMD_CIRCLE:
+ define_circle();
+ break;
+ case DMD_ELLIPSE:
+ define_ellipse();
+ break;
+ case DMD_DRAWPATH:
+ draw_path();
+ break;
+ case DMD_FILLPATH:
+ fill_path();
+ break;
+ case DMD_PENSIZE:
+ set_pen();
+ break;
+ default:
+ break;
+ }
+}
+
+/* request an index number for a new font */
+ldfont()
+{
+ register struct fontinfo *f;
+ register int i, j;
+ register int x = -1;
+ char name[MAXFONTNAME];
+ register char *p;
+ char loaded[16];
+
+ p = name;
+ while (*p++ = inchar())
+ if (p >= &name[MAXFONTNAME]) {
+ while (inchar())
+ continue;
+ break;
+ }
+ for (i = 0; i < sizeof(loaded); i++)
+ loaded[i] = 0;
+ /* look for the font... */
+ for (i = 0; i < MAXFAMILY; i++) {
+ f = ftbl[i];
+ if (f && strncmp(f->f_name, name, sizeof(f->f_name)) == 0) {
+ for (j = 0; j < 128; j++) {
+ if (f->f_glyph[j].g_bitmap.base)
+ loaded[j>>3] |= 1 << (~j & 07);
+ }
+ send(i);
+ sendnchars(sizeof(loaded), loaded);
+ return;
+ }
+ if (x == -1 && f == 0)
+ x = i;
+ }
+ if (x == -1) {
+ send(-1);
+ return;
+ }
+ f = (struct fontinfo *)alloc(sizeof (struct fontinfo));
+ if (f == 0) {
+ send(-1);
+ return;
+ }
+ ftbl[x] = f;
+ strncpy(f->f_name, name, sizeof(f->f_name));
+ send(x);
+ sendnchars(sizeof(loaded), loaded);
+}
+
+/* download a particular character in a font */
+ldglyph(c)
+ int c;
+{
+ register struct glyph *g;
+ register int i, j;
+ register char *p;
+ short chr, fam, w;
+ int words;
+ int o;
+ short xs, ys;
+ int endb;
+ static struct glyph gdummy;
+
+ w = inshort();
+ fam = (w >> 7) & 0177;
+ chr = w & 0177;
+ if (ftbl[fam])
+ g = &(ftbl[fam]->f_glyph[chr]);
+ else {
+ ftbl[fam] = (struct fontinfo *)alloc(sizeof (struct fontinfo));
+ g = ftbl[fam] ? &(ftbl[fam]->f_glyph[chr]) : &gdummy;
+ }
+
+ if (c == DMD_SGLYPH) {
+ g->g_pxwidth = insignchar();
+ xs = inchar();
+ g->g_xoffset = insignchar();
+ ys = inchar();
+ g->g_yoffset = insignchar();
+ } else {
+ g->g_pxwidth = inshort();
+ xs = inshort();
+ g->g_xoffset = inshort();
+ ys = inshort();
+ g->g_yoffset = inshort();
+ }
+ words = RoundUp(xs, WORDSIZE) >> WORDSHIFT;
+ o = RoundUp(xs, 8) >> 3;
+ endb = words * sizeof(Word);
+ if (g->g_bitmap.base)
+ free(g->g_bitmap.base);
+ if (g == &gdummy || (p = alloc(ys * endb)) == 0) {
+ /* skip raster bytes */
+ j = o * ys;
+ for (i = 0; i < j; i++)
+ inchar();
+ } else {
+ /* read raster here */
+ g->g_bitmap.base = (Word *)p;
+ g->g_bitmap.width = words;
+ g->g_bitmap.rect.origin.x = 0;
+ g->g_bitmap.rect.origin.y = 0;
+ g->g_bitmap.rect.corner.x = xs;
+ g->g_bitmap.rect.corner.y = ys;
+ g->g_bitmap._null = 0;
+ p = (char *)g->g_bitmap.base;
+ for (j = 0; j < ys; j++) {
+ for (i = 0; i < o; i++)
+ *p++ = inchar();
+ for ( ; i < endb; i++)
+ *p++ = 0;
+ }
+ }
+}
+
+/* mouse and keyboard input routines at end of page */
+
+static char *b3m[] = {
+ "redraw",
+ "next",
+ "prev",
+ "quit",
+ "exit",
+ NULL
+};
+
+static Menu menu = { b3m };
+
+Texture16 ok = {
+ 0x1C44, 0x2248, 0x2250, 0x2270,
+ 0x2248, 0x1C44, 0x0000, 0x0380,
+ 0x0440, 0x0440, 0x0080, 0x0100,
+ 0x0100, 0x0100, 0x0000, 0x0100,
+};
+
+minkbd()
+{
+ Texture16 *t;
+ register int i;
+ int oscroll = 0;
+ register int inscroll = 0;
+ Point selpt;
+
+ while (i = wait(KBD|MOUSE|RCV)) {
+ if (i&KBD)
+ return(kbdchar());
+ else if (i&RCV)
+ return(rcvchar());
+ selpt = mouse.xy;
+ i = selpt.x - Drect.origin.x;
+ inscroll = 0;
+ if (i >= 0 && i < SCROLLSIZE)
+ inscroll += 1;
+ i = Drect.corner.y - selpt.y;
+ if (i >= 0 && i < SCROLLSIZE)
+ inscroll += 2;
+ if (inscroll != oscroll) {
+ cursswitch(inscroll ? &C_crosshair : &prompt);
+ oscroll = inscroll;
+ }
+ switch (inscroll) {
+ case 0:
+ if (!bttn3())
+ break;
+ switch (i = menuhit(&menu, 3)) {
+ case -1:
+ break;
+ case 4:
+ t = cursswitch(&ok);
+ while (!bttn123()) sleep(1);
+ i = bttn3();
+ while (bttn123()) sleep(1);
+ (void)cursswitch(t);
+ if (i)
+ return('x');
+ break;
+ default:
+ return("rnpq"[i]);
+ }
+ break;
+ case 1:
+ if (!bttn13())
+ break;
+ if (bttn1())
+ typeorg.y -= selpt.y - Drect.origin.y;
+ else
+ typeorg.y += selpt.y - Drect.origin.y;
+ /* primitive scroll for now */
+ while (bttn123());
+ return('s');
+ case 2:
+ if (!bttn13())
+ break;
+ if (bttn1())
+ typeorg.x -= selpt.x - Drect.origin.x;
+ else
+ typeorg.x += selpt.x - Drect.origin.x;
+ /* primitive scroll for now */
+ while (bttn123());
+ return('s');
+ case 3:
+ if (bttn1())
+ return('n');
+ else if (bttn2())
+ return('r');
+ else if (bttn3())
+ return('p');
+ break;
+ }
+ sleep(1);
+ }
+ /*NOT REACHED*/
+}
+
+pagecmd()
+{
+ register int i;
+ register Texture16 *t;
+ int cmd;
+ Point p1, p2;
+ int redraw;
+#ifdef PAGECHAR
+ int pagesaved;
+ char buf[40];
+
+ pagesaved = savechars != CHAR_DISCARD;
+#endif
+ t = cursswitch(&prompt);
+pgstart:
+ redraw = 0;
+ /*
+ * draw outlines of scroll bars. We will draw
+ * the whole lines when we can't write in the
+ * scroll area, but for now, do it this way.
+ */
+ p1 = Drect.origin;
+ p1.x += SCROLLSIZE;
+ p2.x = p1.x;
+ p2.y = p1.y + SCROLLSIZE;
+ segment(&display, p1, p2, F_STORE);
+ p1.y = Drect.corner.y - 2*SCROLLSIZE;
+ p2.y = Drect.corner.y;
+ segment(&display, p1, p2, F_STORE);
+ p1.y = Drect.corner.y - SCROLLSIZE;
+ p2.y = p1.y;
+ p1.x = Drect.origin.x;
+ p2.x = p1.x + 2*SCROLLSIZE;
+ segment(&display, p1, p2, F_STORE);
+ p1.x = Drect.corner.x - SCROLLSIZE;
+ p2.x = Drect.corner.x;
+ segment(&display, p1, p2, F_STORE);
+#ifdef PAGECHAR
+ savechars = CHAR_DISCARD;
+#ifdef DEBUG
+ sprintf(buf, "%d", saveptr-savebuf);
+ p1 = org;
+ p1.x += 20;
+ p1.y += 20;
+ string(&defont, buf, &display, p1, F_XOR);
+#endif
+#endif
+ switch (cmd = minkbd()) {
+ case 0177:
+ case 04:
+ case 'q':
+ send(DMD_EXIT);
+ resetmode(DMD_TERM);
+ t = 0;
+ break;
+ case 'x':
+ send(DMD_EXIT);
+ bye();
+ break;
+ case 'r':
+ case '\f':
+ typeorg = org;
+ /* fall into... */
+ case 's':
+ redraw = 1;
+ break;
+ case 'n':
+ case ' ':
+ typeorg.y -= Drect.corner.y - Drect.origin.y;
+ if (org.y - typeorg.y < PAGEPIXELS) {
+ redraw = 1;
+ break;
+ }
+ /* fall into... */
+ case '+':
+ case '\r':
+ case '\n':
+ typeorg = org;
+ send(DMD_PAGE);
+ send(1);
+ break;
+ case 'p':
+ typeorg.y += Drect.corner.y - Drect.origin.y;
+ if (org.y >= typeorg.y) {
+ redraw = 1;
+ break;
+ }
+ /* fall into... */
+ case '-':
+ typeorg = org;
+ send(DMD_PAGE);
+ send(-1);
+ break;
+ default:
+ /* ringbell(); */
+ goto pgstart;
+ }
+ if (redraw) {
+#ifdef PAGECHAR
+ if (pagesaved) {
+#ifdef MPX
+ if (P->state&(RESHAPED|MOVED))
+ windowupdate();
+#endif
+ typeset(DMD_PAGE);
+ saveptr = savebuf;
+ savechars = CHAR_FETCH;
+ while ((i = inchar()) != DMD_ENDPAGE)
+ typeset(i);
+ (void)cursswitch(&prompt);
+ goto pgstart;
+ }
+#endif
+ send(DMD_PAGE);
+ send(0);
+ }
+ (void)cursswitch(t);
+}
+
+inkbd()
+{
+ wait(RCV|KBD);
+ return((own()&KBD)? kbdchar():rcvchar());
+}
+
+bye()
+{
+ register int i;
+
+ for (i = 0; i < MAXFAMILY; i++) {
+ if (ftbl[i])
+ freefont(ftbl[i]);
+ }
+ exit();
+}
+
+freefont(f)
+ struct fontinfo *f;
+{
+ struct glyph *g;
+
+ for (g = f->f_glyph; g < &f->f_glyph[128]; g++)
+ if (g->g_bitmap.base)
+ free((char *)g->g_bitmap.base);
+ free((char *)f);
+}
+
+#ifdef notdef
+edit(s)
+ char *s;
+{
+ char buf[40];
+ Point p;
+ int c;
+ register i;
+
+ strcpy(buf, s);
+ p = mouse.xy;
+ disp(buf, p);
+ for(i = strlen(buf); (c = inkbd()) != '\r';)
+ {
+ disp(buf, p);
+ p = mouse.xy;
+ switch(c)
+ {
+ case '\b':
+ if((buf[i] != ' ') && (i > 0))
+ buf[--i] = 0;
+ break;
+ case '@':
+ while(buf[i] != ' ') i--;
+ buf[++i] = 0;
+ break;
+ default:
+ buf[i++] = c;
+ buf[i] = 0;
+ break;
+ }
+ disp(buf, p);
+ }
+ disp(buf, p);
+ strcpy(s, buf);
+}
+
+disp(s, p)
+ char *s;
+ Point p;
+{
+ string(&defont, "\001", &display,
+ string(&defont, s, &display, p, F_XOR), F_XOR);
+}
+#endif
+
+resetmode(c)
+ int c;
+{
+ if (c == DMD_TERM) {
+ cursvis = dotypeset = 0;
+#ifdef MPX
+ request(SEND|RCV);
+#else
+ request(SEND|RCV|KBD);
+#endif
+ curpos.x = org.x + fudge.x;
+ curpos.y = Drect.corner.y - fudge.y - defont.height;
+ } else {
+ dotypeset = 1;
+ request(SEND|RCV|KBD|MOUSE);
+ typeorg = org;
+ }
+}
+
+windowupdate()
+{
+#ifdef MPX
+ if (P->state&RESHAPED) {
+#endif
+ org = Drect.origin;
+ typeorg = org;
+ curpos = add(org, fudge);
+ line.bufp = line.buf;
+ if (cursvis) {
+ term(CURSOR, 0); /* flip state */
+ cursvis = 0;
+ }
+#ifdef MPX
+ } else {
+ curpos = add(sub(curpos, org), Drect.origin);
+ typeorg = add(sub(typeorg, org), Drect.origin);
+ org = Drect.origin;
+ }
+ P->state &= ~(MOVED|RESHAPED);
+#endif
+ artdeco();
+}
+
+static Texture16 vstripe = {
+ 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
+ 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
+ 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0,
+ 0xf0f0, 0xf0f0, 0xf0f0, 0xf0f0
+};
+
+static Texture16 hstripe = {
+ 0xffff, 0xffff, 0xffff, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+ 0xffff, 0xffff, 0xffff, 0xffff,
+ 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+artdeco()
+{
+ texture16(&display, Rect(display.rect.origin.x, display.rect.origin.y,
+ display.rect.corner.x, Drect.origin.y), &vstripe, F_XOR);
+ texture16(&display, Rect(display.rect.origin.x, Drect.origin.y,
+ Drect.origin.x, Drect.corner.y), &hstripe, F_XOR);
+ texture16(&display, Rect(Drect.corner.x, Drect.origin.y,
+ display.rect.corner.x, Drect.corner.y), &hstripe, F_XOR);
+ texture16(&display, Rect(display.rect.origin.x, Drect.corner.y,
+ display.rect.corner.x, display.rect.corner.y), &vstripe, F_XOR);
+}
+
+/* graphics support; for now there are some unimplemented operations */
+
+#define MAXPOINTS 60
+
+#define PATH_NONE -1
+#define PATH_SEGMENT 0
+#define PATH_SPLINE 1
+#define PATH_CIRCLE 2
+#define PATH_ELLIPSE 3
+
+int path_type = PATH_NONE;
+int pen_size = 1;
+
+struct {
+ Point c_center;
+ Point c_start;
+ Point c_finish;
+} path_circle;
+
+struct {
+ Point e_center;
+ Point e_start;
+ Point e_finish;
+ short e_xradius;
+ short e_yradius;
+} path_ellipse;
+
+Point path_pts[MAXPOINTS+2];
+int path_len;
+
+define_path(c)
+{
+ register int i, n;
+ register Point *pp;
+
+ path_type = (c==DMD_SEGMENT) ? PATH_SEGMENT : PATH_SPLINE;
+ n = inshort();
+ path_len = n;
+ if (path_len > MAXPOINTS) {
+ path_len = MAXPOINTS;
+ for (i = path_len; i < n; i++)
+ (void)inpoint();
+ }
+ pp = &path_pts[1];
+ for (i = 0; i < path_len; i++)
+ *pp++ = inpoint();
+}
+
+define_circle()
+{
+ path_circle.c_center = inpoint();
+ path_circle.c_start = inpoint();
+ path_circle.c_finish = inpoint();
+ path_type = PATH_CIRCLE;
+}
+
+define_ellipse()
+{
+ path_ellipse.e_center = inpoint();
+ path_ellipse.e_start = inpoint();
+ path_ellipse.e_finish = inpoint();
+ path_ellipse.e_xradius = inshort();
+ path_ellipse.e_yradius = inshort();
+ path_type = PATH_ELLIPSE;
+}
+
+draw_path()
+{
+ int rop;
+
+ rop = inchar(); /* ignore for now */
+ switch (path_type) {
+ case PATH_SEGMENT:
+ draw_segment(F_OR);
+ break;
+ case PATH_SPLINE:
+ draw_spline(F_OR);
+ break;
+ case PATH_CIRCLE:
+ draw_circle(F_OR);
+ break;
+ case PATH_ELLIPSE:
+ draw_ellipse(F_OR);
+ break;
+ }
+}
+
+fill_path()
+{
+ int rop;
+
+ rop = inchar(); /* ignore for now */
+}
+
+set_pen()
+{
+ int i = inchar();
+
+ if (i < 1)
+ i = 1;
+ pen_size = i;
+}
+
+/* draw a spline path */
+draw_spline(f)
+ int f;
+{
+ register Point *pp = path_pts;
+ register long w, t1, t2, t3, scale=1000;
+ register int i, j, steps=10;
+ int n = path_len + 1;
+ Point p, q;
+
+ pp[0] = pp[1];
+ pp[n] = pp[n-1];
+ p = pp[0];
+ for (i = 0; i < n-1; i++) {
+ for (j = 0; j < steps; j++) {
+ w = scale * j / steps;
+ t1 = w * w / (2 * scale);
+ w = w - scale/2;
+ t2 = 3*scale/4 - w * w / scale;
+ w = w - scale/2;
+ t3 = w * w / (2*scale);
+ q.x = (t1*pp[i+2].x + t2*pp[i+1].x +
+ t3*pp[i].x + scale/2) / scale;
+ q.y = (t1*pp[i+2].y + t2*pp[i+1].y +
+ t3*pp[i].y + scale/2) / scale;
+ line_btw(p, q, f);
+ p = q;
+ }
+ }
+}
+
+/* draw a segment path */
+draw_segment(f)
+ int f;
+{
+ register Point *pp;
+ register int i;
+
+ pp = &path_pts[1];
+ if (path_len == 1) {
+ if (pen_size > 1)
+ disc(&display, pp[0], pen_size, f);
+ else
+ point(&display, pp[0], f);
+ } else {
+ for (i = 1; i < path_len; i++) {
+ line_btw(pp[0], pp[1], f);
+ pp++;
+ }
+ }
+}
+
+draw_circle(f)
+ int f;
+{
+ /* ignore pen size for now */
+
+ if (path_circle.c_center.x == path_circle.c_finish.x &&
+ path_circle.c_center.y == path_circle.c_finish.y) {
+ circle(&display, path_circle.c_center, path_circle.c_start.x, f);
+ } else {
+ arc(&display, path_circle.c_center, path_circle.c_start,
+ path_circle.c_finish, f);
+ }
+}
+
+draw_ellipse(f)
+ int f;
+{
+ /* ignore pen size for now */
+
+ if (path_ellipse.e_center.x == path_ellipse.e_finish.x &&
+ path_ellipse.e_center.y == path_ellipse.e_finish.y) {
+ ellipse(&display, path_ellipse.e_center, path_ellipse.e_xradius,
+ path_ellipse.e_yradius, f);
+ } else {
+ elarc(&display, path_ellipse.e_center, path_ellipse.e_xradius,
+ path_ellipse.e_yradius, path_ellipse.e_start,
+ path_ellipse.e_finish, f);
+ }
+}
+
+/* Draw a line on the screen. */
+line_btw(p0, p1, rop)
+ Point p0, p1;
+{
+ register int i;
+ register int incx;
+
+ if (abs(p1.y-p0.y) > abs(p1.x-p0.x)) {
+ incx = 1;
+ p0.x -= pen_size/2;
+ p1.x -= pen_size/2;
+ } else {
+ incx = 0;
+ p0.y -= pen_size/2;
+ p1.y -= pen_size/2;
+ }
+ for (i = 0; i < pen_size; i++) {
+ segment(&display, p0, p1, rop);
+ if (incx) {
+ p0.x++; p1.x++;
+ } else {
+ p0.y++; p1.y++;
+ }
+ }
+}
diff --git a/dviware/umddvi/dev/dvipr.sh b/dviware/umddvi/dev/dvipr.sh
new file mode 100644
index 0000000000..65ada43730
--- /dev/null
+++ b/dviware/umddvi/dev/dvipr.sh
@@ -0,0 +1,71 @@
+#! /bin/sh
+#
+# print a dvi file on the versatec
+#
+# NOTE: sense of -h is inverted (-h => no horizontal printing)
+
+flags=
+hflag=-h
+q=
+v=
+title=
+
+# eat arguments
+
+while [ $# -gt 0 ]
+do
+ case "$1" in
+ -m)
+ shift
+ flags="$flags -m $1";;
+ -h)
+ hflag=;;
+ -q)
+ q=q;;
+ -v)
+ v=v;;
+ -t)
+ echo tape interface not yet implemented 2>&1;;
+ -T)
+ shift
+ title="$1";;
+ -T*)
+ title="$1";;
+ -*)
+ flags="$flags $1";;
+ *)
+ break
+ esac
+ shift
+done
+
+if [ $# != 1 ]; then
+ echo "Usage: $0 [-q] [-v] [-h] [-s] [-m mag] [-d drift] [-T title] filename" 2>&1
+ exit 1
+fi
+
+if [ x"$title" = x ]; then
+ title="$*"
+fi
+
+# pass 2 only?
+if [ x$v = xv ]; then
+ exec spool -d versatec -verser2 -t "$title" $*
+fi
+
+dvifile=$1
+
+if [ ! -r $dvifile ]; then
+ dvifile=$1.dvi
+ if [ ! -r $dvifile ]; then
+ echo "$0: cannot find $1 or $1.dvi" 2>&1
+ exit 1
+ fi
+fi
+
+# pass 1 only?
+if [ x$q = xq ]; then
+ exec verser1 $hflag $flags $dvifile
+fi
+
+verser1 $hflag $flags $dvifile | spool -d versatec -verser2 -t "$title"
diff --git a/dviware/umddvi/dev/fontdesc b/dviware/umddvi/dev/fontdesc
new file mode 100644
index 0000000000..3954e1d339
--- /dev/null
+++ b/dviware/umddvi/dev/fontdesc
@@ -0,0 +1 @@
+font pxl * 0 /usr/local/lib/tex/fonts/pxl/%n.%mpxl
diff --git a/dviware/umddvi/dev/imagen1-special.c b/dviware/umddvi/dev/imagen1-special.c
new file mode 100644
index 0000000000..628b26c483
--- /dev/null
+++ b/dviware/umddvi/dev/imagen1-special.c
@@ -0,0 +1,718 @@
+/*
+ * Support drawing routines for Chris Torek's DVI->ImPress program.
+ *
+ * Requires v1.7 or later ImPress to handle paths.
+ * Better if v1.9 or later for arc, circle, and ellipse primitives
+ * (define USEGRAPHICS).
+ *
+ * Tim Morgan, UC Irvine, 11/17/85
+ *
+ *
+ * At the time these routines are called, the position of the Imagen should
+ * have been updated to the upper left corner of the graph (the position
+ * the \special appears at in the dvi file). Then the coordinates in the
+ * graphics commands are in terms of a virtual page with axes oriented the
+ * same as the Imagen normally has:
+ *
+ * 0,0
+ * +-----------> +x
+ * |
+ * |
+ * |
+ * \ /
+ * +y
+ *
+ * Angles are measured in the conventional way, from +x towards +y.
+ * Unfortunately, that reverses the meaning of "counterclockwise" from
+ * what you see in the output.
+ *
+ * Unfortunately, some 8/300's don't have an aspect ratio which is 1:1.
+ * One of ours appears to be 295 dpi in the horizontal direction and 300dpi
+ * vertically. If ASPECT is defined, then dviimp/imagen1 and draw_imp/special
+ * use two different variables for the horizontal and vertical resolution, and
+ * otherwise, just one. Because the drawing routines which are defined
+ * in ImPress for circles, arcs, and ellipses in V1.9 and later assume that
+ * the output device is 1:1, they can't be used if ASPECT is defined, and
+ * because I don't want to hack up imagen1 to understand different horizontal
+ * and vertical resolutions, we're currently ignoring this problem, and not
+ * defining ASPECT.
+ */
+
+#define USEGRAPHICS /* Only if v1.9 or later imPRESS */
+#undef ASPECT
+
+#ifdef ASPECT /* Can't have both! */
+#undef USEGRAPHICS
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include "types.h"
+#include "imPcodes.h"
+
+/* Put a two-byte (word) value to the Imagen */
+#define putword(w) (putchar((w) >> 8), putchar(w))
+
+extern char *malloc();
+
+
+#define TRUE 1
+#define FALSE 0
+
+#define TWOPI (3.14157926536*2.0)
+#define MAXPOINTS 300 /* Most number of points in a path */
+#define SPLINEPOINTS 900 /* Most points in a spline */
+#define RADTOPXL 2607.435436 /* (16383 / (2pi)). This
+ converts from radians to the
+ angle units used by ImPress */
+
+/* Convert radian angles to 2**-14 angle units used by ImPress */
+#define RadToImpUnits(a) ((short) ((a)*RADTOPXL + 0.5))
+
+/* Graphics operations */
+#define WHITE 0
+#define SHADE 3
+#define OR 7
+#define BLACK 15
+
+extern double cos(), sin(), sqrt();
+#ifndef ASPECT
+extern int DPI; /* Resolution of device */
+#define PixPerInX DPI
+#define PixPerInY DPI
+#else
+extern int DPIx, DPIy; /* x,y resolution of device */
+#define PixPerInX DPIx
+#define PixPerInY DPIy
+#endif
+
+extern int UserMag;
+#define conv(x, f)\
+ ((int) ((((double)(x)/1000.0) * ((double)(f)) * ((double)UserMag/1000.0)) + 0.5))
+#define xconv(x) conv(x, PixPerInX)
+#define yconv(y) conv(y, PixPerInY)
+
+extern int ImHH; /* Imagen horizontal position */
+extern int ImVV; /* Imagen vertical position */
+extern int hh; /* current horizontal position, in DEVs */
+extern int vv; /* current vertical position, in DEVs */
+
+extern int NextFamilyNumber; /* Number of next ImPress family to use */
+#define fnum NextFamilyNumber
+
+static int xx[MAXPOINTS], yy[MAXPOINTS], pathlen,
+ pensize = 2; /* Size we want Imagen to draw at, default 2 pixels */
+
+#define MAXPENSIZE 20 /* Imagen restriction */
+
+static int
+ family_defined = FALSE, /* Have we chosen family yet? */
+ texture_defined = FALSE,/* Have we done a set_texture yet? */
+ whiten_next = FALSE, /* Should next object be whitened? */
+ blacken_next = FALSE, /* Should next object be blackened? */
+ shade_next = FALSE; /* Should next object be shaded? */
+
+/* Predefined shading (texture) glyph */
+/* First, define size of glyph */
+#define THEIGHT 32 /* bits high */
+#define TWIDTH 4 /* bytes wide */
+/* Next, declare the bit map for the glyph */
+static char stexture[THEIGHT][TWIDTH]={
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}};
+
+/*
+ * Copy a default texture into the stexture array
+ */
+static void glyph_init()
+{
+ static char btexture[THEIGHT][TWIDTH]={
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
+ {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}};
+
+ int i;
+ for (i=0; i<THEIGHT; i++)
+ bcopy(btexture[i],stexture[i],TWIDTH);
+
+}
+
+
+/*
+ * Push the state of the Imagen and set up a new virtual coord system
+ */
+static void push_location()
+{
+ putchar(imP_Push);
+ putchar(imP_SetHVSystem);
+ putchar(0140);
+}
+
+
+/*
+ * Create the pushed virtual page, and pop the state of the printer
+ */
+static void pop_location()
+{
+ putchar(imP_Pop);
+}
+
+
+/*
+ * Set the pen size
+ * Called as \special{pn size}
+ * eg: \special{pn 8}
+ * The size is the number of milli-inches for the diameter of the pen.
+ * This routine converts that value to device-dependent pixels, and makes
+ * sure that the resulting value is within legal bounds.
+ */
+static void im_pensize(cp)
+char *cp;
+{
+ int size;
+
+ if (sscanf(cp, " %d ", &size) != 1) return;
+ pensize = yconv(size);
+ if (pensize < 1) pensize = 1;
+ else if (pensize > MAXPENSIZE) pensize = MAXPENSIZE;
+}
+
+
+/*
+ * Make sure the pen size is set. Since we push and pop the state,
+ * this has to be sent for each different object (I think).
+ */
+static void set_pen_size()
+{
+ putchar(imP_SetPen);
+ putchar(pensize);
+}
+
+
+/*
+ * Actually apply the attributes (shade, whiten, or blacken) to the currently
+ * defined path/figure.
+ */
+static void do_attributes()
+{
+ static int family; /* Family of downloaded texture glyph */
+ static int member; /* Member of family */
+ int i,j; /* Loop through glyph array */
+
+ if (shade_next) {
+ shade_next = FALSE;
+ if (!family_defined) {
+ family_defined = TRUE;
+ family = fnum++;
+ member = -1;
+ }
+ if (!texture_defined) {
+ texture_defined = TRUE;
+ member++;
+ putchar(imP_DefGlyph);
+ putchar((family & 0x7e) >> 1);
+ putchar((family & 0x01) << 7 | (member & 0x7f));
+ /*putword(0); */ /* Advance width */
+ putword(32);
+ putword(TWIDTH*8); /* pixel width (8 x number of bytes) */
+ /*putword(0); */ /* left offset */
+ putword(32);
+ putword(THEIGHT); /* and height of glyph */
+ /*putword(0); */ /* top offset */
+ putword(32);
+ for (i=0; i<THEIGHT; i++)/* Do rows */
+ for (j=0; j<TWIDTH; j++) putchar(stexture[i][j]);
+ }
+ putchar(imP_SetTexture);
+ putchar((family & 0x7e) >> 1);
+ putchar((family & 0x01) << 7 | (member & 0x7f));
+ putchar(imP_FillPath);
+ putchar(SHADE);
+ glyph_init(); /* reinitialize the array */
+ }
+ else if (whiten_next) {
+ whiten_next = FALSE;
+ putchar(imP_FillPath);
+ putchar(WHITE);
+ }
+ else if (blacken_next) {
+ blacken_next = FALSE;
+ putchar(imP_FillPath);
+ putchar(BLACK);
+ }
+}
+
+
+/*
+ * Flush the path that we've built up with im_drawto()
+ * Called as \special{fp}
+ */
+static void im_flushpath()
+{
+ register int i;
+
+ push_location();
+ if (pathlen <= 0) return;
+ set_pen_size();
+ putchar(imP_CreatePath);
+ putword(pathlen);
+ for (i=1; i<=pathlen; i++) {
+ putword(xx[i]);
+ putword(yy[i]);
+ }
+ pathlen = 0;
+ putchar(imP_DrawPath);
+ putchar(BLACK);
+ do_attributes();
+ pop_location();
+}
+
+
+/* Helper routine for dashed_line() */
+static void connect(x0, y0, x1, y1)
+int x0, y0, x1, y1;
+{
+ set_pen_size();
+ putchar(imP_CreatePath);
+ putword(2); /* Path length */
+ putword(x0); putword(y0);/* The path */
+ putword(x1); putword(y1);
+ putchar(imP_DrawPath);
+ putchar(BLACK);
+}
+
+
+/* Another helper. Draw a dot at the indicated point */
+static void dot_at(x, y)
+int x,y;
+{
+ set_pen_size();
+ putchar(imP_CreatePath);
+ putword(1); /* Path length */
+ putword(x); putword(y); /* The path */
+ putchar(imP_DrawPath);
+ putchar(BLACK);
+}
+
+
+/*
+ * Draw a dashed or dotted line between the first pair of points in the array
+ * Called as \special{da <inchesperdash>} (dashed line)
+ * or \special{dt <inchesperdot>} (dotted line)
+ * eg: \special{da 0.05}
+ */
+static void dashed_line(cp, dotted)
+char *cp;
+int dotted; /* boolean */
+{
+ int i, numdots, x0, y0, x1, y1;
+ double cx0, cy0, cx1, cy1;
+ double d, spacesize, a, b, dx, dy, pixperdash;
+ float inchesperdash;
+
+ if (sscanf(cp, " %f ", &inchesperdash) != 1) return;
+ if (pathlen <= 1) return;
+ pixperdash = inchesperdash * ((float) PixPerInY);
+ x0 = xx[1]; x1 = xx[2];
+ y0 = yy[1]; y1 = yy[2];
+ dx = x1 - x0;
+ dy = y1 - y0;
+ push_location();
+ if (dotted) {
+ numdots = sqrt(dx*dx + dy*dy) / pixperdash + 0.5;
+ if (numdots > 0)
+ for (i = 0; i <= numdots; i++) {
+ a = (float) i / (float) numdots;
+ cx0 = ((float) x0) + (a*dx) + 0.5;
+ cy0 = ((float) y0) + (a*dy) + 0.5;
+ dot_at((int) cx0, (int) cy0);
+ }
+ }
+ else {
+ d = sqrt(dx*dx + dy*dy);
+ if (d <= 2 * pixperdash) {
+ connect(x0, y0, x1, y1);
+ pathlen = 0;
+ pop_location();
+ return;
+ }
+ numdots = d / (2 * pixperdash) + 1;
+ spacesize = (d - numdots * pixperdash) / (numdots - 1);
+ for (i=0; i<numdots-1; i++) {
+ a = i * (pixperdash + spacesize) / d;
+ b = a + pixperdash / d;
+ cx0 = ((float) x0) + (a*dx) + 0.5;
+ cy0 = ((float) y0) + (a*dy) + 0.5;
+ cx1 = ((float) x0) + (b*dx) + 0.5;
+ cy1 = ((float) y0) + (b*dy) + 0.5;
+ connect((int) cx0, (int) cy0, (int) cx1, (int) cy1);
+ b += spacesize / d;
+ }
+ cx0 = ((float) x0) + (b*dx) + 0.5;
+ cy0 = ((float) y0) + (b*dy) + 0.5;
+ connect((int) cx0, (int) cy0, x1, y1);
+ }
+ pathlen = 0;
+ pop_location();
+}
+
+
+/*
+ * Virtually draw to a given x,y position on the virtual page.
+ * X and Y are expressed in thousandths of an inch, and this
+ * routine converts them to pixels.
+ *
+ * Called as \special{pa <x> <y>}
+ * eg: \special{pa 0 1200}
+ */
+static void im_drawto(cp)
+char *cp;
+{
+ int x,y;
+
+ if (sscanf(cp, " %d %d ", &x, &y) != 2) return;
+
+ if (++pathlen >= MAXPOINTS)
+ error(1, 0, "Too many points specified");
+ xx[pathlen] = xconv(x);
+ yy[pathlen] = yconv(y);
+}
+
+#ifndef USEGRAPHICS
+/*
+ * Helper routine for im_arc().
+ * Convert x and y to integers, then call im_drawto() normally.
+ */
+static void im_fdraw(x, y)
+float x, y;
+{
+ int ix,iy;
+
+ ix = (int) x + 0.5;
+ iy = (int) y + 0.5;
+ im_drawto(ix, iy);
+}
+
+
+/*
+ * Draw the indicated arc on the virtual page and flush it.
+ * The arc is always drawn counter clockwise from start_angle to end_angle on
+ * the virtual page. That is, clockwise in the real world (since +y is down).
+ * It is assumed that start_angle has been adjusted to be in the range
+ * 0.0 <= start_angle < 2*PI
+ * and that end_angle is the smallest suitable angle >= start_angle. Thus
+ * end_angle MAY be >= 2*PI.
+ *
+ * Called as \special{ar <xcenter> <ycenter> <xradius> <yradius>
+ * <startangle> <endangle>}
+ *
+ * <xcenter>,<ycenter>,<xradius>,<yradius> are in 1/1000's of an inch.
+ * <startangle> and <endangle> are in radians.
+ *
+ * eg: \special{ar 240 240 30 30 0.000 6.283}
+ */
+static void im_arc(cp)
+char *cp;
+{
+ int xc, yc, xrad, yrad;
+ float start_angle, end_angle;
+ double angle, theta, r, xcenter, ycenter, xradius, yradius;
+ int n;
+
+ if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
+ &end_angle) != 6) return;
+ xcenter = xc; /* Convert to floating point */
+ ycenter = yc;
+ xradius = xrad;
+ yradius = yrad;
+ r = (xradius+yradius)/2.0;
+ theta = sqrt(1.0 / r);
+ n = TWOPI / theta + 0.5;
+ if (n<6) n = 6;
+ if (n>80) n = 80;
+ theta = TWOPI / n;
+
+ im_fdraw( xcenter + xradius*cos(start_angle),
+ ycenter + yradius*sin(start_angle) );
+ angle = start_angle + theta;
+ while (angle < end_angle) {
+ im_fdraw(xcenter + xradius*cos(angle),
+ ycenter + yradius*sin(angle) );
+ angle += theta;
+ }
+ im_fdraw( xcenter + xradius*cos(end_angle),
+ ycenter + yradius*sin(end_angle) );
+ im_flushpath();
+}
+
+#else USEGRAPHICS
+
+/* Same routine as above, but it uses the special graphics primitives */
+static void im_arc(cp)
+char *cp;
+{
+ int xc, yc, xrad, yrad;
+ float start_angle, end_angle;
+ short alpha0, alpha1;
+
+ if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
+ &end_angle) != 6) return;
+ push_location();
+ set_pen_size();
+ putchar(imP_SetHAbs);
+ putword(xconv(xc));
+ putchar(imP_SetVAbs);
+ putword(yconv(yc));
+
+/*
+ * If end_angle > TWOPI, we can't simply use it, since it will be > 16383,
+ * and thus an illegal angle. Simply subtracting TWOPI will make it <
+ * start_angle, which will reverse the direction the arc is drawn, resulting
+ * in the wrong arc. So we also exchange start_angle and end_angle. But then
+ * start_angle < end_angle, so the arc goes back to its original direction!
+ * So we also subtract TWOPI from the original start_angle, foring end_angle
+ * to be negative (since 0<=start_angle<TWOPI originally), which will cause
+ * the Imagen to draw in a true CCW direction (opposite of normal).
+ */
+ if (end_angle > TWOPI) {
+ double temp;
+ temp = end_angle - TWOPI;
+ end_angle = start_angle - TWOPI;
+ start_angle = temp;
+ }
+ if (xrad >= yrad-1 && xrad <= yrad+1) { /* Circle or arc */
+ alpha0 = RadToImpUnits(start_angle);
+ alpha1 = RadToImpUnits(end_angle);
+ putchar(imP_CircleArc);
+ putword(xconv((double) xrad));
+ putword(alpha0);
+ putword(alpha1);
+ }
+ else { /* Ellipse */
+ putchar(imP_EllipseArc);
+ putword(xconv((double) xrad));
+ putword(yconv((double) yrad));
+ putword(0); /* alphaoff */
+ putword(0); /* zero start angle */
+ putword(16383); /* two pi end angle */
+ }
+ putchar(imP_DrawPath);
+ putchar(BLACK);
+ do_attributes();
+ pop_location();
+}
+#endif USEGRAPHICS
+
+
+/*
+ * Create a spline through the points in the array.
+ * Called like flush path (fp) command, after points
+ * have been defined via pa command(s).
+ *
+ * eg: \special{sp}
+ */
+static void flush_spline()
+{
+ int xp, yp, N;
+ float t1, t2, t3, w;
+ int i, j, steps;
+ int splinex[SPLINEPOINTS], spliney[SPLINEPOINTS], splinelen;
+
+ push_location();
+ set_pen_size();
+ putchar(imP_CreatePath);
+ splinelen = 0;
+ N = pathlen + 1;
+ xx[0] = xx[1];
+ yy[0] = yy[1];
+ xx[N] = xx[N-1];
+ yy[N] = yy[N-1];
+ for (i = 0; i < N-1; i++) { /* interval */
+ steps = (dist(xx[i],yy[i], xx[i+1],yy[i+1]) +
+ dist(xx[i+1],yy[i+1], xx[i+2],yy[i+2])) / 20;
+ for (j = 0; j < steps; j++) { /* points within */
+ w = ((float) j) / ((float) steps);
+ t1 = 0.5 * w * w;
+ w -= 0.5;
+ t2 = 0.75 - w * w;
+ w -= 0.5;
+ t3 = 0.5 * w * w;
+ xp = t1 * xx[i+2] + t2 * xx[i+1] + t3 * xx[i] + 0.5;
+ yp = t1 * yy[i+2] + t2 * yy[i+1] + t3 * yy[i] + 0.5;
+ if (splinelen >= SPLINEPOINTS)
+ error(1, 0, "Too many points in spline");
+ splinex[splinelen] = xp;
+ spliney[splinelen++] = yp;
+ }
+ }
+ putword(splinelen);
+ for (i=0; i<splinelen; i++) {
+ putword(splinex[i]);
+ putword(spliney[i]);
+ }
+
+ pathlen = 0;
+ putchar(imP_DrawPath);
+ putchar(BLACK);
+ pop_location();
+}
+
+
+static int dist(x1, y1, x2, y2) /* integer distance from x1,y1 to x2,y2 */
+{
+ float dx, dy;
+
+ dx = x2 - x1;
+ dy = y2 - y1;
+ return sqrt(dx*dx + dy*dy) + 0.5;
+}
+
+
+/*
+ * Whiten the interior of the next figure (path). Command is:
+ * \special{wh}
+ */
+static void im_whiten()
+{
+ whiten_next = TRUE;
+}
+
+
+/*
+ * Blacken the interior of the next figure (path). Command is:
+ * \special{bk}
+ */
+static void im_blacken()
+{
+ blacken_next = TRUE;
+}
+
+
+/*
+ * Shade the interior of the next figure (path) with the predefined
+ * texture. Command is:
+ * \special{sh}
+ */
+static void im_shade()
+{
+ shade_next = TRUE;
+}
+
+
+/*
+ * Define the texture array. Command is:
+ * \special{tx 32bits 32bits ....}
+ */
+static void im_texture(pcount,bitpattern)
+int pcount, bitpattern[32];
+{
+ int i,j,k;
+ unsigned long ul_one;
+
+#ifdef DEBUG
+ if (sizeof ul_one != TWIDTH)
+ error(1, 0, "pointer/size mismatch");
+#endif
+ j = 0;
+ for (k=0; k < THEIGHT/pcount; k++) {
+ for (i=0; i<pcount; i++) {
+ ul_one = htonl((unsigned long) bitpattern[i]);
+ bcopy((char *) &ul_one, stexture[j++], TWIDTH);
+ }
+ }
+ texture_defined = FALSE;
+}
+
+
+/*
+ * This routine takes the string argument for a tx command and
+ * parses out the separate bitpatterns to call im_texture with.
+ * Written by Tinh Tang
+ */
+static void do_texture(t)
+char *t;
+{
+ int bitpattern[32];
+ int pcount = 0;
+
+ while (isspace (*t)) t++;
+ while (*t) {
+ if (sscanf(t, "%x", &bitpattern[pcount++]) != 1) {
+ error(0, 0, "malformed tx command");
+ return;
+ }
+ while (*t && !isspace(*t)) t++;/* Skip to space */
+ while (*t && isspace(*t)) t++;/* Skip to nonspace */
+ }
+ if (pcount != 4 && pcount != 8 && pcount != 16 && pcount != 32) {
+ error(0, 0, "malformed tx command");
+ return;
+ }
+ im_texture(pcount, bitpattern);
+}
+
+
+#define COMLEN 3 /* Length of a tpic command plus one */
+
+DoSpecial(k)
+ i32 k;
+{
+ char *spstring, *cp, command[COMLEN];
+ register int len;
+
+ spstring = malloc((unsigned) (k+1));
+ if (spstring == NULL) error(2, 0, "Out of memory");
+ len = 0;
+ while (k--) spstring[len++] = GetByte(stdin);
+ spstring[len] = '\0';
+ cp = spstring;
+ while (isspace(*cp)) ++cp;
+ len = 0;
+ while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
+ command[len] = '\0';
+
+ if (ImHH != hh || ImVV != vv)
+ ImSetPosition(hh, vv);
+
+ if (strcmp(command, "pn") == 0) im_pensize(cp);
+ else if (strcmp(command, "fp") == 0) im_flushpath();
+ else if (strcmp(command, "da") == 0) dashed_line(cp, 0);
+ else if (strcmp(command, "dt") == 0) dashed_line(cp, 1);
+ else if (strcmp(command, "pa") == 0) im_drawto(cp);
+ else if (strcmp(command, "ar") == 0) im_arc(cp);
+ else if (strcmp(command, "sp") == 0) flush_spline();
+ else if (strcmp(command, "sh") == 0) im_shade();
+ else if (strcmp(command, "wh") == 0) im_whiten();
+ else if (strcmp(command, "bk") == 0) im_blacken();
+ else if (strcmp(command, "tx") == 0) im_texture(cp);
+ else error(0, 0, "warning: ignoring \\special");
+
+ free(spstring);
+}
diff --git a/dviware/umddvi/dev/imagen1.c b/dviware/umddvi/dev/imagen1.c
new file mode 100644
index 0000000000..78b60a5a81
--- /dev/null
+++ b/dviware/umddvi/dev/imagen1.c
@@ -0,0 +1,867 @@
+/*
+ * 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: imagen1.c,v 2.6 87/06/16 17:14:18 chris Exp $";
+#endif
+
+/*
+ * DVI to Imagen driver
+ *
+ * Reads DVI version 2 files and converts to imPRESS commands for spooling to
+ * the Imagen (via ipr).
+ *
+ * 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 "imagen.h"
+#include "imPcodes.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 font *f; /* the font */
+ 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 family; /* Imagen family number (we pick one) */
+#ifdef notyet
+ int UseTime; /* cache info: flush fonts on LRU basis */
+#endif
+};
+
+/*
+ * We use one of the per-glyph user flags to keep track of whether a
+ * glyph has been loaded into the Imagen.
+ */
+#define GF_LOADED GF_USR0
+
+/*
+ * The exception that proves the rule is that hh and fromSP(dvi_h) are not
+ * allowed to get more than MaxDrift units apart.
+ */
+int MaxDrift; /* the maximum allowable difference between
+ hh and fromSP(dvi_h) */
+
+struct fontinfo *CurrentFont; /* the current font */
+int NextFamilyNumber; /* next available Imagen glyph-family index */
+
+int ExpectBOP; /* true => BOP ok */
+int ExpectEOP; /* true => EOP ok */
+
+int DPI; /* -d => device resolution (dots/inch) */
+int PFlag; /* -p => no page reversal */
+int LFlag; /* -l => landscape mode (eventually...) */
+int SFlag; /* -s => silent (no page numbers) */
+int Debug; /* -D => debug flag */
+
+int XOffset;
+int YOffset; /* offsets for margins */
+
+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 HHMargin; /* horizontal margin (in DEVs) */
+int VVMargin; /* vertical margin (in DEVs) */
+
+long PrevPagePointer; /* The previous page pointer from the DVI
+ file. This allows us to read the file
+ backwards, which obviates the need for
+ page reversal (reversal is unsupported
+ on the 8/300). */
+
+int Numerator; /* numerator from DVI file */
+int Denominator; /* denominator from DVI file */
+int DVIMag; /* magnification from DVI file */
+int UserMag; /* user-specified magnification */
+
+int ImHH; /* Imagen horizontal position */
+int ImVV; /* Imagen vertical position */
+int ImFamily; /* Imagen current-font number */
+
+char *PrintEngine; /* e.g., canon, ricoh */
+struct search *FontFinder; /* maps from DVI index to internal fontinfo */
+int FontErrors; /* true => error(s) occurred during font
+ definitions from DVI postamble */
+
+struct fontinfo NoFont; /* a fake font to help get things started */
+
+char *getenv(), *malloc();
+
+/* Absolute value */
+#define ABS(n) ((n) >= 0 ? (n) : -(n))
+
+/* Put a two-byte (word) value to the Imagen */
+#define putword(w) (putchar((w) >> 8), putchar(w))
+
+/*
+ * Correct devpos (the actual device position) to be within MaxDrift pixels
+ * of dvipos (the virtual DVI position).
+ */
+#define FIXDRIFT(devpos, dvipos) \
+ if ((devpos) < (dvipos)) \
+ if ((dvipos) - (devpos) <= MaxDrift) \
+ /* void */; \
+ else \
+ (devpos) = (dvipos) - MaxDrift; \
+ else \
+ if ((devpos) - (dvipos) <= MaxDrift) \
+ /* void */; \
+ else \
+ (devpos) = (dvipos) + MaxDrift
+
+SelectFont(n)
+ i32 n;
+{
+ int x = S_LOOKUP;
+
+ if ((CurrentFont = (struct fontinfo *)SSearch(FontFinder, n, &x)) == 0)
+ GripeNoSuchFont(n);
+}
+
+/*
+ * Start a page (process a DVI_BOP).
+ */
+BeginPage()
+{
+ register int *i;
+ static int count[10]; /* the 10 counters */
+ static int beenhere;
+
+ if (!ExpectBOP)
+ GripeUnexpectedOp("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, PrevPagePointer);
+
+ if (!SFlag) {
+ (void) fprintf(stderr, "[%d", count[0]);
+ (void) fflush(stderr);
+ }
+ putchar(imP_Page);
+ ImHH = 0;
+ ImVV = 0;
+
+ hh = HHMargin;
+ vv = VVMargin;
+ dvi_h = toSP(hh);
+ dvi_v = toSP(vv);
+ dvi_w = 0;
+ dvi_x = 0;
+ dvi_y = 0;
+ dvi_z = 0;
+}
+
+/*
+ * End a page (process a DVI_EOP)
+ */
+EndPage()
+{
+ if (!ExpectEOP)
+ GripeUnexpectedOp("EOP");
+
+ if (!SFlag) {
+ putc(']', stderr);
+ (void) fflush(stderr);
+ }
+ ExpectEOP = 0;
+ ExpectBOP++;
+
+ putchar(imP_EndPage);
+
+ if (!PFlag && PrevPagePointer != -1)
+ (void) fseek(stdin, PrevPagePointer, 0);
+}
+
+/*
+ * Store the relevant information from the DVI postamble, and set up
+ * various internal things.
+ */
+PostAmbleHeader(p)
+ register struct PostAmbleInfo *p;
+{
+ register int n;
+
+ PrevPagePointer = p->pai_PrevPagePointer;
+ Numerator = p->pai_Numerator;
+ Denominator = p->pai_Denominator;
+ DVIMag = p->pai_DVIMag;
+
+ /*
+ * Set the conversion factor. This must be done before using
+ * any fonts.
+ */
+ SetConversion(DPI, UserMag, Numerator, Denominator, DVIMag);
+
+ n = p->pai_DVIStackSize * sizeof *dvi_stack;
+ dvi_stack = (struct localstack *) malloc((unsigned) n);
+ if ((dvi_stackp = dvi_stack) == NULL)
+ GripeOutOfMemory(n, "DVI stack");
+}
+
+/* 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;
+ char *fname;
+ int def = S_CREATE | S_EXCL;
+
+ 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*/
+ }
+ if (NextFamilyNumber == MaxImFamily)
+ error(0, 0, "\
+WARNING: out of Imagen font family indicies;\n\
+\toutput will probably resemble freshly scrambled eggs.");
+ fi->family = NextFamilyNumber++;
+ f = GetFont(p->paf_name, p->paf_DVIMag, p->paf_DVIDesignSize,
+ PrintEngine, &fname);
+ if ((fi->f = f) == NULL) {
+ GripeCannotGetFont(p->paf_name, p->paf_DVIMag,
+ p->paf_DVIDesignSize, PrintEngine, 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);
+
+ 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);
+}
+
+/* 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;
+ char *inname;
+
+ setbuf(stderr, serrbuf);
+
+ ProgName = *argv;
+ UserMag = 1000;
+ MaxDrift = DefaultMaxDrift;
+ DPI = DefaultDPI;
+ inname = "stdin";
+ PrintEngine = "canon";
+
+ while ((c = getopt(argc, argv, "d:e:lm:pr:sDX:Y:")) != EOF) {
+ switch (c) {
+
+ case 'd': /* max drift value */
+ MaxDrift = atoi(optarg);
+ break;
+
+ case 'e': /* engine */
+ PrintEngine = optarg;
+ break;
+
+ case 'l': /* landscape mode */
+ LFlag++;
+ break;
+
+ case 'm': /* magnification */
+ UserMag = atoi(optarg);
+ break;
+
+ case 'p': /* no page reversal */
+ PFlag++;
+ break;
+
+ case 'r': /* resolution */
+ DPI = atoi(optarg);
+ break;
+
+ case 's': /* silent */
+ SFlag++;
+ break;
+
+ case 'D':
+ Debug++;
+ break;
+
+ case 'X': /* x offset, in 1/10 inch increments */
+ XOffset = atoi(optarg);
+ break;
+
+ case 'Y': /* y offset */
+ YOffset = atoi(optarg);
+ break;
+
+ case '?':
+ (void) fprintf(stderr, "\
+Usage: %s [-d drift] [-l] [-m mag] [-s] [more options, see manual] [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);
+
+ /* Ensure that stdin is seekable */
+ if (MakeSeekable(stdin))
+ error(1, 0,
+ "unable to copy input to temp file (see the manual)");
+
+/* fontinit((char *) NULL); */
+
+ ReadPostAmble();
+
+ /* Margins -- needs work! */
+ HHMargin = DefaultLeftMargin + XOffset * DPI / 10;
+ VVMargin = DefaultTopMargin + YOffset * DPI / 10;
+
+ ReadPreAmble();
+ ExpectBOP++;
+ if (!PFlag)
+ (void) fseek(stdin, PrevPagePointer, 0);
+
+ /* All set! */
+ printf("@document(language imPRESS, name \"%s\")", inname);
+ if (LFlag) {
+ putchar(imP_SetHVSystem);
+ putchar(0x55); /* origin=ulc, h:v=90, h:x=90 */
+ putchar(imP_SetAdvDirs);
+ putchar(0); /* main=0 (degrees), secondary=90 */
+ }
+
+ /*
+ * 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();
+ if (!SFlag) {
+ (void) fprintf(stderr, "\n");
+ (void) fflush(stderr);
+ }
+ putchar(imP_EOF);
+
+ 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);
+}
+
+/*
+ * 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;
+{
+ register i32 h, w, rw;
+
+ fGetLong(stdin, h);
+ fGetLong(stdin, rw);
+
+ h = ConvRule(h);
+ w = ConvRule(rw);
+
+ /* put the rule out */
+ if (ImHH != hh || ImVV != vv)
+ ImSetPosition(hh, vv);
+ putchar(imP_Rule);
+ putword(w);
+ putword(h);
+ putword(-h + 1);
+ if (advance) {
+ hh += w;
+ dvi_h += rw;
+ w = fromSP(dvi_h);
+ FIXDRIFT(hh, w);
+ }
+}
+
+/* if anyone ever uses character codes > 127, this driver will need work */
+char chartoobig[] = "Warning: character code %d too big for Imagen!";
+
+/*
+ * This rather large routine reads the DVI file and calls on other routines
+ * to do anything moderately difficult (except put characters: there is
+ * some ugly code with `goto's which makes things faster).
+ */
+
+ReadDVIFile()
+{
+ register int c;
+ register struct glyph *g;
+ register struct font *f;
+ register i32 p;
+ int advance;
+
+ ImFamily = -1; /* force imP_SetFamily command */
+
+ /*
+ * 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 the
+ * program run a bit faster.
+ */
+ if (DVI_IsChar(c)) {
+ advance = 1;
+do_char:
+ 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;
+ }
+ if ((g->g_flags & GF_LOADED) == 0)
+ DownLoadGlyph(c, g);
+ if (HASRASTER(g)) { /* workaround for Imagen bug */
+ /* BEGIN INLINE EXPANSION OF ImSetPosition */
+ 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 != CurrentFont->family) {
+ putchar(imP_SetFamily);
+ putchar(CurrentFont->family);
+ ImFamily = CurrentFont->family;
+ }
+ putchar(c);
+ ImHH += g->g_pixwidth;
+ }
+ 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 */
+ }
+
+ switch (DVI_DT(c)) {
+
+ case DT_SET:
+ advance = 1;
+ c = p;
+ if (c > 127)
+ error(0, 0, chartoobig, c);
+ goto do_char;
+
+ case DT_PUT:
+ advance = 0;
+ c = p;
+ if (c > 127)
+ error(0, 0, chartoobig, c);
+ 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();
+ if (!PFlag && PrevPagePointer == -1)
+ return; /* was first page: done */
+ 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 (PFlag)
+ return;
+ GripeUnexpectedOp("POST");
+ /* NOTREACHED */
+
+ 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;
+}
+
+/*
+ * Download the character c/g in the current font.
+ */
+DownLoadGlyph(c, g)
+ int c;
+ register struct glyph *g;
+{
+ register char *p;
+ register int i, j, w;
+
+ g->g_pixwidth = fromSP(g->g_tfmwidth);
+ g->g_flags |= GF_LOADED;
+ if (!HASRASTER(g)) /* never load dull glyphs */
+ return;
+
+ if (!LFlag) {
+ w = 0;
+ p = RASTER(g, CurrentFont->f, ROT_NORM);
+ } else {
+ w = 1 << 14;
+ p = RASTER(g, CurrentFont->f, ROT_RIGHT);
+ }
+
+ w |= (CurrentFont->family << 7) | c;
+
+ /* Define the character */
+ putchar(imP_DefGlyph); /* a.k.a. BGLY */
+ putword(w); /* rotation, family, member */
+ putword(g->g_pixwidth); /* advance */
+ putword(g->g_width); /* width */
+ putword(g->g_xorigin); /* left offset */
+ putword(g->g_height); /* height */
+ putword(g->g_yorigin); /* top-offset */
+
+ /*
+ * Now put out the bitmap.
+ */
+ w = (g->g_width + 7) >> 3;
+ for (i = g->g_height; --i >= 0;)
+ for (j = w; --j >= 0;)
+ (void) putchar(*p++);
+
+ if (g->g_raster) { /* XXX */
+ free(g->g_raster);
+ g->g_raster = NULL;
+ }
+
+}
+
+/*
+ * Set the Imagen's h & v positions. It is currently at ImHH, ImVV.
+ */
+ImSetPosition(h, v)
+ register int h, v;
+{
+
+ if (ImHH != h) {
+ if (ImHH == h - 1)
+ putchar(imP_Forw);
+ else if (ImHH == h + 1)
+ putchar(imP_Backw);
+ else {
+ putchar(imP_SetHAbs);
+ putword(h);
+ }
+ ImHH = h;
+ }
+ if (ImVV != v) {
+ putchar(imP_SetVAbs);
+ putword(v);
+ ImVV = v;
+ }
+}
diff --git a/dviware/umddvi/dev/interpress.h b/dviware/umddvi/dev/interpress.h
new file mode 100644
index 0000000000..e116267d88
--- /dev/null
+++ b/dviware/umddvi/dev/interpress.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/* you are assumed to have read the Xerox Interpress documents... I am
+ not going to attempt to explain what these mean. */
+
+/* sequences */
+#define SeqString 1
+#define SeqInteger 2
+#define SeqRational 4
+#define SeqIdentifier 5
+#define SeqComment 6
+#define SeqContinued 7
+#define SeqLargeVec 8
+#define SeqPackedPixVec 9
+#define SeqComprPixVec 10
+#define SeqAdapPixVec 12
+
+/* operators */
+
+/* pseudo ops */
+#define IPBegin 102
+#define IPEnd 103
+#define IPPageInstr 105
+#define IPLB 106 /* { */
+#define IPRB 107 /* } */
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);
+ }
+ }
+}
diff --git a/dviware/umddvi/dev/iptex.sh b/dviware/umddvi/dev/iptex.sh
new file mode 100644
index 0000000000..919544ad2a
--- /dev/null
+++ b/dviware/umddvi/dev/iptex.sh
@@ -0,0 +1,61 @@
+#! /bin/sh
+#
+# print a dvi file on the imagen
+
+flags=
+cflag=-c
+# put default offset here: -X3 -Y-4 moves output .3in left, .4in up
+# from the usual 1" margin in both directions.
+offset=
+
+# eat arguments
+
+while [ $# -gt 0 ]
+do
+ case "$1" in
+ -c)
+ cflag=;;
+ -d|-m|-r|-X|-Y)
+ flags="$flags $1 $2"; shift;;
+ -)
+ break;;
+ -*)
+ flags="$flags $1";;
+ *)
+ break;;
+ esac
+ shift
+done
+
+if [ $# != 1 ]; then
+ echo "Usage: $0 [-c] [-l] [-s] [-m mag] [-d drift] [-r resol] filename" 2>&1
+ exit 1
+fi
+
+dvifile=$1
+if [ x$dvifile = x- ]; then
+ dvifile=
+else
+ # people insist that iptex should look for file.dvi first:
+ if [ -r $dvifile.dvi ]; then
+ dvifile=$dvifile.dvi
+ else
+ if [ ! -r $dvifile ]; then
+ echo "$0: cannot find $1 or $1.dvi" 1>&2
+ exit 1
+ fi
+ fi
+fi
+
+tmpfile=${TMPDIR-/tmp}/iptex$$
+if [ "$cflag" = -c ]; then
+ trap 'rm -f $tmpfile' 0 1 2 3 15
+ if imagen1 $offset $flags $dvifile > $tmpfile; then
+ ipr $tmpfile
+ else
+ echo "$0: output not spooled (use -c to force)" 1>&2
+ exit 1
+ fi
+else
+ imagen1 $offset $flags $dvifile | ipr
+fi
diff --git a/dviware/umddvi/dev/makefile b/dviware/umddvi/dev/makefile
new file mode 100644
index 0000000000..27202b1c59
--- /dev/null
+++ b/dviware/umddvi/dev/makefile
@@ -0,0 +1,143 @@
+#
+# 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.
+#
+# $Header: Makefile,v 1.3 87/06/16 17:13:19 chris Exp $
+#
+# Makefile for device conversion programs
+#
+# You must run "make conf" to set up Makefile.local if you do not want
+# the default `all' configuration (see the file "conf.sh"). Remember to
+# use `make update'!
+DESTDIR=
+CFLAGS= -O -R -I../h
+MAKE= make
+
+# these are intended to be overridden by the definitions in ../Makefile
+# but just in case, they are here too
+BINDIR= ${DESTDIR}/usr/local/bin
+MANDIR= ${DESTDIR}/usr/local/man
+
+# Make options
+OPTS= BINDIR=${BINDIR} MANDIR=${MANDIR} DESTDIR=${DESTDIR} CC="${CC}" \
+ CFLAGS="${CFLAGS}" ${MFLAGS}
+
+SRCS= imagen1.c verser1.c verser2.c
+
+# First, the main entry used in the original Makefile.
+# It is also enabled by a `conf none'; this is just so that the
+# configurer will disable it in Makefile.local.
+# Whenever you run `make' afterward, this entry will run
+# make on your local Makefile.
+
+# conf none
+first:
+ @if [ -f Makefile.local ]; then :; else \
+ echo "You should run \`make conf' first!"; \
+ echo \
+"I will give you the default \`all' configuration for now."; \
+ sh conf.sh all; \
+ fi
+ @${MAKE} -f Makefile.local ${OPTS}
+# endconf none
+
+# In Makefile.local, this is the default (if you just say `make').
+# The `make' invocation will be commented out there.
+all:
+# conf none
+ @${MAKE} -f Makefile.local ${OPTS} $@
+# endconf none
+
+# Likewise, but for `make install'.
+install:
+# conf none
+ @${MAKE} -f Makefile.local ${OPTS} $@
+# endconf none
+
+# conf imagen
+# all: imagen1
+# install: inst-iptex inst-imagen1
+# endconf imagen
+
+# conf versatec
+# all: verser1 verser2
+# install: inst-dvipr inst-verser1 inst-verser2
+# endconf versatec
+
+# The rest of these are copied to Makefile.local, though many are
+# unused.
+conf:
+ @sh conf.sh
+ @echo "Remember to use \`make update' if you change the Makefile!"
+
+clean:
+ rm -f core *.o verser1 verser2 imagen1
+
+depend: ${SRCS}
+ cc -M ${CFLAGS} ${SRCS} |\
+ awk '{ if ($$1 != prev) { if (rec != "") print rec;\
+ rec = $$0; prev = $$1; }\
+ else { if (length(rec $$2) > 78) { print rec; rec = $$0; }\
+ else rec = rec " " $$2 } }\
+ END { print rec }' >makedep
+ echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
+ echo '$$r makedep' >>eddep
+ echo 'w' >>eddep
+ cp Makefile Makefile.bak
+ ed - Makefile <eddep
+ rm eddep makedep
+ echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile
+ echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile
+ echo '# see make depend above' >>Makefile
+ sh conf.sh update
+
+update:
+ @sh conf.sh update
+
+inst-dvipr:
+ install -c dvipr.sh ${BINDIR}/dvipr
+ install -c -m 444 ../man/dvipr.1 ${MANDIR}/man1/dvipr.1
+inst-verser1: verser1
+ install -s verser1 ${BINDIR}/verser1
+inst-verser2: verser2
+ install -s verser2 ${BINDIR}/verser2
+
+inst-iptex:
+ install -c iptex.sh ${BINDIR}/iptex
+ install -c -m 444 ../man/iptex.1 ${MANDIR}/man1/iptex.1
+inst-imagen1: imagen1
+ install -s imagen1 ${BINDIR}/imagen1
+
+lint: ${SRCS}
+ lint -hbxuL ../lib/llib-lib imagen1.c
+ lint -hbxuL ../lib/llib-lib verser1.c
+ lint -hbxuL ../lib/llib-lib verser2.c
+
+dist:
+ rm -f Makefile.bak Makefile.local Makefile.l.bak
+ sh conf.sh all
+
+imagen1: imagen1.o
+verser1: verser1.o
+verser2: verser2.o
+
+imagen1 verser1 verser2: ../lib/lib.a
+ ${CC} ${CFLAGS} -o $@ $@.o ../lib/lib.a
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
+imagen1.o: imagen1.c /usr/include/stdio.h ../h/types.h ../h/conv.h ../h/dvi.h
+imagen1.o: ../h/dviclass.h ../h/dvicodes.h ../h/fio.h ../h/font.h
+imagen1.o: ../h/postamble.h ../h/search.h ../h/imagen.h ../h/imPcodes.h
+verser1.o: verser1.c /usr/include/stdio.h ../h/types.h ../h/conv.h ../h/dvi.h
+verser1.o: ../h/dviclass.h ../h/dvicodes.h ../h/fio.h ../h/font.h
+verser1.o: ../h/postamble.h ../h/search.h ../h/verser.h
+verser2.o: verser2.c /usr/include/errno.h /usr/include/setjmp.h
+verser2.o: /usr/include/stdio.h /usr/include/sys/vcmd.h
+verser2.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
+verser2.o: /usr/include/sys/ttydev.h ../h/types.h ../h/conv.h ../h/fio.h
+verser2.o: ../h/font.h ../h/verser.h
+# DEPENDENCIES MUST END AT END OF FILE
+# IF YOU PUT STUFF HERE IT WILL GO AWAY
+# see make depend above
diff --git a/dviware/umddvi/dev/makefile.3b b/dviware/umddvi/dev/makefile.3b
new file mode 100644
index 0000000000..487370252d
--- /dev/null
+++ b/dviware/umddvi/dev/makefile.3b
@@ -0,0 +1,149 @@
+# Makefile for device conversion programs
+#
+# You must run "make conf" to set up Makefile.local if you do not want
+# the default `all' configuration (see the file "conf.sh").
+DESTDIR=
+CFLAGS= -g -I../h -Dsys5
+MAKE= make
+MCC=dmdcc
+MCFLAGS= -g
+
+# these are intended to be overridden by the definitions in ../Makefile
+# but just in case, they are here too
+BINDIR= ${DESTDIR}/usr/local/bin
+MANDIR= ${DESTDIR}/usr/local/man
+
+# Make options
+OPTS= BINDIR=${BINDIR} MANDIR=${MANDIR} DESTDIR=${DESTDIR} CC="${CC}" \
+ CFLAGS="${CFLAGS}" ${MFLAGS}
+
+SRCS= imagen1.c imagen1-sp.c verser1.c verser2.c dmd.c dmdhost.c dmd-sp.c
+
+# First, the main entry used in the original Makefile.
+# It is also enabled by a `conf none'; this is just so that the
+# configurer will disable it in Makefile.local.
+# Whenever you run `make' afterward, this entry will run
+# make on your local Makefile.
+
+# conf none
+# first:
+# @if [ -f Makefile.local ]; then :; else \
+# echo "You should run \`make conf' first!"; \
+# echo \
+# "I will give you the default \`all' configuration for now."; \
+# sh conf.sh all; \
+# fi
+# @${MAKE} -f Makefile.local ${OPTS}
+# endconf none
+
+# In Makefile.local, this is the default (if you just say `make').
+# The `make' invocation will be commented out there.
+all:
+# conf none
+# @${MAKE} -f Makefile.local ${OPTS} $@
+# endconf none
+
+# Likewise, but for `make install'.
+install:
+# conf none
+# @${MAKE} -f Makefile.local ${OPTS} $@
+# endconf none
+
+# conf imagen
+all: imagen1 dvidmd dvidmd.j dvidmd.m
+install: inst-iptex inst-imagen1
+# endconf imagen
+
+# conf versatec
+# all: verser1 verser2
+# install: inst-dvipr inst-verser1 inst-verser2
+# endconf versatec
+
+# The rest of these are copied to Makefile.local, though many are
+# unused.
+conf:
+ @sh conf.sh
+ @echo "Remember to use \`make update' if you change the Makefile!"
+
+clean:
+ rm -f core *.o verser1 verser2 imagen1 dvidmd dvidmd.[jm]
+
+depend: ${SRCS}
+ cc -M ${CFLAGS} ${SRCS} |\
+ awk '{ if ($$1 != prev) { if (rec != "") print rec;\
+ rec = $$0; prev = $$1; }\
+ else { if (length(rec $$2) > 78) { print rec; rec = $$0; }\
+ else rec = rec " " $$2 } }\
+ END { print rec }' >makedep
+ echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
+ echo '$$r makedep' >>eddep
+ echo 'w' >>eddep
+ cp Makefile Makefile.bak
+ ed - Makefile <eddep
+ rm eddep makedep
+ echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile
+ echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile
+ echo '# see make depend above' >>Makefile
+ sh conf.sh update
+
+update:
+ @sh conf.sh update
+
+inst-dvipr:
+ install -c dvipr.sh ${BINDIR}/dvipr
+ install -c -m 444 ../man/dvipr.1 ${MANDIR}/man1/dvipr.1
+inst-verser1: verser1
+ install -s verser1 ${BINDIR}/verser1
+inst-verser2: verser2
+ install -s verser2 ${BINDIR}/verser2
+
+inst-iptex:
+ install -c iptex.sh ${BINDIR}/iptex
+ install -c -m 444 ../man/iptex.1 ${MANDIR}/man1/iptex.1
+inst-imagen1: imagen1
+ install -s imagen1 ${BINDIR}/imagen1
+
+lint: ${SRCS}
+ lint -hbxuL ../lib/llib-lib imagen1.c
+ lint -hbxuL ../lib/llib-lib verser1.c
+ lint -hbxuL ../lib/llib-lib verser2.c
+
+dist:
+ rm -f Makefile.bak Makefile.local Makefile.l.bak
+ sh conf.sh all
+
+dvidmd: dmd.o dmdhost.o dmd-sp.o
+ ${CC} ${CFLAGS} -o dvidmd dmd.o dmdhost.o dmd-sp.o ../lib/lib.a /usr/local/lib/libcompat.a -lm
+
+dvidmd.m: dmdslave.c
+ $(MCC) $(MCFLAGS) -o dvidmd.m dmdslave.c
+
+dvidmd.j: dmdslave.c
+ $(MCC) -J $(MCFLAGS) -o dvidmd.j dmdslave.c
+
+imagen1: imagen1.o imagen1-sp.o
+verser1: verser1.o
+verser2: verser2.o
+
+imagen1: ../lib/lib.a
+ ${CC} ${CFLAGS} -o imagen1 imagen1.o imagen1-sp.o ../lib/lib.a /usr/local/lib/libcompat.a -lm
+
+imagen1 verser1 verser2: ../lib/lib.a
+ ${CC} ${CFLAGS} -o $@ $@.o ../lib/lib.a /usr/local/lib/libcompat.a
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
+imagen1.o: imagen1.c /usr/include/stdio.h ../h/types.h ../h/conv.h ../h/dvi.h
+imagen1.o: ../h/dviclass.h ../h/dvicodes.h ../h/fio.h ../h/font.h
+imagen1.o: ../h/postamble.h ../h/search.h ../h/imagen.h ../h/imPcodes.h
+verser1.o: verser1.c /usr/include/stdio.h ../h/types.h ../h/conv.h ../h/dvi.h
+verser1.o: ../h/dviclass.h ../h/dvicodes.h ../h/fio.h ../h/font.h
+verser1.o: ../h/postamble.h ../h/search.h ../h/verser.h
+verser2.o: verser2.c /usr/include/errno.h /usr/include/setjmp.h
+verser2.o: /usr/include/stdio.h /usr/include/sys/vcmd.h
+verser2.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
+verser2.o: /usr/include/sys/ttydev.h ../h/types.h ../h/conv.h ../h/fio.h
+verser2.o: ../h/font.h ../h/verser.h
+# DEPENDENCIES MUST END AT END OF FILE
+# IF YOU PUT STUFF HERE IT WILL GO AWAY
+# see make depend above
diff --git a/dviware/umddvi/dev/makefile.local b/dviware/umddvi/dev/makefile.local
new file mode 100644
index 0000000000..e23d533f08
--- /dev/null
+++ b/dviware/umddvi/dev/makefile.local
@@ -0,0 +1,143 @@
+#
+# 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.
+#
+# $Header: Makefile,v 1.3 87/06/16 17:13:19 chris Exp $
+#
+# Makefile for device conversion programs
+#
+# You must run "make conf" to set up Makefile.local if you do not want
+# the default `all' configuration (see the file "conf.sh"). Remember to
+# use `make update'!
+DESTDIR=
+CFLAGS= -O -R -I../h
+MAKE= make
+
+# these are intended to be overridden by the definitions in ../Makefile
+# but just in case, they are here too
+BINDIR= ${DESTDIR}/usr/local/bin
+MANDIR= ${DESTDIR}/usr/local/man
+
+# Make options
+OPTS= BINDIR=${BINDIR} MANDIR=${MANDIR} DESTDIR=${DESTDIR} CC="${CC}" \
+ CFLAGS="${CFLAGS}" ${MFLAGS}
+
+SRCS= imagen1.c verser1.c verser2.c
+
+# First, the main entry used in the original Makefile.
+# It is also enabled by a `conf none'; this is just so that the
+# configurer will disable it in Makefile.local.
+# Whenever you run `make' afterward, this entry will run
+# make on your local Makefile.
+
+# conf none
+# first:
+# @if [ -f Makefile.local ]; then :; else \
+# echo "You should run \`make conf' first!"; \
+# echo \
+# "I will give you the default \`all' configuration for now."; \
+# sh conf.sh all; \
+# fi
+# @${MAKE} -f Makefile.local ${OPTS}
+# endconf none
+
+# In Makefile.local, this is the default (if you just say `make').
+# The `make' invocation will be commented out there.
+all:
+# conf none
+# @${MAKE} -f Makefile.local ${OPTS} $@
+# endconf none
+
+# Likewise, but for `make install'.
+install:
+# conf none
+# @${MAKE} -f Makefile.local ${OPTS} $@
+# endconf none
+
+# conf imagen
+all: imagen1
+install: inst-iptex inst-imagen1
+# endconf imagen
+
+# conf versatec
+all: verser1 verser2
+install: inst-dvipr inst-verser1 inst-verser2
+# endconf versatec
+
+# The rest of these are copied to Makefile.local, though many are
+# unused.
+conf:
+ @sh conf.sh
+ @echo "Remember to use \`make update' if you change the Makefile!"
+
+clean:
+ rm -f core *.o verser1 verser2 imagen1
+
+depend: ${SRCS}
+ cc -M ${CFLAGS} ${SRCS} |\
+ awk '{ if ($$1 != prev) { if (rec != "") print rec;\
+ rec = $$0; prev = $$1; }\
+ else { if (length(rec $$2) > 78) { print rec; rec = $$0; }\
+ else rec = rec " " $$2 } }\
+ END { print rec }' >makedep
+ echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
+ echo '$$r makedep' >>eddep
+ echo 'w' >>eddep
+ cp Makefile Makefile.bak
+ ed - Makefile <eddep
+ rm eddep makedep
+ echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile
+ echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile
+ echo '# see make depend above' >>Makefile
+ sh conf.sh update
+
+update:
+ @sh conf.sh update
+
+inst-dvipr:
+ install -c dvipr.sh ${BINDIR}/dvipr
+ install -c -m 444 ../man/dvipr.1 ${MANDIR}/man1/dvipr.1
+inst-verser1: verser1
+ install -s verser1 ${BINDIR}/verser1
+inst-verser2: verser2
+ install -s verser2 ${BINDIR}/verser2
+
+inst-iptex:
+ install -c iptex.sh ${BINDIR}/iptex
+ install -c -m 444 ../man/iptex.1 ${MANDIR}/man1/iptex.1
+inst-imagen1: imagen1
+ install -s imagen1 ${BINDIR}/imagen1
+
+lint: ${SRCS}
+ lint -hbxuL ../lib/llib-lib imagen1.c
+ lint -hbxuL ../lib/llib-lib verser1.c
+ lint -hbxuL ../lib/llib-lib verser2.c
+
+dist:
+ rm -f Makefile.bak Makefile.local Makefile.l.bak
+ sh conf.sh all
+
+imagen1: imagen1.o
+verser1: verser1.o
+verser2: verser2.o
+
+imagen1 verser1 verser2: ../lib/lib.a
+ ${CC} ${CFLAGS} -o $@ $@.o ../lib/lib.a
+
+# DO NOT DELETE THIS LINE -- make depend uses it
+
+imagen1.o: imagen1.c /usr/include/stdio.h ../h/types.h ../h/conv.h ../h/dvi.h
+imagen1.o: ../h/dviclass.h ../h/dvicodes.h ../h/fio.h ../h/font.h
+imagen1.o: ../h/postamble.h ../h/search.h ../h/imagen.h ../h/imPcodes.h
+verser1.o: verser1.c /usr/include/stdio.h ../h/types.h ../h/conv.h ../h/dvi.h
+verser1.o: ../h/dviclass.h ../h/dvicodes.h ../h/fio.h ../h/font.h
+verser1.o: ../h/postamble.h ../h/search.h ../h/verser.h
+verser2.o: verser2.c /usr/include/errno.h /usr/include/setjmp.h
+verser2.o: /usr/include/stdio.h /usr/include/sys/vcmd.h
+verser2.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h
+verser2.o: /usr/include/sys/ttydev.h ../h/types.h ../h/conv.h ../h/fio.h
+verser2.o: ../h/font.h ../h/verser.h
+# DEPENDENCIES MUST END AT END OF FILE
+# IF YOU PUT STUFF HERE IT WILL GO AWAY
+# see make depend above
diff --git a/dviware/umddvi/dev/readme b/dviware/umddvi/dev/readme
new file mode 100644
index 0000000000..0dd6cc1744
--- /dev/null
+++ b/dviware/umddvi/dev/readme
@@ -0,0 +1,7 @@
+This directory is for DVI to device conversion programs (including
+shell scripts to drive them).
+
+N.B.: verser2.c is probably vax-dependent.
+
+You should run "make conf" before trying to make or install any of
+these, else you will get all drivers.
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;
+}
diff --git a/dviware/umddvi/dev/verser2.c b/dviware/umddvi/dev/verser2.c
new file mode 100644
index 0000000000..8969e7595d
--- /dev/null
+++ b/dviware/umddvi/dev/verser2.c
@@ -0,0 +1,758 @@
+/*
+ * 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: verser2.c,v 2.5 87/06/16 17:15:19 chris Exp $";
+#endif
+
+/*
+ * Verser2 -- Second half of DVI to Versatec driver
+ *
+ * Reads pre-sorted pages as put out by verser1, and shovels bitmaps
+ * out to the Versatec as fast as possible. Warning: there is some
+ * inline assembly code used in inner loops, where the C compiler
+ * produced particuarly poor code.
+ *
+ * We use a technique known as a `band buffer', where we keep track
+ * of what has yet to be written to the Versatec in a buffer that
+ * represents a `band' across the current page, analagous to a magnifying
+ * bar across the page. Only the region in the band can be written,
+ * and the band moves only downward; this is why verser1 must sort
+ * each page, at least by y coordinate. This also implies that the
+ * `tallest' object we can write is the same height as the band. This
+ * is a problem for large characters. For these there is some (as yet
+ * unimplemented) code that will ask for a `part' of each character
+ * to be drawn into the band. The character would then be repeated
+ * with a request for the next part when the band has moved down to
+ * just below the bottom of the previous part. Rules are also broken
+ * up as appropriate (and that code *is* implemented).
+ *
+ * Another important point is that the band buffer is treated as a
+ * `cylinder' rather than a `strip': we write bits onto the cylinder,
+ * then roll it forward over the page, moving the bits off the cylinder
+ * and onto the paper, leaving that part of the cylinder clean, ready
+ * for more bits. The variable `CurRow' points at the current row
+ * in the buffer/on the cylinder, and `FirstRow' and `LastRow' bound
+ * the `dirty' part of the cylinder. Modular arithmetic suffices to
+ * change linear to cylindrical.
+ *
+ * Whenever CurRow is more than MIN_OUT rows ahead of FirstRow, we
+ * write out that much of the cylinder, cleaning it. This keeps the
+ * paper moving, lest the developer soak one spot and produce `streaky'
+ * output.
+ *
+ * Yet another point of note is that because the band always moves
+ * `down' on the page, we need only a positive offset from the current
+ * row to move to a new row. This means (among other things) that we
+ * can use negative offsets for special purposes.
+ */
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <sys/vcmd.h>
+#ifdef ACCOUNT_FILE
+#include <pwd.h>
+#endif ACCOUNT_FILE
+#include "types.h"
+#include "conv.h"
+#include "fio.h"
+#include "font.h"
+#include "verser.h"
+
+#define SPEED_HACK
+
+char *ProgName;
+extern int errno;
+extern char *optarg;
+extern int optind;
+
+/* Globals */
+jmp_buf failbuf; /* in case of Versatec write() problems */
+
+struct font *Fonts[NFONTS]; /* the fonts */
+
+char TeXFontDesc[256]; /* getenv("TEXFONTDESC") from verser1 */
+
+int RasterOrientation; /* ROT_NORM or ROT_RIGHT, based on HFlag */
+
+int DFlag; /* -d => output discarded */
+int HFlag; /* -h => horizontal (rotated bitmaps) */
+int SFlag; /* -s => silent processing */
+int TFlag; /* -t => output to tape */
+int Debug; /* -D => debug flag */
+
+char VBuffer[ROWS][COLUMNS]; /* Versatec band buffer */
+
+int CurRow; /* current row in buffer */
+int CurCol; /* current column in buffer */
+int FirstRow; /* the first row used */
+int LastRow; /* the last row used */
+int NLines; /* counts lines; used for pagefeeds */
+int Pages; /* counts pages; for accounting */
+
+int vp; /* Versatec file descriptor */
+
+int pltmd[] = {VPLOT, 0, 0};/* print & plot mode, for ioctl */
+int prtmd[] = {VPRINT, 0, 0};
+
+#ifdef ACCOUNT_FILE
+struct passwd *getpwuid();
+#endif ACCOUNT_FILE
+
+/*
+ * RowsBetween tells how many rows (in cylindrical arithmetic) there
+ * are between the first position and the second. If the second value
+ * is less than the first value, add ROWS to do the appropriate modular
+ * arithmetic. We cannot use `%' as C `%' is machine-dependent with
+ * respect to negative values.
+ */
+#define RowsBetween(f, n) ((n) >= (f) ? (n) - (f) : (n) - (f) + ROWS)
+
+/*
+ * This is it... on your marks ... get set ... main!
+ */
+main(argc, argv)
+ int argc;
+ register char **argv;
+{
+ register int c;
+ register char *s;
+ int dpi, usermag, num, denom, dvimag;
+ int VFlag = 0;
+#ifdef ACCOUNT_FILE
+ int acct_fd;
+
+ acct_fd = open(ACCOUNT_FILE, 1);
+ (void) setuid(getuid());
+#endif ACCOUNT_FILE
+
+ ProgName = *argv;
+
+ if (setjmp(failbuf)) { /* still have to do accounting */
+#ifdef ACCOUNT_FILE
+ /*
+ * Kind of strange to charge for a printout that failed
+ * because we ran out of paper, but that was the way they
+ * wanted it....
+ */
+ if (NLines)
+ Pages++;/* count the partial page */
+ DoAccount(acct_fd);
+#endif ACCOUNT_FILE
+ exit(1);
+ /* NOTREACHED */
+ }
+ while ((c = getopt(argc, argv, "dstv:D")) != EOF) {
+ switch (c) {
+
+ case 'd': /* output to /dev/null */
+ DFlag++;
+ break;
+
+ case 's': /* silent processing except for errors */
+ SFlag++;
+ break;
+
+ case 't': /* output to tape (not implemented) */
+ TFlag++;
+ error(0, 0, "tape option not yet implemented");
+ break;
+
+ case 'v': /* Versatec already open as fd <n> */
+ VFlag++;
+ vp = atoi(optarg);
+ break;
+
+ case 'D':
+ Debug++;
+ break;
+
+ case '?':
+ fprintf(stderr, "Usage: %s [-d] [-s] [-t] [file]\n",
+ ProgName);
+ exit(1);
+ }
+ }
+ if (optind < argc)
+ if (freopen(argv[optind], "r", stdin) == NULL)
+ error(1, 0, "can't open %s", argv[optind]);
+
+ HFlag = getchar();
+ if ((HFlag >> 1) != VERSION)
+ error(1, 0, "input file is not version %d", VERSION);
+ HFlag &= 1;
+ RasterOrientation = HFlag ? ROT_RIGHT : ROT_NORM;
+
+ s = TeXFontDesc;
+ c = GetLong(stdin);
+ while (--c >= 0)
+ *s++ = getchar();
+ if (feof(stdin))
+ (void) GetByte(stdin); /* let GetByte do error */
+ *s = 0;
+
+ dpi = GetLong(stdin);
+ usermag = GetLong(stdin);
+ num = GetLong(stdin);
+ denom = GetLong(stdin);
+ dvimag = GetLong(stdin);
+ SetConversion(dpi, usermag, num, denom, dvimag);
+
+ fontinit(*TeXFontDesc ? TeXFontDesc : (char *) NULL);
+ ReadFonts();
+
+ if (DFlag) {
+ (void) fprintf(stderr, "Output will be discarded\n");
+ (void) fflush(stderr);
+ vp = open("/dev/null", 1);
+ } else {
+ if (!VFlag) {
+ vp = open(VERSATEC_FILE, 1);
+ if (vp < 0) {
+ if (errno == ENXIO)
+ error(1, 0, "\
+can't open versatec---already in use");
+ if (errno == EIO)
+ error(1, 0, "\
+can't open versatec---device offline");
+ error(1, errno, "can't open %s",
+ VERSATEC_FILE);
+ }
+ }
+ ioctl(vp, VSETSTATE, pltmd);
+ }
+
+ if (!HFlag)
+ CutMarks(); /* initial cut marks */
+
+ ReadInput();
+
+ FormFeed(0); /* end up in print mode */
+
+ if (!SFlag)
+ (void) putc('\n', stderr);
+
+#ifdef ACCOUNT_FILE
+ DoAccounting(acct_fd);
+#endif ACCOUNT_FILE
+
+ exit(0);
+}
+
+#ifdef ACCOUNT_FILE
+/*
+ * Accounting is done by writing the program name ("tex"), the user name,
+ * and the number of pages at the end of the file. (The program name is
+ * for statistics.)
+ */
+DoAccounting(fd)
+ int fd;
+{
+ register struct passwd *p;
+ char buf[128];
+
+ if (fd < 0 || (p = getpwuid(getuid())) == 0)
+ return;
+
+ /*
+ * The '+ 2' is because there is an extra page at the end, and
+ * because the Versatec does pagefeeds when it is opened.
+ */
+ (void) sprintf(buf, "tex %s %d\n", p->pw_name, Pages + 2);
+ (void) lseek(fd, 0L, 2);
+ (void) write(fd, buf, strlen(buf));
+}
+#endif ACCOUNT_FILE
+
+/*
+ * Read the font definitions.
+ *
+ * Anti-streak hack: get the rasters ahead of time, #ifdef SPEED_HACK.
+ */
+ReadFonts()
+{
+ register struct font *f, **fp;
+ register int c;
+ register char *s;
+#ifdef SPEED_HACK
+ register struct glyph *g;
+#endif
+ i32 mag, dsize;
+ char *fname;
+ char nm[512];
+
+ if (!SFlag)
+ (void) fprintf(stderr, "[fonts:\n");
+ fp = Fonts;
+ while (GetByte(stdin) == 1) {
+ (void) GetLong(stdin); /* checksum */
+ mag = GetLong(stdin); /* magfactor */
+ dsize = GetLong(stdin); /* design size */
+ c = GetLong(stdin);
+ s = nm;
+ while (--c >= 0)
+ *s++ = getchar();
+ if (feof(stdin))
+ (void) GetByte(stdin); /* let GetByte do error */
+ *s = 0;
+ f = GetFont(nm, mag, dsize, "versatec", &fname);
+ if (f == NULL) {
+ GripeCannotGetFont(nm, mag, dsize, "versatec", fname);
+ exit(1);
+ /* NOTREACHED */
+ }
+ if (Debug) {
+ (void) fprintf(stderr, "[%s -> %s]\n",
+ Font_TeXName(f), fname);
+ (void) fflush(stderr);
+ }
+ if (!SFlag) {
+ register char *t = fname;
+
+ s = fname;
+ while (*s)
+ if (*s++ == '/' && *s)
+ t = s;
+ (void) fprintf(stderr, " %s\n", t);
+ }
+#ifdef SPEED_HACK
+ for (c = 0; c < 128; c++) {
+ g = GLYPH(f, c);
+ if (GVALID(g))
+ (void) RASTER(g, f, RasterOrientation);
+ }
+#endif
+ *fp++ = f;
+ }
+ if (!SFlag)
+ (void) fprintf(stderr, "]\n");
+}
+
+/*
+ * Read the input stream, decode it, and put character rasters or rules at
+ * the positions given.
+ */
+ReadInput()
+{
+ register int yx, fcp, height;
+
+ /*
+ * Loop forever. I had a `for (;;)' but everything crept off the
+ * right side of the screen.
+ */
+next:
+ fGetLong(stdin, yx); /* position */
+ fGetLong(stdin, fcp); /* character, most likely */
+ if (feof(stdin))
+ return; /* done */
+
+ /*
+ * A `position' of -1 indicates either a rule or an end of page.
+ * Anything else is a character.
+ */
+ if (yx != -1) { /* place character */
+ register struct glyph *g;
+ register struct font *f;
+ register int fnum;
+
+ /*
+ * Any delta-y required is stored in the upper 16 bits of yx.
+ */
+ if ((height = yx >> 16) != 0)
+ MoveDown(height);
+ /*
+ * Extract the x, font, char, and part info into CurCol,
+ * fnum, yx, and fcp.
+ */
+ CurCol = yx & 0xffff;
+ fnum = fcp >> FONTSHIFT;
+ yx = (fcp >> CHARSHIFT) & CHARMASK;
+ fcp = fcp & PARTMASK;
+ f = Fonts[fnum]; /* trusting */
+ g = GLYPH(f, yx);
+
+ /*
+ * In case this character does not fit, write
+ * out the used part of the band. It had better
+ * fit afterward....
+ */
+ height = g->g_height;
+ if (height >= ROWS - RowsBetween(FirstRow, CurRow))
+ DumpTopOfBand();
+ if (fcp) /* cannot handle these yet */
+ error(0, 0, "\
+part code not implemented; skipping char %d in %s",
+ yx, f->f_path);
+ else if (HASRASTER(g)) {
+#ifdef SPEED_HACK
+ /* XXX, but saves time */
+ VWriteChar(g->g_raster, height, g->g_width);
+#else
+ VWriteChar(RASTER(g, f, RasterOrientation),
+ height, g->g_width);
+#endif
+ }
+ /* dump if we can do at least MIN_OUT rows */
+ if (RowsBetween(FirstRow, CurRow) > MIN_OUT)
+ DumpTopOfBand();
+ goto next; /* done with character */
+ }
+
+ /*
+ * If the `character' is negative, we need to move down first,
+ * possibly because this is an end-of-page. If this is not the
+ * end of the page, it must be a rule.
+ */
+ if (fcp < 0) { /* move down */
+ yx = -fcp;
+ fGetLong(stdin, fcp); /* junk */
+ fGetLong(stdin, fcp);
+ if (fcp == 0) { /* end page */
+ /* dump entire band */
+ WriteBuf(&VBuffer[0][0], FirstRow, LastRow, 1);
+ CurRow = LastRow = FirstRow;
+ if (!HFlag) {
+ WriteBlanks(yx - NLines);
+ CutMarks();
+ } else
+ FormFeed(1);
+ if (!SFlag)
+ (void) fprintf(stderr, ".");
+ NLines = 0;
+ Pages++;
+ goto next; /* all done */
+ }
+
+ MoveDown(yx); /* must be a rule; move down by yx rows */
+ }
+
+ /*
+ * At this point we have a rule to put at the current
+ * position, CurRow.
+ */
+ height = (fcp & 0xff00) >> 8;
+ /* make sure it fits */
+ if (height >= ROWS - RowsBetween(FirstRow, CurRow))
+ DumpTopOfBand();
+ VWriteRule(fcp);
+ goto next; /* done with rule */
+}
+
+/*
+ * Write the given raster for the given character.
+ *
+ * Basically, the task is to move bits from the raster to the Versatec
+ * buffer. However, because the character being plotted can be on an
+ * arbitrary bit boundary, things are not as simple as we might like.
+ * The solution used here is to shift each raster value right, OR it
+ * into the buffer, then (at the next location) OR in the bits that
+ * `fell off the right edge'.
+ */
+VWriteChar(rastp, height, width)
+ char *rastp; /* raster pointer */
+ int height, width; /* height & width of char */
+{
+ register char *bp; /* Versatec buffer pointer [r11] */
+ register char *rp; /* raster pointer [r10] */
+ register int rshift; /* right shift index [r9] */
+ register int lshift; /* left shift index [r8] */
+ register int j; /* width loop downcounter */
+ register int o; /* offset to next row in buffer */
+ int row; /* current row in buffer */
+ int col; /* column in buffer of left edge */
+ int i; /* height loop downcounter */
+ int w; /* raster width (bytes) */
+
+ if ((rp = rastp) == NULL)
+ return; /* an all-white character (`cannot happen') */
+
+ row = CurRow;
+ col = CurCol >> 3;
+ i = height;
+ w = (width + 7) >> 3;
+ o = COLUMNS - w;
+
+#if defined(lint) || !defined(vax)
+ rshift = CurCol & 7;
+ lshift = 8 - rshift;
+#else lint || !vax
+ rshift = -(CurCol & 7); /* Vax does '>>' as negative '<<' */
+ lshift = 8 + rshift;
+#endif lint || !vax
+ bp = &VBuffer[row][col];
+
+#define avoiding_shifts_is_faster /* but is it??? */
+#ifdef avoiding_shifts_is_faster
+ /*
+ * One out of eight or so times, the shift values will be
+ * zero. This makes the code run faster.
+ */
+ if (rshift == 0) {
+ while (--i >= 0) {
+ j = w;
+ while (--j >= 0)
+ *bp++ |= *rp++;
+ if (++row >= ROWS) {
+ row = 0;
+ bp = &VBuffer[0][col];
+ } else
+ bp += o;
+ }
+ } else
+#endif
+ {
+ while (--i >= 0) {
+ j = w;
+ while (--j >= 0) {
+#if defined(lint) || !defined(vax)
+ *bp++ |= (*rp & 255) >> rshift;
+ *bp |= (*rp++ & 255) << lshift;
+#else lint || !vax
+ /*
+ * THE FOLLOWING ASSEMBLY CODE IS INSERTED
+ * BECAUSE THE COMPILER CAN'T OPTIMIZE THE
+ * C CODE WORTH A DARN
+ */
+ asm(" movzbl (r10)+,r1 # *rp++ & 255");
+ asm(" ashl r9,r1,r0 # >> rshift");
+ asm(" bisb2 r0,(r11)+ # *bp++ |=");
+ asm(" ashl r8,r1,r0 # << lshift");
+ asm(" bisb2 r0,(r11) # *bp |=");
+#endif lint || !vax
+ }
+ if (++row >= ROWS) {
+ row = 0;
+ bp = &VBuffer[0][col];
+ } else
+ bp += o;
+ }
+ }
+
+ j = height + CurRow - 1;/* have now set bits this far */
+ if (j >= ROWS)
+ j -= ROWS; /* keep it modular */
+
+ /*
+ * There are two cases. Either the buffer is not currently wrapped,
+ * in which case the regions past LastRow or before FirstRow extend
+ * it; or it is wrapped, in which case the region between LastRow
+ * and FirstRow extends it:
+ *
+ * case 1 case 2
+ * -------- --------
+ * | | last ->| XXXX |
+ * first ->| XXXX | | |
+ * | XXXX | | |
+ * last ->| XXXX | first ->| XXXX |
+ * | | | XXXX |
+ * -------- --------
+ *
+ * The `X's mark the region that is in use; the blank spaces
+ * mark the region that causes the `last' value to change.
+ */
+ if (FirstRow <= LastRow) {
+ /* first case: not wrapped */
+ if (j < FirstRow || j > LastRow)
+ LastRow = j;
+ } else {
+ /* second case: wrapped */
+ if (j > LastRow && j < FirstRow)
+ LastRow = j;
+ }
+}
+
+/*
+ * Write a rule at the current row according to the (packed) information in
+ * 'info'. This includes the x position and the height and width of the
+ * rule.
+ */
+VWriteRule(info)
+ int info;
+{
+ register char *bp; /* buffer pointer */
+ register int j;
+ register int lbits; /* bits along left */
+ register int rbits; /* bits along right */
+ register int o; /* offset to next row */
+ register int i;
+ register int full; /* number of 8 bit words to set */
+ register int height; /* rule height */
+ register int width; /* rule width */
+ register int row;
+ register int col;
+
+ i = info;
+ CurCol = (i & 0x7fff0000) >> 16;
+ height = (i & 0xff00) >> 8;
+ width = i & 0xff;
+ col = CurCol >> 3;
+ row = CurRow;
+ j = CurCol & 7; /* bit # of start position */
+ lbits = 0xff >> j; /* bits to set along left edge */
+ /* there are 8-j bits set in lbits */
+ o = 8 - j - width;
+ if (o > 0) { /* then lbits has o too many bits set */
+ lbits >>= o;
+ lbits <<= o; /* puts zeros into o righthand bits */
+ rbits = 0;
+ full = 0;
+ } else {
+ i = (CurCol + width) & 7; /* bit # of ending position */
+ rbits = 0xff00 >> i; /* bits to set along right edge */
+ /* there are i bits set in rbits (well, in the low byte) */
+ full = (width - i - (8 - j)) >> 3;
+ }
+ bp = &VBuffer[row][col];
+ i = height;
+
+ /* Often "full" is zero, which makes things faster */
+ if (full) { /* oh well */
+ o = COLUMNS - full - 1;
+ while (--i >= 0) {
+ *bp++ |= lbits;
+ for (j = full; --j >= 0;)
+ *bp++ |= 0xff;
+ *bp |= rbits;
+ if (++row >= ROWS) {
+ row = 0;
+ bp = &VBuffer[0][col];
+ } else
+ bp += o;
+ }
+ } else {
+ o = COLUMNS - 1;
+ while (--i >= 0) {
+ *bp++ |= lbits;
+ *bp |= rbits;
+ if (++row >= ROWS) {
+ row = 0;
+ bp = &VBuffer[0][col];
+ } else
+ bp += o;
+ }
+ }
+ i = CurRow + height - 1;
+ if (i >= ROWS)
+ i -= ROWS;
+ /*
+ * This is another way of expressing both cases 1 and 2 in
+ * VWriteChar(). I think the other way is likely to be
+ * faster, and characters occur far more frequently; but this
+ * is the more readable by far.
+ */
+ if (RowsBetween(FirstRow, LastRow) < RowsBetween(FirstRow, i))
+ LastRow = i;
+}
+
+/*
+ * Dump out the top portion of the band (rows [Firstrow, CurRow)).
+ */
+DumpTopOfBand()
+{
+
+ /*
+ * To exclude CurRow, subtract one, but modularly, modularly!
+ */
+ WriteBuf(&VBuffer[0][0], FirstRow, CurRow ? CurRow - 1 : ROWS - 1, 1);
+ FirstRow = CurRow;
+}
+
+/*
+ * Move the current row in the band buffer down by delta rows, by,
+ * if necessary, writing out the currently-used portion of the buffer.
+ */
+MoveDown(delta)
+ register int delta;
+{
+
+ if (delta >= ROWS - RowsBetween(FirstRow, CurRow)) {
+ /*
+ * Need to roll the cylinder forward. Write out the used
+ * part, and then write as many blank lines as necessary.
+ */
+ WriteBuf(&VBuffer[0][0], FirstRow, LastRow, 1);
+ WriteBlanks(delta - RowsBetween(CurRow, LastRow) - 1);
+ CurRow = LastRow = FirstRow; /* band is now empty */
+ } else {
+ /*
+ * Because RowsBetween returns nonnegative integers, we
+ * know delta <= ROWS, so can do mod more quickly thus:
+ */
+ CurRow += delta; /* result < 2*ROWS */
+ if (CurRow >= ROWS)
+ CurRow -= ROWS; /* now result < ROWS */
+ }
+}
+
+/*
+ * Write the lines between the first and last inclusive from the given
+ * buffer. If 'cl', clear after writing.
+ */
+WriteBuf(buf, first, last, cl)
+ register char *buf;
+ register int first, last;
+{
+
+ if (first > last) { /* recursively do wrapped part first */
+ WriteBuf(buf, first, ROWS - 1, cl);
+ first = 0;
+ }
+ buf = &buf[first * COLUMNS];
+ last = COLUMNS * (first = last - first + 1);
+
+ /*
+ * If the write fails, the Versatec is probably out of paper, and in
+ * any case, things are probably in bad shape.
+ */
+ if (write(vp, buf, last) != last) {
+ error(0, errno, "Versatec write error");
+ longjmp(failbuf, 1);
+ }
+ if (cl)
+ bzero(buf, (unsigned) last);
+ NLines += first;
+}
+
+/*
+ * Write 'n' blank lines.
+ */
+WriteBlanks(n)
+ register int n;
+{
+ register int k;
+ static char nullbuf[MIN_OUT][COLUMNS];
+
+ while (n > 0) {
+ k = n > MIN_OUT ? MIN_OUT : n;
+ WriteBuf(&nullbuf[0][0], 0, k - 1, 0);
+ n -= k;
+ }
+}
+
+/*
+ * Write cut marks. We borrow row 0 of VBuffer for this.
+ */
+CutMarks()
+{
+ register short *bp = (short *) &VBuffer[0][0];
+
+ *bp = 0xffff;
+ bp[(COLUMNS / 2) - 1] = 0xffff;
+ WriteBuf(&VBuffer[0][0], 0, 0, 1);
+}
+
+/*
+ * Perform a page feed. Restore plot mode if `setplot'.
+ */
+FormFeed(setplot)
+ int setplot;
+{
+ ioctl(vp, VSETSTATE, prtmd);
+ (void) write(vp, "\f", 2); /* \0 really IS required occasionally */
+ if (setplot)
+ ioctl(vp, VSETSTATE, pltmd);
+}