/* Output from p2c, the Pascal-to-C translator */
/* From input file "textyl.p" */

#include	"defs.h"
#include	"globals.h"
#include	"tables.h"

extern int	abs PP((int));

/*----------------------------------------------------------
        TeXtyl  line-drawing interface for TeX.
              copyright (c) 1987 John S. Renner
                All rights reserved.

ABSTRACT: TeXtyl reads in a DVI file, and processes 'specials'
        that refer to graphics capabilities that it knows about,
        like line, spline, ThickThinSpline, and musical
        beams and slurs. TeXtyl then outputs a new DVI file,
        with the special-macros expanded and converted to
        DVI-commands for character setting.

DEPENDENCIES:  Few assumptions about Pascal are assumed. All
        identifiers are unique to eight characters. There are
        notes to indicate system-dependencies.
        I assume the standard definition of "READ(fil, x)" to be
        equivalent to "x := fil^; GET(fil)" , and
        "WRITE(fil, x)" == "fil^ := x; PUT(fil)" .
        Arrays are passed by reference (VAR) for efficiency.
        See also the "sysdependent"  procedure;
        Problem areas, or areas for expansion are marked with ###

-------------------------------------------------------------*/
/*-Revision History:
    Jun. 1986  v1.0   Basic version of TeXtyl
    Dec. 1986  v1.1   Added adaptive subdivision for spline
                        interpolation. Added Cardinal basis.
    Mar. 1987  v1.2   Added F and W flags for beginfigure
                        to allow required and/or actual dimensions
                        to interface with files output by the
                        DP drawing program from Carnegie-Mellon
                        also various fixes
    Apr. 1987  v1.3   Added linestyles (dotted, dashed, dotdashed)
    Aug. 1991         Translated to C with p2c, then hacked a bit. (Ken Yap)
*/

/* ===========================TYPES============================= */

/* ---- PUBLIC types ---- */

typedef int     MusIndex;
typedef int     SplineSegments[MAXSPLINESEGS][2];

/* ----- Private Types ---- */

typedef struct FontInfRec
{
	int32           Cht, Cdp, Cwd;
	double          Angle;
}               FontInfRec;

/* vector font info */

typedef struct VectFontInfRec
{
	VectKind        vkind;
	int32           DesSize, PenSize;
	VThickness      psize;
	int32           MaxVectLen;
	charstring      FontName;
	int32           Cksum;
	int		Isdefined;
	int32           DVIFontNum;
	FontInfRec      FontInfo[128];
}               VectFontInfRec;

/* music font info */

typedef struct MusFontInfRec
{
	int32           DesSize, Family;
	charstring      FontName;
	int32           Cksum;
	int		Isdefined;
	int32           DVIFontNum, Staffsize, ghu, gvu;
	FontInfRec      FontInfo[128];
}               MusFontInfRec;

/*
 * representation of list of fonts that have to be defined
 * before we output the BOP of the page we just scanned
 */

typedef struct ToBeDefinedRec
{
	char            which;
	int32           indx;
}               ToBeDefinedRec;

/* ==============================VARS============================ */

/* ----- Private vars */
static int32    ourxpos;	/* internal x-position on page */
static int32    ourypos;	/* internal y-position on page */

static VectFontInfRec *VFontTable[SizVFontTable];
static MusFontInfRec *MFontTable[SizMFontTable];
/* the font tables, and the number of fonts defined in each */
static int32    VFontsDefd, MFontsDefd, LFontsDefd;

static int	GDVIFN = 301;	/* dvi font number currently in use */

/* table of fonts yet  To-Be-Defined */
static ToBeDefinedRec TBD[MAXTBDs];
static int32    FTBDs;		/* number of fonts to be defined for current page */

static Item    *pageitems;
/*
 * list of primitives in current use in the current figure on the current page
 */

static int32    specstart = 0;
/*
 * the place in the DVI buffer where the start of the special begins.
 * this is so that we know how far to back up and over-write
 * the old \special macro string with the cmds of our 'macro-expansion'
 */

static int32    multifigure;	/* depth of definition recursion of figures */
static int	skiptsclamp;	/* DEBUG: should we skip post-clamping ties */
static int	ErrorOccurred;	/* global flag in case some error happened */


/* ----- End private vars */

static short	tfm[TFMSIZE + 101];

static char     s = 0;
struct stackrec
{
	int32           sh, sv, sw, sx, sy, sz;
}               stack[STACKSIZE + 1];

static int32    inwidth[256];
static int32    tfmchecksum;
static double   conv, trueconv;
static int32    numerator, denominator;
static double   mag, magfactor;
static int32    maxv, maxh, maxs, maxpages = 10000, totalpages;
static double   resolution = 300.0;
static int	inpostamble;
static int32    newbackptr = -1, oldbackptr = -1, p, k;

/* forward declarations */
static void definebeams PP((MusFontInfRec ** M));
static void definevectors PP((VectFontInfRec ** Vec));

static jmp_buf  _JL666;

static int 
opentfmfile(tfmname)
	charstring      tfmname;
{
	charstring      thefilename;
	char           *path, *p, *q, *getenv PP((char *));

	if ((path = getenv("TEXFONTS")) == 0)
		path = DEFTEXFONTS;
	if (tfmfile != NULL)
	{
		fclose(tfmfile);
		tfmfile = NULL;
	}
	for (p = path; p != 0 && tfmfile == NULL; p = q ? q + 1 : 0)
	{
		if ((q = strchr(p, ':')) == 0)
			strcpy(thefilename, p);
		else
			strncpy(thefilename, p, q - p);
		strcat(thefilename, "/");
		if (strcmp(thefilename, "./") == 0)
			thefilename[0] = '\0';
		strcat(thefilename, tfmname);
		tfmfile = fopen(thefilename, "r");
	}
	return (tfmfile != NULL);
}

void 
jumpout()
{
	longjmp(_JL666, 1);	/* global label */
}

void 
complain(severity)
	int             severity;
{
	fprintf(logfile, "Error in fig#%ld on page %ld\n", pgfigurenum, currpagenum);
	switch (severity)
	{
	case ERRNOTBAD:
		putc(ERRSIGNAL, logfile);
		break;
	case ERRBAD:
		putc(ERRSIGNAL, logfile);
		ErrorOccurred = true;
		break;
	case ERRREALBAD:
		fprintf(logfile, "%c! ", ERRSIGNAL);
		ErrorOccurred = true;
		break;
	}
}

double 
float_(i)
	int32           i;
{
	return ((double) i);
}

static int 
tolowercase(let)
	int             let;
{
	return (isupper(let) ? tolower(let) : let);
}

#define	streq(a,b,n)	(!strncmp((a),(b),(n)))

/*
 * Move the current DVI position to posx, posy by moving relatively from our current position and store the new position
 */
void 
isetpos(posx, posy)
	int             posx, posy;
{
	ScaledPts       dy, dx;
	int32           numbytes;

	dx = posx - ourxpos;
	dy = posy - ourypos;
	numbytes = 1;
	if (dx < 128 && dx >= -128)
		numbytes = 1;
	else if (dx < 32768 && dx >= -32768)
		numbytes = 2;
	else if (dx < TWO23 && dx >= -TWO23)
		numbytes = 3;
	else if (dx < TWO31 && dx >= -TWO31)
		numbytes = 4;
	else
	{
		complain(ERRREALBAD);
		fprintf(logfile, "Panic: dx is too big/small in isetpos: %12ld\n", dx);
	}

	cmd1byte(RIGHTLEFT + numbytes - 1);
	/* number of bytes in its arg list */
	cmdSigned(dx, numbytes);

	numbytes = 1;
	if (dy < 128 && dy >= -128)
		numbytes = 1;
	else if (dy < 32768 && dy >= -32768)
		numbytes = 2;
	else if (dy < TWO23 && dy >= -TWO23)
		numbytes = 3;
	else if (dy < TWO31 && dy >= -TWO31)
		numbytes = 4;
	else
	{
		complain(ERRREALBAD);
		fprintf(logfile, "Panic: dy is too big/small in isetpos: %12ld\n", dy);
	}
	cmd1byte(DOWNUP + numbytes - 1);
	cmdSigned(dy, numbytes);
	ourxpos = posx;
	ourypos = posy;
}

/* put out a character */
static void 
iputchar(charno)
	int             charno;
{
	cmd1byte(PUT1);
	cmd1byte(charno);
}

/*
 * set the font number, but only if it is different than the last one
 * we accessed.
 */
void 
isetfont(DVINum)
	int             DVINum;
{
	if (ourfontnum == DVINum)
		return;
	cmd1byte(USEFONT);
	cmd2byte(DVINum);
	ourfontnum = DVINum;
}

/* Assumes that the correct font is currently set */
static void 
Tyldot(dotx, doty)
	int32           dotx, doty;
{
	if (dotx != 0 && doty != 0)
		isetpos(dotx, doty);
	iputchar(DOTCHAR);
}

/*
 * ### Note: "pageitems" could be extended to be a list
 * { of macrodefinitions which contain primitives , and { then could be
 * instanced.  E.g., a library of common { figures callable from \special level
 */

void 
pushItem(depth, newthing)
	int             depth;
	Item           *newthing;
{
	Item           *i, *p;

	if (pageitems == NULL)
	{
		if (newthing->kind == Afigure)
		{
			pageitems = newthing;
			return;
		}
		pageitems = NewItem(Afigure);
		pageitems->UU.U8.depthnumber = depth;
	}

	/* Assume that pageitems points to Afigure */
	/* traverse the list */
	i = pageitems;		/* point to front of list for now */
	p = i->UU.U8.body->things;
	while (p != NULL)
	{
		if (depth == i->UU.U8.depthnumber)
		{		/* simple push */
/*
 * Note: this is the case when pushing another figure item onto
 * an already-existing list. We push the
 * newfigure with a depth of (fig^.depthnumber - 1) because
 * it really is part of the higer-level figure
 */
			break;
		}
		if (depth <= i->UU.U8.depthnumber)
			continue;
		/* there MUST be a figure with a higher number deeper */
		while (p->kind != Afigure && p->nextitem != NULL)
			p = p->nextitem;

		if (p->kind == Afigure)
		{
			i = p;
			p = i->UU.U8.body->things;
		}
		else
		{
			complain(ERRREALBAD);
			fprintf(logfile,
				"OOPS p^.kind isnt a figure. It must be near endoflist\n");
		}
	}

	/*
	 * we have the correct front of list-list, and i points to Afigure item
	 */
	newthing->nextitem = p;
	i->UU.U8.body->things = newthing;
}

static double 
Tgetfixword(k)
	int             k;
{
	short           a;
	int32           f;

	a = tfm[k + 100] * 16 + tfm[k + 101] / 16;
	f = ((tfm[k + 101] & 15) * 256 + tfm[k + 102]) * 256 + tfm[k + 103];
	if (a <= 2047)
		return (a + (double) f / TWO20);
	a = 4096 - a;
	if (f > 0)
	{
		f = TWO20 - f;
		a--;
	}
	return (a + (double) f / TWO20);
}

static int32 
TgetSigned(k)
	int             k;
{
	int32           i;

	i = tfm[k + 100];
	if (i < 128)
		i -= 256;
	return (((i * 256 + tfm[k + 101]) * 256 + tfm[k + 102]) * 256 + tfm[k + 103]);
}

/*
 * open a .tfm file and return the parameters in it.
 * Used only in conjuction with the vector and music fonts
 */
