diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/umddvi/dev |
Initial commit
Diffstat (limited to 'dviware/umddvi/dev')
-rw-r--r-- | dviware/umddvi/dev/conf.sh | 113 | ||||
-rw-r--r-- | dviware/umddvi/dev/config | 3 | ||||
-rw-r--r-- | dviware/umddvi/dev/dmd-sp.c | 568 | ||||
-rw-r--r-- | dviware/umddvi/dev/dmd.c | 920 | ||||
-rw-r--r-- | dviware/umddvi/dev/dmdcodes.h | 39 | ||||
-rw-r--r-- | dviware/umddvi/dev/dmdhost.c | 236 | ||||
-rw-r--r-- | dviware/umddvi/dev/dmdslave.c | 1176 | ||||
-rw-r--r-- | dviware/umddvi/dev/dvipr.sh | 71 | ||||
-rw-r--r-- | dviware/umddvi/dev/fontdesc | 1 | ||||
-rw-r--r-- | dviware/umddvi/dev/imagen1-special.c | 718 | ||||
-rw-r--r-- | dviware/umddvi/dev/imagen1.c | 867 | ||||
-rw-r--r-- | dviware/umddvi/dev/interpress.h | 29 | ||||
-rw-r--r-- | dviware/umddvi/dev/ip.c | 696 | ||||
-rw-r--r-- | dviware/umddvi/dev/iptex.sh | 61 | ||||
-rw-r--r-- | dviware/umddvi/dev/makefile | 143 | ||||
-rw-r--r-- | dviware/umddvi/dev/makefile.3b | 149 | ||||
-rw-r--r-- | dviware/umddvi/dev/makefile.local | 143 | ||||
-rw-r--r-- | dviware/umddvi/dev/readme | 7 | ||||
-rw-r--r-- | dviware/umddvi/dev/verser1.c | 1047 | ||||
-rw-r--r-- | dviware/umddvi/dev/verser2.c | 758 |
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); +} |