DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦a4c85a45c⟧ TextFile

    Length: 35849 (0x8c09)
    Types: TextFile
    Names: »df.c.backup«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./DVIware/laser-setters/quicspool/src/df.c.backup« 
└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦af5ba6c8e⟧ »unix3.0/DVIWARE.tar.Z« 
        └─⟦ca79c7339⟧ 
            └─⟦this⟧ »DVIware/laser-setters/quicspool/src/df.c.backup« 

TextFile

/* TeX driver */
/*
$Log:	df.c.backup,v $
Revision 1.2  88/02/03  08:52:23  simpson
added tpic support

Revision 1.1  88/01/15  13:03:27  simpson
initial release

Revision 0.2  87/12/18  11:39:36  simpson
added void for lint

Revision 0.1  87/12/11  18:30:46  simpson
beta test

*/
#ifndef lint
static char *rcs = "$Header: df.c.backup,v 1.2 88/02/03 08:52:23 simpson Exp $";
#endif
#include <stdio.h>
#include <signal.h>
#include <assert.h>
#include <math.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <local/profile.h>
#include <local/qms.h>
#include "dvi.h"
#include "constants.h"
#include "fontinfo.h"
#include "fontnode.h"

/* Cast for accessing LocalInfo */
#define LI(p)	((struct LocalInfo *)p->localinfo)

struct Stack {
    long h, v, w, x, y, z;
};

struct DviNode {
    long		dvinumber;
    struct DviNode	*next;
};

struct LocalInfo {
    long 	widths[256];	/* RSUs. Font but ! file mag in account */
    short	mapsize[2][256];/* Width & height of each char bitmap */
    int		qmsheight;	/* Height to give QMS printer */
    int		qmsbaseline;	/* Baseline height to give QMS printer */
    struct DviNode *dvifontnumbers; /* List of #s DVI file uses */
    char	pathname[81];	/* Full pathname in file system */
};

double	ConvInches;	    /* RSU->inches. File mag not taken into account */
char	*Whoami;	    /* argv[0] */
char    Orientation = 'P';  /* P=Portrait, L=Landscape */
char    *Model;		    /* Model of printer being used */
char	PKName[101];	    /* Only used by pkeofsocleanup() */
char	*Xxxstring;	    /* String found in XXX? command */
char 	*Pxxxstring;	    /* And a pointer used by lexical analyzer */
char	PKDir[101];	    /* Location of PK font files */
int     Magnification;	    /* Magnification file was TeXed at (x1000) */
int	MaxBlocks;	    /* # of free blocks w/out ram or rom fonts, ovls */
int	CurRamBlocks;	    /* # of blocks used by ram fonts */
int	CurRomBlocks;	    /* # of blocks used by rom fonts */
int     DownLoadFNum;	    /* Number of font currently being downloaded */
int	UserFontCount = 30001;	/* User fonts start getting #s from here */
int	Origin[2];		/* Origin of a postprocessor graph in pixels */
long    Numerator, Denominator; /* From .dvi preamble */
FILE    *ReadLine;	    /* Debugger port tty */
struct sigvec   SigStruct;
struct FontNode *FontList;  /* List containing all fnts & their attributes */
extern char    *Host, *User;
extern FILE    *Accting;
extern Boolean Accounting;
extern int     NumPages;