static void 
gettfm(tfmfilnam, dessize, p1, p2, p3, p4, p5, p6, p7, cksum)
	charstring      tfmfilnam;
	int32          *dessize, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *cksum;
{
	int32           tfmptr, lf, lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np, charbase, widthbase, heightbase, depthbase,
	                italicbase, ligkernbase, kernbase, extenbase, parambase;
	ScaledPts       tempdesignsize;

	*p1 = 0;
	*p2 = 0;
	*p3 = 0;
	*p4 = 0;
	*p5 = 0;
	*p6 = 0;
	*p7 = 0;
	*cksum = -1;
	if (!opentfmfile(tfmfilnam))
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loaded, TFM file can't be opened!\n", tfmfilnam);
		jumpout();
	}
	tfm[100] = Tgetc();
	tfm[101] = Tgetc();
	lf = tfm[100] * 256 + tfm[101];
	if (lf * 4 - 1 > TFMSIZE)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "The tfm file:%s is bigger than I can handle!\n", tfmfilnam);
		return;
	}
	for (tfmptr = 102; tfmptr <= lf * 4 + 99; tfmptr++)
		tfm[tfmptr] = Tgetc();
	tfmptr = 2;
	lh = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	bc = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	ec = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	nw = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	nh = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	nd = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	ni = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	nl = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	nk = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	ne = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	np = tfm[tfmptr + 100] * 256 + tfm[tfmptr + 101];
	tfmptr += 2;
	if (lf != lh + ec - bc + nw + nh + nd + ni + nl + nk + ne + np + 7)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s: subfile sizes don't add up to the stated total!\n", tfmfilnam);
		fprintf(logfile,
			"Sorry, but I can't go on; are you sure this is a TFM?\n");
		return;
	}
	if (bc > ec + 1 || ec > 255)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "The character code range %ld..%ld is illegal!\n", bc, ec);
		fprintf(logfile, "Sorry, but I can't go on; are you sure this is a TFM?\n");
		return;
	}
	charbase = lh - bc + 6;
	widthbase = charbase + ec + 1;
	heightbase = widthbase + nw;
	depthbase = heightbase + nh;
	italicbase = depthbase + nd;
	ligkernbase = italicbase + ni;
	kernbase = ligkernbase + nl;
	extenbase = kernbase + nk;
	parambase = extenbase + ne - 1;

	*dessize = (int32) floor(Tgetfixword(28) * SPPERPT + 0.5);
	/* now in ScaledPts */
	tempdesignsize = (int32) floor(*dessize * magfactor + 0.5);
	*cksum = TgetSigned(24);
	/* return the special 7 parameters for the  font */
	*p1 = (int32) floor(Tgetfixword((parambase + 1) * 4) * tempdesignsize + 0.5);
	*p2 = (int32) floor(Tgetfixword((parambase + 2) * 4) * tempdesignsize + 0.5);
	*p3 = (int32) floor(Tgetfixword((parambase + 3) * 4) * tempdesignsize + 0.5);
	*p4 = (int32) floor(Tgetfixword((parambase + 4) * 4) * tempdesignsize + 0.5);
	*p5 = (int32) floor(Tgetfixword((parambase + 5) * 4) * tempdesignsize + 0.5);
	*p6 = (int32) floor(Tgetfixword((parambase + 6) * 4) * tempdesignsize + 0.5);
	*p7 = (int32) floor(Tgetfixword((parambase + 7) * 4) * tempdesignsize + 0.5);
}

static void 
initVnMnLtables()
{
	int32           i;

	for (i = 0; i < SizVFontTable; i++)
		VFontTable[i] = NULL;
	for (i = 0; i < SizMFontTable; i++)
		MFontTable[i] = NULL;
	for (i = 0; i < SizLFontTable; i++)
		LFontTable[i] = NULL;
	VFontsDefd = 0;
	MFontsDefd = 0;
	LFontsDefd = 0;
}

static void 
fonttobedefined(kind, findex)
	char            kind;
	int             findex;
{
	FTBDs++;
	/*
	 * reset this to zero after outputting 1. fontdefs 2. bop
	 * 3. contents of dvi page 4. eop
	 */
	TBD[FTBDs - 1].which = kind;
	TBD[FTBDs - 1].indx = findex;
}

static void 
enterfont(fontnum, ck, scalefact, dessiz, nam)
	int32           fontnum, ck, scalefact, dessiz;
	charstring      nam;
{
	int32           n, len;

	cmd1byte(FONTDEF);
	cmd2byte(fontnum);
	cmd4byte(ck);
	cmd4byte(scalefact);
	cmd4byte(dessiz);
	cmd1byte(USESTDAREA);
	cmd1byte(len = strlen(nam) - 4);/* skip the length of the .tfm suffix */
	for (n = 0; n < len; n++)	/* skip the .tfm suffix */
		cmd1byte(nam[n]);

}

static void 
Outputfont(fontnum, ck, scalefact, dessiz, nam)
	int32           fontnum, ck, scalefact, dessiz;
	charstring      nam;
{
	int32           n, len;

	OutputByte(FONTDEF);
	Output2Byte(fontnum);
	Output4Byte(ck);
	Output4Byte(scalefact);
	Output4Byte(dessiz);
	OutputByte(USESTDAREA);
	/* dont output the default dir prefix, nor the .tfm suffix */
	OutputByte(len = strlen(nam) - 4);
	for (n = 0; n < len; n++)
		OutputByte(nam[n]);

}

void 
defineNewfonts()
{
	/*
	 * this needs to be done before first access to a font
	 * on a page later someone else will have to re-define all of them
	 * in the postamble
	 */
	int32           i, f, FORLIM;
	VectFontInfRec *WITH;
	MusFontInfRec  *WITH1;
	LabFontInfRec  *WITH2;

	FORLIM = FTBDs;
	for (i = 0; i < FORLIM; i++)
	{
		if (TBD[i].which == 'V')
		{
			f = TBD[i].indx;
			WITH = VFontTable[f - 1];	/* with */
			if (WITH->Isdefined)
				continue;
			Outputfont(WITH->DVIFontNum, WITH->Cksum, WITH->DesSize, WITH->DesSize,
				   WITH->FontName);
			WITH->Isdefined = true;
		}		/* if */
		else if (TBD[i].which == 'M')
		{
			f = TBD[i].indx;
			WITH1 = MFontTable[f - 1];	/* with */
			if (WITH1->Isdefined)
				continue;
			Outputfont(WITH1->DVIFontNum, WITH1->Cksum, WITH1->DesSize,
				   WITH1->DesSize, WITH1->FontName);
			WITH1->Isdefined = true;
		}
		else if (TBD[i].which == 'L')
		{
			f = TBD[i].indx;
			WITH2 = LFontTable[f - 1];	/* with */
			if (WITH2->Isdefined)	/* ### is this right? */
				continue;
			Outputfont(WITH2->DVIFontNum, WITH2->Cksum, WITH2->DesSize,
				   WITH2->DesSize, WITH2->FontName);
			WITH2->Isdefined = true;
		}
		else
		{
			complain(ERRREALBAD);
			fprintf(logfile, "Unknown type of font to be defined:\"%c\"\n",
				TBD[i].which);
		}
	}
}

static int32 
GetMusFont(stfsiz, fam)
	int32           stfsiz, fam;
{
	charstring      mustfmnam;
	MusIndex        i;
	ScaledPts       design, p1, p2, p3, p4, linesp, gwidth, p7;
	int32           cksm, FORLIM;
	MusFontInfRec  *WITH;

	/* see if it already exists */
	FORLIM = MFontsDefd;
	for (i = 1; i <= FORLIM; i++)
	{			/* loop through since there are few */
		WITH = MFontTable[i - 1];
		if (WITH->Staffsize == stfsiz && WITH->Family == fam)
			return (i);
	}

	sprintf(mustfmnam, "mus%c%c.tfm", stfsiz + '0', fam + '0');
	gettfm(mustfmnam, &design, &p1, &p2, &p3, &p4, &linesp, &gwidth, &p7, &cksm);

	MFontsDefd++;
	if (MFontsDefd > SizMFontTable)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loadable. Size of Music Font table too small\n", mustfmnam);
		jumpout();
	}

	i = MFontsDefd;
	MFontTable[i - 1] = (MusFontInfRec *) xmalloc(sizeof(MusFontInfRec));
	WITH = MFontTable[i - 1];

	WITH->Staffsize = stfsiz;
	WITH->Family = fam;
	WITH->DesSize = design;
	strcpy(WITH->FontName, mustfmnam);
	WITH->Cksum = cksm;
	WITH->ghu = (int32) floor(gwidth / QNOTEGHUS + 0.5);
	WITH->gvu = (int32) floor(linesp / QNOTEGVUS + 0.5);
	WITH->DVIFontNum = GDVIFN++;
	WITH->Isdefined = false;
	/* call someone to do the defns of cdp, cht, cwd foreach beam */
	definebeams(&MFontTable[i - 1]);
	fonttobedefined('M', i);
	return (i);
}

int32 
GetVectFont(size, vk)
	VThickness      size;
	VectKind        vk;
{
	charstring      vectfmnam;
	VecIndex        i;
	ScaledPts       design, p1, p2, w0, w1, maxveclen, p6, p7;
	int32           cksm, r, FORLIM;
	VectFontInfRec *WITH;

	/* see if it already exists */
	FORLIM = VFontsDefd;
	for (i = 1; i <= FORLIM; i++)
	{			/* with */
		WITH = VFontTable[i - 1];
		if (WITH->psize == size && WITH->vkind == vk)
			return (i);
	}
	switch (vk)
	{
	case VKCirc:
		r = 'c';
		break;
	case VKVert:
		r = 'v';
		break;
	case VKHort:
		r = 'h';
		break;
	}
	sprintf(vectfmnam, "%cvec%d.tfm", r, size);
	gettfm(vectfmnam, &design, &p1, &p2, &w0, &w1, &maxveclen, &p6, &p7, &cksm);
	VFontsDefd++;
	if (VFontsDefd > SizVFontTable)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loadable. Size of Vector Font table too small\n", vectfmnam);
		jumpout();
	}

	i = VFontsDefd;
	VFontTable[i - 1] = (VectFontInfRec *) xmalloc(sizeof(VectFontInfRec));
	WITH = VFontTable[i - 1];

	WITH->vkind = vk;
	WITH->psize = size;
	WITH->DesSize = design;
	if (vk == VKVert)
		WITH->PenSize = w1;
	else
		WITH->PenSize = w0;
	WITH->PenSize = (int32) floor(size * (MAXVECLENsp / 16.0) + 0.5);
	WITH->MaxVectLen = maxveclen;
	strcpy(WITH->FontName, vectfmnam);
	WITH->Cksum = cksm;
	WITH->Isdefined = false;
	WITH->DVIFontNum = GDVIFN++;

	definevectors(&VFontTable[i - 1]);
	/* someone asked for it, so they must want it, and we should fntdef it */
	fonttobedefined('V', i);
	return (i);
}


/*----------------------------------------------------------*/
int32 
GetLabFont(style)
	int32           style;
{
	charstring      labtfmnam;
	int32           i, cksm, FORLIM;
	ScaledPts       design, p1, space, p3, p4, p5, p6, p7;
	LabFontInfRec  *WITH;

	if (style > MAXLABELFONTS)
		style = 1;
	FORLIM = LFontsDefd;
	for (i = 1; i <= FORLIM; i++)
	{
		WITH = LFontTable[i - 1];
		if (WITH->internalnumber == style)
			return (i);
	}

	switch (style)
	{
	case 1:		/* cmtt10 */
		strcpy(labtfmnam, "cmtt10");
		break;
	case 2:		/* cmb10 */
		strcpy(labtfmnam, "cmb10");
		break;
	case 3:		/* cmsl10 */
		strcpy(labtfmnam, "cmsl10");
		break;
	case 4:		/* cmtt8 */
		strcpy(labtfmnam, "cmtt8");
		break;
	case 5:		/* cmsl8 */
		strcpy(labtfmnam, "cmsl8");
		break;
	}
	strcat(labtfmnam, ".tfm");
	gettfm(labtfmnam, &design, &p1, &space, &p3, &p4, &p5, &p6, &p7, &cksm);

	LFontsDefd++;

	if (LFontsDefd > SizLFontTable)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loadable. Size of Label Font table too small\n", labtfmnam);
		jumpout();
	}

	i = LFontsDefd;
	LFontTable[i - 1] = (LabFontInfRec *) xmalloc(sizeof(LabFontInfRec));
	WITH = LFontTable[i - 1];	/* with */

	strcpy(WITH->FontName, labtfmnam);
	WITH->Cksum = cksm;
	WITH->DesSize = design;
	WITH->internalnumber = style;
	WITH->spacewidth = space;
	WITH->DVIFontNum = GDVIFN++;
	WITH->Isdefined = false;
	fonttobedefined('L', i);
	return (i);
}

static double 
vectangle(dx, dy)
	int32           dx, dy;
{
	if (dx != 0)
		return (atan(dy / (double) dx) * RADTODEG);
	else
		return (dy > 0 ? 90.0 : -90.0);
}

