[comp.sources.misc] v19i065: dvi - C++ DVI filter for HP LaserJets, Part02/03

parag@hpsdeb.sde.hp.com (Parag Patel) (05/15/91)

Submitted-by: Parag Patel <parag@hpsdeb.sde.hp.com>
Posting-number: Volume 19, Issue 65
Archive-name: dvi/part02

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is part 02 of dvi
# ============= stack.C ==============
if test -f 'stack.C' -a X"$1" != X"-c"; then
	echo 'x - skipping stack.C (File already exists)'
else
echo 'x - extracting stack.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'stack.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: stack.C,v 1.7 91/02/22 15:57:07 hmgr Exp $";
X
// manipulate a DVI stack
//
// by Parag Patel
X
#include "defs.h"
X
X
// a stack representation
struct stkrep
{
X    double h, v, w, x, y, z;
};
X
declare_array(Stack, stkrep);
implement_array(Stack, stkrep);
X
static int top = 0;			// top of the stack;
static Stack sp(50);			// the DVI stack itself
X
X
// save current DVI/TeX variable values
// 
void pushdvi()
{
X    sp[top].h = H;
X    sp[top].v = V;
X    sp[top].w = W;
X    sp[top].x = X;
X    sp[top].y = Y;
X    sp[top].z = Z;
X    top++;
}
X
X
// restore current DVI/TeX variable values
// 
void popdvi()
{
X    if (top <= 0)
X	quit("Stack underflow");
X    top--;
X    H = sp[top].h;
X    V = sp[top].v;
X    W = sp[top].w;
X    X = sp[top].x;
X    Y = sp[top].y;
X    Z = sp[top].z;
}
X
X
// clear the stack and dvi vars
// 
void cleardvi()
{
X    H = V = W = X = Y = Z = 0.0;
X    top = 0;
}
SHAR_EOF
chmod 0444 stack.C ||
echo 'restore of stack.C failed'
Wc_c="`wc -c < 'stack.C'`"
test 970 -eq "$Wc_c" ||
	echo 'stack.C: original size 970, current size' "$Wc_c"
fi
# ============= dirs.C ==============
if test -f 'dirs.C' -a X"$1" != X"-c"; then
	echo 'x - skipping dirs.C (File already exists)'
else
echo 'x - extracting dirs.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dirs.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: dirs.C,v 1.10 91/02/22 15:57:16 hmgr Exp $";
X
// read font directory names into memory for fast traversal
//
// by Parag Patel
X
#include "defs.h"
#include "dirs.h"
#ifdef	__ZTC__
#include <dos.h>
#define	d_name	name
#else
#ifdef	BSD
#include <sys/dir.h>
#else
#include <ndir.h>
#endif
#endif
X
X
implement_array(Dirlist, Dirent);
implement_array(Pathlist, Pathent);
X
X
Pathlist pathlist;
X
X
Dirent::Dirent()
{
X    name = NULL;
X    val = 0;
}
X
Pathent::Pathent()
{
X    path = NULL;
}
X
Pathent &Pathent::operator=(Pathent &x)
{
X    path = x.path;
X    dirs = x.dirs;
X    return *this;
}
X
X
void setupdirs(char *path)
{
X    path = strdup(path);
X    char *save = path;
X
X    pathlist.reset();
X
X    debug(3, "Setup dirpaths = %s", path);
X    while (path != NULL && *path != '\0')
X    {
X	char *dirpath = path;
X	while (*path != PATHSEP && *path != '\0')
X	    path++;
X	if (*path != '\0')
X	    *path++ = '\0';
X	debug(4, "  DIR = %s", dirpath);
X
#ifndef	__ZTC__
X	DIR *dir = opendir(dirpath);
X	if (dir == NULL)
X	{
X	    warn("Cannot opendir directory \"%s\" for scanning", dirpath);
X	    continue;
X	}
#endif
X
X	Pathent & path = pathlist[pathlist.size()];
X	path.path = strdup(dirpath);
X	path.dirs.reset();
X
#ifdef	__ZTC__
X	char dos_dirpath[64];
X	(void)strcpy(dos_dirpath, dirpath);
X	(void)strcat(dos_dirpath, "/*.*");
X	for (FIND *ent = findfirst(dos_dirpath, FA_DIREC); ent != NULL;
X		ent = findnext())
#else
X	for (direct * ent = readdir(dir); ent != NULL; ent = readdir(dir))
#endif
X	{
X	    char *s = strchr(ent->d_name, '.');
X	    int magent;
X
X	    if (s != NULL)
X	    {
X		// if there is a dot in the name, it may be the newer
X		// magnification value naming conventions: "1.000"
X		*s = '\0';
X		magent = atoi(ent->d_name) * 1000 + atoi(s + 1);
X		*s = '.';
X	    }
X	    else
X		// older resolution naming convention: "300", "1000"
X		magent = atoi(ent->d_name);
X
X	    if (magent <= 0)
X		continue;
X
X	    Dirent & d = path.dirs[path.dirs.size()];
X	    d.name = strdup(ent->d_name);
X	    d.val = magent;
X	    debug(5, "    name=%s  val=%d", d.name, d.val);
X	}
X
#ifndef	__ZTC__
X	closedir(dir);
#endif
X    }
X    strfree(save);
}
SHAR_EOF
chmod 0444 dirs.C ||
echo 'restore of dirs.C failed'
Wc_c="`wc -c < 'dirs.C'`"
test 2199 -eq "$Wc_c" ||
	echo 'dirs.C: original size 2199, current size' "$Wc_c"
fi
# ============= dvi.C ==============
if test -f 'dvi.C' -a X"$1" != X"-c"; then
	echo 'x - skipping dvi.C (File already exists)'