main(argc, argv)
int	argc;
char	*argv[];
{
    extern char	*optarg;
    extern int	optind;
    void	qmsfntfree(), cleanup(), dvieofsoexit(), readpreamble(),
    		seteoffunction(), dvieofsocleanup(), process();
    Boolean	found, loadnametable(), setnewid();
    int		c;
    int		*intptr, *tempintptr;
    int		simplyexit(), callcleanup();
    int		romlist[41];			/* List of rom font #s */
    char	*strcpy();
#ifdef DEBUG
    char	*malloc(), orien;
    int		i, fontno, size;
    struct fontnode *fn;
    FILE	*f;
#endif
    PROFILE_VALUE	*v, *getbindingvalue();
    struct qmsram	*raminfo;
    struct qmsfnt	*fntinfo;
    struct FontNode	*createfontlist();
    struct fontnode	*p;		

    Whoami = argv[0];
    while ((c = getopt(argc, argv, "x:y:n:h:w:l:i:")) != EOF)
	switch (c) {
	case 'x':
	    if (atoi(optarg) > 2550)
		Orientation = 'L';
	    break;
	case 'h':
	    Host = optarg;
	    break;
	case 'n':
	    User = optarg;
	    break;
	case 'y':
	case 'w':
	case 'l':
	case 'i':
	    break;
	default:
	    exit(2);
	}
    SigStruct.sv_handler = simplyexit;
    SigStruct.sv_mask = 0;
    SigStruct.sv_onstack = 0;
    (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL);
    if (optind < argc) {
	Accounting = TRUE;
	if (!(Accting = fopen(argv[optind], "a"))) {
	    fprintf(stderr, "%s: cannot open accounting file %s\n", Whoami,
	    argv[optind]);
	    Accounting = FALSE;
	}
    }
    if (!(v = getbindingvalue("model")) || v->class != PROFILE_STRING &&
    v->class != PROFILE_OTHER) {
	fprintf(stderr,
	"%s: model binding missing or invalid in configuration file\n",
	Whoami);
	exit(2);
    }
    Model = v->value.s;
    fputs(QUICON, stdout);
    printf("%s^Z%s%s", CLEAROVERLAY, CLEARAOVERLAY, ENDCMD);
    fputs(QUICOFF, stdout);
    (void)fflush(stdout);
    if (!(v = getbindingvalue("readline")) || v->class != PROFILE_STRING &&
    v->class != PROFILE_OTHER) {
	fprintf(stderr,
	"%s: readline binding missing or invalid in configuration file\n",
	Whoami);
	exit(2);
    }
    if (!(ReadLine = fopen(v->value.s, "r"))) {
	fprintf(stderr, "%s: could not open %s for reading\n", Whoami,
	v->value.s);
	exit(2);
    }
#ifdef DEBUG
    raminfo = (struct qmsram *)malloc((unsigned)sizeof(struct qmsram));
    raminfo->TR = 401;
    raminfo->AR = 387;
    raminfo->FR = 13;
    raminfo->OR = 0;
#else
    qmsopen(fileno(stdout), fileno(ReadLine));
    if (!(raminfo = qmsram())) {
	fprintf(stderr, "%s: could not get printer ram info\n", Whoami);
	exit(2);
    }
#endif
    MaxBlocks = raminfo->AR + raminfo->FR;
    /* Save 5 blocks for filling with tpic */
    MaxBlocks -= 5;
#ifdef DEBUG
    fntinfo = (struct qmsfnt *)malloc((unsigned)sizeof(struct qmsfnt));
    fntinfo->ram = fntinfo->rom = NULL;
    for (i = 0; i < 13; i++) {
    	switch (i) {
	case 0:
	    fontno = 521;
	    orien = 'L';
	    break;
	case 1:
	    fontno = 522;
	    orien = 'L';
	    break;
	case 2:
	    fontno = 523;
	    orien = 'L';
	    break;
	case 3:
	    fontno = 524;
	    orien = 'L';
	    break;
	case 4:
	    fontno = 1100;
	    orien = 'P';
	    break;
	case 5:
	    fontno = 1103;
	    orien = 'P';
	    break;
	case 6:
	    fontno = 1200;
	    orien = 'P';
	    break;
	case 7:
	    fontno = 1204;
	    orien = 'P';
	    break;
	case 8:
	    fontno = 1217;
	    orien = 'L';
	case 9:
	    fontno = 7009;
	    orien = 'P';
	    break;
	case 10:
	    fontno = 7010;
	    orien = 'P';
	    break;
	case 11:
	    fontno = 7036;
	    orien = 'P';
	    break;
	case 12:
	    fontno = 7037;
	    orien = 'P';
	    break;
	}
        fn = (struct fontnode *)malloc((unsigned)sizeof(struct fontnode));
        fn->next = fntinfo->rom, fntinfo->rom = fn;
        fn->orientation = orien;
        fn->number = fontno;
	fn->bytes = 1024;	/* Rom fonts occupy one block */
	fn->version = '0';
	fn->class = '1';
    }
    /* For testing, ramfonts contains the already loaded fonts.  It should 
     * consist of lines containing two numbers and a letter, the first being 
     * the font number, the second being the font size, and the third letter
     * is an orientation.  The orientation should be the character immediately 
     * after the size of the font.
     */
    if (f = fopen("ramfonts", "r")) {	/* File is optional for testing */
	while (fscanf(f, "%d%d%c", &fontno, &size, &orien) == 3)
	{
	    fn = (struct fontnode *)malloc((unsigned)sizeof(struct fontnode));
	    fn->next = fntinfo->ram, fntinfo->ram = fn;
	    fn->orientation = orien;
	    fn->number = fontno;
	    fn->bytes = size;
	    fn->version = '0';
	    fn->class = '1';
	    raminfo->AR -= CEILING(size / 1024.0);
	    raminfo->FR += CEILING(size / 1024.0);
	}
	fclose(f);
    }
#else
    if (!(fntinfo = qmsfnt())) {
	fprintf(stderr, "%s: could not get printer font info\n", Whoami);
	exit(2);
    }
#endif
    for (CurRomBlocks = 0, p = fntinfo->rom; p; p = p->next)
	CurRomBlocks += CEILING(p->bytes / (double)1024);
    CurRamBlocks = raminfo->FR - CurRomBlocks;
    /* Make an array of rom font #s */
    for (p = fntinfo->rom, intptr = romlist; p; p = p->next) {
	for (tempintptr = romlist, found = FALSE; tempintptr < intptr;
	tempintptr++)
	    if (*tempintptr == p->number)
	    	found = TRUE;
	if (!found)
	    *intptr++ = p->number;
    }
    *intptr = 0;
    if (EQ(Model, "QMS800"))
	(void)strcpy(PKDir, "--PKDIR1--");
    else
	(void)strcpy(PKDir, "--PKDIR2--");
    if (!loadnametable(PKDir, romlist, 1)) {
	fprintf(stderr, "%s: could not open font directory %s\n", Whoami,
	PKDir);
	exit(2);
    }
    FontList = createfontlist(fntinfo);
    qmsfntfree(fntinfo);
    if (!setnewid(Host, User)) {
	fprintf(stderr, "%s: could not change user id to %s\n", Whoami,
	User);
	exit(2);		/* This is fatal, bud. */
    }
    seteoffunction(dvieofsoexit);
    readpreamble();
    SigStruct.sv_handler = callcleanup;
    (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL);
    fputs(QUICON, stdout);
    if (Orientation == 'P')
    	fputs(PORTRAIT, stdout);
    else
    	fputs(LANDSCAPE, stdout);
    printf("%s%c%c", TEXTPROC, '0', '0');
    printf("%s00000%05d", INITMARGVERT, Orientation == 'P' ? 11 * 1000 :
    (int)(8.5 * 1000));
    printf("%s00000%05d", INITMARGHORZ, Orientation == 'P' ? (int)(8.5 *
    1000) : 11 * 1000);
    printf("%s0000", CHARSPACING);
    fputs(FREEOFF, stdout);
    seteoffunction(dvieofsocleanup);
    process();
    cleanup(FontList, SUCCEED);
}