static void 
definevectors(Vec)
	VectFontInfRec **Vec;
{
	/* var Vec: pVectFontInfRec */
	int             i;
	double          units;
	VectFontInfRec *V;
	FontInfRec     *F;
	struct vecinfo *v;

	V = *Vec;
	units = V->MaxVectLen / 16.0;
	for (i = 0, F = V->FontInfo, v = vectab; i < 128; ++i, ++F, ++v)
	{
		F->Cht = floor(v->Cht * units + 0.5);
		F->Cdp = floor(v->Cdp * units + 0.5);
		F->Cwd = floor(v->Cwd * units + 0.5);
		F->Angle = v->Angle;
	}
}

/*
 * If, for some reason, you do not want to deal with music capabilities,
 * replace the body of this procedure with just a begin
 * end; pair  and also the TylBeam proc.
 */
static void 
definebeams(M)
	MusFontInfRec **M;
{
	/* var M : pMusFontInfRec */
}

#define UnitRadius      16777216/* TWO24 scaledpts */

/*
 * use pre-calculated coordinates of a circle that has a given unit-radius.
 * Scale those points to fit the desired radius
 */
void 
defineCircleCpts(rad, centx, centy, CircleCpt, numpts)
	int32           rad, centx, centy;
	int32		(*CircleCpt)[2];
	int32          *numpts;
{
	double          ratio;

	if (rad == 0)
	{
		complain(ERRBAD);
		fprintf(logfile, "Error in fig#%ld on page %ld\n",
			pgfigurenum, currpagenum);
		fprintf(logfile, "Zero length radius for circle! Setting to 1 sp\n");
		rad = 1;
	}
	ratio = float_(rad) / float_(UnitRadius);
	*numpts = 16;
	CircleCpt[1][0] = (int32) floor(ratio * 16777216.00000 + 0.5) + centx;
	CircleCpt[1][1] = centy;/* round (ratio *      0.00000) */
	CircleCpt[2][0] = (int32) floor(ratio * 15500126.47492 + 0.5) + centx;
	CircleCpt[2][1] = (int32) floor(ratio * 6420362.60441 + 0.5) + centy;
	CircleCpt[3][0] = (int32) floor(ratio * 11863283.20303 + 0.5) + centx;
	CircleCpt[3][1] = (int32) floor(ratio * 11863283.20303 + 0.5) + centy;
	CircleCpt[4][0] = (int32) floor(ratio * 6420362.60441 + 0.5) + centx;
	CircleCpt[4][1] = (int32) floor(ratio * 15500126.47492 + 0.5) + centy;
	CircleCpt[5][0] = centx;/* round (ratio *     -0.00000) */
	CircleCpt[5][1] = (int32) floor(ratio * 16777216.00000 + 0.5) + centy;
	CircleCpt[6][0] = (int32) floor(0.5 - ratio * 6420362.60441) + centx;
	CircleCpt[6][1] = (int32) floor(ratio * 15500126.47492 + 0.5) + centy;
	CircleCpt[7][0] = (int32) floor(0.5 - ratio * 11863283.20303) + centx;
	CircleCpt[7][1] = (int32) floor(ratio * 11863283.20303 + 0.5) + centy;
	CircleCpt[8][0] = (int32) floor(0.5 - ratio * 15500126.47492) + centx;
	CircleCpt[8][1] = (int32) floor(ratio * 6420362.60441 + 0.5) + centy;
	CircleCpt[9][0] = (int32) floor(0.5 - ratio * 16777216.00000) + centx;
	CircleCpt[9][1] = centy;/* round (ratio *     -0.00000) */
	CircleCpt[10][0] = (int32) floor(0.5 - ratio * 15500126.47492) + centx;
	CircleCpt[10][1] = (int32) floor(0.5 - ratio * 6420362.60441) + centy;
	CircleCpt[11][0] = (int32) floor(0.5 - ratio * 11863283.20303) + centx;
	CircleCpt[11][1] = (int32) floor(0.5 - ratio * 11863283.20303) + centy;
	CircleCpt[12][0] = (int32) floor(0.5 - ratio * 6420362.60441) + centx;
	CircleCpt[12][1] = (int32) floor(0.5 - ratio * 15500126.47492) + centy;
	CircleCpt[13][0] = centx;	/* round (ratio *      0.00000) */
	CircleCpt[13][1] = (int32) floor(0.5 - ratio * 16777216.00000) + centy;
	CircleCpt[14][0] = (int32) floor(ratio * 6420362.60441 + 0.5) + centx;
	CircleCpt[14][1] = (int32) floor(0.5 - ratio * 15500126.47492) + centy;
	CircleCpt[15][0] = (int32) floor(ratio * 11863283.20303 + 0.5) + centx;
	CircleCpt[15][1] = (int32) floor(0.5 - ratio * 11863283.20303) + centy;
	CircleCpt[16][0] = (int32) floor(ratio * 15500126.47492 + 0.5) + centx;
	CircleCpt[16][1] = (int32) floor(0.5 - ratio * 6420362.60441) + centy;
	/* create the pre-list phantom */
	CircleCpt[0][0] = CircleCpt[16][0];
	CircleCpt[0][1] = CircleCpt[16][1];
}

#undef UnitRadius

/*
 * compute control points for an arc going from startangle to stopangle, centered at (centx, centy)
 */
void 
definearcpts(rad, centx, centy, startang, stopang, cpts, nknots)
	int32           rad, centx, centy, startang, stopang;
	int32		(*cpts)[2];
	int32          *nknots;
{
	int32           n;
	double          a, b, curr, delta;
	int32           i;

	a = startang * DEGTORAD;
	b = stopang * DEGTORAD;
	n = 16;
	if (a > b)
		a -= 2 * PI;
	delta = fabs(b - a) / n;
	if (a == b)
	{
		complain(ERRNOTBAD);
		fprintf(logfile, "Error in compute arc points:: should be a circle\n");
	}
	curr = a;
	i = 1;
	while (curr <= b)
	{			/* make arc about (centx,centy) */
		cpts[i][0] = (int32) floor(rad * cos(curr) + 0.5) + centx;
		cpts[i][1] = (int32) floor(rad * sin(curr) + 0.5) + centy;
		i++;
		curr += delta;
	}

	/*
	 * go one point beyond -- around the arc so that we can have
	 * good smoothness for this phantom point
	 */

	cpts[i][0] = (int32) floor(rad * cos(b + delta) + 0.5) + centx;
	cpts[i][1] = (int32) floor(rad * sin(b + delta) + 0.5) + centy;

	/* and one phantom point before the list */
	cpts[0][0] = (int32) floor(rad * cos(a - delta) + 0.5) + centx;
	cpts[0][1] = (int32) floor(rad * sin(a - delta) + 0.5) + centy;

	*nknots = i - 1;
}

static int 
isaletter(b)
	int             b;
{
	return (isalpha(b) || b == '@' || b == '"');
}

static int 
getnumber(cpp)
	char		**cpp;
{
	int             n;
	int		isneg;

	n = 0;
	isneg = false;
	for ( ; **cpp != '\0' && (!isdigit(**cpp)); ++*cpp)
		if (**cpp == '-')
			isneg = true;
	while (isspace(**cpp))	/* Skip spaces */
		++*cpp;
	for ( ; **cpp != '\0' && isdigit(**cpp); ++*cpp)
		n = n * 10 + **cpp - '0';
	return (isneg ? -n : n);
}

static int 
getletter(cpp)
	char		**cpp;
{
	char		*cp;

	cp = *cpp;
	/* non letter */
	for (cp = *cpp; *cp != '\0' && !isaletter(*cp) && !isspace(*cp); ++cp)
		;
	if (*cp != '\0' && (isaletter(*cp) ||
				(isspace(*cp) && !isdigit(*cp))))
	{
		*cpp = cp + 1;
		return (*cp);
	}
	return (' ');
}

static int 
getanything(cpp)
	char		**cpp;
{
	char		c;

	if ((c = **cpp) != '\0')
	{
		++*cpp;
		return (c);
	}
	return (' ');
}

/*****************************************************
   The following routines look for key - letter tokens
  that indicate certain attributes for a primitive.

Currently, the letters used are:
        Sfor scaled-points measurement
        Pfor printers points
        Mmillimeters measurement
        Cuse a Circular vector for drawing
        HHorizontal-pen vector
        VVertical vector
        BB-spline
        IInterpolating B-spline
        KCatmull-Rom spline
        DCardinal spline
        UOpen spline
        Oclosed spline
        Xput marks on spline control pts
        TTransformation marker
        RRegular beam characters
        GGrace Beam characters
        @Specify center-point for arc/circle
        LLine-style
        Ffor beginfigure: Fit figure to wid/ht
        Wfor beginfigure: figure was created at this wid & ht
***************************************************/

static void 
gettransforms(sc1, sc2, r, tr1, tr2, cpp)
	double         *sc1, *sc2, *r;
	int32          *tr1, *tr2;
	char		**cpp;
{
	char		*cp;

	*sc1 = 1.0;
	*sc2 = 1.0;
	*tr1 = 0;
	*tr2 = 0;
	*r = 0.0;
	for (cp = *cpp; *cp != '\0'; ++cp)
	{
		if (*cp == 't' || *cp == 'T')
		{
			if (!isaletter(cp[-1]) && !isaletter(cp[1]))
			{
				/* get transform parameters and modify ptr */
				*cpp = cp;
				*sc1 = getnumber(cpp) / 100.0;
				*sc2 = getnumber(cpp) / 100.0;
				*tr1 = getnumber(cpp);
				*tr2 = getnumber(cpp);
				*r = float_(getnumber(cpp));
				/* degrees about primitive center */
				if (*r < 0.0)
					*r += 360.0;
				break;
			}
		}
	}
}

static int 
findmarker(set, cp)
	char	*set;
	char	*cp;
{
	for ( ; *cp != '\0'; ++cp)
	{
		if (strchr(set, *cp))
			if (!isaletter(cp[-1]) && !isaletter(cp[1]))
				return (tolowercase(*cp));
	}
	return (0);
}

#define	findscale(p)		findmarker("sSpPmM", p)
#define	findvectkind(p)		findmarker("cChHvV", p)
#define	findlinestyle(p)	findmarker("lL", p)
#define	findbeamkind(p)		findmarker("rRgG", p)
#define	findsplinekind(p)	findmarker("bBiIkKdD", p)
#define	findsplclosure(p)	findmarker("oOuU", p)
#define	findatsign(p)		findmarker("@", p)
#define	finddotmark(p)		findmarker("xX", p)
#define	findfigdimens(p)	findmarker("wW", p)
#define	findfitsizes(p)		findmarker("fF", p)

static double 
thescaleof(scal)
	int32           scal;
{
	if (scal == 's')
		return (1 * magfactor);
	if (scal == 'p')
		return (SPPERPT * magfactor);
	if (scal == 'm')
		return (SPPERMM * magfactor);
	if (scal == 0)
		return (SPPERPT * magfactor);
}


static VectKind 
thevectorof(vkin)
	int32           vkin;
{
	if (vkin == 'c')
		return VKCirc;
	if (vkin == 'v')
		return VKVert;
	if (vkin == 'h')
		return VKHort;
	if (vkin == 0)
		return VKCirc;
}

static LineStyle 
thestyleof(linest)
	int32           linest;
{
	static LineStyle styletab[4] = {solid, dotted, dashed, dotdash};

	if (linest > 3 || linest < 0)
		linest = 0;
	return (styletab[linest]);
}