else
echo 'x - extracting dvi.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dvi.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: dvi.C,v 1.24 91/02/22 15:57:33 hmgr Exp $";
X
// dvi scanning routines
//
// by Parag Patel
X
#include "defs.h"
X
X
static long mag = 1000;
static double magval = 1.0;
X
X
// print the specified page from the file "fp" at the specified
// magnification - this is called for any page in the DVI file provided
// that the "fp" has been set to the start of a page in the DVI file -
// thus pages may be printed in any random order
// 
static void dopage(FILE *fp, long page)
{
X    // clear and initialize the global state for a new page
X    cleardvi();
X    clearfonts();
X
X    // if this is not the first page, then eject the previous
X    // page from the printer
X    // 
X    static first = TRUE;
X    dev_newpage((page & 0x01) || page == 0, first);
X    first = FALSE;
X
X    // now go through the DVI file executing opcodes...
X    register int opcode;
X    while ((opcode = (int)getuval(1, fp)) != EOP)
X    {
X	debug(7, "    H=%f V=%f  W=%f X=%f  Y=%f Z=%f", H, V, W, X, Y, Z);
X	debug(6, "opcode = %d", opcode);
X
X	if (opcode >= SET0 && opcode <= SET127)
X	{
X	    // typeset (print) a character
X	    typeset(opcode, TRUE, magval);
X	    continue;
X	}
X	if (opcode >= FONT0 && opcode <= FONT63)
X	{
X	    // switch to a new font
X	    newfont(opcode - FONT0);
X	    continue;
X	}
X	switch (opcode)
X	{
X	    // print (typeset) a character and move the cursor
X	Case SET1: 
X	    typeset(getuval(1, fp), TRUE, magval);
X	Case SET2: 
X	    typeset(getuval(2, fp), TRUE, magval);
X	Case SET3: 
X	    typeset(getuval(3, fp), TRUE, magval);
X	Case SET4: 
X	    typeset(getsval(4, fp), TRUE, magval);
X
X	    // just typeset a character
X	Case PUT1: 
X	    typeset(getuval(1, fp), FALSE, magval);
X	Case PUT2: 
X	    typeset(getuval(2, fp), FALSE, magval);
X	Case PUT3: 
X	    typeset(getuval(3, fp), FALSE, magval);
X	Case PUT4: 
X	    typeset(getsval(4, fp), FALSE, magval);
X
X	    // print a rule
X	Case SETRULE: 
X	    typerule(fp, TRUE, magval);
X	Case PUTRULE: 
X	    typerule(fp, FALSE, magval);
X
X	Case NOOP: 
X
X	Case PUSH: 
X	    pushdvi();
X	Case POP: 
X	    popdvi();
X
X	    // horizontal moves (negative == move left)
X	Case RIGHT1: 
X	    moveright(Getsval(1, fp) * magval);
X	Case RIGHT2: 
X	    moveright(Getsval(2, fp) * magval);
X	Case RIGHT3: 
X	    moveright(Getsval(3, fp) * magval);
X	Case RIGHT4: 
X	    moveright(Getsval(4, fp) * magval);
X
X	    // move horizontal based on the var W
X	Case W0: 
X	    moveright(W);
X	Case W1: 
X	    moveright(W = Getsval(1, fp) * magval);
X	Case W2: 
X	    moveright(W = Getsval(2, fp) * magval);
X	Case W3: 
X	    moveright(W = Getsval(3, fp) * magval);
X	Case W4: 
X	    moveright(W = Getsval(4, fp) * magval);
X
X	    // move horizontal based on the var X
X	Case X0: 
X	    moveright(X);
X	Case X1: 
X	    moveright(X = Getsval(1, fp) * magval);
X	Case X2: 
X	    moveright(X = Getsval(2, fp) * magval);
X	Case X3: 
X	    moveright(X = Getsval(3, fp) * magval);
X	Case X4: 
X	    moveright(X = Getsval(4, fp) * magval);
X
X	    // move vertically (negative == towards top of page)
X	Case DOWN1: 
X	    movedown(Getsval(1, fp) * magval);
X	Case DOWN2: 
X	    movedown(Getsval(2, fp) * magval);
X	Case DOWN3: 
X	    movedown(Getsval(3, fp) * magval);
X	Case DOWN4: 
X	    movedown(Getsval(4, fp) * magval);
X
X	    // move vertically based on the var Y
X	Case Y0: 
X	    movedown(Y);
X	Case Y1: 
X	    movedown(Y = Getsval(1, fp) * magval);
X	Case Y2: 
X	    movedown(Y = Getsval(2, fp) * magval);
X	Case Y3: 
X	    movedown(Y = Getsval(3, fp) * magval);
X	Case Y4: 
X	    movedown(Y = Getsval(4, fp) * magval);
X
X	    // move vertically based on the var Z
X	Case Z0: 
X	    movedown(Z);
X	Case Z1: 
X	    movedown(Z = Getsval(1, fp) * magval);
X	Case Z2: 
X	    movedown(Z = Getsval(2, fp) * magval);
X	Case Z3: 
X	    movedown(Z = Getsval(3, fp) * magval);
X	Case Z4: 
X	    movedown(Z = Getsval(4, fp) * magval);
X
X	    // change current font
X	Case FNT1: 
X	    newfont(getuval(1, fp));
X	Case FNT2: 
X	    newfont(getuval(2, fp));
X	Case FNT3: 
X	    newfont(getuval(3, fp));
X	Case FNT4: 
X	    newfont(getsval(4, fp));
X
X	    // special - used definable
X	Case XXX1: 
X	    special(fp, getuval(1, fp));
X	Case XXX2: 
X	    special(fp, getuval(2, fp));
X	Case XXX3: 
X	    special(fp, getuval(3, fp));
X	Case XXX4: 
X	    special(fp, getsval(4, fp));
X
X	    // define a font - note that this will be a redefinition
X	Case FNTDEF1: 
X	    definefont(fp, getuval(1, fp), mag);
X	Case FNTDEF2: 
X	    definefont(fp, getuval(2, fp), mag);
X	Case FNTDEF3: 
X	    definefont(fp, getuval(3, fp), mag);
X	Case FNTDEF4: 
X	    definefont(fp, getsval(4, fp), mag);
X
X	Default: 
X	    quit("Unexpected opcode %d", opcode);
X	}
X    }
}
X
X
// read the DVI file and create a list with pointers to every
// page in the file - also calculate a section number for each page
//
static void loadpages(FILE *fp, long pageloc, long numpages, 
X		long &sections, Pageinfo &pages)
{
X    long loc = pageloc;
X    long lastpage = MAXLONG;
X    long i;
X
X    sections = 1;
X
X    // search backwards through the DVI file
X    for (i = numpages - 1; loc >= 0 && i >= 0; i--)
X    {
X	(void)fseek(fp, loc, SEEK_SET);
X	if (getuval(1, fp) != BOP)
X	    quit("Expected BOP");
X
X	// get the values of the internal TeX variables
X	// - the first is a page number (c[0])
X	long c[10];
X	for (int j = 0; j < 10; j++)
X	    c[j] = getsval(4, fp);
X	loc = getsval(4, fp);	// location of previous page in file
X
X	// new section if we see a page larger than the previous one
X	if (c[0] >= lastpage)
X	    sections++;
X	lastpage = c[0];
X
X	// save the "real" page number and the offset in the file
X	pages[i].page = c[0];
X	pages[i].section = sections;
X	pages[i].loc = ftell(fp);
X    }
X
X    // now change the section numbers to be in the proper order
X    for (i = 0; i < numpages; i++)
X	pages[i].section = sections - pages[i].section + 1;
}
X
X
// dump only the specified pages from the DVI file
//
static void dumppages(FILE *fp, Pagespec &pages, 
X			Pageinfo &allpages, long sections)
{
X    long numpages = allpages.size();
X
X    for (int i = 0; i < pages.size(); i++)
X    {
X	// get the page spec entry in normal or reverse order
X	long pent = reverse ? pages.size() - i - 1 : i;
X
X	// if the end is not specified, take the current maximum
X	long endsect = pages[pent].endsection == MAXLONG ? sections
X		: pages[pent].endsection;
X	long endpage = pages[pent].endpage == MAXLONG ? numpages
X		: pages[pent].endpage;
X
X	// print only the last section? make sure we go through loop once
X	long startsect = pages[pent].section;
X	if (startsect == MAXLONG)
X	    startsect = endsect;
X
X	for (long s = startsect; s <= endsect; s++)
X	{
X	    long snum = reverse ? endsect - s + startsect : s;
X	    for (long p = pages[pent].page; p <= endpage; p++)
X	    {
X		long pnum = reverse ? endpage - p + pages[pent].page : p;
X
X		// look for this page/section in the list of allpages
X		// - if section == MAXLONG - 1, then use the last section
X		long ent;
X		for (ent = numpages - 1; ent >= 0; ent--)
X		    if (allpages[ent].page == pnum
X			    && allpages[ent].section == snum)
X			break;
X
X		if (ent < 0)
X		{
X		    // print an error only if the user explicitly specified
X		    // a page that does not exist - do not print an error
X		    // if we are going through to the end
X		    if (pages[pent].section == MAXLONG
X			    || pages[pent].endsection <= pages[pent].section)
X			if (pages[pent].endpage == MAXLONG
X				|| pages[pent].endpage < pages[pent].page)
X			    if (pages[pent].section <= sections)
X				continue;
X
X		    error("No page/section %ld.%ld in DVI file", pnum, snum);
X		    continue;
X		}
X
X		// seek to that page and spit it out
X		(void)fseek(fp, allpages[ent].loc, SEEK_SET);
X		mesg(" [%ld.%ld", allpages[ent].page, allpages[ent].section);
X		debug(1, "Page: %ld.%ld (%ld)", allpages[ent].page,
X			allpages[ent].section, ent + 1);
X		dopage(fp, allpages[ent].page);
X		mesg("]");
X	    }
X	}
X    }
}
X
X
// dump all the pages in the DVI file in either forward or reverse order
//
static void dumpall(FILE *fp, Pageinfo &allpages)
{
X    long numpages = allpages.size();
X    for (int i = 0; i < numpages; i++)
X    {
X	long p = reverse ? numpages - i - 1 : i;
X	(void)fseek(fp, allpages[p].loc, SEEK_SET);
X	mesg(" [%ld.%ld", allpages[p].page, allpages[p].section);
X	debug(1, "Page: %ld.%ld (%ld)", allpages[p].page,
X		allpages[p].section, p + 1);
X	dopage(fp, allpages[p].page);
X	mesg("]");
X    }
}
X
X
// process the DVI file "fp" - verify the file, setup the fonts, then
// print pages in the file either backwards or forwards - print only
// that "pages" specified, or everything if none were specified
// 
void dodvi(FILE *fp, Pagespec &pages)
{
X    // verify the preamble and id value
X    if (getuval(1, fp) != PRE)
X	quit("Not a DVI file");
X    long version = getuval(1, fp);
X    if (version != ID)
X    {
X	debug(7, "DVI file version = %ld instead of %d", version, ID);
X	quit("Incorrect DVI file version");
X    }
X
X    // if we cannot seek, then we cannot do anything
X    if (fseek(fp, 0, SEEK_END) != 0)
X	quit("Cannot seek to end of DVI file");
X
X    long floc = ftell(fp);
X    debug(2, "DVI file len = %ld", floc);
X
X    // now look for the real end of the DVI file (after the POSTPOST)
X    register int opcode = FILLER;
X    while (opcode == FILLER && floc > 0)
X    {
X	(void)fseek(fp, --floc, SEEK_SET);
X	opcode = (int)getuval(1, fp);
X    }
X    if (opcode != ID)
X    {
X	debug(7, "DVI file version = %d instead of %d", opcode, ID);
X	quit("Incorrect DVI file version");
X    }
X
X    // get the pointer to the start of the postamble
X    (void)fseek(fp, floc -= 4, SEEK_SET);
X    long postloc = getuval(4, fp);
X    (void)fseek(fp, postloc, SEEK_SET);
X
X    // verify that we are where we think we are
X    if (getuval(1, fp) != POST)
X	quit("Expected POST");
X
X    // pointer to the last page in the DVI file
X    long pageloc = getsval(4, fp);
X
X    // read in the other values in the postamble
X    double numerator = Getsval(4, fp);
X    if (numerator <= 0)
X	quit("Illegal numerator");
X
X    double denominator = Getsval(4, fp);
X    if (denominator <= 0)
X	quit("Illegal denominator");
X
X    mag = getsval(4, fp);
X    if (usermag > 0)
X	mag = usermag;
X    magval = (double)mag;
X    if (mag <= 0)
X	quit("Illegal magnification");
X    magval *= numerator / denominator / 25400000.0 * 473628672.0 / 1000.0;
X    debug(3, "num=%f denom=%f mag=%ld/%f", numerator, denominator,
X	    mag, magval);
X
X    // worst-case page sizes - we ignore these for now
X    long tallest = getsval(4, fp);
X    long widest = getsval(4, fp);
X    long maxdepth = getsval(2, fp);
X    long numpages = getuval(2, fp);
X    debug(3, "tallest=%ld widest=%ld maxdepth=%ld", tallest, widest, maxdepth);
X    debug(1, "numpages=%ld", numpages);
X
X    // scan the opcodes in the rest of the postamble - only font
X    // definitions and specials are allowed here
X    while ((opcode = (int)getuval(1, fp)) != POSTPOST)
X	switch (opcode)
X	{
X	Case FNTDEF1: 
X	    definefont(fp, getuval(1, fp), mag);
X	Case FNTDEF2: 
X	    definefont(fp, getuval(2, fp), mag);
X	Case FNTDEF3: 
X	    definefont(fp, getuval(3, fp), mag);
X	Case FNTDEF4: 
X	    definefont(fp, getsval(4, fp), mag);
X
X	Case XXX1: 
X	    special(fp, getuval(1, fp));
X	Case XXX2: 
X	    special(fp, getuval(2, fp));
X	Case XXX3: 
X	    special(fp, getuval(3, fp));
X	Case XXX4: 
X	    special(fp, getsval(4, fp));
X
X	Case NOOP: 
X
X	Default: 
X	    quit("Illegal opcode = %d in font definitions", opcode);
X	}
X
X    // initialize the page pointer table
X    Pageinfo allpages(numpages);
X    long sections;
X    loadpages(fp, pageloc, numpages, sections, allpages);
X
X    // process the pages as specified
X    if (pages.size() < 1)
X	dumpall(fp, allpages);
X    else
X	dumppages(fp, pages, allpages, sections);
X
X    mesg(NULL);
}
SHAR_EOF
chmod 0444 dvi.C ||
echo 'restore of dvi.C failed'
Wc_c="`wc -c < 'dvi.C'`"
test 11617 -eq "$Wc_c" ||
	echo 'dvi.C: original size 11617, current size' "$Wc_c"
