summaryrefslogtreecommitdiff
path: root/dviware/umddvi/dev/imagen1.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/umddvi/dev/imagen1.c')
-rw-r--r--dviware/umddvi/dev/imagen1.c867
1 files changed, 867 insertions, 0 deletions
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;
+ }
+}