static void 
tylspecials(cp)
	char		*cp;
{
	/*
	 * specnum is the DVI-number of the special
	 * nbytes is the number of parameter bytes
	 */
	int32           siz, numknots;	/* Lots of temp vars that we use */
	int32           x1, y1, x2, y2;
	double          sx100, sy100, rot, SPscale;
	ScaledPts       transx, transy, minx, miny, maxx, maxy;
	ControlPoints   cpts;
	VThickness      thk;
	LineStyle       patt;
	ThickAryType    TTary;
	VectKind        vk;
	BeamKind        bk;
	int32           markdiam, radius, ang1, ang2;
	charstring      phrase;
	int32           style;
	char		nam[5];	/* the first parameter of the \special */
	char            let;
	int32           i;
	Item           *pi;
	int32           maxthk, minthk;
	SplineKind      splinetype;
	int		isclosedspline;
	int		free PP((char *));

	/* Lets look for a primitive to tyl */
	for ( ; !isaletter(*cp) && *cp != '\0'; ++cp)
		;
	/* get the name of the primitive */
	for (i = 0; isaletter(*cp); ++cp)
		if (i < 4)
			nam[i++] = tolowercase(*cp);
	nam[i] = '\0';

	/* --- BEGINFIGURE ---- */
	if (streq(nam, "beginfigure", 3))
	{
		multifigure++;
		i = findscale(cp);
		SPscale = thescaleof(i);

		gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);
		/*
		 * store all the primitives on pageitems, and dont output them
		 * until we get a endfigure. this way, we can take
		 * care of dealing with all the primitives according to some
		 * global tranformation for the whole figure
		 */
		pi = NewItem(Afigure);
		pi->UU.U8.figtheta = rot;
		pi->UU.U8.fsx = sx100;
		pi->UU.U8.fsy = sy100;
		pi->UU.U8.fdx = (int32) floor(transx * SPscale + 0.5);
		pi->UU.U8.fdy = (int32) floor(transy * SPscale + 0.5);
		pi->UU.U8.depthnumber = multifigure;	/* we're at a new level */
		i = findfigdimens(cp);
		if (i != 0)
		{
			pi->UU.U8.preWid = (int32) floor(getnumber(&cp) * SPscale + 0.5);
			pi->UU.U8.preHt = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		}
		i = findfitsizes(cp);
		if (i != 0)
		{		/* with */
			pi->UU.U8.postWid = (int32) floor(getnumber(&cp) * SPscale + 0.5);
			pi->UU.U8.postHt = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		}
		BackupInBuf(DVIMark() - specstart);
		pushItem(multifigure - 1, pi);
		return;
	}
	/* ---- ENDFIGURE ---- */
	if (streq(nam, "endfigure", 3))
	{
		multifigure--;
		if (multifigure < 0)
		{
			complain(ERRBAD);
			fprintf(logfile, "Warning: Too many \"endfigure\"s !");
			multifigure = 0;
		}
		BackupInBuf(DVIMark() - specstart);
		if (multifigure == 0)
		{
			/* go do our set of figures (within figures...) */
			figurehandle(pageitems, pageitems, 1);
			free((char *)pageitems);/* #### should maybe garbage collect here */
			pageitems = NULL;
		}		/* if */
		return;
	}

	/* --- LINE  --- */
	if (streq(nam, "line", 3))
	{
		i = findscale(cp);
		SPscale = thescaleof(i);

		gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);
		thk = getnumber(&cp);	/* get the vector thickness */
		if (thk < 1)
		{
			complain(ERRBAD);
			fprintf(logfile, "?? Thickness not found. Setting to 1\n");
			thk = 1;
		}
		i = findvectkind(cp);
		vk = thevectorof(i);

		i = findlinestyle(cp);
		if (i != 0)
			patt = thestyleof(getnumber(&cp));
		else
			patt = solid;

		x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);

		minx = min(x1, x2);
		maxx = max(x1, x2);
		miny = min(y1, y2);
		maxy = max(y1, y2);

		BackupInBuf(DVIMark() - specstart);
		cmd1byte(OURFONTFLAG);
		linehandle(multifigure, SPscale, x1, y1, x2, y2, 0, 0, thk, vk, patt,
			   minx, maxx, miny, maxy, transx, transy, sx100, sy100, rot);
	}			/* line */
	else if (streq(nam, "spline", 3) || streq(nam, "ttspline", 3))
	{
		i = findscale(cp);
		SPscale = thescaleof(i);

		gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);

		if (streq(nam, "spline", 3))
		{
			thk = getnumber(&cp);
			if (thk < 1)
			{
				complain(ERRBAD);
				fprintf(logfile, "Spline Thickness not found. Setting to 1\n");
				thk = 1;
			}
		}
		i = findvectkind(cp);
		vk = thevectorof(i);

		i = findlinestyle(cp);
		if (i != 0)
			patt = thestyleof(getnumber(&cp));
		else
			patt = solid;

		i = findsplinekind(cp);
		if (i == 'b')
			splinetype = BSPL;
		else if (i == 'i')
			splinetype = INTBSPL;
		else if (i == 'k')
			splinetype = CATROM;
		else if (i == 'd')
			splinetype = CARD;
		else if (i == 0)
			splinetype = CATROM;

		i = findsplclosure(cp);
		if (i == 'o')
			isclosedspline = true;
		else if (i == 'u')
			isclosedspline = false;
		else if (i == 0)
			isclosedspline = false;

		i = finddotmark(cp);
		if (i == 'x')
			markdiam = getnumber(&cp);
		else if (i == 0)
			markdiam = 0;

		numknots = min(getnumber(&cp), (int32) MAXCTLPTS);
		if (numknots < 1)
		{
			complain(ERRBAD);
			fprintf(logfile,
				"Number of spline/ttspline knot points not found. Setting to 1\n");
			numknots = 1;
		}

		minx = TWO24;
		miny = TWO24;
		maxx = -TWO24;
		maxy = -TWO24;

		for (i = 0; i <= numknots + 3; i++)
		{
			cpts[i][0] = 0;
			cpts[i][1] = 0;
		}		/* for */

		for (i = 1; i <= numknots; i++)
		{
			x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
			cpts[i][0] = x1;
			if (x1 < minx)
				minx = x1;
			if (x1 > maxx)
				maxx = x1;
			y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
			cpts[i][1] = y1;
			if (y1 < miny)
				miny = y1;
			if (y1 > maxy)
				maxy = y1;
		}		/* for */

		if (streq(nam, "ttspline", 3))
		{
			for (i = 1; i <= numknots; i++)
				TTary[i] = getnumber(&cp);
		}

		BackupInBuf(DVIMark() - specstart);
		cmd1byte(OURFONTFLAG);

		if (streq(nam, "spline", 3))
			splinehandle(multifigure, SPscale, splinetype, isclosedspline, markdiam,
				     cpts, numknots, 0, 0, thk, vk, patt, minx, maxx, miny,
				     maxy, transx, transy, sx100, sy100, rot);
		else
			ttsplhandle(multifigure, SPscale, splinetype, isclosedspline, markdiam,
				    cpts, TTary, numknots, 0, 0, vk, patt, minx, maxx, miny,
				    maxy, transx, transy, sx100, sy100, rot);
	}
	else if (streq(nam, "beam", 4))
	{
		i = findscale(cp);
		SPscale = thescaleof(i);

		/* no transforms */

		siz = getnumber(&cp);	/* the staffsize */
		i = findbeamkind(cp);
		if (i == 'g')
			bk = grace;
		else if (i == 'r')
			bk = regular;
		else if (i == 0)
			bk = regular;

		x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);

		BackupInBuf(DVIMark() - specstart);
		cmd1byte(OURFONTFLAG);

		beamhandle(multifigure, siz, bk, x1, y1, x2, y2);
	}
	else if (streq(nam, "tieslur", 3))
	{
		i = findscale(cp);
		SPscale = thescaleof(i);

		minthk = getnumber(&cp);
		if (minthk < 1)
		{
			complain(ERRBAD);
			fprintf(logfile, "Tie/Slur Min Thickness not found. Setting to 1\n");
			minthk = 1;
		}

		maxthk = getnumber(&cp);
		if (maxthk < 1)
		{
			complain(ERRBAD);
			fprintf(logfile, "Tie/Slur MaxThickness not found. Setting to 1\n");
			maxthk = 1;
		}

		numknots = min(getnumber(&cp), (int32) MAXCTLPTS);
		if (numknots < 1)
		{
			complain(ERRBAD);
			fprintf(logfile,
				"Tie/Slur Number of knot points not found. Setting to 1. Should be 5\n");
			numknots = 1;
		}
		for (i = 1; i <= numknots; i++)
		{
			cpts[i][0] = (int32) floor(getnumber(&cp) * SPscale + 0.5);
			cpts[i][1] = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		}		/* for */
		BackupInBuf(DVIMark() - specstart);
		cmd1byte(OURFONTFLAG);

		tieslurhandle(multifigure, cpts, numknots, (int) minthk, (int) maxthk);
	}
	else if (streq(nam, "arc", 3))
	{
		i = findscale(cp);
		SPscale = thescaleof(i);

		gettransforms(&sx100, &sy100, &rot, &transx, &transy, &cp);

		thk = getnumber(&cp);
		if (thk < 1)
		{
			complain(ERRBAD);
			fprintf(logfile, "Arc Thickness not found. Setting to 1\n");
			thk = 1;
		}
		i = findvectkind(cp);
		vk = thevectorof(i);

		i = findlinestyle(cp);
		if (i != 0)
			patt = thestyleof(getnumber(&cp));
		else
			patt = solid;

		radius = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		if (radius == 0)
			radius = (int32) floor(1 * SPscale + 0.5);
		i = findatsign(cp);
		if (i != 0)
		{
			x2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
			y2 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		}
		else
		{
			x2 = 0;
			y2 = 0;	/* assume center at origin */
		}

		ang1 = getnumber(&cp);
		if (abs(ang1) > 360)
		{
			ang1 %= 360;
			/*
			 * p2c: x.p, line 5570: Note: Using % for possibly-negative arguments [317]
			 */
		}
		ang2 = getnumber(&cp);
		if (abs(ang2) > 360)
		{
			ang2 %= 360;
			/*
			 * p2c: x.p, line 5573: Note: Using % for possibly-negative arguments [317]
			 */
		}

		minx = TWO24;
		miny = TWO24;
		maxx = -TWO24;
		maxy = -TWO24;

		if (ang1 == ang2)	/* a circle */
			defineCircleCpts(radius, x2, y2, cpts, &numknots);
		else		/* a real arc */
			definearcpts(radius, x2, y2, ang1, ang2, cpts, &numknots);

		for (i = 1; i <= numknots; i++)
		{
			x1 = cpts[i][0];
			if (x1 < minx)
				minx = x1;
			if (x1 > maxx)
				maxx = x1;

			y1 = cpts[i][1];
			if (y1 < miny)
				miny = y1;
			if (y1 > maxy)
				maxy = y1;
		}		/* for */

		BackupInBuf(DVIMark() - specstart);
		cmd1byte(OURFONTFLAG);


		arccirclehandle(multifigure, SPscale, x2, y2, radius, ang1, ang2, cpts,
				numknots, 0, 0, thk, vk, patt, minx, maxx, miny, maxy,
				transx, transy, sx100, sy100, rot);
	}
	else if (streq(nam, "label", 3))
	{
		i = findscale(cp);
		SPscale = thescaleof(i);

		style = getnumber(&cp);	/* font style number */
		if (style < 1 || style > MAXLABELFONTS)
		{
			complain(ERRBAD);
			fprintf(logfile, "Label style bad? Setting to Style 1\n");
			style = 1;
		}

		x1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);
		y1 = (int32) floor(getnumber(&cp) * SPscale + 0.5);

		let = getletter(&cp);
		while (let != '"')
			let = getletter(&cp);
		let = getanything(&cp);	/* get next letter or whatever */
		for (i = 0; let != '"'; ++i)
		{		/* get the label phrase */
			phrase[i] = let;
			let = getanything(&cp);	/* getletter; */
		}
		phrase[i] = '\0';

		BackupInBuf(DVIMark() - specstart);
		cmd1byte(OURFONTFLAG);
		labelhandle(multifigure, SPscale, x1, y1, 0, 0, style, phrase, 0, 0);
	}
	else if (streq(nam, "param", 3))
	{
		i = getnumber(&cp);	/* addressable param number */

		fprintf(logfile, " I do not know what internal parameter #%ld is\n", i);
		/* else */
		BackupInBuf(DVIMark() - specstart);
	}
	else
	{
		complain(ERRNOTBAD);
		fprintf(logfile, "Sorry, I don't know how to tyl %s\n", nam);
	}
}

static int
otherspecials(cp)
	char		*cp;
{
	fprintf(logfile, "Special: %s\n", cp);
	return (1);
}

static void 
mainhandlespecials(specnum, nbytes)
	int32           specnum, nbytes;
{
	/*
	 * specnum is the DVI-number of the special
	 * nbytes is the number of parameter bytes
	 */
	char	 	sysnam[4];
	char            *cp, *buf;
	int32           i;
	char		*malloc PP((unsigned));
	int		free PP((char *));

	specstart = DVIMark() - specnum + 237;
	ourxpos = h;
	ourypos = v;		/* note the global DVI (h,v) coords */

	cp = buf = malloc((unsigned)(nbytes + 1));
	for (i = 0; i < nbytes; ++i)
		cp[i] = Dget1byte();
	cp[i] = '\0';

	while (isspace(*cp))
		++cp;
	/* get the name of the system --- Hopefully 'tyl' */
	for (i = 0; *cp != '\0' && *cp != ' '; ++cp)
		if (i < 3)
			sysnam[i++] = tolowercase(*cp);
	sysnam[i] = '\0';	/* end of string */
	if (streq(sysnam, "tyl", 3))
		tylspecials(cp);
	else if (otherspecials(buf))
		;
	else
		fprintf(logfile, "Unknown special ignored: %s\n", buf);
	free((char *)buf);
}