fi
# ============= font.C ==============
if test -f 'font.C' -a X"$1" != X"-c"; then
	echo 'x - skipping font.C (File already exists)'
else
echo 'x - extracting font.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'font.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: font.C,v 1.42 91/04/02 17:59:01 hmgr Exp $";
X
// font manipulation and basic typesetting functions
//
// by Parag Patel
X
#include "defs.h"
X
X
// local globals
static int fontsonpage;			// # of fonts on current page
static long devv;			// current device Vertical coord
static long devh;			// Horizontal coord (both in pixels)
static font *devfont;			// current font in device
X
X
font::font()
{
X    chr = new fontchar[MAXCHARS];
X    // this initialization is redundant, but safer
X    fp = NULL;
X    use = 0;
X    path = basename = NULL;
X    onpage = toomany = downloaded = setup = NULL;
}
X
font::~font()
{
X    if (fp != NULL)
X	fclose(fp);
X    delete[MAXCHARS] chr;
}
X
// return the fontlist location for the font number specified
// - returns one more than the current size if there is no such font
static long getfontloc(long fnum)
{
X    for (long f = 0; f < fontlist.size(); f++)
X	if (fontlist[f] != NULL && fontlist[f]->num == fnum)
X	    break;
X    return f;
}
X
// clear font info for a new page - there are currently no fonts on
// this page - reset the device coordinates to "unknown" - there is no
// current font selected, nor a current font in the device
// 
void clearfonts()
{
X    for (int i = 0; i < fontlist.size(); i++)
X	if (fontlist[i] != NULL)
X	    fontlist[i]->toomany = fontlist[i]->onpage = FALSE;
X    fontsonpage = 0;
X    devh = devv = -MAXLONG;
X    currfont = devfont = NULL;
}
X
X
static void setupbits(font &f)
{
X    static long minm = MAXLONG;
X    static long maxm = -MAXLONG;
X    static long minn = MAXLONG;
X    static long maxn = -MAXLONG;
X
X    if (f.minm >= minm && f.maxm <= maxm
X	    && f.minn >= minn && f.maxn <= maxn)
X	return;
X
X    if (fontbits != NULL)
X    {
X	for (long i = maxn - minn; i >= 0; i--)
X	    delete fontbits[i];
X	delete fontbits;
X    }
X
X    if (f.maxm > maxm)
X	maxm = f.maxm + 10;
X    if (f.minm < minm)
X	minm = f.minm - 10;
X    if (f.maxn > maxn)
X	maxn = f.maxn + 10;
X    if (f.minn < minn)
X	minn = f.minn - 10;
X
X    debug(4, "newbits maxm=%ld minm=%ld  maxn=%ld minn=%ld",
X	    maxm, minm, maxn, minn);
X
X    // allocate the memory that we will need
X    fontbits = new Bitvec *[maxn - minn + 2];
X    for (long i = maxn - minn; i >= 0; i--)
X	fontbits[i] = new Bitvec(maxm - minm + 2);
}
X
X
// define a font "fnum" from the file "fp" at the magnification "mag"
// - "fp" is a pointer into a DVI file right after the FNTDEF byte
// - this function will be called twice for each font - once in the
// postamble and once just before it is used (if it is used)
// 
void definefont(FILE *fp, long fnum, long mag)
{
X    // find the font with this number in our fontlist
X    long floc = getfontloc(fnum);
X
X    // if already loaded, then we are not in the postamble anymore
X    boolean loaded = (fontlist[floc] != NULL);
X
X    debug(2, "fontnum = %ld(%ld)%s", fnum, floc, loaded ? " loaded" : "");
X
X    // allocate space for this font, if necessary
X    if (!loaded)
X	fontlist[floc] = new font;
X
X    font &f = *fontlist[floc].ptr;
X
X    if (loaded)
X    {
X	// ignore the values in the file - we already have them
X	(void)getsval(4, fp);
X	(void)getsval(4, fp);
X	(void)getsval(4, fp);
X	skipbytes(getuval(1, fp) + getuval(1, fp), fp);
X	return;
X    }
X
X    // initialize the font and start reading the values out of the file
X    f.fp = NULL;
X    f.use = 0;
X    f.num = fnum;
X    f.checksum = getsval(4, fp);
X    f.scaledsize = getsval(4, fp);
X    f.designsize = getsval(4, fp);
X    debug(3, "checksum=%ld scaled=%ld design=%ld",
X	    f.checksum, f.scaledsize, f.designsize);
X
X    f.mag = (long)((double)mag * (double)f.scaledsize /
X	                                (double)f.designsize + 0.5);
X
X    // get the name of the font file - if the library name length
X    // (liblen) is 0, then use the default library directory instead
X
X    int liblen = (int)getuval(1, fp);
X    int namelen = (int)getuval(1, fp);
X
X    f.path = NULL;
X    f.basename = new char[namelen + 1];
X    int i;
X
X    // read the optional font directory name from the DVI file
X    if (liblen != 0)
X    {
X	// just use what the DVI file has
X	char *s = f.path = new char[liblen + 1];
X	for (i = 0; i < liblen; i++)
X	    *s++ = (unsigned char)getuval(1, fp);
X	*s = '\0';
X    }
X
X    // get the name of the font file to load
X    char *s = f.basename;
X    for (i = 0; i < namelen; i++)
X	*s++ = (unsigned char)getuval(1, fp);
X    *s = '\0';
X    debug(4, "libname=%s  basename=%s", 
X	    f.path == NULL ? "" : f.path, f.basename);
X
X    // just defined - not yet downloaded - not setup
X    f.setup = f.downloaded = f.onpage = f.toomany = FALSE;
X
X    // no characters are downloaded either
X    for (i = 0; i < MAXCHARS; i++)
X	f.chr[i].downloaded = f.chr[i].charbig = FALSE;
}
X
X
// change to a new font "fnum" - this is the FNT DVI command
// 
void newfont(long fnum)
{
X    long f = getfontloc(fnum);
X    debug(5, "Change to font %ld(%ld)", fnum, f);
X
X    currfont = fontlist[f];
X    if (currfont == NULL)
X	quit("Font %ld(%ld) has not been defined yet", fnum, f);
}
X
X
// move the device's cursor to the current H and V values
// 
void makecurrent(boolean force)
{
X    long h = dev_sp2dev(H);
X    long v = dev_sp2dev(V);
X
X    // use the most efficient move that we can
X    if (force || (devh != h && devv != v))
X	dev_movehv(h, v);
X    else if (devh != h)
X	dev_moveh(h);
X    else if (devv != v)
X	dev_movev(v);
X
X    debug(8, "lastH=%ld lastV=%ld  H=%ld V=%ld", devh, devv, h, v);
X
X    // update the current cursor values
X    devh = h;
X    devv = v;
}
X
X
static void dumpescape(const char *s, long len)
{
X    for (long i = 0; i < len; s++, i++)
X    {
X	if (*s != '\\' && *s != '`')
X	{
X	    putchar(*s);
X	    continue;
X	}
X	s++;
X	i++;
X	if (i >= len)
X	    break;
X
X	if (isdigit(*s))
X	{
X	    int chr = *s - '0';
X	    int base = 8;
X	    if (*s == '0')
X	    {
X		s++;
X		i++;
X		switch (isupper(*s) ? tolower(*s) : *s)
X		{
X		Case 'b': 
X		    base = 2;
X		Case 'o': 
X		    base = 8;
X		Case 'd': 
X		    base = 10;
X		Case 'x': 
X		    base = 16;
X		Default: 
X		    s--;
X		    i--;
X		}
X	    }
X	    s++;
X	    i++;
X	    for (; isxdigit(*s) && i < len; s++, i++)
X	    {
X		int d = (islower(*s) ? toupper(*s) : *s)
X			- (isdigit(*s) ? '0' : 'A' - 10);
X		if (d >= base)
X		    break;
X		chr = (chr * base) + d;
X	    }
X	    s--;
X	    i--;
X	    putchar(chr);
X	    continue;
X	}
X
X	switch (isupper(*s) ? tolower(*s) : *s)
X	{
X	Case 'b': 
X	    putchar('\b');
X	Case 'f': 
X	    putchar('\f');
X	Case 'n': 
X	    putchar('\n');
X	Case 'r': 
X	    putchar('\r');
X	Case 't': 
X	    putchar('\t');
X	Case 'v': 
X	    putchar('\v');
X	Case '\\': 
X	    putchar('\\');
X	Case '`': 
X	    putchar('`');
X	Case 'e': 
X	    putchar('\033');
X	Case '?': 
X	    putchar('\177');
X	Case '^': 
X	    s++;
X	    i++;
X	    putchar(*s == '?' ? '\177' : (*s & 037));
X	Default: 
X	    // putchar('\\');
X	    putchar(*s);
X	}
X    }
}
X
// DVI XXX special command - "num" is the number of bytes in the DVI
//      file that are for the special command
// take the special string as a file name of a raw device-specific
// image file and dump it straight to the device
// 
void special(FILE *fp, long num)
{
X    debug(2, "special length = %ld", num);
X
X    // allocate a buffer that is large enough for this length
X    static char *buf = NULL;
X    static long blen = 0;
X    if (num >= blen)
X    {
X	if (buf != NULL)
X	    delete buf;
X	buf = new char[blen = num + 1];
X    }
X
X    // read in the data from the DVI file into our buffer
X    char *s = buf;
X    for (long i = num; i-- > 0;)
X	*s++ = (unsigned char)getuval(1, fp);
X    *s = '\0';
X
X    // we use the first word (up to a space) for identifying different
X    // kinds of special files
X    enum Specials
X    {
X	S_NONE = 0,
X	S_RASTERFILE,
X	S_ESCAPESEQ,
X	S_RAWSTRING,
X    } type;
X
X    // handle special escape-sequences
X    if (strncmp("escapeseq ", buf, 10) == 0)
X    {
X	s = buf + 10;
X	num -= 10;
X	type = S_ESCAPESEQ;
X	debug(4, "Special == escapeseq = %s", s);
X	mesg(" <<escapeseq");
X	makecurrent();
X	dev_push();
X	dumpescape(s, num);
X	dev_pop();
X	mesg(">>");
X	return;
X    }
X
X    // handle special raw-strings
X    if (strncmp("rawstring ", buf, 10) == 0)
X    {
X	s = buf + 10;
X	num -= 10;
X	type = S_RAWSTRING;
X	debug(4, "Special == rawstring = %s", s);
X	mesg(" <<rawstring");
X	makecurrent();
X	dev_push();
X	while (num-- > 0)
X	    putchar(*s++);
X	dev_pop();
X	mesg(">>");
X	return;
X    }
X
X    // handle raw file dumps - usually graphics data
X    if (strncmp("rasterfile ", buf, 11) == 0)
X    {
X	s = buf + 11;
X	type = S_RASTERFILE;
X    }
X    else if (strncmp("pcl:", buf, 4) == 0)
X    {
X	s = buf + 4;
X	type = S_RASTERFILE;
X    }
X    else
X	s = buf;
X
X    debug(4, "Special == rasterfile = %s", s);
X    mesg(" <%s", s);
X
X    // now open this file and dump it to the device
X
X    FILE *sp = fopenp(dviinput, s, F_READ);
X    if (sp == NULL)
X	quit("Cannot open \"%s\" for reading", s);
X
X    // move the cursor, and save the current location in the device
X    makecurrent();
X    dev_push();
X
X    // dump the file
X    int l;
X    char dat[1024];
X    while ((l = fread(dat, sizeof *dat, sizeof dat, sp)) > 0)
X	fwrite(dat, sizeof *dat, l, stdout);
X
X    fclose(sp);
X
X    // restore the cursor
X    dev_pop();
X    mesg(">");
}
X
X
// change the current font that is downloaded to the device if we have
// to - this is completely demand-driven - a font is never even read into
// memory much less downloaded unless a character from it is actually
// going to be printed
// 
static void changefont()
{
X    // do we need to download this font?
X    if (!currfont->downloaded)
X    {
X	mesg(" (");
X
X	if (!currfont->setup)
X	{
X	    // load in the font info - we're really going to use it
X	    setupfont(*currfont);
X	    setupbits(*currfont);
X	    currfont->setup = TRUE;
X	}
X	mesg("%s", currfont->basename);
X
X	static int fontsdown = 0;
X	currfont->use++;
X
X	if (fontsdown < MAXLOADED)
X	    fontsdown++;
X	else
X	{
X	    // we need to delete a font from the device
X	    register int i;
X	    int fn = -1;
X	    long u = MAXLONG;
X
X	    // find the least recently used font
X	    for (i = 0; i < fontlist.size(); i++)
X		if (fontlist[i] != NULL && fontlist[i]->downloaded
X			&& !fontlist[i]->onpage && fontlist[i]->use < u)
X		{
X		    fn = i;
X		    u = fontlist[i]->use;
X		}
X
X	    // we need too many fonts - dump currfont in graphics mode
X	    if (fn < 0)
X	    {
X		currfont->toomany = TRUE;
X		mesg("#)");
X		return;
X	    }
X
X	    // mark it as not downloaded, then delete it
X	    font &f = *fontlist[fn].ptr;
X	    for (i = 0; i < MAXCHARS; i++)
X		f.chr[i].downloaded = FALSE;
X	    f.toomany = f.downloaded = FALSE;
X	    dev_delfont(f);
X	}
X
X	// downloaded this font
X	dev_newfont(*currfont);
X	currfont->downloaded = TRUE;
X
X	mesg(")");
X    }
X
X    // select this font in the device
X    dev_usefont(*currfont);
X    devfont = currfont;
X
X    // if this font is already being used on page, we are done
X    if (currfont->onpage || currfont->toomany)
X	return;
X    currfont->onpage = TRUE;
X
X    // are there too many fonts on this page?  if so, mark
X    // the font as toomany to print it in graphics mode
X    if (++fontsonpage > MAXONPAGE)
X    {
X	debug(3, "too many fonts on page - currfont marked");
X	currfont->toomany = TRUE;
X	mesg("#");
X    }
}
X
X
// typeset a character - this is the DVI SET or PUT command - if "move"
// is TRUE, then the cursor will be moved right by the width of the
// character
//
void typeset(long ch, boolean move, double magval)
{
X    fontchar & gch = currfont->chr[ch];
X
X    // change the font if we have to
X    if (currfont != devfont)
X	changefont();
X
X    // download the character if we have to - this also gets bigchars
X    if (!gch.downloaded || gch.charbig || currfont->toomany)
X	downchar((int)ch, currfont->toomany);
X
X    // print the character if it is not too big
X    if (!gch.charbig && !currfont->toomany)
X    {
X	makecurrent();
X	int len;
X	const char *dat = dev_char2dev((int)ch, len);
X	fwrite(dat, sizeof *dat, len, stdout);
X	devh += gch.dx >> 16;
X    }
X
X    if (move)
X	moveright(gch.width * magval);
}
X
X
// DVI SETRULE or PUTRULE command - again, if "move" is TRUE, then the
// cursor is moved to the right, else it isn't
// 
void typerule(FILE *fp, boolean move, double magval)
{
X    double a = Getsval(4, fp) * magval;
X    double b = Getsval(4, fp) * magval;
X
X    // let the device do the work (if it can)
X    if (a > 0 && b > 0)
X	dev_rule(a, b);
X
X    if (move)
X	moveright(b);
}
SHAR_EOF
chmod 0444 font.C ||
echo 'restore of font.C failed'
Wc_c="`wc -c < 'font.C'`"
test 12300 -eq "$Wc_c" ||
	echo 'font.C: original size 12300, current size' "$Wc_c"
