|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 19246 (0x4b2e)
Types: TextFile
Names: »dmd.c«
└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
└─⟦this⟧ »./DVIware/laser-setters/umd-dvi/dev/dmd.c«
#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;
}
}