/*
 * ==================================================
 * 
 * The routines below assume coordinates are already in 4th Quadrant DVI-space
 * 
 * =====================================================
 */

/*
 * returns 0 if dy.dx not in font 1 if ok 2 if ok and caller should use two of the "code"s coding scheme requires  0<= [dx, dy]
 * <= 16 AND that max(dx, abs(dy)) is in [0,1,2,4,8,16]
 */
static int32 
outvector(dx, dy, code)
	int32           dx, dy, *code;
{
	int32           c, result;

	if (dx < 0)
		return (0);

	result = 0;		/* init for potential failure */
	*code = -1;
	if (dy < 0)
		c = dy + dx - max(dx, -dy) * 9 + 160;
	else
		c = dy - dx - max(dx, dy) * 7 + 160;

	/*
	 * here translate to OUR coding scheme and return the correct number
	 * this is needed because "c" thinks the char range
	 * is 0 to 160, while we have only 128 chars
	 */

	if (c == 0)
	{			/* special cases */
		*code = 63;
		result = 2;
	}
	else if (c == 64)
	{
		*code = 95;
		result = 2;
	}
	else
	{
		result = 1;	/* just one char is fine */
		if (c >= 1 && c <= 63)	/* c - 33 */
			*code = c - 1;
		else if (c >= 80 && c <= 112)
			*code = c - 17;
		else if (c >= 120 && c <= 136)
			*code = c - 24;
		else if (c >= 140 && c <= 148)
			*code = c - 27;
		else if (c >= 150 && c <= 154)
			*code = c - 28;
		else if (c == 160)
			*code = 127;
	}
	return result;
}

/* take care of a Manhattan (horizontal /vertical) line */
static void 
hvline(lx, by, rx, ty, fontindex)
	int32           lx, by, rx, ty, fontindex;
{
	int32           t, rth, x, y, width, height;

	rth = VFontTable[fontindex - 1]->PenSize;	/* thickness of vector in sp */
	if (lx == rx)
	{			/* Vertical line */
		if (ty > by)
		{
			t = by;
			by = ty;
			ty = t;	/* swap */
		}
		x = (int32) floor(lx - rth / 2.0 + 0.5);
		y = by;
		width = rth;
		height = by - ty;
	}
	else
	{			/* Horizontal line */
		if (ty < by)
		{
			t = by;
			by = ty;
			ty = t;	/* swap */
		}
		if (lx > rx)
		{
			t = lx;
			lx = rx;
			rx = t;	/* swap */
		}
		x = lx;

		y = by + rth / 2;	/* + rth for {h,v}-space */
		width = rx - lx;
		height = rth;
	}

	isetpos(x, y);
	cmd1byte(PUTRULE);
	cmd4byte(height);
	cmd4byte(width);

	/*
	 * output two dots on ends of the rules at    lx, by  and rx, ty
	 */
	/* the font has already been set before these calls */
	Tyldot(lx, by);
	Tyldot(rx, ty);
	isetpos(rx, ty);
}


/* Local variables for diagonal: */
struct LOC_diagonal
{
	int32           xl, yb, xr, yt, curx, cury;
	double          slope;
	ScaledPts       mxveclen;
};

/* compute maximum length vector character that we  can use */
static void 
getincr(outdx, outdy, LINK)
	int32          *outdx, *outdy;
	struct LOC_diagonal *LINK;
{
	int32           radius, x, y, sign;

	radius = LINK->mxveclen;/* radius of semi-square */
	/*
	 * make sure the pt is outside of the semi-square, scaling down radius if necessary
	 */
	while (LINK->xr - LINK->curx < radius &&
	       abs(LINK->yt - LINK->cury) < radius)
		radius /= 2;
	if (LINK->slope < 0.0)	/* <0 since in 4th quad by now */
		sign = -1;
	else
		sign = 1;
	if (LINK->xr == LINK->curx)
	{
		*outdx = 0;
		*outdy = sign * radius;
		return;
	}
	if (LINK->yt == LINK->cury)
	{
		*outdx = abs(radius);
		*outdy = 0;
		return;
	}

	/*
	 * compute the intersection with the semi-square, choose whichever slope is best
	 */
	if (fabs(LINK->slope) < 1.0)
	{			/* mostly horizontal */
		*outdx = abs(radius);
		y = LINK->yb +
			(int32) floor((LINK->curx + abs(radius) - LINK->xl) * LINK->slope + 0.5);
		*outdy = y - LINK->cury;
	}
	else
	{			/* mostly vertical */
		x = LINK->xl +
			(int32) floor((LINK->cury + sign * radius - LINK->yb) / LINK->slope + 0.5);
		*outdx = x - LINK->curx;
		*outdy = sign * radius;
	}

	if (abs(*outdy) > abs(LINK->yt - LINK->cury))	/* truncate */
		*outdy = LINK->yt - LINK->cury;
	if (*outdx > LINK->xr - LINK->curx)	/* truncate */
		*outdx = LINK->xr - LINK->curx;
	if (*outdx < 0)
		*outdx = 0;

	/*
	 * method to find the exact intersection of the line segment with the semi-circle, used to determine the x and y
	 * values:: we do this by using the arctangent of the slope as the angle 'a' from the x-axis. Then use the relation y =
	 * r cos a, and x = r sin a we can be smart about all this trig stuff by using the relation : sin (arctan a) = 1/sqrt(1
	 * + a^2) cos (arctan a) = a/sqrt(1 + a^2) Thus: q := (1.0 / sqrt (slope * slope + 1.0)); outdx := round (q * radius);
	 * outdy := round (q * radius * slope);
	 * 
	 * Unfortunately, we cannot access the Vector Font coding scheme because the outdx, outdy 's produced here do no conform
	 * to the condition max (dx, abs(dy)) in [0,1,2,4,8,16] when converted to vector-font sizes with sptovecs (see  the
	 * 'diagonal' proc.).
	 */
}

static void 
diagonal(xl_, yb_, xr_, yt_, fontindex)
	int32           xl_, yb_, xr_, yt_, fontindex;
{
	struct LOC_diagonal V;
	int32           t, dx, dy, code;
	double          sptovecs;
	ScaledPts       rho;

	V.xl = xl_;
	V.yb = yb_;
	V.xr = xr_;
	V.yt = yt_;
	if (V.xr != V.xl)	/* some illegal value */
		V.slope = (double) (V.yt - V.yb) / (V.xr - V.xl);
	else
		V.slope = BIGREAL;

	if (V.xl > V.xr)
	{
		t = V.xl;
		V.xl = V.xr;
		V.xr = t;
		t = V.yb;
		V.yb = V.yt;
		V.yt = t;
	}			/* swap */

	V.curx = V.xl;
	V.cury = V.yb;
	V.mxveclen = VFontTable[fontindex - 1]->MaxVectLen;
	rho = V.mxveclen / 16;	/* minimum radius of vector fonts */
	if (rho == 0)
	{
		complain(ERRREALBAD);
		fprintf(logfile,
			"Diagonal: Min radius of vector font is zero. setting to 1\n");
		rho = 1;
	}

	if (abs(V.xl - V.xr) <= rho && abs(V.yb - V.yt) <= rho)
	{			/* pretty much a null line */
		Tyldot(V.xl, V.yb);
		return;
	}
	sptovecs = 1.0 / rho;	/* conversion for scaled pts to vectorfont units */

	code = -1;		/* initialize to a bogus number */

	/*
	 * this conditional really has to have "or" instead of "and", because of lines that are nearly*  horizontal or vertical
	 */
	while (V.xr - V.curx >= rho || abs(V.yt - V.cury) >= rho)
	{
		getincr(&dx, &dy, &V);

		/*
		 * Get the vector character code corresponding to this approximate incremental amount
		 */
		t = outvector((int32) floor(dx * sptovecs + 0.5),
			      (int32) floor(dy * sptovecs + 0.5), &code);
		/*
		 * Now that we have the character code, go find out its actual physical dimensions for the real dy/dx amounts
		 */
		if (dy > 0)
			dy = VFontTable[fontindex - 1]->FontInfo[code].Cdp;
		else
			dy = -VFontTable[fontindex - 1]->FontInfo[code].Cht;

		dx = VFontTable[fontindex - 1]->FontInfo[code].Cwd;

		switch (t)
		{

		case 0:
			complain(ERRREALBAD);
			fprintf(logfile, "Error in Diagonal:: bad dydx\n");
			break;

		case 1:
			isetpos(V.curx, V.cury);
			iputchar(code);
			break;

		case 2:
			isetpos(V.curx, V.cury);
			iputchar(code);
			isetpos(V.curx + dx / 2, V.cury + dy / 2);
			iputchar(code);
			break;
		}		/* case */

		V.curx += dx;
		V.cury += dy;
	}			/* while */
	/*
	 * Get the approximate incremental amount. We use this dy/dx pair in order to index into our vector font coding scheme
	 */


	if (code >= 0 && V.xr - V.curx >= rho && abs(V.yt - V.cury) >= rho)
		iputchar(code);

	/* not null line */
}


/* Local variables for tylBrokenLine: */
struct LOC_tylBrokenLine
{
	int32           fontindex;
	LineStyle       line_type;
	int		useXaxis;
	int32           a0, b0, a1, b1, a2, a3, b2, b3, gap, dot, dash;
	double          s, z;
	int32           J, frame, Dotgap, Dotdot, Dashgap, Dashdash, DDotgap, DDotdot, DDotdash;
};

static void 
spread(lt, extra, T, LINK)
	LineStyle       lt;
	int32           extra, T;
	struct LOC_tylBrokenLine *LINK;
{
	if (T == 0)
	{			/* only partial frame fits */
		if (LINK->useXaxis)
			diagonal(LINK->a0, LINK->b0, LINK->a1, LINK->b1, LINK->fontindex);
		else
			diagonal(LINK->b0, LINK->a0, LINK->b1, LINK->a1, LINK->fontindex);
		return;
	}
	LINK->J = 0;
	LINK->s = float_(LINK->b1 - LINK->b0) / float_(LINK->a1 - LINK->a0);
	LINK->z = float_(extra) / float_(T);
	switch (lt)
	{

	case dotted:
		do
		{
			LINK->a2 = LINK->a0 + LINK->J * LINK->frame;
			if (extra > 0)
				LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5);
			LINK->a3 = LINK->a2 + LINK->dot;
			LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
			LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
			if (LINK->a3 <= LINK->a1)
			{
				if (LINK->useXaxis)
					diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
				else
					diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
			}
			LINK->J++;
		} while (LINK->a3 < LINK->a1);
		break;

	case dashed:
		do
		{
			LINK->a2 = LINK->a0 + LINK->J * LINK->frame;
			if (extra > 0)
				LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5);
			LINK->a3 = LINK->a2 + LINK->dash;
			LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
			LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
			if (LINK->a3 <= LINK->a1)
			{
				if (LINK->useXaxis)
					diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
				else
					diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
			}
			LINK->J++;
		} while (LINK->a3 < LINK->a1);
		break;

	case dotdash:
		do
		{
			LINK->a2 = LINK->a0 + LINK->J * LINK->frame;
			if (extra > 0)
				LINK->a2 += (int32) floor(LINK->J * LINK->z + 0.5);
			LINK->a3 = LINK->a2 + LINK->dash;
			LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
			LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
			if (LINK->a3 <= LINK->a1)
			{
				if (LINK->useXaxis)
					diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
				else
					diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
				LINK->a2 = LINK->a3 + LINK->gap;
				if (extra > 0)
					LINK->a2 += (int32) floor(LINK->z * 0.5 + 0.5);
				LINK->a3 = LINK->a2 + LINK->dot;
				LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
				LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
				if (LINK->a3 <= LINK->a1)
				{
					if (LINK->useXaxis)
						diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
					else
						diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
				}
			}
			LINK->J++;
		} while (LINK->a3 < LINK->a1);
		break;
	}
}				/* spread */