fi
# ============= readfont.C ==============
if test -f 'readfont.C' -a X"$1" != X"-c"; then
	echo 'x - skipping readfont.C (File already exists)'
else
echo 'x - extracting readfont.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'readfont.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: readfont.C,v 1.21 91/04/02 17:50:26 hmgr Exp $";
X
// read font data from the METAFONT GF (generic font) files
//
// by Parag Patel
X
#include "defs.h"
X
X
// maximum number of file that we can keep open at one time - we try to
// keep as many font files open at one time as we can instead of
// reading the entire font into memory - this should gain a little
// speed if only a few characters are loaded from many different fonts
// (which is the normal case)
//
#ifdef _SC_OPEN_MAX
const long MAXFILES = sysconf(_SC_OPEN_MAX) - NUMOPENFILES;
#else
const long MAXFILES = _NFILE - NUMOPENFILES;
#endif
X
static int numfiles = 0;		// number of files currently open
X
X
// try looking for a particular type of font file - this is called 
// multiple times until we succeeding in finding a font we can use
//
static int tryfile(font &f, char *dir, char *mag, char *base, char *ext)
{
X    static char buf[MAXPATHLEN + 1];
X    sprintf(buf, "%s/%s/%s%s", dir, mag, base, ext);
X    char *path = buf;
X    FILE *fp = fopen(path, F_READ);
X    if (fp == NULL)
X	return FALSE;
X
X    // first byte is a preamble byte - same for GF and PK files
X    if (getuval(1, fp) != FPRE)
X    {
X	fclose(fp);
X	return FALSE;
X    }
X
X    // second byte is the font version ID field
X    f.type = (int)getuval(1, fp);
X    char *old = f.path;
X    f.path = path;
X    switch (f.type)
X    {
X    Case GFID:
X	debug(2, "GF font file %s", path);
X	setupgffont(f, fp);
X    Case PKID:
X	debug(2, "PK font file %s", path);
X	setuppkfont(f, fp);
X    Default:
X	fclose(fp);
X	f.path = old;
X	return FALSE;
X    }
X
X    delete old;
X    f.path = strdup(path);
X    old = f.basename;
X    sprintf(buf, "%s/%s%s", mag, base, ext);
X    f.basename = strdup(buf);
X    delete old;
X    debug(6, "font basename = %s", f.basename);
X
X    // keep only a MAXFILES number of font files open at one time
X    if (numfiles >= MAXFILES)
X    {
X	fclose(fp);
X	f.fp = NULL;
X    }
X    else
X    {
X	f.fp = fp;
X	numfiles++;
X    }
X
X    return TRUE;
}
X
X
// setup a new font in memory - the font is already initialized with
// the information from the DVI file - we now have to actually read the
// font file (GF or PK) to get the rest of the font's description
// 
void setupfont(font &f)
{
X    if (f.path != NULL)
X	if (tryfile(f, f.path, "", f.basename, ""))
X	    return;
X
X    // setup the font directory cache if we need to
X    if (pathlist.size() < 1)
X	setupdirs(fontpath);
X
X    for (int i = 0; i < pathlist.size(); i++)
X    {
X	Pathent & p = pathlist[i];
X
X	if (tryfile(f, p.path, pkmagdir(p.dirs, f.mag), f.basename, ".pk"))
X	    return;
X	if (tryfile(f, p.path, gfmagdir(p.dirs, f.mag), f.basename, ".gf"))
X	    return;
X	if (tryfile(f, p.path, gfmagdir(p.dirs, f.mag), f.basename, ""))
X	    return;
X	if (tryfile(f, p.path, pkmagdir(p.dirs, f.mag), f.basename, ""))
X	    return;
X    }
X    quit("Cannot find font file \"%s\" (at or near magnification %ld.%03ld) anywhere",
X	    f.basename, f.mag / 1000, f.mag % 1000);
}
X
X
// dump the current "fontbits" on screen in a human-readable
// format - this is really for debugging only
// 
void dumpbits(int ch)
{
X    register long i, j;
X    font & f = *currfont;
X    fontchar & g = f.chr[ch];
X
X    // print a row of 2-digit X coordinate values across the top
X    fprintf(stderr, "     ");
X    for (j = 0; j <= g.maxm - g.minm; j++)
X	fprintf(stderr, "%2ld", j + g.minm);
X    fprintf(stderr, "\n\n");
X
X    // print the Y coordinate on both sides of each row of pixels
X    for (i = g.maxn - g.minn; i >= 0; i--)
X    {
X	fprintf(stderr, "%3ld  ", i + g.minn);
X	for (j = 0; j <= g.maxm - g.minm; j++)
X	    fprintf(stderr, "%s", fontbits[i]->isin(j) ? "[]" : " .");
X	fprintf(stderr, "  %3ld\n", i + g.minn);
X    }
X
X    // and finally another row of X-coords across the bottom
X    fprintf(stderr, "\n     ");
X    for (j = 0; j <= g.maxm - g.minm; j++)
X	fprintf(stderr, "%2ld", j + g.minm);
X    fprintf(stderr, "\n");
}
X
X
// down load the specified character "ch" to the device - we read this
// character's GF paint commands to build a bitmap of the character in
// memory - then we download this image to the printer
// 
void downchar(int ch, boolean toomany)
{
X    font & f = *currfont;
X    fontchar & g = f.chr[ch];
X
X    // is this font file open?
X    if (f.fp == NULL)
X    {
X	// we need to close another font file if we already have the
X	// maximum number open
X	if (numfiles >= MAXFILES)
X	{
X	    register int i;
X	    int fn = -1;
X	    long u = MAXLONG;
X
X	    // look for the least-recently used font
X	    for (i = 0; i < fontlist.size(); i++)
X		if (fontlist[i] != NULL && fontlist[i]->fp != NULL
X			&& fontlist[i]->use < u)
X		{
X		    fn = i;
X		    u = fontlist[i]->use;
X		}
X	    if (fn < 0)
X		quit("Cannot open another font file - all fonts are in use");
X
X	    // close this font file
X	    fclose(fontlist[fn]->fp);
X	    fontlist[fn]->fp = NULL;
X	    numfiles--;
X	    mesg("@");
X	}
X
X	// open the new font file
X	f.fp = fopen(f.path, F_READ);
X	if (f.fp == NULL)
X	    quit("Cannot re-open font file \"%s\"", f.path);
X	numfiles++;
X    }
X
X    switch (f.type)
X    {
X    Case GFID:
X	getgfchar(f, g, ch);
X    Case PKID:
X	getpkchar(f, g, ch);
X    Default:
X	quit("?!BUG? Internal font type id changed");
X    }
X
X    // show what this character looks like
X    if (debuglevel > 12)
X	dumpbits(ch);
X
X    // now download this character to the printer...
X
X    long width = g.maxm - g.minm + 1;
X    long height = g.maxn - g.minn + 1;
X    if (toomany || g.minm < FHMIN || g.minm > FHMAX || width > FWIDTH
X	    || g.maxn < FVMIN || g.maxn > FVMAX || height > FHEIGHT)
X    {
X	// char is too big - send it down as a graphics
X	// image but do NOT mark it as downloaded
X	if (!toomany)
X	    g.charbig = TRUE;
X	dev_bigchar(f, g, ch);
X	return;
X    }
X
X    // this is the usual method...
X    g.downloaded = TRUE;
X    dev_downchar(f, g, ch);
}
SHAR_EOF
chmod 0444 readfont.C ||
echo 'restore of readfont.C failed'
Wc_c="`wc -c < 'readfont.C'`"
test 5861 -eq "$Wc_c" ||
	echo 'readfont.C: original size 5861, current size' "$Wc_c"