/* Reads the info in the DVI preamble */
void readpreamble()
{
    int			i, k;
    long		integer();
    unsigned long	uinteger();

    if (cgetchar() != PRE) {
	fprintf(stderr, "%s: input file is not a DVI file\n", Whoami);
	exit(2);
    }
    if (cgetchar() != DVIID) {
	fprintf(stderr, "%s: wrong version of DVI file \n", Whoami);
	exit(2);
    }
    Numerator = uinteger(stdin, 4);
    Denominator = uinteger(stdin, 4);
    Magnification = integer(stdin, 4);
    k = cgetchar();		/* Ignore comment */
    for (i = 0; i < k; i++)
    	(void)cgetchar();
    ConvInches = 1 / 100000.0 / 2.54;
    /* RSU       1m      100cm   1inch    n inches */
    /*     x --------- x ----- x ------ =          */
    /*       10^7 RSUs     1m    2.54cm            */
}
    
/* Main routine that interprets the DVI file */
void process()
{
    unsigned long uinteger(), ulk, uli;
    struct FontNode *curfontnode = NULL, *getdvifontnode(), *tempcurfontnode;
    struct Stack    *tempstack;
    Boolean	download(), makeroom(), fontselected = FALSE;
    int		ch, ldirectory, lfontname, i;
    long	dvifontnum, dvichecksum, scalefactor, designsize, curfontnum,
    		integer(), a, b;
    char	directory[256], fontname[256], *push(), *pop(), *malloc();
    void	fonttolist(), adjust(), endoflist();
    long	h, v, w, x, y, z;	/* In RSUs. Mag not taken in account */
    long	realhpxl, realvpxl;	/* Real h & v in printer in pixels */
    long	virthpxl, virtvpxl;	/* Virtual h & v current point in */
    					/* pixels.  Mag is taken in account */

    for (ch = cgetchar(); ch != BOP; ch = cgetchar())
    	switch (ch) {
	case NOP:
	    break;
	case FNTDEF1:
	case FNTDEF2:
	case FNTDEF3:
	case FNTDEF4:
	    dvifontnum = integer(stdin, ch - FNTDEF1 + 1);
	    dvichecksum = integer(stdin, 4);
	    scalefactor = integer(stdin, 4);
	    designsize = integer(stdin, 4);
	    ldirectory = cgetchar();
	    lfontname = cgetchar();
	    for (i = 0; i < ldirectory; i++)
	    	directory[i] = cgetchar();
	    directory[i] = '\0';
	    for (i = 0; i < lfontname; i++)
	        fontname[i] = cgetchar();
	    fontname[i] = '\0';
	    fonttolist(dvifontnum, dvichecksum, scalefactor, designsize,
	    directory, fontname);
	    break;
	default:
#ifndef lint
	    assert(FALSE);
#else
	    ;
#endif
	    cleanup(FontList, 2);
	}
    while (ch == BOP) {
	for (i = 0; i < 10; i++)
	    (void)integer(stdin, 4);
	(void)uinteger(stdin, 4);	/* Pointer to previous page */
	virthpxl = virtvpxl = realhpxl = realvpxl = h = v = w = x = y = z = 0;
	for (ch = cgetchar(); ch != EOP; ch = cgetchar()) {
	    virthpxl = ROUND(h*ConvInches*RESOLUTION*(Magnification/1000.0));
	    virtvpxl = ROUND(v*ConvInches*RESOLUTION*(Magnification/1000.0));
	    if (SETCHAR0 <= ch && ch < 128) {
		/* The following statement will only be true if the first
		 * font in the dvi file was not found at any magnification.
		 * In this case, skip this character since we don't know
		 * how to increment the virtual or real pixel locations!
		 * The true coordinates will probably be reset when TeX
		 * pops the stack at the beginning of a line.
		 */
		if (!curfontnode || !curfontnode->localinfo)
		    continue;
		adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		if (!(curfontnode->flags & LOADED)) {
		    if (!makeroom(FontList, MaxBlocks, &CurRamBlocks, 
		    CurRomBlocks, curfontnode->blocksize)) {
			fprintf(stderr, 
			"%s: could not free %d blocks for font %s\n", Whoami,
			curfontnode->blocksize, LI(curfontnode)->pathname);
			goto trytocontinue1;
		    }
		    if (!download(curfontnode))
		    	goto trytocontinue1;
		    realhpxl = realvpxl = 0;
		    adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		}
		if (!fontselected) {
		    printf("%s%d%s", DEFFONT, curfontnode->qmsnumber, ENDCMD);
		    fontselected = TRUE;
		}
		/* SliTeX fonts have width but no bitmap.  Unfortunately the
		 * QMS will not print (or download) a character with width and
		 * no bitmap so we must not print characters that are not in
		 * the font.  If you do, you will get the lowest character in
		 * the font.
		 */
trytocontinue1: if (LI(curfontnode)->mapsize[0][ch] != 0 && 
		LI(curfontnode)->mapsize[1][ch] != 0) {
    		    if (ch == '^' || ch <= 32 || ch >= 127)
			printf("%s%02X", SPECIAL, ch);
		    else
		        (void)putchar(ch);
		    realhpxl += ROUND(LI(curfontnode)->widths[ch] *
		    (Magnification / 1000.0) * ConvInches * RESOLUTION);
		}
		h += LI(curfontnode)->widths[ch];
	    } else if (FNTNUM0 <= ch && ch < FNT1) {
		curfontnum = ch - FNTNUM0;
		if (!(tempcurfontnode = getdvifontnode(FontList,
		curfontnum, Orientation)))
		    continue; /* Font file was not found during FNTDEF */
		curfontnode = tempcurfontnode;
		endoflist(&FontList, curfontnode);
		fontselected = FALSE;
		putchar('\r');	/* Ends the pass */
		printf("%s00000%s", TAB, ENDCMD);
		printf("%s00000%s", JUSTIFYMARGIN, ENDCMD);
		realhpxl = realvpxl = 0;
	    } else switch (ch) {
		case SET1:
		case SET2:
		case SET3:
		case SET4:
		    ch = uinteger(stdin, ch - SET1 + 1);
		    assert(0 <= ch && ch <= 255);
		    if (!curfontnode || !curfontnode->localinfo)
			continue;
		    adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		    if (!(curfontnode->flags & LOADED)) {
		        if (!makeroom(FontList, MaxBlocks, &CurRamBlocks, 
		        CurRomBlocks, curfontnode->blocksize)) {
			    fprintf(stderr, 
			    "%s: could not free %d blocks for font %s\n",
			    Whoami, curfontnode->blocksize,
			    LI(curfontnode)->pathname);
			    goto trytocontinue2;
			}
		        if (!download(curfontnode))
		    	    goto trytocontinue2;
		    	realhpxl = realvpxl = 0;
		    	adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		    }
		    if (!fontselected) {
		    	printf("%s%d%s", DEFFONT, curfontnode->qmsnumber,
		        ENDCMD);
		    	fontselected = TRUE;
		    }
trytocontinue2:     if (LI(curfontnode)->mapsize[0][ch] != 0 && 
		    LI(curfontnode)->mapsize[1][ch] != 0) {
    		        if (ch == '^' || ch <= 32 || ch >= 127)
			    printf("%s%02X", SPECIAL, ch);
		    	else
		            (void)putchar(ch);
		        realhpxl += ROUND(LI(curfontnode)->widths[ch] *
		        (Magnification / 1000.0) * ConvInches * RESOLUTION);
		    }
		    h += LI(curfontnode)->widths[ch];
		    break;
		case SETRULE:
		    adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		    a = integer(stdin, 4);
		    b = integer(stdin, 4);
		    if (a > 0 && b > 0) {
			printf("%s-%05d", JUSTIFYRELATIVE, ROUND(a /
			(double)SPOINT / PPI * (double)Magnification));
			printf("%s%05d%05d", LINE, 
			ROUND(b/(double)SPOINT/PPI*(double)Magnification),
			ROUND(a/(double)SPOINT/PPI*(double)Magnification));
			printf("%s+%05d", JUSTIFYRELATIVE, ROUND(a /
			(double)SPOINT / PPI * (double)Magnification));
			realhpxl += ROUND(b / (double)SPOINT / PPI *
			RESOLUTION * (Magnification / 1000.0));
		    }
		    h += ROUND(b * (Numerator / (double)Denominator));
		    break;
		case PUT1:
		case PUT2:
		case PUT3:
		case PUT4:
		    ch = uinteger(stdin, ch - PUT1 + 1);
		    assert(0 <= ch && ch <= 255);
		    if (!curfontnode || !curfontnode->localinfo)
			continue;
		    adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		    if (!(curfontnode->flags & LOADED)) {
		        if (!makeroom(FontList, MaxBlocks, &CurRamBlocks, 
		        CurRomBlocks, curfontnode->blocksize)) {
			    fprintf(stderr, 
			    "%s: could not free %d blocks for font %s\n",
			    Whoami, curfontnode->blocksize,
			    LI(curfontnode)->pathname);
			    goto trytocontinue3;
			}
		        if (!download(curfontnode))
		    	    goto trytocontinue3;
		    	realhpxl = realvpxl = 0;
		    	adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		    }
		    if (!fontselected) {
		    	printf("%s%d%s", DEFFONT, curfontnode->qmsnumber,
		        ENDCMD);
		    	fontselected = TRUE;
		    }
trytocontinue3:     if (LI(curfontnode)->mapsize[0][ch] != 0 && 
		    LI(curfontnode)->mapsize[1][ch] != 0) {
    		        if (ch == '^' || ch <= 32 || ch >= 127)
			    printf("%s%02X", SPECIAL, ch);
		    	else
		            (void)putchar(ch);
		        realhpxl += ROUND(LI(curfontnode)->widths[ch] *
		        (Magnification / 1000.0) * ConvInches * RESOLUTION);
		    }
		    break;
		case PUTRULE:
		    adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		    a = integer(stdin, 4);
		    b = integer(stdin, 4);
		    if (a > 0 && b > 0) {
			printf("%s-%05d", JUSTIFYRELATIVE, ROUND(a /
			(double)SPOINT / PPI * (double)Magnification));
			printf("%s%05d%05d", LINE, 
			ROUND(b/(double)SPOINT/PPI*(double)Magnification), 
			ROUND(a/(double)SPOINT/PPI*(double)Magnification));
			printf("%s+%05d", JUSTIFYRELATIVE, ROUND(a /
			(double)SPOINT / PPI * (double)Magnification));
			realhpxl += ROUND(b / (double)SPOINT / PPI *
			RESOLUTION * (Magnification / 1000.0));
		    }
		    break;
		case NOP:
		    break;
		case PUSH:
		    tempstack = (struct Stack *)malloc((unsigned)sizeof(
		    struct Stack));
		    tempstack->h = h, tempstack->v = v, tempstack->w = w,
		    tempstack->x = x, tempstack->y = y, tempstack->z = z;
		    (void)push((char *)tempstack);
		    break;
		case POP:
		    tempstack = (struct Stack *)pop();
		    assert(tempstack);
		    h = tempstack->h, v = tempstack->v, w = tempstack->w,
		    x = tempstack->x, y = tempstack->y, z = tempstack->z;
		    free((char *)tempstack);
		    break;
		case RIGHT1:
		case RIGHT2:
		case RIGHT3:
		case RIGHT4:
		    h += integer(stdin, ch - RIGHT1 + 1) * (Numerator / 
		    (double)Denominator);
		    break;
		case W0:
horw:		    h += w;
		    break;
		case W1:
		case W2:
		case W3:
		case W4:
		    w = integer(stdin, ch - W1 + 1) * (Numerator / 
		    (double)Denominator);
		    goto horw;
		case X0:
horx:		    h += x;
		    break;
		case X1:
		case X2:
		case X3:
		case X4:
		    x = integer(stdin, ch - X1 + 1) * (Numerator / 
		    (double)Denominator);
		    goto horx;
		case DOWN1:
		case DOWN2:
		case DOWN3:
		case DOWN4:
		    v += integer(stdin, ch - DOWN1 + 1) * (Numerator /
		    (double)Denominator);
		    break;
		case Y0:
very:		    v += y;
		    break;
		case Y1:
		case Y2:
		case Y3:
		case Y4:
		    y = integer(stdin, ch - Y1 + 1) * (Numerator /
		    (double)Denominator);
		    goto very;
		case Z0:
verz:		    v += z;
		    break;
		case Z1:
		case Z2:
		case Z3:
		case Z4:
		    z = integer(stdin, ch - Z1 + 1) * (Numerator /
		    (double)Denominator);
		    goto verz;
		case FNT1:
		case FNT2:
		case FNT3:
		case FNT4:
		    curfontnum = uinteger(stdin, ch - FNT1 + 1);
		    if (!(tempcurfontnode = getdvifontnode(FontList,
		    curfontnum, Orientation)))
		        continue;
		    curfontnode = tempcurfontnode;
		    endoflist(&FontList, curfontnode);
		    fontselected = FALSE;
		    putchar('\r');	/* Ends the pass */
		    printf("%s00000%s", TAB, ENDCMD);
		    printf("%s00000%s", JUSTIFYMARGIN, ENDCMD);
		    realhpxl = realvpxl = 0;
		    break;
		case XXX1:
		case XXX2:
		case XXX3:
		case XXX4:
		    ulk = uinteger(stdin, ch - XXX1 + 1);
		    Pxxxstring = Xxxstring = malloc((unsigned)(ulk + 1));
		    for (uli = 0; uli < ulk; uli++)
			Xxxstring[uli] = cgetchar();
		    Xxxstring[uli] = '\0';
		    adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl, h, v);
		    Origin[0] = virthpxl + RESOLUTION, Origin[1] = virtvpxl +
		    RESOLUTION;
		    (void)yyparse();
		    free(Xxxstring);
		    fputs(QUICON, stdout);
		    if (Orientation == 'P')
			fputs(PORTRAIT, stdout);
		    else
			fputs(LANDSCAPE, stdout);
		    printf("%s%c%c", TEXTPROC, '0', '0');
		    printf("%s00000%05d", INITMARGVERT, Orientation == 'P' ? 
		    11 * 1000 : (int)(8.5 * 1000));
		    printf("%s00000%05d", INITMARGHORZ, Orientation == 'P' ? 
		    (int)(8.5 * 1000) : 11 * 1000);
		    printf("%s0000", CHARSPACING);
		    realhpxl = realvpxl = 0;
		    break;
		case FNTDEF1:
		case FNTDEF2:
		case FNTDEF3:
		case FNTDEF4:
		    dvifontnum = integer(stdin, ch - FNTDEF1 + 1);
		    dvichecksum = integer(stdin, 4);
		    scalefactor = integer(stdin, 4);
		    designsize = integer(stdin, 4);
		    ldirectory = cgetchar();
		    lfontname = cgetchar();
		    for (i = 0; i < ldirectory; i++)
			directory[i] = cgetchar();
		    directory[i] = '\0';
		    for (i = 0; i < lfontname; i++)
			fontname[i] = cgetchar();
		    fontname[i] = '\0';
		    fonttolist(dvifontnum, dvichecksum, scalefactor,
		    designsize, directory, fontname);
		    break;
		default:	    /* Bad DVI command */
#ifndef lint
		    assert(FALSE);  
#else
		    ;
#endif
		    cleanup(FontList, 2);
	    }
	}
	NumPages++;
	printf("%s", FORMFEED);
	for (ch = cgetchar(); ch != BOP && ch != POST; ch = cgetchar())
	    switch (ch) {
	    case NOP:
		break;
	    case FNTDEF1:
	    case FNTDEF2:
	    case FNTDEF3:
	    case FNTDEF4:
		dvifontnum = integer(stdin, ch - FNTDEF1 + 1);
		dvichecksum = integer(stdin, 4);
		scalefactor = integer(stdin, 4);
		designsize = integer(stdin, 4);
		ldirectory = cgetchar();
		lfontname = cgetchar();
		for (i = 0; i < ldirectory; i++)
		    directory[i] = cgetchar();
		directory[i] = '\0';
		for (i = 0; i < lfontname; i++)
		    fontname[i] = cgetchar();
		fontname[i] = '\0';
		fonttolist(dvifontnum, dvichecksum, scalefactor,
		designsize, directory, fontname);
		break;
	    default:
#ifndef lint
		assert(FALSE);
#else
		;
#endif
		cleanup(FontList, 2);
	    }
    }
    while (getchar() != EOF)
	;
}

		       
/* Returns the full pathname of the pk file found or NULL if not found.
 * The algorithm is as follows:
 *	Create a new path, say TEXFONTS*, which is equal to $TEXFONTS:PKDir
 *	if there is a directory name in the DVI file {
 *	    look in that directory for the font at any magnification
 *	    if found {
 *		select this font
 *		return it
 *	    }
 *	}
 *	look in TEXFONTS* directories consecutively for font with closest
 *	magnification
 *	if no font matches, return NULL
 */