static void 
balance(lt, extra, T, LINK)
	LineStyle       lt;
	int32           extra, T;
	struct LOC_tylBrokenLine *LINK;
{
	if (T == 0)
	{			/* only partial frame fits */
		if (LINK->useXaxis)
			diagonal(LINK->a0, LINK->b0, LINK->a1, LINK->b1, LINK->fontindex);
		else
			diagonal(LINK->b0, LINK->a0, LINK->b1, LINK->a1, LINK->fontindex);
		return;
	}
	LINK->J = 0;
	LINK->s = float_(LINK->b1 - LINK->b0) / float_(LINK->a1 - LINK->a0);
	switch (lt)
	{

	case dashed:
		do
		{
			LINK->a2 = LINK->a0 + LINK->J * LINK->frame - extra / 2;
			LINK->a3 = LINK->a2 + LINK->dash;
			if (LINK->J == 0)
				LINK->a2 = LINK->a0;
			if (LINK->a3 > LINK->a1)
				LINK->a3 = LINK->a1;
			LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
			LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
			if (LINK->a3 <= LINK->a1)
			{
				if (LINK->useXaxis)
					diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
				else
					diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
			}
			LINK->J++;
		} while (LINK->a3 < LINK->a1);
		break;

	case dotdash:
		do
		{
			LINK->a2 = LINK->a0 + LINK->J * LINK->frame - extra / 2;
			LINK->a3 = LINK->a2 + LINK->dash;
			if (LINK->J == 0)
				LINK->a2 = LINK->a0;
			if (LINK->a3 > LINK->a1)
				LINK->a3 = LINK->a1;
			LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
			LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
			if (LINK->a3 <= LINK->a1)
			{
				if (LINK->useXaxis)
					diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
				else
					diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
				LINK->a2 = LINK->a3 + LINK->gap;
				LINK->a3 = LINK->a2 + LINK->dot;
				LINK->b2 = (int32) floor(LINK->s * (LINK->a2 - LINK->a0) + LINK->b0 + 0.5);
				LINK->b3 = (int32) floor(LINK->s * (LINK->a3 - LINK->a0) + LINK->b0 + 0.5);
				if (LINK->a3 <= LINK->a1)
				{
					if (LINK->useXaxis)
						diagonal(LINK->a2, LINK->b2, LINK->a3, LINK->b3, LINK->fontindex);
					else
						diagonal(LINK->b2, LINK->a2, LINK->b3, LINK->a3, LINK->fontindex);
				}
			}
			LINK->J++;
		} while (LINK->a3 < LINK->a1);
		break;
	}
}				/* balance */

static int32 
project(I, LINK)
	int32           I;
	struct LOC_tylBrokenLine *LINK;
{
	int32           K;	/* gives the projection of lengths onto axes */

	K = (int32) floor(I * float_(abs(LINK->a1 - LINK->a0)) / LINK->s + 0.5);
	if (K == 0)
		K = 1;
	return K;
}

static void 
setlengths(findex, LINK)
	int32           findex;
	struct LOC_tylBrokenLine *LINK;
{
	/* sets the "optimal" sizes for textured lines */
	int32           penrad;
	VThickness      siz;

	penrad = VFontTable[findex - 1]->PenSize;
	siz = VFontTable[findex - 1]->psize;

	LINK->Dotdot = penrad / siz;
	LINK->Dotgap = penrad * 6;
	LINK->Dashdash = penrad * 6;
	LINK->Dashgap = penrad * 6;
	LINK->DDotdash = penrad * 6;
	LINK->DDotgap = penrad * 4;
	LINK->DDotdot = penrad / siz;
}

static void 
setframesize(LINK)
	struct LOC_tylBrokenLine *LINK;
{
	switch (LINK->line_type)
	{
		/* length of frame depends on type of broken line */
	case solid:
		LINK->frame = 0;
		break;
	case dotted:
		LINK->frame = LINK->gap + LINK->dot;
		break;
	case dashed:
		LINK->frame = LINK->gap + LINK->dash;
		break;
	case dotdash:
		LINK->frame = LINK->gap * 2 + LINK->dot + LINK->dash;
		break;
	}
}

static void 
tylBrokenLine(x0, y0, x1, y1, fontindex_, line_type_)
	int32           x0, y0, x1, y1, fontindex_;
	LineStyle       line_type_;
{
	struct LOC_tylBrokenLine V;
	double          fit;
	int32           T, a1ma0;

	V.fontindex = fontindex_;
	V.line_type = line_type_;
	if (x0 == x1 && y0 == y1)
	{
		diagonal(x0, y0, x1, y1, V.fontindex);	/* null line */
		return;
	}

	setlengths(V.fontindex, &V);

	if (abs(y1 - y0) > abs(x1 - x0))
	{			/* longer axis is used as base */
		V.useXaxis = false;
		V.a0 = y0;
		V.b0 = x0;
		V.a1 = y1;
		V.b1 = x1;
	}
	else
	{
		V.useXaxis = true;
		V.a0 = x0;
		V.b0 = y0;
		V.a1 = x1;
		V.b1 = y1;
	}
	/* the distance between a0 and a1 is now greater than that between b0 and b1. */

	/* redefine distances as integral units along axes */
	V.s = distance(float_(V.a0), float_(V.b0), float_(V.a1), float_(V.b1));

	switch (V.line_type)
	{

	case solid:
		/* blank case */
		break;
	case dotted:
		V.gap = project(V.Dotgap, &V);
		V.dot = project(V.Dotdot, &V);
		break;
	case dashed:
		V.gap = project(V.Dashgap, &V);
		V.dash = project(V.Dashdash, &V);
		break;
	case dotdash:
		V.gap = project(V.DDotgap, &V);
		V.dot = project(V.DDotdot, &V);
		V.dash = project(V.DDotdash, &V);
		break;
	}

	/*
	 * ensure direction of line is from smaller to larger along the longer axis
	 */
	if (V.a0 > V.a1)
	{
		V.J = V.a0;
		V.a0 = V.a1;
		V.a1 = V.J;
		V.J = V.b0;
		V.b0 = V.b1;
		V.b1 = V.J;
	}

	setframesize(&V);

	a1ma0 = V.a1 - V.a0;

	/* fit is the number of frames that fit in line */
	if (V.frame != 0)
		fit = float_(a1ma0) / float_(V.frame);
	else
		fit = 1.0;

	if (fit >= 1.0)
		T = (int32) floor(fit + 0.5);
	else
	{
		/* change frame elements (dot, dash, gap) since frame is too large */
		switch (V.line_type)
		{

		case dotted:
			V.gap += a1ma0 - V.frame;
			if (V.gap < V.dot)
				return;	/* exit */
			setframesize(&V);
			break;

		case dashed:
		case dotdash:
			/* idea:decrease gap; if too small then shrink dash and refigure gap */
			if (V.frame - a1ma0 > V.gap / 2)
			{
				V.dash = (int32) floor(V.dash * fit * 0.80 + 0.5);
				V.gap = (int32) floor(V.gap * fit + 0.5);
				setframesize(&V);
			}
			V.gap += a1ma0 - V.frame;
			if (V.line_type == dotdash)
				V.gap /= 2;
			if (V.gap < V.dot)
				return;	/* exit */
			setframesize(&V);
			break;
		}		/* case */
		T = 1;		/* NOW it will fit */
	}			/* else */


	switch (V.line_type)
	{
	case solid:
		if (V.useXaxis)
			diagonal(V.a0, V.b0, V.a1, V.b1, V.fontindex);
		else
			diagonal(V.b0, V.a0, V.b1, V.a1, V.fontindex);
		break;
	case dotted:		/* dotted lines begin and end on a dot */
		if (T * V.frame + V.dot == a1ma0)
			spread(dotted, 0, T, &V);
		else if (T * V.frame + V.dot > a1ma0)
		{
			/*
			 * gap := gap - ((T*frame+dot)-a1ma0); {
			 */
			spread(dotted, a1ma0 - T * V.frame - V.dot, T, &V);

			/*
			 * spread(dotted, a1ma0 - (T-1)*frame - dot, T-1); {
			 */
		}
		else
			spread(dotted, a1ma0 - T * V.frame - V.dot, T, &V);
		break;
	case dashed:
		/*
		 * dashed lines begin and end on dash : the beginning and ending dashes are at least half the dash length
		 * int32.
		 */
		if (T * V.frame + V.dash == a1ma0)
			spread(dashed, 0, T, &V);
		else if (T * V.frame + V.dash > a1ma0)
			balance(dashed, T * V.frame + V.dash - a1ma0, T, &V);
		else
			spread(dashed, a1ma0 - T * V.frame - V.dash, T, &V);
		break;
	case dotdash:
		/*
		 * if ending on a dash then beginning and ending dashes are half the dash length long - final dots are full
		 * dot length
		 */
		if (T * V.frame + V.dash == a1ma0)
			spread(dotdash, 0, T, &V);
		else if (T * V.frame + V.dash + V.gap + V.dot == a1ma0)
			spread(dotdash, 0, T, &V);
		else if (T * V.frame + V.dash > a1ma0)
			balance(dotdash, T * V.frame + V.dash - a1ma0, T, &V);
		else if (T * V.frame + V.dash + V.gap + V.dot > a1ma0)
			spread(dotdash, a1ma0 - T * V.frame - V.dash, T, &V);
		else
			spread(dotdash, a1ma0 - T * V.frame - V.dash - V.gap - V.dot, T, &V);
		break;
	}
}

void 
clampthickness(thic)
	VThickness     *thic;
{
	/*
	 * #### this is just a simple clamp really should be something like: while not (thic in set_of_appropriate_thicknesses)
	 * do modify thic and try again
	 */
	if (*thic <= LoVThick)
		*thic = LoVThick + 1;
	while (((1 << (*thic)) & 0x1ffe) == 0 && *thic <= HiVThick)
		(*thic)++;
	if (*thic > HiVThick)
		*thic = HiVThick;
}

static void 
slurclamp(thic, totpts)
	VThickness     *thic;
	int32           totpts;
{
	/*
	 * this post-clamps the sampled thicknesses calculated over the whole of the spline
	 */
	int32           i, oneseventh, middle, startval, endval;
	double          deltaval, val, incrval, alpha, alphaincr;

	/*
	 * $$ NOTE:: How does the ttspline interpolation of thicknesses compare to the below results?? Can we avoid having it
	 * done elsewhere and concentrate on it here??
	 */

	oneseventh = (int32) floor(totpts / 7.0 + 0.5);
	for (i = 1; i <= oneseventh; i++)
		thic[i] = thic[1];
	for (i = oneseventh * 6; i <= totpts; i++)
		thic[i] = thic[totpts];

	middle = (int32) floor(totpts / 2.0 + 0.5);
	for (i = oneseventh * 3; i <= oneseventh * 4; i++)
		thic[i] = thic[middle];

	startval = thic[oneseventh - 1];
	endval = thic[oneseventh * 3 + 1];
	deltaval = (endval - startval) * 2.0 / (oneseventh * 2);
	alphaincr = PI / (oneseventh * 2 + 1);
	alpha = PI;
	val = float_(startval);
	for (i = oneseventh; i < oneseventh * 3; i++)
	{			/* interpolate: ease in from minthick to middlethickness */
		alpha += alphaincr;
		incrval = (cos(alpha) + 1.0) / 2.0 * deltaval;
		val += incrval;
		thic[i] = (int32) floor(val + 0.5);
	}

	startval = thic[oneseventh * 4 - 1];
	endval = thic[oneseventh * 6 + 1];
	deltaval = (endval - startval) * 2.0 / (oneseventh * 2);
	alphaincr = PI / (oneseventh * 2 + 1);
	alpha = 0.0;
	val = float_(startval);
	for (i = oneseventh * 4 + 1; i <= oneseventh * 6; i++)
	{			/* ease out from middle thickness to min thick at far end */
		alpha += alphaincr;
		incrval = (cos(alpha) + 1.0) / 2.0 * deltaval;
		val += incrval;
		thic[i] = (int32) floor(val + 0.5);
	}
}