fi
# ============= gffont.C ==============
if test -f 'gffont.C' -a X"$1" != X"-c"; then
	echo 'x - skipping gffont.C (File already exists)'
else
echo 'x - extracting gffont.C (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'gffont.C' &&
// Copyright (c) 1991 by Parag Patel.  All Rights Reserved.
static const char rcsid[] = "$Header: gffont.C,v 1.20 91/02/22 15:58:04 hmgr Exp $";
X
// read font data from the METAFONT GF (generic font) files
//
// by Parag Patel
X
#include "defs.h"
X
X
// these are for "drawing" an image of a character in a font
const int WHITE = FALSE;
const int BLACK = TRUE;
X
X
// return a string containing the magnification sub-directory for the
// requested magnification
// 
char *gfmagdir(Dirlist &dirlist, long mag)
{
X    // look for the closest magnification value to the one desired
X    int ent = -1;
X    long diff = MAXLONG;
X
X    for (int i = 0; i < dirlist.size(); i++)
X    {
X	long d = mag - dirlist[i].val;
X	long newdiff = d < 0 ? -d : d;	// absolute value
X	if (newdiff >= diff)
X	    continue;
X	diff = newdiff;
X	ent = i;
X    }
X
X    // we should be within 1/32 (.03%) of the desired mag value
X    if (ent < 0 || diff > (mag >> 5))
X	return "";
X
X    // return the new value as a string
X    return dirlist[ent].name;
}
X
X
// setup a GF font file in memory
//
void setupgffont(font &f, FILE *fp)
{
X    // skip the comment
X    int len = (int)getuval(1, fp);
X    while (len-- > 0)
X	(void)getuval(1, fp);
X
X    // now we jump to the end to find the postamble
X    if (fseek(fp, 0, SEEK_END) != 0)
X	quit("Cannot seek to end of GF file %s", f.path);
X
X    register int op = GFILLER;
X    long floc = ftell(fp);
X
X    // skip the filler bytes at the end of the file
X    while (op == GFILLER && floc > 0)
X    {
X	(void)fseek(fp, --floc, SEEK_SET);
X	op = (int)getuval(1, fp);
X    }
X    if (op != GFID)
X	quit("Incorrect GF version for %s", f.path);
X
X    // now we get the file-pointer to the start of the postamble
X    (void)fseek(fp, floc -= 4, SEEK_SET);
X    long postloc = getuval(4, fp);
X
X    // verify that we have a POST byte
X    (void)fseek(fp, postloc, SEEK_SET);
X    if (getuval(1, fp) != FPOST)
X	quit("Expected FPOST");
X
X    long fsize = getuval(4, fp);// pointer to last EOC in file
X    debug(3, "GF last EOC=%ld", fsize);
X
X    // get and verify that the design size is ok - the GF file stores
X    // this value as a "fix_word" value while the DVI file keeps it as
X    // a "scaled-point" value - also note that the "basename" pointer
X    // is NULL only for the "dumpfont" main program
X
X    long dsize = getsval(4, fp);
X    debug(4, "GF designsize=%ld", dsize);
X    if (f.basename != NULL && dsize >> 4 != f.designsize)
X	if (dochecksum && dsize != 0 && f.designsize != 0)
X	    quit("Designsize in DVI and GF file %s does not match", f.path);
X	else
X	    warn("Designsize in DVI and GF file %s does not match", f.path);
X
X    // check the checksum (!)
X    long check = getuval(4, fp);
X    debug(5, "GF checksum=%ld", check);
X    if (f.basename != NULL && check != f.checksum)
X	if (dochecksum && check != 0 && f.checksum != 0)
X	    quit("Checksums in DVI and GF file %s do not match", f.path);
X	else
X	    warn("Checksums in DVI and GF file %s do not match", f.path);
X
X    // get the horizontal and vertical pixels per point values
X    f.hppp = getuval(4, fp);
X    f.vppp = getuval(4, fp);
X
X    // get the size ranges of the characters in this font
X    f.minm = getsval(4, fp);
X    f.maxm = getsval(4, fp);
X    f.minn = getsval(4, fp);
X    f.maxn = getsval(4, fp);
X
X    debug(3,"mag=%ld  hppp=%ld vppp=%ld  minm=%ld maxm=%ld  minn=%ld, maxn=%ld",
X	    f.mag, f.hppp, f.vppp, f.minm, f.maxm, f.minn, f.maxn);
X
X    // now initialize the info for each character in this font - note
X    // that there may only be CHARLOC or NOOPs in this part of the file
X    while ((op = (int)getuval(1, fp)) != FPOSTPOST)
X    {
X	if (op == FNOOP)
X	    continue;
X
X	// assume that the next byte is a character "residue" (id % 256)
X	int c = (int)getuval(1, fp);
X	if (c >= MAXCHARS)
X	    quit("Char %d too big in GF file %s", c, f.path);
X	fontchar & g = f.chr[c];
X
X	// get the values for delta-x, delta-y, width, and file-pointer
X	// for this character
X	switch (op)
X	{
X	Case CHARLOC:
X	    g.dx = getuval(4, fp);
X	    g.dy = getuval(4, fp);
X	    g.width = Getsval(4, fp);
X	    g.floc = getsval(4, fp);
X
X	Case CHARLOC0:
X	    g.dx = getuval(1, fp) << 16;
X	    g.dy = 0;
X	    g.width = Getsval(4, fp);
X	    g.floc = getsval(4, fp);
X
X	Default:
X	    quit("Illegal opcode %d in GF postamble", op);
X	}
X
X	g.width = g.width / double(16) * double(f.designsize) /
X	double(65536L) * double(f.mag) / 1000.0;
X    }
}
X
X
// load the specified character "ch" into the bitmap - we read this
// character's GF paint commands to paint this font
// 
void getgfchar(font &f, fontchar &g, int ch)
{
X    // go to the file where this character is defined
X    if (fseek(f.fp, g.floc, SEEK_SET) < 0)
X	quit("Cannot fseek to start of font in %s", f.path);
X
X    register int op = (int)getuval(1, f.fp);
X
X    // we had better get some flavor of BOC here...
X    switch (op)
X    {
X    Case BOC:
X	// verify the character (Just In Case)
X	if (ch != getsval(4, f.fp))
X	    quit("Character definition for %d does not match", ch);
X
X	(void)getuval(4, f.fp);	// pointer to next character % 256
X
X	// get the size (in pixels) of this character
X	g.minm = getsval(4, f.fp);
X	g.maxm = getsval(4, f.fp);
X	g.minn = getsval(4, f.fp);
X	g.maxn = getsval(4, f.fp);
X
X    Case BOC1:
X	if (ch != getuval(1, f.fp))
X	    quit("Character definition for %d does not match", ch);
X
X	// decode the size (in pixels) of this character
X	g.minm = getuval(1, f.fp);
X	g.maxm = getuval(1, f.fp);
X	g.minm = g.maxm - g.minm;
X
X	g.minn = getuval(1, f.fp);
X	g.maxn = getuval(1, f.fp);
X	g.minn = g.maxn - g.minn;
X
X    Default:
X	quit("Expected BOC* (not %d) in font file %s for char %d",
X		op, f.path, ch);
X    }
X
X    {
X	int len;
X	const char *x = dev_char2dev(ch, len);
X	debug(5, "char=%d(%s)  minm=%ld maxm=%ld  minn=%ld maxn=%ld",
X		ch, x, g.minm, g.maxm, g.minn, g.maxn);
X	debug(5, "    dx=%ld dy=%ld  dx/=%ld dy/=%ld  width=%f", g.dx, g.dy,
X		g.dx >> 16, g.dy >> 16, g.width);
X    }
X
X    // initialize the character painting variables
X    register long m = 0;
X    register long n = g.maxn - g.minn;
X    int p = WHITE;
X
X    long width = g.maxm - g.minm + 1;
X    long height = g.maxn - g.minn + 1;
X
X    // clear the global fontbits for the bitmap
X    register long d;
X    for (d = f.maxn - f.minn; d >= 0; d--)
X	fontbits[d]->clear();
X
X    // paint the fontbits to build the character
X    while ((op = (int)getuval(1, f.fp)) != EOC)
X    {
X	if (op > PAINT0 && op <= PAINT63)
X	{
X	    // paint with the current color, advance X
X	    if (p == BLACK)
X		while (op-- > 0)
X		    *fontbits[n] += m++;
X	    else
X		m += op;
X	    p = !p;
X	    continue;
X	}
X	if (op >= NEWROW0 && op <= NEWROW164)
X	{
X	    // advance Y, paint to black
X	    n--;
X	    m = op - NEWROW0;
X	    p = BLACK;
X	    continue;
X	}
X
X	switch (op)
X	{
X	    // paint with current color, advange X
X	Case PAINT0:
X	    p = !p;
X	Case PAINT1:
X	    d = getuval(1, f.fp);
X	    if (p == BLACK)
X		while (d-- > 0)
X		    *fontbits[n] += m++;
X	    else
X		m += d;
X	    p = !p;
X	Case PAINT2:
X	    d = getuval(2, f.fp);
X	    if (p == BLACK)
X		while (d-- > 0)
X		    *fontbits[n] += m++;
X	    else
X		m += d;
X	    p = !p;
X	Case PAINT3:
X	    d = getuval(3, f.fp);
X	    if (p == BLACK)
X		while (d-- > 0)
X		    *fontbits[n] += m++;
X	    else
X		m += d;
X	    p = !p;
X
X	    // advance Y, paint to white
X	Case SKIP0:
X	    n--;
X	    m = 0;
X	    p = WHITE;
X	Case SKIP1:
X	    n -= getuval(1, f.fp) + 1;
X	    m = 0;
X	    p = WHITE;
X	Case SKIP2:
X	    n -= getuval(2, f.fp) + 1;
X	    m = 0;
X	    p = WHITE;
X	Case SKIP3:
X	    n -= getuval(3, f.fp) + 1;
X	    m = 0;
X	    p = WHITE;
X
X	    // special opcodes - just ignore for now
X	Case FXXX1:
X	    skipbytes(getuval(1, f.fp), f.fp);
X	Case FXXX2:
X	    skipbytes(getuval(2, f.fp), f.fp);
X	Case FXXX3:
X	    skipbytes(getuval(3, f.fp), f.fp);
X	Case FXXX4:
X	    skipbytes(getuval(4, f.fp), f.fp);
X
X	    // special numeric opcode - also ignored
X	Case YYY:
X	    (void)getuval(4, f.fp);
X
X	Case FNOOP:
X
X	Default:
X	    quit("Illegal GF opcode %ld in file %f", d, f.path);
X	}
X    }
}
SHAR_EOF
chmod 0444 gffont.C ||
echo 'restore of gffont.C failed'
Wc_c="`wc -c < 'gffont.C'`"
test 7918 -eq "$Wc_c" ||
	echo 'gffont.C: original size 7918, current size' "$Wc_c"
fi
true || echo 'restore of pkfont.C failed'
echo End of part 2, continue with part 3
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.