char *findpkfont(directory, fontname, designsize, scalefactor)
char	*directory;
char	*fontname;
long	designsize, scalefactor;
{
    int		    closestnumber = MAX_INTEGER;
    int		    desiredmagnification = ROUND(RESOLUTION *
		    ((double)scalefactor / designsize) * (Magnification /
		    1000.0));
    int		    dirdsize, dirmag;
    Boolean	    extractinfo();
    static char	    returnvalue[101];
    char	    dirfname[81], dirsfname[81], hostname[81], component[81];
    char	    fontpaths[201], *strcpy(), *nextcomponent();
    char	    *p, *comp, *fgetenv(), *expandtilde(), *expandhome();
    DIR		    *dirp;
    struct direct   *direntry;

    returnvalue[0] = '\0';
    (void)gethostname(hostname, 80);
    if (!EQ(hostname, Host) || !(p = fgetenv("TEXFONTS", User)))
	(void)strcpy(fontpaths, PKDir);
    else
	(void)sprintf(fontpaths, "%s:%s", p, PKDir);
    if (directory && strlen(directory) > 0) {
	if (dirp = opendir(directory)) {
	    for (direntry = readdir(dirp); direntry; direntry =
	    readdir(dirp)) {
		if (direntry->d_namlen < 5 || !extractinfo(direntry->d_name,
		dirfname, dirsfname, &dirdsize, &dirmag) || !EQ(dirfname,
		fontname))
		    continue;
		if (ABS(dirmag - desiredmagnification) < closestnumber) {
		    closestnumber = ABS(dirmag - desiredmagnification);
		    (void)sprintf(returnvalue, "%s%s", directory, 
		    direntry->d_name);
		}
	    }
	    closedir(dirp);
	    if (strlen(returnvalue) > 0)
		return returnvalue;
	}
    }
    for (p = &fontpaths[0]; comp = nextcomponent(&p); ) {
	(void)strcpy(component, comp);
	(void)expandtilde(component);
	(void)expandhome(component);
	if (dirp = opendir(component)) {
	    for (direntry = readdir(dirp); direntry; direntry = readdir(dirp))
	    {
		if (direntry->d_namlen < 5 || !extractinfo(direntry->d_name,
		dirfname, dirsfname, &dirdsize, &dirmag) || !EQ(dirfname,
		fontname))
		    continue;
		if (ABS(dirmag - desiredmagnification) < closestnumber) {
		    closestnumber = ABS(dirmag - desiredmagnification);
		    (void)sprintf(returnvalue, "%s/%s", component, 
		    direntry->d_name);
		}
	    }
	    closedir(dirp);
	}
    }
    if (strlen(returnvalue) > 0)
	return returnvalue;
    return NULL;
}