void 
layline(xl, yb, xr, yt, fontindex, pattern, useVecfontOnly)
	int32           xl, yb, xr, yt, fontindex;
	LineStyle       pattern;
	int		useVecfontOnly;
{
	int32           t;

	if (xr < xl)
	{
		t = xr;
		xr = xl;
		xl = t;
		t = yb;
		yb = yt;
		yt = t;
	}

	isetfont(VFontTable[fontindex - 1]->DVIFontNum);

	/*
	 * we may want to require using a vector font only, instead of a combination of vectors and TeX-rules. It may look
	 * better this way.
	 */
	if (useVecfontOnly)
	{
		tylBrokenLine(xl, yb, xr, yt, fontindex, pattern);
		return;
	}

	if ((xl != xr || yb != yt) && (xl == xr || yb == yt))
	{			/* Null or diagonal lines */
		/*
		 * if (pattern = solid) then hvline (xl, yb, xr, yt, fontindex) (* make use of rules *) else USENORULES
		 */
		tylBrokenLine(xl, yb, xr, yt, fontindex, pattern);
		return;
	}
	if (pattern == solid)
		diagonal(xl, yb, xr, yt, fontindex);
	else
		tylBrokenLine(xl, yb, xr, yt, fontindex, pattern);
	/* be smart about the lines */
}


#define DontDoThicks    false
#define VectorsOnly     true

/* Local variables for layAspline: */
struct LOC_layAspline
{
	VThickness      thick;
};

void 
layAspline(thetype, isclosed, isanArc, domarks, cpts, numpts,
	   thick_, vkind, patt)
	SplineKind      thetype;
	int		isclosed, isanArc;
	int32           domarks;
int32(*cpts)[2];
	int32           numpts;
	VThickness      thick_;
	VectKind        vkind;
	LineStyle       patt;
{
	struct LOC_layAspline V;
	SplineSegments  pointList;
	int32           i, xs, ys;
	ThickAryType    tt1, tt2;
	VecIndex        F;
	int32           FORLIM;

	V.thick = thick_;
	clampthickness(&V.thick);
	for (i = 0; i <= numpts + 3; i++)
		tt1[i] = V.thick;

	/* do any marks if necessary to show the control points */
	if (domarks > 0)
	{
		F = GetVectFont((int) domarks, VKCirc);
		isetfont(VFontTable[F - 1]->DVIFontNum);
		for (i = 1; i <= numpts; i++)
			Tyldot(cpts[i][0], cpts[i][1]);
	}

	drawSpline(thetype, isclosed, isanArc, patt, numpts, cpts, pointList,
		   DontDoThicks, tt1, tt2);


	F = GetVectFont(V.thick, vkind);
	xs = pointList[0][0];
	ys = pointList[0][1];

	FORLIM = lastPoint;
	for (i = 1; i < FORLIM; i++)
	{
		layline(xs, ys, pointList[i][0], pointList[i][1], F, patt, VectorsOnly);
		xs = pointList[i][0];
		ys = pointList[i][1];
	}
	if (isclosed)		/* complete the motion */
		layline(pointList[lastPoint - 1][0], pointList[lastPoint - 1]
			[1], pointList[0][0], pointList[0][1], F, patt, VectorsOnly);
}

#define NotAnArc        false
#define DoThicksToo     true
#define VectorsOnly     true

void 
layNspline(thetype, isclosed, isitaslur, domarks, cpts, numpts,
	   thickmatrix, vkind, patt)
	SplineKind      thetype;
	int		isclosed, isitaslur;
	int32           domarks;
int32(*cpts)[2];
	int32           numpts;
	VThickness     *thickmatrix;
	VectKind        vkind;
	LineStyle       patt;
{
	SplineSegments  pointList;
	int32           i, xs, ys;
	VThickness      ts;
	ThickAryType    tt;
	VecIndex        F;
	int32           FORLIM;

	/* do any marks if necessary to show the control points */
	if (domarks > 0)
	{
		F = GetVectFont((int) domarks, VKCirc);
		isetfont(VFontTable[F - 1]->DVIFontNum);
		for (i = 1; i <= numpts; i++)
			Tyldot(cpts[i][0], cpts[i][1]);
	}

	drawSpline(thetype, isclosed, NotAnArc, patt, numpts, cpts, pointList,
		   DoThicksToo, thickmatrix, tt);
	if (isitaslur && !skiptsclamp)
		slurclamp(tt, lastPoint);	/* which kind of clamping to use */

	xs = pointList[0][0];
	ys = pointList[0][1];
	ts = tt[1];

	FORLIM = lastPoint;
	for (i = 1; i < FORLIM; i++)
	{
		clampthickness(&ts);
		F = GetVectFont(ts, vkind);
		layline(xs, ys, pointList[i][0], pointList[i][1], F, patt, VectorsOnly);
		xs = pointList[i][0];
		ys = pointList[i][1];
		ts = tt[i + 1];
	}
	if (!isclosed)
		return;
	ts = tt[lastPoint];
	clampthickness(&ts);
	F = GetVectFont(ts, vkind);
	layline(pointList[lastPoint - 1][0], pointList[lastPoint - 1]
		[1], pointList[0][0], pointList[0][1], F, patt, VectorsOnly);
}

/* && start dvidvi section */
/*-----------------------------------------------------*/
static void 
initialize()
{
	initVnMnLtables();
	multifigure = 0;
	pgfigurenum = 0;
	TotBytesWritten = 0;
	ourq = 0;
	currpagenum = 0;
	FTBDs = 0;
	InitDVIBuf();
	inpostamble = false;
	didnewfonts = false;
	skiptsclamp = false;
	ErrorOccurred = false;
}

/*-----------------------------------------------------*/
static int 
inTFM(z)
	int32           z;
{
	int32           k, lh, nw, alpha, beta, FORLIM;
	fontinfo	*WITH;

	readtfmword();
	lh = b2 * 256 + b3;
	readtfmword();
	font[nf].bc = b0 * 256 + b1;
	font[nf].ec = b2 * 256 + b3;
	if (font[nf].ec < font[nf].bc)
		font[nf].bc = font[nf].ec + 1;
	readtfmword();
	nw = b0 * 256 + b1;
	if (nw == 0 || nw > 256)
		return (false);
	for (k = 1; k <= lh + 3; k++)
	{
		if (feof(tfmfile))
			return (false);
		readtfmword();
		if (k == 4)
		{
			if (b0 < 128)
				tfmchecksum = ((b0 * 256 + b1) * 256 + b2) * 256 + b3;
			else
				tfmchecksum = (((b0 - 256) * 256 + b1) * 256 + b2) * 256 + b3;
		}
	}

	FORLIM = font[nf].ec - font[nf].bc;
	for (k = 0; k <= FORLIM; k++)
	{
		readtfmword();
		if (b0 > nw)
			return (false);
		font[nf].widths[k] = b0;
	}
	alpha = z * 16;
	beta = 16;
	while (z >= TWO23)
	{
		z /= 2;
		beta /= 2;
	}
	for (k = 0; k < nw; k++)
	{
		readtfmword();
		inwidth[k] = ((b3 * z / 256 + b2 * z) / 256 + b1 * z) / beta;
		if (b0 > 0)
		{
			if (b0 < 255)
				return (false);
			inwidth[k] -= alpha;
		}
	}
	if (inwidth[0] != 0)
		return (false);
	WITH = &font[nf];	/* with */
	FORLIM = WITH->ec - WITH->bc;
	for (k = 0; k <= FORLIM; k++)
	{
		if (WITH->widths[k] == 0)
		{
			WITH->widths[k + WITH->bc] = TWO31;
			/* pixelwidths[k + bc] := 0; */
		}
		else
		{
			WITH->widths[k + WITH->bc] = inwidth[WITH->widths[k]];
			/* pixelwidths[k + bc] := round(conv * widths[k]); */
		}
	}
	return (true);
}

static void 
Fastdefinefont(fn)
	int32           fn;
{
	int32           p, k, n;

	(void) Dsign4byte();
	(void) Dsign4byte();
	(void) Dsign4byte();
	p = Dget1byte();
	n = Dget1byte();
	for (k = 1; k <= p + n; k++)
		(void) Dget1byte();
}				/* Fastdefinefont */

static void 
definefont(e)
	int32           e;
{
	char            f;
	int32           p, k, n, c, q, d;
	charstring      tfmname;

	if (nf == MAXFONTS)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "TeXtyl capacity exceeded (max fonts=%d)!\n",
			MAXFONTS);
		jumpout();
	}
	font[nf].num = e;
	f = 0;
	while (font[f].num != e)/* find first occurrence */
		f++;
	c = Dsign4byte();
	font[nf].checksum = c;
	q = Dsign4byte();
	font[nf].scaledsize = q;
	d = Dsign4byte();
	font[nf].designsize = d;
	p = Dget1byte();
	n = Dget1byte();
	for (k = 0; k < p + n; k++)
		font[nf].name[k] = Dget1byte();
	font[nf].name[k] = '\0';

	if (f != nf)		/* f = nf */
		return;

	strcpy(tfmname, font[nf].name);
	strcat(tfmname, ".tfm");

	if (!opentfmfile(tfmname))
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loaded, TFM file can't be opened!\n", tfmname);
		jumpout();
		return;
	}
	if (q <= 0 || q >= TWO27)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loaded, bad scale (%d)!\n", tfmname, q);
		return;
	}
	if (d <= 0 || d >= TWO27)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loaded, bad design size (%d)!\n", tfmname, d);
		return;
	}
	if (!inTFM(q))
	{			/* intfm */
		complain(ERRREALBAD);
		fprintf(logfile, "%s---not loaded, TFM file is bad\n", tfmname);
		return;
	}			/* intfm */
	font[nf].space = q / 6;
	if (c != 0 && tfmchecksum != 0 && c != tfmchecksum)
	{
		fprintf(logfile, "Problem in fig#%d on page %d\n",
			pgfigurenum, currpagenum);
		fprintf(logfile, "%s---beware: check sums do not agree!\n", tfmname);
		fprintf(logfile, "   (%d vs. %d)\n", c, tfmchecksum);
	}
	d = (int32) floor(100.0 * conv * q / (trueconv * d) + 0.5);
	nf++;
	font[nf].space = 0;
}

static int32 
firstpar(o)
	int             o;
{
	int32           fpar;

	if (0 <= o && o <= 127)
		fpar = o;
	else if (171 <= o && o <= 234)
		fpar = o - 171;
	else
		switch (o)
		{
		case 128:
		case 133:
		case 235:
		case 239:
		case 243:
			fpar = Dget1byte();
			break;
		case 129:
		case 134:
		case 236:
		case 240:
		case 244:
			fpar = Dget2byte();
			break;
		case 130:
		case 135:
		case 237:
		case 241:
		case 245:
			fpar = Dget3byte();
			break;
		case 143:
		case 148:
		case 153:
		case 157:
		case 162:
		case 167:
			fpar = Dsign1byte();
			break;
		case 144:
		case 149:
		case 154:
		case 158:
		case 163:
		case 168:
			fpar = Dsign2byte();
			break;
		case 145:
		case 150:
		case 155:
		case 159:
		case 164:
		case 169:
			fpar = Dsign3byte();
			break;
		case 131:
		case 132:
		case 136:
		case 137:
		case 146:
		case 151:
		case 156:
		case 160:
		case 165:
		case 170:
		case 238:
		case 242:
		case 246:
			fpar = Dsign4byte();
			break;
		case 138:
		case 139:
		case 140:
		case 141:
		case 142:
		case 247:
		case 248:
		case 249:
		case 250:
		case 251:
		case 252:
		case 253:
		case 254:
		case 255:
			fpar = 0;
			break;
		case 147:
			fpar = w;
			break;
		case 152:
			fpar = x;
			break;
		case 161:
			fpar = y;
			break;
		case 166:
			fpar = z;
			break;
		}
	return fpar;
}

static int 
specialcases(o, p)
	int32           o, p;
{
	if (o < 157 || o > 249)
	{
		complain(ERRREALBAD);
		fprintf(logfile, "undefined command %d!\n", o);
		return (true);
	}
	else if (171 <= o && o <= 238)
	{
		font[nf].num = p;
		curfont = 0;
		while (font[curfont].num != p)
			curfont++;
		return (true);
	}
	switch (o)
	{
	case 157:
	case 158:
	case 159:
	case 160:
		break;
	case 161:
	case 162:
	case 163:
	case 164:
	case 165:
		y = p;
		break;
	case 166:
	case 167:
	case 168:
	case 169:
	case 170:
		z = p;
		break;
	case 243:
	case 244:
	case 245:
	case 246:
		definefont(p);
		return (true);
	case 239:
	case 240:
	case 241:
	case 242:		/* =========specials============= */
		mainhandlespecials(o, p);
		return (true);
	case 247:
		complain(ERRREALBAD);
		fprintf(logfile, "preamble command within a page!\n");
		return (false);
	case 248:
	case 249:
		complain(ERRREALBAD);
		fprintf(logfile, "postamble command within a page!\n");
		return (false);
	}
	if (v > 0 && p > 0)
	{
		if (v > TWO31 - p)
			p = TWO31 - v;
	}
	if (v < 0 && p < 0)
	{
		if (-v > p + TWO31)
			p = -v - TWO31;
	}
	v += p;
	return (true);
}

