|
|
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 v
Length: 16664 (0x4118)
Types: TextFile
Names: »verser1.c«
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
└─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z«
└─⟦ca79c7339⟧
└─⟦this⟧ »DVIware/laser-setters/mctex/versatec/verser1.c«
/*
* Copyright (c) 1987, 1989 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: /usr/src/local/tex/local/mctex/versatec/RCS/verser1.c,v 3.2 89/09/01 13:58:36 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 "dviclass.h"
#include "dvicodes.h"
#include "error.h"
#include "fio.h"
#include "font.h"
#include "gripes.h"
#include "dvistate.h"
#include "verser.h"
char *ProgName;
extern char *optarg;
extern int optind;
/* Globals */
char serrbuf[BUFSIZ]; /* buffer for stderr */
char *DVIFileName; /* name of input dvi file */
char *TeXFontDesc; /* getenv(CONFENV): passed to verser2 */
/* 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
/*
* If there are many characters and rules that do not 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 BottomMargin; /* bottom margin (in pixels) */
int TopMargin; /* top margin (in pixels) */
int WidestPageWidth; /* width of widest page (in pixels) */
int TallestPageHeight; /* height of tallest page (in pixels) */
char *malloc(), *realloc(), *getenv();
/*
* Compute the pixel widths of the characters in the given font.
*/
void
ComputeCWidths(f)
register struct font *f;
{
register struct glyph *g;
register int i;
for (i = 0; i < 128; i++) {
g = GLYPH(f, i);
if (GVALID(g))
g->g_pixwidth = fromSP(g->g_tfmwidth);
}
}
/*
* Have run out of room in the current yx and fcp arrays, so expand them.
*/
void
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; /* we are about to use one */
}
/*
* Sort the page arrays so that the values in yx are in ascending order. We
* use a Shell sort.
*/
void
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;
}
}
/*
* Assign a unique number to each font in the DVI file.
* Compute character widths for all the glyphs.
*/
struct font *
DefineFont(name, dvimag, dvidsz)
char *name;
i32 dvimag, dvidsz;
{
register struct font *f;
char *path;
int len;
static int next; /* verser2 knows that we use sequential indicies */
if (next >= NFONTS) /* fix this later */
error(1, 0, "too many fonts (%d) used", next);
f = GetRasterlessFont(name, dvimag, dvidsz, "versatec", &path);
if (f == NULL) {
GripeCannotGetFont(name, dvimag, dvidsz, "versatec", path);
return (NULL);
}
if (Debug) {
(void) fprintf(stderr, "[%s -> %s]\n", Font_TeXName(f), path);
(void) fflush(stderr);
}
if (next == 0) {
/*
* verser2 also needs the conversion factor,
* before the first font.
*/
PutLong(stdout, 200); /* dots per inch */
PutLong(stdout, ds.ds_usermag);
PutLong(stdout, ds.ds_num);
PutLong(stdout, ds.ds_denom);
PutLong(stdout, ds.ds_dvimag);
}
putbyte(stdout, 1); /* signal another font */
PutLong(stdout, f->f_checksum);
PutLong(stdout, dvimag);
PutLong(stdout, dvidsz);
len = strlen(name);
PutLong(stdout, len);
(void) fputs(name, stdout);
ComputeCWidths(f);
f->f_un.f_int = next++;
return (f);
}
/*
* Start a new page (interpreter found a DVI_BOP).
*/
void
BeginPage(count)
i32 *count;
{
if (!SFlag) {
if (nextyx)
(void) putc(' ', stderr);
(void) fprintf(stderr, "[%d", (int)count[0]);
(void) fflush(stderr);
}
/* Chars now becomes "number of characters left" */
Chars = MaxChars; /* empty the arrays */
nextyx = yx;
nextfcp = fcp;
TopEMsg = 0;
BottomEMsg = 0;
LeftEMsg = 0;
RightEMsg = 0;
RuleEMsg = 0;
}
/*
* End a page (process a DVI_EOP).
*/
EndPage()
{
register int i, *y, *f, t, v, oldv;
/* Chars now becomes "number of characters on page" */
i = Chars = MaxChars - Chars;
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 */
}
/*
* Perform a \special.
* This version ignores all, with a warning.
*/
void
DoSpecial(len)
i32 len; /* length of the \special string */
{
error(0, 0, "warning: ignoring \\special");
(void) fseek(ds.ds_fp, (long) len, 1);
}
#ifndef lint
#define maxysize min(MaxCharHeight, 255)
#else
#define maxysize 255
#endif
/*
* Set a rule at dvi_hh, dvi_vv, where h is the height of the rule
* and w is the width (both in pixels). (dvi_hh,dvi_vv) is the lower
* left corner of the rule.
*/
void
SetRule(h, w)
register int h, w;
{
register int y; /* temporary y value */
register int x; /* temporary x value */
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;
if (!HFlag) {
xmin = dvi_hh;
ymax = dvi_vv;
ymin = ymax - h;
xmax = xmin + w;
} else {
ymin = dvi_hh;
xmin = MaxPageWidth - dvi_vv - 1;/* ???DO I NEED -1 ANYMORE?? */
xmax = xmin + h;
ymax = ymin + w;
#ifdef notdef
if (ymax > MaxPageHeight)
ymax = MaxPageHeight, anybad++;
#endif
}
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++;
}
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;
}
}
}
/*
* Check the range of a character, to be sure the device can handle it.
* Called for DVI_SET and DVI_PUT opcodes only.
*/
int
CheckChar(c)
i32 c;
{
/* this driver needs work for codes > 127 */
if ((ui32)c > 127) {
error(0, 0, "Warning: character code %ld too big",
(long)c);
return (1);
}
return (0);
}
/*
* Main page loop. This reads one page of the DVI file.
* Returns 1 for EOP and 0 for end of last page (POST).
*/
int
PageLoop()
{
static struct font NoFont; /* font with zero pspace, etc */
register int c;
register i32 p;
register struct font *f = &NoFont;
register FILE *fp = ds.ds_fp;
int doingpage = 0, advance;
static char warn[] = "\
WARNING: text object(s) run off %s of page; ignored";
#define CHECK(cond, msg, flag) \
if (cond) { \
if (!flag) { \
error(0, 0, warn, msg); \
flag = 1; \
} \
goto ignore; \
}
/*
* This would be a `for (;;)', but that makes the function
* crawl off the right of the screen.
*
* We handle ordinary characters early, as they are the
* most common opcodes in DVI files, and doing so makes the
* loop run faster.
*/
loop:
c = fgetbyte(fp);
if (DVI_IsChar(c)) {
register struct glyph *g;
register int ulcx, ulcy, height;
p = c;
advance = 1;
do_char:
g = GLYPH(f, p);
if (!GVALID(g)) {
GripeBadGlyph(p, f);
goto loop;
}
if (!HFlag) {
ulcy = dvi_vv - g->g_yorigin;
ulcx = dvi_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 = dvi_hh - g->g_xorigin;
ulcx = MaxPageWidth -
(dvi_vv + g->g_height - g->g_yorigin);
height = g->g_width;
CHECK(ulcy < 0, "left", LeftEMsg);
#ifdef notdef
CHECK(ulcy + height >= MaxPageHeight,
"right", RightEMsg);
#endif
CHECK(ulcx < 0, "bottom", BottomEMsg);
CHECK(ulcx + g->g_height >= MaxPageWidth,
"top", TopEMsg);
}
for (c = 0; height > 0; c++) {
if (--Chars < 0)
ExpandArrays();
*nextyx++ = (ulcy << 16) | ulcx;
*nextfcp++ = (f->f_un.f_int << FONTSHIFT) |
((p & CHARMASK) << CHARSHIFT) | c;
height -= MaxCharHeight;
ulcy += MaxCharHeight;
}
ignore:
if (advance) {
dvi_h += g->g_tfmwidth;
dvi_hh += g->g_pixwidth;
p = fromSP(dvi_h);
FIXDRIFT(dvi_hh, p);
}
goto loop;
}
if (c == EOF) /* unexpected end of DVI file */
GripeUnexpectedDVIEOF();
/*
* Gather up a parameter, if known.
*/
switch (DVI_OpLen(c)) {
case DPL_NONE:
break;
case DPL_SGN1:
p = fgetbyte(fp);
p = Sign8(p);
break;
case DPL_SGN2:
fGetWord(fp, p);
p = Sign16(p);
break;
case DPL_SGN3:
fGet3Byte(fp, p);
p = Sign24(p);
break;
case DPL_SGN4:
fGetLong(fp, p);
break;
case DPL_UNS1:
p = fgetbyte(fp);
p = UnSign8(p);
break;
case DPL_UNS2:
fGetWord(fp, p);
p = UnSign16(p);
break;
case DPL_UNS3:
fGet3Byte(fp, p);
p = UnSign24(p);
break;
default:
panic("DVI_OpLen(%d) = %d", c, DVI_OpLen(c));
/* NOTREACHED */
}
/*
* Now switch on the type.
*/
switch (DVI_DT(c)) {
case DT_SET:
advance = 1;
if (CheckChar(p))
goto loop;
goto do_char;
case DT_PUT:
advance = 0;
if (CheckChar(p))
goto loop;
goto do_char;
case DT_SETRULE:
DVIRule(SetRule, 1);
goto loop;
case DT_PUTRULE:
DVIRule(SetRule, 0);
goto loop;
case DT_NOP:
goto loop;
case DT_BOP:
if (doingpage)
GripeUnexpectedOp("BOP (already in page)");
DVIBeginPage(BeginPage);
doingpage = 1;
goto loop;
case DT_EOP:
if (!doingpage)
GripeUnexpectedOp("EOP (no BOP)");
EndPage();
return (1);
case DT_PUSH:
*ds.ds_sp++ = ds.ds_cur;
goto loop;
case DT_POP:
ds.ds_cur = *--ds.ds_sp;
goto loop;
case DT_W0:
p = dvi_w;
goto right;
case DT_W:
dvi_w = p;
goto right;
case DT_X0:
p = dvi_x;
goto right;
case DT_X:
dvi_x = p;
goto right;
case DT_RIGHT:
right:
dvi_h += p;
if (F_SMALLH(f, p)) {
dvi_hh += fromSP(p);
p = fromSP(dvi_h);
FIXDRIFT(dvi_hh, p);
} else
dvi_hh = fromSP(dvi_h);
goto loop;
case DT_Y0:
p = dvi_y;
goto down;
case DT_Y:
dvi_y = p;
goto down;
case DT_Z0:
p = dvi_z;
goto down;
case DT_Z:
dvi_z = p;
goto down;
case DT_DOWN:
down:
dvi_v += p;
if (F_SMALLV(f, p)) {
dvi_vv += fromSP(p);
p = fromSP(dvi_v);
FIXDRIFT(dvi_vv, p);
} else
dvi_vv = fromSP(dvi_v);
goto loop;
case DT_FNTNUM:
f = DVIFindFont((i32)(c - DVI_FNTNUM0));
goto loop;
case DT_FNT:
f = DVIFindFont(p);
goto loop;
case DT_XXX:
DoSpecial(p);
goto loop;
case DT_FNTDEF:
SkipFontDef(fp);
goto loop;
case DT_PRE:
GripeUnexpectedOp("PRE");
/* NOTREACHED */
case DT_POST:
if (doingpage) {
GripeUnexpectedOp("POST (no EOP)");
/* NOTREACHED */
}
return (0);
case DT_POSTPOST:
GripeUnexpectedOp("POSTPOST");
/* NOTREACHED */
case DT_UNDEF:
GripeUndefinedOp(c);
/* NOTREACHED */
default:
panic("DVI_DT(%d) = %d", c, DVI_DT(c));
/* NOTREACHED */
}
/* NOTREACHED */
}
main(argc, argv)
int argc;
register char **argv;
{
register int c;
register char *s;
int lmargin;
FILE *fp = stdin;
setbuf(stderr, serrbuf);
ProgName = *argv;
ds.ds_usermag = 1000;
ds.ds_maxdrift = DefaultMaxDrift;
DVIFileName = "`stdin'";
while ((c = getopt(argc, argv, "cd:hm:sD")) != EOF) {
switch (c) {
case 'c':
CFlag++;/* centered output */
break;
case 'd': /* max drift value */
ds.ds_maxdrift = atoi(optarg);
break;
case 'h': /* horizontal output */
HFlag++;
break;
case 'm': /* magnification */
ds.ds_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 ((fp = fopen(DVIFileName = argv[optind], "r")) == NULL)
error(1, -1, "can't open %s", argv[optind]);
if ((TeXFontDesc = getenv(CONFENV)) == NULL)
TeXFontDesc = "";
c = (VERSION << 1) + (HFlag ? 1 : 0);
putbyte(stdout, c);
c = strlen(s = TeXFontDesc);
PutLong(stdout, c);
while (--c >= 0)
putbyte(stdout, *s++);
/* the margin offsets here are 0; margins computed later */
DVISetState(fp, DefineFont, 200, 0, 0);
TallestPageHeight = fromSP(ds.ds_maxheight);
WidestPageWidth = fromSP(ds.ds_maxwidth);
/*
* 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 */
if (CFlag) {
lmargin = (MaxPageWidth - WidestPageWidth) >> 1;
if (lmargin < MinimumLeftMargin) {
lmargin = MinimumLeftMargin;
error(0, 0, "\
cannot center (page too wide); placing flush left instead");
}
} else
lmargin = HFlag ? DefaultTopMargin - FFMargin :
DefaultLeftMargin;
if (HFlag) {
TopMargin = DefaultRightMargin;
BottomMargin = DefaultLeftMargin;
} else {
TopMargin = DefaultTopMargin;
BottomMargin = DefaultBottomMargin;
}
/* set the `fresh page' margins */
ds.ds_fresh.hh = lmargin;
ds.ds_fresh.vv = TopMargin;
ds.ds_fresh.h = toSP(ds.ds_fresh.hh);
ds.ds_fresh.v = toSP(ds.ds_fresh.vv);
/* 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");
while (PageLoop())
/* void */;
exit(0);
/* NOTREACHED */
}