/* Adjusts the real current position to the virtual current position */
void adjust(realh, realv, virth, virtv, h, v)
long	*realh, *realv;
long	virth, virtv;
long	h, v;
{
    if (*realh != virth + RESOLUTION) {
	printf("%s%05d%s", TAB, ROUND(h * ConvInches * Magnification) + 1000,
	ENDCMD);	/* Add 1000 since the origin is (1in,1in) */
	*realh = virth + RESOLUTION;
    }
    if (*realv != virtv + RESOLUTION) {
	printf("%s%05d%s", JUSTIFYMARGIN, ROUND(v * ConvInches *
	Magnification) + 1000,  ENDCMD);
	*realv = virtv + RESOLUTION;
    }
}

/* Adds a new font to the font list.  The width info, mapsize, qmsheight,
 * qmsbaseline, pathname, blocksize and dvifontnumber in the FontNode 
 * structure and LocalInfo structure are filled in also.  If the font is
 * loaded on startup, the blocksize is left as is; otherwise, the blocksize
 * is estimated.
 */
void fonttolist(fontnumber, dvichecksum, scalefactor, designsize, directory,
fontname)
long	fontnumber;
long	dvichecksum;
long	scalefactor, designsize;
char	*directory, *fontname;
{
    struct DviNode	*d;
    struct FontInfo	*fi, *getfontinfo();
    struct FontNode	*fn, *getfontnode();
    char		*fullfontpath, *findpkfont(), *tail();
    void		cleanup(), pkeofsocleanup(), seteoffunction(),
    			dvieofsocleanup();
    int			qmsfontnum, i;
    Boolean		found;

    if (!(fullfontpath = findpkfont(directory, fontname, designsize,
    scalefactor))) {
	fprintf(stderr, "%s: could not find font %s anywhere\n", Whoami,
	fontname);
	return;	/* Try to continue */
    }
    if (EQN(PKDir, fullfontpath, strlen(PKDir)) && fullfontpath[strlen(PKDir)]
    == '/' && EQ(&fullfontpath[strlen(PKDir)+1], tail(fullfontpath)))
    	qmsfontnum = getnumfromtable(tail(fullfontpath));
    else /*tail(fullfontpath) ! necessarily == fontname if exact size !found*/
    	qmsfontnum = UserFontCount++;
    assert(qmsfontnum > 0);
    if (!(fn = getfontnode(FontList, qmsfontnum, Orientation))) {
	bzero((char *)(fn = (struct FontNode *)malloc((unsigned)sizeof(struct
	FontNode))), sizeof(struct FontNode));
	fn->next = FontList, FontList = fn;
    }
    if (!fn->localinfo)
    	bzero(fn->localinfo = malloc((unsigned)sizeof(struct LocalInfo)),
	sizeof(struct LocalInfo));
    fn->flags |= RAM;
    if (Orientation == 'P')
    	fn->flags |= PORT;
    fn->qmsnumber = qmsfontnum;
    (void)strcpy(LI(fn)->pathname, fullfontpath);
    for (d = LI(fn)->dvifontnumbers, found = FALSE; d && !found; d = d->next)
    	if (d->dvinumber == fontnumber)
    	    found = TRUE;
    if (!found) {
	d = (struct DviNode *)malloc(sizeof(struct DviNode));
	d->next = LI(fn)->dvifontnumbers, LI(fn)->dvifontnumbers = d;
	d->dvinumber = fontnumber;
    }
    (void)strcpy(PKName, fullfontpath);
    seteoffunction(pkeofsocleanup);
    if (!(fi = getfontinfo(fullfontpath, (EQ(Model, "QMS800") ||
    EQ(Model, "QMS1500")) && Orientation == 'P' || (!EQ(Model, "QMS800") && 
    !EQ(Model, "QMS1500")) && Orientation == 'L' ? 'X' : 'Y'))) {
	fprintf(stderr, "%s: cannot open or invalid font file %s\n", Whoami,
	fullfontpath);
	fn->flags |= LOADED;	/* Try to continue */
	fn->blocksize = 0;
	return;
    }
    seteoffunction(dvieofsocleanup);
    LI(fn)->qmsheight = fi->qmsheight;
    LI(fn)->qmsbaseline = fi->qmsbaseline;
    if (!(fn->flags & PRELOADED))
    	fn->blocksize = fi->blocksize;
    for (i = 0; i < 256; i++) {
	LI(fn)->widths[i] = ROUND(fi->chararray[i].tfm * ((fi->ds /
	(double)FIX) / FIX) * (2.54 / PPI * 100000) * ((fi->hppp /
        (double)SPOINT * PPI / RESOLUTION) / (Magnification / 1000.0)));
	LI(fn)->mapsize[0][i] = fi->chararray[i].w;
	LI(fn)->mapsize[1][i] = fi->chararray[i].h;
    }
/* fi->chararray[i].tfm is in units of FIXes/designsize. fi->hppp is in units
 * of scaled points times pixels/point.  Convert the width into RSUs with only
 * font magnification taken into account by the following formulas:
 *
 *  tfm   designsize
 *      x ---------- = width in points
 *           FIX
 *
 * width      1inch    2.54cm     1m    10^7RSUs
 * in     x -------- x ------ x ----- x -------- = width in RSUs
 * points   72.27pts    1inch   100cm      1m
 *
 *  hppp    PPI
 * ------ x      = Resolution designed for (the number before "pk" in the
 * SPOINT          file name)
 *
 * Multiplying the width in RSUs by the number before the "pk" in the file 
 * name yields the width in RSUs with font and file magnification taken into
 * account.  Dividing by the file magnification yields the width with only
 * the font magnification taken into account.
 */
    if (dvichecksum != 0 && fi->cs != 0)
    	if (dvichecksum != fi->cs)
	    fprintf(stderr,
	    "%s: DVI checksum (O%lo) != PK checksum (O%lo) in %s\n",
	    Whoami, dvichecksum, fi->cs, LI(fn)->pathname);
}