static int 
dopage()
{
	int32           o, p, q;
	struct stackrec *WITH;

	curfont = nf;
	s = 0;
	h = 0;
	v = 0;
	w = 0;
	x = 0;
	y = 0;
	z = 0;

	ourxpos = 0;
	ourypos = 0;
	ourfontnum = -1;
	for (;;)
	{
		o = Dget1byte();
		p = firstpar(o);
		if (feof(dvifile))
		{
			fprintf(logfile, "Bad DVI file: the file ended prematurely!\n");
			jumpout();
		}
		if (o <= 131)
			goto _L41;
		if (o > 156)
		{
			if (specialcases(o, p))
				continue;
			else
				return (false);
		}

		switch (o)
		{
		case 133:
		case 134:
		case 135:
		case 136:
			goto _L41;
			break;
		case 132:
		case 137:
			goto _L42;
			break;
		case 138:
			continue;
		case 139:	/* BOP */
			complain(ERRREALBAD);
			fprintf(logfile, "bop occurred before eop\n");
			return (false);	/* Fail */
			break;
		case 140:	/* EOP */
			if (s != 0)
			{
				complain(ERRREALBAD);
				fprintf(logfile, "stack not empty at end of page (level %d)!\n", s);
			}
			if (multifigure != 0)
			{
				complain(ERRBAD);
				fprintf(logfile,
					"Some figure definition not closed at end of page %d!\n",
					currpagenum);
			}
			fprintf(logfile, "%d]", currpagenum);
			if (currpagenum % 10 == 0)
				putc('\n', logfile);
			return (true);
		case 141:	/* PUSH */
			WITH = &stack[s];	/* with */
			WITH->sh = h;
			WITH->sv = v;
			WITH->sw = w;
			WITH->sx = x;
			WITH->sy = y;
			WITH->sz = z;
			s++;
			continue;
		case 142:	/* POP */
			if (s == 0)
			{
				complain(ERRREALBAD);
				fprintf(logfile, "illegal pop at level zero!\n");
			}
			else
			{
				s--;
				WITH = &stack[s];
				h = WITH->sh;
				v = WITH->sv;
				w = WITH->sw;
				x = WITH->sx;
				y = WITH->sy;
				z = WITH->sz;
			}
			continue;
		case 143:
		case 144:
		case 145:
		case 146:
			q = p;
			goto _L43;
			break;
		case 147:
		case 148:
		case 149:
		case 150:
		case 151:
			w = p;
			q = p;
			goto _L43;
			break;
		case 152:
		case 153:
		case 154:
		case 155:
		case 156:
			x = p;
			q = p;
			goto _L43;
			break;
		}		/* case */
_L41:				/* finish cmd to set/put a char */
		if (p < 0)
			p = 255 - ((-p - 1) & 255);
		else if (p >= 256)
			p &= 255;
		if (p < font[curfont].bc || p > font[curfont].ec)
			q = TWO31;
		else
			q = font[curfont].widths[p];
		if (q == TWO31)
		{
			complain(ERRREALBAD);
			fprintf(logfile, "Character %d invalid in font #%d\n", p, curfont);
		}
		if (o >= 133)
			continue;
		if (q == TWO31)
			q = 0;
		goto _L43;
_L42:				/* finish cmd to set/put rule */
		q = Dsign4byte();
		if (o == 137)
			continue;
		goto _L43;
_L43:				/* finish cmd that sets h += q */
		if (h > 0 && q > 0)
		{
			if (h > TWO31 - q)
				q = TWO31 - h;
		}
		if (h < 0 && q < 0)
		{
			if (-h > q + TWO31)
				q = -h - TWO31;
		}
		h += q;
	}
}

static void 
skippages()
{
	int32           p;
	int32           k;

	for (;;)
	{
		if (feof(dvifile))
		{
			fprintf(logfile, "Bad DVI file: the file ended prematurely!\n");
			jumpout();
		}
		k = Dget1byte();
		p = firstpar(k);
		switch (k)
		{
		case 139:	/* BOP */
			newbackptr = DVIMark() + TotBytesWritten - 1;
			currpagenum = Dsign4byte();	/* count[0] */
			for (k = 1; k <= 9; k++)	/* WAS count[k] := */
				(void) Dsign4byte();
			(void) Dsign4byte();
			BackupInBuf(4);
			cmdSigned(oldbackptr, 4);
			oldbackptr = newbackptr;
			fprintf(logfile, "[");
			return;
		case 132:
		case 137:	/* RULE */
			(void) Dsign4byte();
			break;
		case 243:
		case 244:
		case 245:
		case 246:
			definefont(p);
			break;
		case 239:
		case 240:
		case 241:
		case 242:	/* specials */
			mainhandlespecials(k, p);
			break;
		case 248:	/* POST */
			ourq = DVIMark() + TotBytesWritten - 1;
			inpostamble = true;
			return;
		}
	}
}

static void 
readpostamble()
{
	int32           k, p, m, indx, FORLIM;
	MusFontInfRec  *WITH;
	VectFontInfRec *WITH1;
	LabFontInfRec  *WITH2;

	if (Dsign4byte() != numerator)
		fprintf(logfile, "Postamble numerator doesn't match the preamble!\n");
	if (Dsign4byte() != denominator)
		fprintf(logfile, "Postamble denominator doesn't match the preamble!\n");
	if (Dsign4byte() != mag)
		fprintf(logfile, "Postamble magnification doesn't match the preamble!\n");
	maxv = Dsign4byte();
	maxh = Dsign4byte();
	maxs = Dget2byte();
	BackupInBuf(2);
	cmd2byte(maxs + 2);
	/*
	 * pretend the stack depth does not increase by more than two
	 */
	totalpages = Dget2byte();
	do
	{
		k = Dget1byte();
		if (k >= 243 && k < 247)
		{
			p = firstpar(k);
			Fastdefinefont(p);
			k = 138;
		}
	} while (k == 138);	/* NOP */

	/*
	 * here, backup 1, enter all our fonts and then output the 249 that we backed over
	 */
	BackupInBuf(1);
	FORLIM = MFontsDefd;
	for (indx = 0; indx < FORLIM; indx++)
	{
		WITH = MFontTable[indx];
		enterfont(WITH->DVIFontNum, WITH->Cksum, WITH->DesSize, WITH->DesSize,
			  WITH->FontName);
	}			/* for */
	FORLIM = VFontsDefd;
	for (indx = 0; indx < FORLIM; indx++)
	{
		WITH1 = VFontTable[indx];
		enterfont(WITH1->DVIFontNum, WITH1->Cksum, WITH1->DesSize, WITH1->DesSize,
			  WITH1->FontName);
	}			/* for */
	FORLIM = LFontsDefd;
	for (indx = 0; indx < FORLIM; indx++)
	{
		WITH2 = LFontTable[indx];
		enterfont(WITH2->DVIFontNum, WITH2->Cksum, WITH2->DesSize, WITH2->DesSize,
			  WITH2->FontName);
	}
	cmd1byte(249);		/* post post */

	if (k != 249)
		fprintf(logfile, "byte %d is not postpost!\n", k);
	(void) Dsign4byte();
	BackupInBuf(4);
	cmd4byte(ourq);
	m = Dget1byte();
	if (m != 2)
		fprintf(logfile, "identification should be %d!\n", 2);
	m = 223;
	while ((m == 223) && (!feof(dvifile)))
		m = Dget1byte();
	if (feof(dvifile))
		return;
	fprintf(logfile, "Bad DVI file: signature in should be 223!\n");
	jumpout();
}


/* MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN MAIN */
int
main(argc, argv)
	int             argc;
	char           *argv[];
{
	void		exit PP((int));

	if (setjmp(_JL666))
		goto _L666;
	initialize();
	if (argc < 3)
	{
		fprintf(stderr, "Usage: textyl dvi-in dvi-out\n");
		exit(1);
	}
	if ((dvifile = fopen(argv[1], "r")) == NULL)
	{
		perror(argv[1]);
		exit(1);
	}
	if ((outputfil = fopen(argv[2], "w")) == NULL)
	{
		perror(argv[2]);
		exit(1);
	}
	logfile = stdout;
	fprintf(logfile, "%s for Berkeley Unix\n", TylVersion);

	p = Dget1byte();
	if (p != 247)
	{
		fprintf(logfile, "Bad DVI file: First byte isn't start of preamble!!\n");
		jumpout();
	}
	p = Dget1byte();
	if (p != 2)
		fprintf(logfile, "identification in byte 1 should be %d!\n", 2);
	numerator = Dsign4byte();
	denominator = Dsign4byte();
	if (numerator <= 0)
	{
		fprintf(logfile, "Bad DVI file: numerator is %d!\n", numerator);
		jumpout();
	}
	if (denominator <= 0)
	{
		fprintf(logfile, "Bad DVI file: denominator is %d!\n", denominator);
		jumpout();
	}
	conv = numerator / 254000.0 * (resolution / denominator);
	mag = Dsign4byte();
	if (mag <= 0)
	{
		fprintf(logfile, "Bad DVI file: magnification is % .1E!\n", mag);
		jumpout();
	}
	magfactor = mag / 1000.0;
	trueconv = conv;
	conv = trueconv * magfactor;
	p = Dget1byte();	/* the 'k' of the preamble */
	while (p > 0)
	{
		p--;
		(void) Dget1byte();
	}

	skippages();
	if (!inpostamble)
	{
		while (maxpages-- > 0)
		{		/* while */
			if (!dopage())
			{
				printf(" Bad DVI file: page ended unexpectedly!");
				fprintf(logfile, "Bad DVI file: page ended unexpectedly!\n");
				jumpout();
			}
			WriteDVIBuf();
			ClearDVIBuf();
			multifigure = 0;
			pgfigurenum = 0;
			FTBDs = 0;
			didnewfonts = false;
			do
			{
				k = Dget1byte();
				if (k >= 243 && k < 247)
				{	/* fontdefs */
					p = firstpar(k);
					definefont(p);
					k = 138;
				}
			} while (k == 138);	/* nop */

			if (k == 248)
			{
				inpostamble = true;
				ourq = DVIMark() + TotBytesWritten - 1;
				break;
			}

			if (k != 139)
			{	/* BOP */
				fprintf(logfile, "We did not find BOP when expected\n");
				jumpout();
				continue;
			}

			newbackptr = DVIMark() + TotBytesWritten - 1;
			currpagenum = Dsign4byte();	/* Count[0] */
			for (k = 1; k <= 9; k++)	/* WAS count[k] := */
				(void) Dsign4byte();
			(void) Dsign4byte();	/* backpointer */
			BackupInBuf(4);
			cmdSigned(oldbackptr, 4);
			oldbackptr = newbackptr;
			fprintf(logfile, "[");
		}		/* while */
	}			/* if not inpostamble */
	if (!inpostamble)
		skippages();
	(void) Dsign4byte();	/* ptr to the last bop in file */
	BackupInBuf(4);
	cmdSigned(oldbackptr, 4);
	readpostamble();
	WriteDVIBuf();

	while ((TotBytesWritten & 3) != 0)	/* final signatures */
		OutputByte(223);

	fprintf(logfile, "(%d page", currpagenum);
	if (currpagenum > 1)
		putc('s', logfile);
	fprintf(logfile, ", %d bytes).\n", TotBytesWritten);

_L666:
	if (ErrorOccurred)
	{
		fprintf(logfile, "\nSome error(s) occurred.\n");
		fprintf(logfile, "Assume that the outputfile is incorrect\n");
	}
	if (dvifile != NULL)
		fclose(dvifile);
	if (tfmfile != NULL)
		fclose(tfmfile);
	if (outputfil != NULL)
		fclose(outputfil);
	if (logfile != NULL)
		fclose(logfile);
	exit(0);
	return (0);
}