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/imagen1.c |
Initial commit
Diffstat (limited to 'dviware/umddvi/dev/imagen1.c')
-rw-r--r-- | dviware/umddvi/dev/imagen1.c | 867 |
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; + } +} |