/* Downloads a font */
Boolean download(fn)
struct FontNode *fn;
{
    struct CharInfo	*ci;
    char		*tail(), *strcpy();
    void		resetpkfile(), seteoffunction(),
    			downloadpkeofsocleanup(), dvieofsocleanup();
    int			downloadinterrupt(), callcleanup();
    int			downloadtype, result, i, truebyteswide, bytestooutput,
    			row, bytes;

    if (!fn || fn->flags & LOADED || !(fn->flags & RAM) || (fn->flags & PORT ?
    'P' : 'L') != Orientation)
    	return FALSE;
    resetpkfile();
    downloadtype = ((EQ(Model, "QMS800") || EQ(Model, "QMS1500")) && 
    Orientation == 'P' || (!EQ(Model, "QMS800") && !EQ(Model, "QMS1500"))
    && Orientation == 'L' ? 'X' : 'Y');
    DownLoadFNum = fn->qmsnumber;
    (void)sigblock(SIGINT);	/* Temporarily block interrupts */
    SigStruct.sv_handler = downloadinterrupt;
    (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL);
    (void)strcpy(PKName, LI(fn)->pathname);
    seteoffunction(downloadpkeofsocleanup);
    /* #defining ASCIILOAD causes ASCII characters to be used for the download
     * sequence.  Twice as many characters must be sent but it is useful for
     * looking at the output when debugging.  Also, you can actually see the
     * bitmaps in the output.  ASCII loading must be used when you can't get
     * hardware flow control to work.  Far out.
     */
#ifdef ASCIILOAD
    fputs(FREEFORM, stdout);
#else
    fputs(EIGHTBITON, stdout);
#endif
    printf("%s%05d%c0%-4.4s%03d%03dT", DOWNLOAD, fn->qmsnumber, Orientation,
    tail(LI(fn)->pathname), LI(fn)->qmsheight, LI(fn)->qmsbaseline);
    (void)sigsetmask(sigblock(0) & ~SIGINT);	/* Unblock interrupts */
    while ((result = getnextcharinfo(LI(fn)->pathname, downloadtype, &ci)) !=
    1)
    	switch (result) {
	case 2:
	    fprintf(stderr, "%s: could not open %s\n", Whoami, 
	    LI(fn)->pathname);
	    return FALSE;
	case 3:
	    fprintf(stderr, "%s: %s is not a PK file\n", Whoami, 
	    LI(fn)->pathname);
	    return FALSE;
	case 4:
	    fprintf(stderr, "%s: %s PK version is incorrect\n", Whoami,
	    LI(fn)->pathname);
	    return FALSE;
	case 0:			/* Ok. Got a bitmap */
	    if (ci->h == 0 || ci->w == 0)
		continue;
	    putchar(',');
	    printf("%02X%03d", ci->cc, ROUND(LI(fn)->widths[ci->cc] * 
	    (Magnification / 1000.0) * ConvInches * RESOLUTION));
	    if (downloadtype == 'X') {
		printf("%03d%03d", ci->h, ci->w);
		printf("%c%03d", LI(fn)->qmsbaseline - ci->voff >= 0 ? '+'
		: '-', ABS(LI(fn)->qmsbaseline - ci->voff));
		printf("%c%03d", -ci->hoff >= 0 ? '+' : '-', ABS(-ci->hoff));
	    } else {
		printf("%03d%03d", ci->w, ci->h);
		printf("%c%03d", -ci->hoff >= 0 ? '+' : '-', ABS(ci->hoff));
		printf("%c%03d", (LI(fn)->qmsheight - LI(fn)->qmsbaseline) -
		(ci->h - ci->voff) >= 0 ? '+' : '-', ABS((LI(fn)->qmsheight
                - LI(fn)->qmsbaseline) - (ci->h - ci->voff)));
		i = ci->w, ci->w = ci->h, ci->h = i; /* Swaparoo! */
	    }
	    truebyteswide = ci->w + 7 >> 3;	/* >> divides by 8 */
	    bytestooutput = (ci->w + 15 >> 4) * 2; /* >> divides by 16 */
#ifdef ASCIILOAD
	    for (row = 0; row < ci->h; row++) {
#else
	    for (row = 0; row < ci->h; row++)
#endif
		for (bytes = 0; bytes < bytestooutput; bytes++) {
		    if (bytes == truebyteswide - 1)
		    	*(ci->bitmap + row * truebyteswide + bytes) &=
			0xFF<<7-(ci->w+7)%8;
		    if (bytes < truebyteswide) {
			i = *(ci->bitmap + row * truebyteswide + bytes) &
			0xFF;
#ifdef ASCIILOAD
			printf("%c%c", "0123456789ABCDEF"[i >> 4],
			"0123456789ABCDEF"[i & 0xF]);
#else
			if (i == '^')
			    printf("^^");
			else
			    (void)putchar(i);
#endif
		    } else
#ifdef ASCIILOAD
		        printf("00");
#else
		        (void)putchar(0);
#endif
		}
#ifdef ASCIILOAD
	        putchar('\n');
	    }
#endif
	    break;
	}	/* End switch */
#ifdef ASCIILOAD
    printf("%s%s", ENDCMD, FREEOFF);
#else
    printf("%s%s", ENDCMD, EIGHTBITOFF);
#endif
    putchar('\r');	/* Ends the pass */
    (void)sigblock(SIGINT);
    printf("%s00000%s", TAB, ENDCMD);
    printf("%s00000%s", JUSTIFYMARGIN, ENDCMD);
    SigStruct.sv_handler = callcleanup;
    (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL);
    seteoffunction(dvieofsocleanup);
    CurRamBlocks += fn->blocksize;
    fn->flags |= LOADED;
    (void)sigsetmask(sigblock(0) & ~SIGINT);
    return TRUE;
}

/* Returns a pointer to a font on the font list using the DVI number; NULL
 * if not found.
 */
struct FontNode *getdvifontnode(head, dvinumber, orientation)
struct FontNode	*head;
long		dvinumber;
int		orientation;
{
    struct FontNode	*p;
    struct DviNode	*d;

    for (p = head; p; p = p->next)
    	if (p->flags & RAM && (p->flags & PORT ? 'P' : 'L') == orientation
	&& p->localinfo && LI(p)->dvifontnumbers)
	    for (d = LI(p)->dvifontnumbers; d; d = d->next)
	    	if (d->dvinumber == dvinumber)
		    return p;
    return NULL;
}

/* The following are routines called when a SIGINT is received or EOF is 
 * unexpectedly encountered when reading a file.
 */
simplyexit()
{
    exit(SUCCEED);
}

callcleanup()
{
    void cleanup();

    fputs(FORMFEED, stdout), NumPages++;
    cleanup(FontList, SUCCEED); /* Interrupting a program is not an error */
}

void dvieofsoexit()
{
    fprintf(stderr, "%s: unexpected EOF when reading DVI file\n", Whoami);
    exit(2);
}

void dvieofsocleanup()
{
    fprintf(stderr, "%s: unexpected EOF when reading DVI file\n", Whoami);
    fputs(FORMFEED, stdout), NumPages++;
    cleanup(FontList, 2);
}

void pkeofsocleanup()
{
    fprintf(stderr, "%s: unexpected EOF in PK file %s\n", Whoami, PKName);
    fputs(FORMFEED, stdout), NumPages++;
    cleanup(FontList, 2);
}

void downloadpkeofsocleanup()
{
    fputs(ENDCMD, stdout);
#ifdef ASCIILOAD
    fputs(FREEOFF, stdout);
#else
    fputs(EIGHTBITOFF, stdout);
#endif
    printf("%s%05d%c%s", DOWNLOAD, DownLoadFNum, Orientation, ENDCMD);
    pkeofsocleanup();
}

downloadinterrupt()
{
    fputs(ENDCMD, stdout);
#ifdef ASCIILOAD
    fputs(FREEOFF, stdout);
#else
    fputs(EIGHTBITOFF, stdout);
#endif
    printf("%s%05d%c%s", DOWNLOAD, DownLoadFNum, Orientation, ENDCMD);
    callcleanup();
}

    
/* Lex and Yacc routines to parse \special command string */
#include "xxx.c"