[net.text] Looking for nroff tables for HP LaserJet

jdz@wucec2.UUCP (02/18/86)

<Gently, fellow net-nauts, gently...>

I ride forth in search of nroff-driving tables for the HP Laser Jet printer.
Somebody out there MUST have these, as it seems like the obvious thing to do
if you have HP's. We just got one, so we're just getting around to the tables.

Gentle readers, please MAIL me NON-PROPRIETARY tables to drive the HP. If you
need to make assumptions about font cartriges, etc., go ahead and do so.

Thanks in advance for any help/pointers. Oh, yes - I don't usually read this
newsgroup, so please don't bother chastising me for not pulling them off the
net when they were posted. Please feel free to yell at my boss[es].
-- 
Jason D. Zions			...!{seismo,cbosgd,ihnp4}!wucs!wucec2!jdz
Box 1045 Washington University
St. Louis MO 63130  USA		(314) 889-6160
Nope, I didn't say nothing. Just random noise.

faustus@cad.UUCP (Wayne A. Christopher) (02/24/86)

I have ditroff width tables for the Times Roman cartridge -- I hope you can
make use of them.  I measured the characters by hand, so I don't have anything
for the other cartidges (it's a lot of trouble).  I'm also including a
simple-minded ditroff filter for the laserjet, and other things that should
be all you need to set up a laserjet, software-wise... This stuff is full
of bugs which I don't have time to fix, so I would be happy to get any bug
fixes.

The diff file is for /usr/src/usr.lib/lpr/filters/lpf.c.

	Wayne

--

# The rest of this file is a shell script which will extract:
# Makefile ljf.c.diff ljfd.c width.c pagereverse.c DESC R I B
echo x - Makefile
cat >Makefile <<'!Funky!Stuff!'
# Makefile for ljfd and ljf

CC =		cc

CFLAGS =	-g

CFILES =	ljfd.c ljf.c width.c pagereverse.c

OFILES =	ljfd.o ljf.o width.o pagereverse.o

HFILES =

all:		ljf ljfd desc/DESC.out pagereverse

ljfd:           ljfd.o width.o
		$(CC) $(CFLAGS) ljfd.o width.o -o ljfd

ljf:		ljf.o
		$(CC) $(CFLAGS) ljf.o -o ljf

pagereverse:	pagereverse.o
		$(CC) $(CFLAGS) pagereverse.o -o pagereverse

desc/DESC.out:	desc/DESC desc/I desc/R desc/B
		(cd desc; ./devconfig DESC; cd ..)

ctags:
		ctags $(CFILES) $(HFILES)

!Funky!Stuff!
echo x - ljf.c.diff
cat >ljf.c.diff <<'!Funky!Stuff!'
18,20d17
<  *
<  * >>>  This version is modified for the HP laserjet, and does tab
<  * >>>  expansion and page reversal.
29,32d25
< #define PAGEREVERSE "/usr/local/pagereverse"
< 
< #define NLINES 66	/* This is bad, but that's life. */
< 
49,50c42
< 	register FILE *p = stdin, *o = stdout, *tf;
< 	FILE *fopen();
---
> 	register FILE *p = stdin, *o = stdout;
55d46
< 	char *mktemp(), *tempf = "/tmp/ljXXXXXX";
91,96d81
< 	tempf = mktemp(tempf);
< 	if (!(tf = fopen(tempf, "w"))) {
< 		/* Well, let's not die horribly... */
< 		tf = stdout;
< 	}
< 	initlj();
172,176c157
< 				if (*cp == '\n') {
< 					putc('\r', tf);
< 					putc('\n', tf);
< 				} else
< 					putc(*cp, tf);
---
> 				putc(*cp, o);
179,185c160,163
< 			if (i < maxrep) {
< 				putc('\r', tf);
< 			} else if (ch == '\n') {
< 				putc('\r', tf);
< 				putc('\n', tf);
< 			} else
< 				putc(ch, tf);
---
> 			if (i < maxrep)
> 				putc('\r', o);
> 			else
> 				putc(ch, o);
187c165
< 				fflush(tf);
---
> 				fflush(o);
194,200c172,174
< 
< 	/* Now take the temp file and run it through pagereverse. */
< 	if (tf != stdout) {
< 		fclose(tf);
< 		sprintf(buf, "%s < %s", PAGEREVERSE, tempf);
< 		system(buf);
< 		unlink(tempf);
---
> 	if (lineno) {		/* be sure to end on a page boundary */
> 		putchar('\f');
> 		npages++;
202d175
< 
209,226d181
< 
< /* Initialize the laserjet -- make sure that the lpr font is current. */
< 
< initlj()
< {
< 	/* Get the right font.  */
< 	printf("\033E\033&l0O\033(8U\033(s0p10h12v0s0b3T");
< 
< 	/* Set page length -- see page 4-28 of the lj manual. */
< 	printf("\033&l14c1e7.64c66F");
< 
< 	/* Set the left margin. */
< 	printf("\033&a2L");
< 
< 	fflush(stdout);
< 	return;
< }
< 
!Funky!Stuff!
echo x - ljfd.c
cat >ljfd.c <<'!Funky!Stuff!'

/* RCS Info: $Revision: 1.1 $ on $Date: 85/10/29 14:44:27 $
 *           $Source: /cad4/faustus/src/laserjet/RCS/ljfd.c,v $
 * Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
 *	Permission is granted to do anything with this code except sell it
 *	or remove this message.
 *
 * Ditroff driver for the hp laserjet. Much of this is generic, and for
 * many printers only a few lines in each routine need be changed to
 * get something that works...
 */

#include <stdio.h>
#include <ctype.h>

extern char *tmalloc(), *copy();

#define eq(a,b)     (!strcmp((a), (b)))
#define prefix(p, s)    (!strncmp((p), (s), strlen(p)))
#define alloc(strname)  ((struct strname *) tmalloc(sizeof(struct strname)))

int pagereverse = 0;

struct command {
	char *c_line;			/* NULL terminated, no newline. */
	struct command *c_next;
	struct command *c_prev;
	struct command *c_nextpage;	/* If this is a 'p' line... */
	struct command *c_prevpage;
} ;

/* Stuff to describe the state of the page. */

int hpos, vpos;
int hmax, vmax;
int curfont, cursize;
int maxfont, maxsize;
int curpage;
int debug = 0;
int wordspace = 0;

main(ac, av)
	char **av;
{
	char buf[BUFSIZ];
	struct command *coms, *cc, *tr = NULL, *lp = NULL, *readcoms();

	if (eq(av[1], "-d"))
		debug = 1;
	else if (eq(av[1], "-D"))
		debug = 2;

	startup();

	/* Gather up all the commands first. */
	coms = readcoms(stdin);

	/* if (debug) printcoms((int) coms); */

	/* Do commands until we get to a 'p' line... */
	for (cc = coms; cc && (*cc->c_line != 'p'); cc = cc->c_next)
		doline(cc->c_line);

	/* Now print the pages out in the proper order. */
	if (pagereverse) {
		while (cc->c_nextpage)
			cc = cc->c_nextpage;
		do {
			doline(cc->c_line);
			lp = cc;
			cc = cc->c_next;
			while (cc && (*cc->c_line != 'p') &&
					!prefix("x trailer", cc->c_line)) {
				doline(cc->c_line);
				cc = cc->c_next;
			}
			if (prefix("x trailer", cc->c_line))
				tr = cc;
			cc = lp;
			if (cc)
				cc = cc->c_prevpage;
			else
				break;
		} while (cc);
		if (tr)
			while (tr) {
				doline(tr->c_line);
				tr = tr->c_next;
			}
		else
			fprintf(stderr, "Warning: no x trailer!\n");
	} else {
		while (cc) {
			doline(cc->c_line);
			cc = cc->c_next;
		}
	}

	cleanup();
	exit(0);
}

/* Read in commands, filtering out comments and breaking up multiple
 * commands on one line. This is really bad -- ditroff should be more
 * nice to us.
 */

struct command *
readcoms(fp)
	FILE *fp;
{
	struct command *comm = NULL, *last = NULL, *prevpage = NULL;
	char *s, *getcom();

	while (s = getcom(fp)) {
		if (comm) {
			last->c_next = alloc(command);
			last->c_next->c_prev = last;
			last = last->c_next;
		} else {
			last = comm = alloc(command);
		}
		last->c_line = s;
		if (*s == 'p') {
			/* Link this one and prevpage together. */
			if (prevpage) {
				prevpage->c_nextpage = last;
				last->c_prevpage = prevpage;
			}
			prevpage = last;
		}
	}
	return (comm);
}

char *
getcom(fp)
	FILE *fp;
{
	static char buf[BUFSIZ] = "";
	char wbuf[BUFSIZ];
	static int i = 0;
	register char *s, *t;
	register int j = 0;

new:	while (!buf[i] || (buf[0] == '#')) {
		if (!fgets(buf, BUFSIZ, fp))
			return (NULL);
		i = 0;
	}
	while (isspace(buf[i]))
		i++;
	if (!buf[i])
		goto new;

	switch (buf[i]) {
		case 's':
		case 'f':
		case 'H':
		case 'V':
		case 'h':
		case 'v':
		case 'p':
			/* Grab the next number. */
			wbuf[j++] = buf[i++];
			while (isdigit(buf[i]))
				wbuf[j++] = buf[i++];
			wbuf[j] = '\0';
			break;
		case 'w':
			wbuf[0] = buf[i++];
			wbuf[1] = '\0';
			break;
		case 'c':
			wbuf[0] = buf[i++];
			wbuf[1] = buf[i++];
			wbuf[2] = '\0';
			break;
		case 'C':
			while (buf[i] && !isspace(buf[i]))
				wbuf[j++] = buf[i++];
			wbuf[j] = '\0';
			break;
		case 'n':
			while (!isspace(buf[i]))
				wbuf[j++] = buf[i++];
			while (buf[i] && isspace(buf[i]))
				wbuf[j++] = buf[i++];
			while (!isspace(buf[i]))
				wbuf[j++] = buf[i++];
			wbuf[j] = '\0';
			break;
		default:
			if (isdigit(buf[i])) {
				wbuf[0] = buf[i++];
				wbuf[1] = buf[i++];
				wbuf[2] = buf[i++];
				wbuf[3] = '\0';
			} else {
				while (buf[i] && (buf[i] != '\n'))
					wbuf[j++] = buf[i++];
				wbuf[j] = '\0';
			}
			;
	}
	return (copy(wbuf));
}

/* Execute one ditroff command, not necessarily a whole line. */

doline(line)
	char *line;
{
	if (debug == 2) {
		fprintf(stderr, "> %s\n", line);
		return;
	}
	switch (*line) {
		case 's':	/* Set point size to num. */
			setsize(atoi(line + 1));
			break;
		case 'f':	/* Set font to num. */
			setfont(atoi(line + 1));
			break;
		case 'c':	/* Write one character. */
			writechar(line[1]);
			break;
		case 'C':	/* Write a special character. */
			writespec(line + 1);
			break;
		case 'H':	/* Go to hpos num. */
			hgoto(atoi(line + 1));
			break;
		case 'V':	/* Go to vpos num. */
			vgoto(atoi(line + 1));
			break;
		case 'h':	/* Move relative num horiz. */
			hmove(atoi(line + 1));
			break;
		case 'v':	/* Move relative num vert. */
			vmove(atoi(line + 1));
			break;
		case 'n':	/* End of line. */
			break;
		case 'w':	/* Paddable word space. */
			wordspace = 1;
			break;
		case 'p':	/* New page. */
			newpage(atoi(line + 1));
			break;
		case 'x':	/* Device control... */
			devcontrol(line);
			break;
		case 'D':	/* Drawing function. */
			drawfunc(line);
			break;
		default:	/* NNc. */
			if (!isdigit(line[0]) || !isdigit(line[1])) {
				fprintf(stderr, "Error: bad line %s\n", line);
				return;
			}
			hmove((line[0] - '0') * 10 + (line[1] - '0'));
			writechar(line[2]);
	}
	return;
}

/* Parse an 'x' control line. */

devcontrol(l)
	char *l;
{
	char *line = l + 1;
	char *getword(), *command;
	char *s;
	int i;

	command = getword(&line);
	switch (*command) {
		case 'i':	/* Initialize printer. */
			initprinter();
			break;
		case 'T':	/* The name of the typesetter... */
			break;	/* Who cares? */
		case 'r':	/* Resolution... We know this... */
			break;
		case 'p':	/* Pause... */
			/*** What do we do? */
			break;
		case 's':	/* Quit. */
			cleanup();
			exit(0);
		case 't':	/* Trailer? */
			break;
		case 'f':	/* Make font n be s. */
			s = getword(&line);
			if (!*s) {
				fprintf(stderr, "Error: bad line %s\n", l);
				return;
			}
			i = atoi(s);
			s = getword(&line);
			loadfont(i, s);
			break;
		case 'H':	/* Set character height. */
			s = getword(&line);
			if (!*s) {
				fprintf(stderr, "Error: bad line %s\n", l);
				return;
			}
			i = atoi(s);
			setheight(i);
			break;
		case 'S':	/* Set character slant. */
			s = getword(&line);
			if (!*s) {
				fprintf(stderr, "Error: bad line %s\n", l);
				return;
			}
			i = atoi(s);
			setslant(i);
			break;
		default:
			fprintf(stderr, "Error: bad device control line %s\n",
					l);
			return;
	}
	return;
}

drawfunc(line)
	char *line;
{
	/* This remains to be implemented... */
	return;
}

/* This returns static data... */

char *
getword(s)
	char **s;
{
	static char buf[BUFSIZ];
	int i = 0;

	while (isspace(**s))
		(*s)++;
	while (**s && !isspace(**s))
		buf[i++] = *(*s)++;
	buf[i] = '\0';
	return (buf);
}

/* Create a copy of a string. */

char *
copy(str)
	char *str;
{
	char *p, *tmalloc();
	
	p = tmalloc(strlen(str) + 1);
	strcpy(p, str);
	return(p);
}

/* Malloc num bytes and initialize to zero. Fatal error if the space can't
 * be malloc'd.
 */

char *
tmalloc(num)
	register int num;
{
	register char *s;
	char *malloc();

	if (!(s = malloc((unsigned) num))) {
		fprintf(stderr, "malloc: can't allocate %d bytes.\n", num);
		exit(1);
	}
	bzero(s, num);
	return(s);
}

/* Diagnostic... */

printcoms(i)
	int i;
{
	struct command *c = (struct command *) i;

	while (c) {
		if (*c->c_line == 'p')
			printf("%s [%0x%x, pp = 0x%x, np = 0x%x]\n",
					c->c_line, (int) c, c->c_prevpage,
					c->c_nextpage);
		else
			printf("%s\n", c->c_line);
		c = c->c_next;
	}
	return;
}

/* Everything above this point is completely generic stuff, so lazy people
 * can just change things in the following routines.
 * ======================================================================
 */

startup()
{
	/* The laserjet spits out pages in reverse order. */
	pagereverse = 1;
	hmax = 2500;
	vmax = 3000;
	cursize = 10;
	maxfont = 4;
	return;
}

cleanup()
{
	/* Reset the font, etc on the laserjet. lpd should do this really.  */

	printf("\033E\033&l0O\033(8U\033(s0p10h12v0s0b3T");	/* Font. */
#ifdef notdef
	printf("\033&l14c1e7.64c66F");			/* Page length.  */
	printf("\033&a2L");				/* Left margin. */
#endif

	return;
}

writechar(c)
	char c;
{
	char *curfontname();

	putchar(c);
	hmove(- askwidth(c, curfontname()));
	return;
}

/* Here is the table of special charactrs that can be made with other
 * characters. Acknowledgements to Ron Saad for some of the codes.
 * The widths are for 10 point Tms Rmn.
 */

struct asctab {
	char *a_name;
	char *a_seq;
	int a_width;
} asctab[] = {
	{ "\\|",	"\033&a+3H",			6 } ,
	{ "\\^",	"\033&a+2H",			2 } ,
	{ "em",		"-",				23 } ,
	{ "hy",		"-",				23 } ,
	{ "\\-",	"-",				23 } ,
	{ "dg",		"|\033&a-30H-",			23 } ,
	{ "aa",		"'",				16 } ,
	{ "ga",		"`",				12 } ,
	{ "en",		"-",				23 } ,
	{ "l.",		".",				12 } ,
	{ "br",		"|",				8 } ,
	{ "vr",		"|",				8 } ,
	{ "fm",		"'",				16 } ,
	{ "or",		"|",				8 } ,
	/*
	{ "fi",		"f\033&a-25Hi",			30 } ,
	{ "ff",		"f\033&a-25Hf",			30 } ,
	{ "fl",		"f\033&a-25Hl",			30 } ,
	{ "Fi",		"f\033&a-30Hf\033&a-25Hi",	30 } ,
	{ "Fl", 	"f\033&a-30Hf\033&a-25Hl",	30 } ,
	{ "ce",		"\277",				30 } ,
	*/
	{ "ci",		"O",				33 } ,
	{ "ul",		"_",				35 } ,
	{ "ru",		"_",				35 }
} ;

writespec(s)
	char *s;
{
	int i, nascs = sizeof (asctab) / sizeof (struct asctab);

	for (i = 0; i < nascs; i++)
		if (eq(s, asctab[i].a_name))
			break;
	if (i == nascs) {
		fprintf(stderr, "Error: can't print character '%s'...\n", s);
		return;
	}
	fputs(asctab[i].a_seq, stdout);
	hmove( - asctab[i].a_width);
	return;
}

/* The laserjet uses decipoints, with one decipoint = 720 / 300 pixels. */

#define pixtodec(num)	(((num) * 720) / 300)

hgoto(num)
{
	if ((num < 0) || (num > hmax)) {
		fprintf(stderr, "Error: can't hgoto %d\n", num);
		return;
	}
	hpos = num;
	printf("\033&a%dH", pixtodec(num));
	return;
}

/* This is strange -- ditroff seems to send vgoto's beyond the end of the 
 * page when it wants to go to the end of the page.
 */

vgoto(num)
{
	if ((num < 0) || (num > vmax)) {
		/* fprintf(stderr, "Error: can't vgoto %d\n", num); */
		/* return; */
		num = vmax - 25;	/* Fudge... */
	}
	vpos = num;
	printf("\033&a%dV", pixtodec(num));
	return;
}

hmove(num)
{
	if ((hpos + num < 0) || (hpos + num > hmax)) {
		fprintf(stderr, "Error: can't hmove %d\n", num);
		return;
	}
	hpos += num;
	printf("\033&a%c%dH", (num > 0) ? '+' : '-', pixtodec(abs(num)));
	return;
}

vmove(num)
{
	if ((vpos + num < 0) || (vpos + num > vmax)) {
		fprintf(stderr, "Error: can't vmove %d\n", num);
		return;
	}
	vpos += num;
	printf("\033&a%c%dV", (num > 0) ? '+' : '-', pixtodec(abs(num)));
	return;
}

newpage(num)
{
	curpage = num;
	printf("\n\f");
	return;
}

initprinter()
{
	/* Nothing to do. */
	return;
}

/* Here we assume that the 'B' TMS font cartridge is loaded. */

#define OR_LAND		1
#define OR_PORT		2

#define SY_ROMAN	1
#define SY_KANA		2
#define SY_USASCII	3
#define SY_LINE		4
#define SY_MATH		5

#define SP_FIXED	1
#define SP_PROP		2

#define ST_UPRIGHT	1
#define ST_ITALIC	2

#define SK_LIGHT	1
#define SK_MEDIUM	2
#define SK_BOLD		3

/* Don't change these -- see page 4-22 of the laserjet manual. */

#define TF_LINEPR	0
#define TF_PICA		1
#define TF_ELITE	2
#define TF_COURIER	3
#define TF_HELV		4
#define TF_TMSRMN	5
#define TF_GOTHIC	6
#define TF_SCRIPT	7
#define TF_PRESTIGE	8

struct hpfontinfo {
	char *fi_name;		/* What ditroff calls it. */
	int fi_cartridge;	/* The one-character cartridge name, 0 = res. */
	int fi_orientation;	/* OR_LAND or OR_PORT. */
	int fi_symbolset;	/* SY_ROMAN or SY_USASCII. */
	int fi_spacing;		/* SP_FIXED or SP_PROP. */
	float fi_pitch;
	float fi_point;
	int fi_style;		/* ST_UPRIGHT or ST_ITALIC. */
	int fi_stroke;		/* SK_LIGHT, SK_MEDIUM, or SK_BOLD. */
	int fi_typeface;	/* TF_*. */
	int fi_number;		/* The number given in 'f' commands. */
} carttab[] = {
	{ "", 0, OR_PORT, SY_ROMAN, SP_FIXED, 10.0, 12.0, ST_UPRIGHT,
			SK_MEDIUM, TF_COURIER, 0 } ,
	{ "", 'B', OR_PORT, SY_USASCII, SP_PROP, 0.0, 14.4, ST_UPRIGHT,
			SK_BOLD, TF_HELV , 0} ,
	{ "R", 'B', OR_PORT, SY_USASCII, SP_PROP, 0.0, 10.0, ST_UPRIGHT,
			SK_MEDIUM, TF_TMSRMN, 0 } ,
	{ "B", 'B', OR_PORT, SY_USASCII, SP_PROP, 0.0, 10.0, ST_UPRIGHT,
			SK_BOLD, TF_TMSRMN, 0 } ,
	{ "I", 'B', OR_PORT, SY_USASCII, SP_PROP, 0.0, 10.0, ST_ITALIC,
			SK_MEDIUM, TF_TMSRMN, 0 } ,
	{ "", 'B', OR_PORT, SY_USASCII, SP_PROP, 0.0, 8.0, ST_UPRIGHT,
			SK_LIGHT, TF_TMSRMN, 0 } ,
	{ "", 'B', OR_LAND, SY_ROMAN, SP_FIXED, 16.66, 8.5, ST_UPRIGHT,
			SK_LIGHT, TF_LINEPR, 0 } ,
	{ "", 0, OR_LAND, SY_ROMAN, SP_FIXED, 10.0, 12.0, ST_UPRIGHT,
			SK_MEDIUM, TF_COURIER, 0 }
} ;

loadfont(num, name)
	char *name;
{
	int i, nfonts = sizeof (carttab) / sizeof (struct hpfontinfo);

	for (i = 0; i < nfonts; i++)
		if (eq(name, carttab[i].fi_name))
			break;
	if (i == nfonts) {
		fprintf(stderr, "Error: no such font as '%s'...\n", name);
		return;
	}
	carttab[i].fi_number = num;
	return;
}

setfont(num)
{
	int i, nfonts = sizeof (carttab) / sizeof (struct hpfontinfo);

	for (i = 0; i < nfonts; i++)
		if (carttab[i].fi_number == num)
			break;
	if (i == nfonts) {
		fprintf(stderr, "Error: no such font numbered %d...\n", num);
		return;
	}
	curfont = num;

	/* Now set all the characteristics of this font. */
	switch (carttab[i].fi_orientation) {
		case OR_LAND:
			fputs("\033&l1O", stdout);
			break;
		case OR_PORT:
			fputs("\033&l0O", stdout);
			break;
		default:
			fprintf(stderr, "Error: bad orientation %d\n...",
					carttab[i].fi_orientation);
			return;
	}

	switch (carttab[i].fi_symbolset) {
		case SY_ROMAN:
			fputs("\033(8U", stdout);
			break;
		case SY_KANA:
			fputs("\033(8K", stdout);
			break;
		case SY_USASCII:
			fputs("\033(0U", stdout);
			break;
		case SY_LINE:
			fputs("\033(0B", stdout);
			break;
		case SY_MATH:
			fputs("\033(0A", stdout);
			break;
		default:
			fprintf(stderr, "Error: bad symbol set %d\n...",
					carttab[i].fi_symbolset);
			return;
	}

	switch (carttab[i].fi_spacing) {
		case SP_PROP:
			fputs("\033(s1P", stdout);
			break;
		case SP_FIXED:
			fputs("\033(s0P", stdout);
			break;
		default:
			fprintf(stderr, "Error: bad spacing %d\n...",
					carttab[i].fi_spacing);
			return;
	}

	if (carttab[i].fi_pitch > 0.0)
		printf("\033(s%.2fH", carttab[i].fi_pitch);

	if (carttab[i].fi_point > 0.0)
		printf("\033(s%.2fV", carttab[i].fi_point);

	switch (carttab[i].fi_style) {
		case ST_ITALIC:
			fputs("\033(s1S", stdout);
			break;
		case ST_UPRIGHT:
			fputs("\033(s0S", stdout);
			break;
		default:
			fprintf(stderr, "Error: bad style %d\n...",
					carttab[i].fi_style);
			return;
	}

	switch (carttab[i].fi_stroke) {
		case SK_LIGHT:
			fputs("\033(s-3B", stdout);
			break;
		case SK_MEDIUM:
			fputs("\033(s0B", stdout);
			break;
		case SK_BOLD:
			fputs("\033(s3B", stdout);
			break;
		default:
			fprintf(stderr, "Error: bad stroke weight %d\n...",
					carttab[i].fi_stroke);
			return;
	}
	
	printf("\033(s%dT", carttab[i].fi_typeface);

	return;
}

char *
curfontname()
{
	int i, nfonts = sizeof (carttab) / sizeof (struct hpfontinfo);

	for (i = 0; i < nfonts; i++)
		if (carttab[i].fi_number == curfont)
			break;
	if (i == nfonts)
		return (NULL);
	else
		return (carttab[i].fi_name);
}

setheight(num)
{
	/* Can't do this apart from setting font... */
	fprintf(stderr, "Error: can't set height...\n");
	return;
}

setslant(num)
{
	/* Can't do this apart from setting font... */
	fprintf(stderr, "Error: can't set slant...\n");
	return;
}

setsize(num)
{
	/* Can't do this apart from setting font... */
	if (num != cursize)
		fprintf(stderr, "Error: can't set size...\n");
	return;
}

!Funky!Stuff!
echo x - width.c
cat >width.c <<'!Funky!Stuff!'

/* RCS Info: $Revision: $ on $Date: $
 *           $Source: $
 * Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
 *	Permission is granted to do anything with this code except sell it
 *	or remove this message.
 *
 * This is a hack to make up for the fact that the laserjet is strange...
 */

int R_width[] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 12, 15, 29, 23, 35, 35, 16,
	15, 16, 21, 23, 14, 23, 12, 21,
	23, 23, 23, 23, 23, 23, 23, 23,
	23, 23, 10, 12, 24, 25, 24, 21,
	38, 35, 29, 31, 34, 30, 28, 36,
	35, 16, 20, 37, 30, 42, 35, 33,
	26, 33, 34, 22, 30, 37, 34, 38,
	36, 33, 31, 13, 21, 14, 24, 35,
	12, 21, 25, 21, 25, 21, 19, 23,
	25, 14, 17, 25, 13, 36, 25, 22,
	25, 24, 17, 17, 15, 25, 24, 34,
	24, 24, 20, 16, 8, 17, 25
} ;

int B_width[] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 13, 18, 28, 24, 38, 34, 12,
	17, 19, 17, 24, 13, 23, 13, 22,
	24, 24, 24, 24, 24, 24, 24, 24,
	24, 24, 11, 11, 25, 26, 25, 21,
	41, 32, 31, 31, 32, 29, 27, 35,
	37, 18, 24, 33, 29, 41, 33, 34,
	28, 34, 32, 26, 30, 35, 33, 41,
	32, 31, 32, 13, 22, 14, 26, 33,
	12, 22, 24, 21, 24, 21, 19, 23,
	27, 14, 17, 26, 14, 36, 25, 22,
	24, 24, 18, 18, 16, 24, 20, 32,
	24, 23, 20, 16, 8, 17, 30
} ;

int I_width[] = {
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 17, 17, 27, 23, 31, 31, 20,
	20, 20, 21, 21, 11, 22, 11, 31,
	22, 22, 22, 22, 22, 22, 22, 22,
	22, 22, 17, 17, 30, 25, 31, 21,
	50, 29, 29, 30, 33, 29, 29, 29,
	35, 19, 24, 30, 29, 40, 33, 33,
	28, 33, 32, 28, 30, 33, 31, 35,
	34, 29, 33, 24, 12, 24, 22, 33,
	9, 22, 24, 22, 25, 20, 21, 25,
	23, 14, 21, 24, 14, 36, 25, 21,
	24, 21, 17, 18, 14, 21, 19, 31,
	25, 23, 23, 21, 7, 21, 25
} ;

/* This routine returns the width of the character in the given font. It
 * should really read the device description file...
 */

askwidth(ch, ft)
	char *ft;
{
	if (!strcmp(ft, "R"))
		return (R_width[ch]);
	else if (!strcmp(ft, "B"))
		return (B_width[ch]);
	else if (!strcmp(ft, "I"))
		return (I_width[ch]);
}

!Funky!Stuff!
echo x - pagereverse.c
cat >pagereverse.c <<'!Funky!Stuff!'

/* RCS Info: $Revision: 1.1 $ on $Date: 85/10/29 14:44:13 $
 *           $Source: /cad4/faustus/src/laserjet/RCS/pagereverse.c,v $
 * Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
 *	Permission is granted to do anything with this code except sell it
 *	or remove this message.
 *
 * Reverse the pages in a file. Usage is pagereverse [pagelength].
 */

#include <stdio.h>

#define MAXPAGES 10000

main(ac, av)
	char **av;
{
	register plen = 66, pnum = 0, line = 0, i = 0;
	long pages[MAXPAGES];	/* The beginning of each page. */
	char buf[BUFSIZ];
	char *mktemp(), *tempf = "/tmp/prXXXXXX";
	FILE *fopen(), *fp;

	if (ac == 2) {
		plen = atoi(av[1]);
		if ((plen <= 0) || (plen > 1000)) {
			fprintf(stderr, "Usage: %s [pagelen]\n");
			exit(1);
		}
	} else if (ac > 2) {
		fprintf(stderr, "Usage: %s [pagelen]\n");
		exit(1);
	}
	tempf = mktemp(tempf);
	if (!(fp = fopen(tempf, "w+"))) {
		perror(tempf);
		exit(1);
	}
	pages[0] = 0;

	/* Copy all the lines and figure out the page boundaries. */
	while (fgets(buf, BUFSIZ, stdin)) {
		if (line++ == plen - (pnum ? 1 : 0)) {
			pages[++pnum] = i;
			line = 0;
		}
		if (*buf == '\f') {
			/* Now we have to expand this as newlines. */
			while (line++ <= plen) {
				putc('\n', fp);
			}
			pages[++pnum] = ftell(fp);
			line = 0;
		} else {
			fputs(buf, fp);
		}
		i = ftell(fp);
	}
	fflush(fp);

	/* Now go back and output them in reversed order. */
	while (pnum >= 0) {
		fseek(fp, pages[pnum], 0);
		for (i = 0; i < plen; i++) {
			if (!fgets(buf, BUFSIZ, fp)) {
				/* Fill the last page with blank lines... */
				while (i++ < plen)
					putchar('\n');
				break;
			}
			fputs(buf, stdout);
		}
		pnum--;
	}
	fclose(fp);
	unlink(tempf);
	exit(0);
}

!Funky!Stuff!
echo x - DESC
cat >DESC <<'!Funky!Stuff!'
# Laserjet Ditroff Description file
fonts 3 R I B
sizes 10 0
unitwidth 10
# This should be res 300, but ditroff is so screwed up...
res 290
hor 2
vert 2
# This is evil -- ditroff ignores these two values completely.
paperwidth 2500
paperlength 2500
# I have yet to add the MSB-set characters that the lj accepts -- these
# are all simulated with ascii.
charset
Fi Fl \- \^ \| aa br ce ci dg em en ff fi fl fm ga hy l. or ru ul vr
!Funky!Stuff!
echo x - R
cat >R <<'!Funky!Stuff!'
# Tms Rmn 
name R
ligatures 0
# char	width	u/d	octal
charset
!	12	2	41
"	15	2	42
#	29	3	43
$	23	2	44
%	35	2	45
&	35	2	46
'	16	2	47
(	15	3	50
)	16	3	51
*	21	2	52
+	23	2	53
,	14	0	54
-	23	0	55
.	12	0	56
/	21	2	57
0	23	2	60
1	23	2	61
2	23	2	62
3	23	2	63
4	23	2	64
5	23	2	65
6	23	2	66
7	23	2	67
8	23	2	70
9	23	2	71
:	10	0	72
;	12	0	73
<	24	2	74
=	25	0	75
>	24	2	76
?	21	2	77
@	38	2	100
A	35	2	101
B	29	2	102
C	31	2	103
D	34	2	104
E	30	2	105
F	28	2	106
G	36	2	107
H	35	2	110
I	16	2	111
J	20	2	112
K	37	2	113
L	30	2	114
M	42	2	115
N	35	2	116
O	33	2	117
P	26	2	120
Q	33	2	121
R	34	2	122
S	22	2	123
T	30	2	124
U	37	2	125
V	34	2	126
W	38	2	127
X	36	2	130
Y	33	2	131
Z	31	2	132
[	13	3	133
\	21	2	134
]	14	3	135
^	24	0	136
_	35	0	137
`	12	2	140
a	21	0	141
b	25	2	142
c	21	0	143
d	25	2	144
e	21	0	145
f	19	2	146
g	23	1	147
h	25	2	150
i	14	2	151
j	17	3	152
k	25	2	153
l	13	2	154
m	36	0	155
n	25	0	156
o	22	0	157
p	25	1	160
q	24	1	161
r	17	0	162
s	17	0	163
t	15	2	164
u	25	0	165
v	24	0	166
w	34	0	167
x	24	0	170
y	24	1	171
z	20	0	172
{	16	3	173
|	8	3	174
}	17	3	175
~	25	0	176
\|	6	0	0
\^	2	0	0
em	23	0	0
hy	23	0	0
\-	0	0	0	xxx
ce	0	0	0	xxx
dg	0	0	0	xxx
aa	16	0	0
ga	12	0	0
en	23	0	0
l.	12	0	0
br	8	0	0
vr	8	0	0
fm	16	0	0
or	8	0	0
fi	30	0	0	xxx
ff	30	0	0	xxx
fl	30	0	0	xxx
Fi	30	0	0	xxx
Fl	30	0	0	xxx
ci	33	0	0
ul	35	0	0
ru	35	0	0
!Funky!Stuff!
echo x - I
cat >I <<'!Funky!Stuff!'
# Tms Rmn Italic
name I
ligatures 0
# char	width	u/d	octal
charset
!	17	2	41
"	17	2	42
#	27	3	43
$	23	2	44
%	31	2	45
&	31	2	46
'	20	2	47
(	20	3	50
)	20	3	51
*	21	2	52
+	21	2	53
,	11	0	54
-	22	0	55
.	11	0	56
/	31	2	57
0	22	2	60
1	22	2	61
2	22	2	62
3	22	2	63
4	22	2	64
5	22	2	65
6	22	2	66
7	22	2	67
8	22	2	70
9	22	2	71
:	17	0	72
;	17	0	73
<	30	2	74
=	25	0	75
>	31	2	76
?	21	2	77
@	50	2	100
A	29	2	101
B	29	2	102
C	30	2	103
D	33	2	104
E	29	2	105
F	29	2	106
Fi	30	0	0	xxx
Fl	30	0	0	xxx
G	29	2	107
H	35	2	110
I	19	2	111
J	24	2	112
K	30	2	113
L	29	2	114
M	40	2	115
N	33	2	116
O	33	2	117
P	28	2	120
Q	33	3	121
R	32	2	122
S	28	2	123
T	30	2	124
U	33	2	125
V	31	2	126
W	35	2	127
X	34	2	130
Y	29	2	131
Z	33	2	132
[	24	3	133
\	12	2	134
\-	0	0	0	xxx
\^	2	0	0
\|	6	0	0
]	24	3	135
^	22	0	136
_	33	0	137
`	9	2	140
a	22	0	141
aa	16	0	0
b	24	2	142
br	8	0	0
c	22	0	143
ce	0	0	0	xxx
ci	33	0	0
d	25	2	144
dg	0	0	0	xxx
e	20	0	145
em	23	0	0
en	23	0	0
f	21	3	146
ff	30	0	0	xxx
fi	30	0	0	xxx
fl	30	0	0	xxx
fm	16	0	0
g	25	1	147
ga	12	0	0
h	23	2	150
hy	23	0	0
i	14	2	151
j	21	3	152
k	24	2	153
l	14	2	154
l.	12	0	0
m	36	0	155
n	25	0	156
o	21	0	157
or	8	0	0
p	24	1	160
q	21	1	161
r	17	0	162
ru	35	0	0
s	18	0	163
t	14	2	164
u	21	0	165
ul	35	0	0
v	19	0	166
vr	8	0	0
w	31	0	167
x	25	0	170
y	23	1	171
z	23	0	172
{	21	3	173
|	7	3	174
}	21	3	175
~	25	0	176
!Funky!Stuff!
echo x - B
cat >B <<'!Funky!Stuff!'
# Tms Rmn Bold
name B
ligatures 0
# char	width	u/d	octal
charset
!	13	2	41
"	18	2	42
#	28	3	43
$	24	2	44
%	38	2	45
&	34	2	46
'	12	2	47
(	17	3	50
)	19	3	51
*	17	2	52
+	24	2	53
,	13	0	54
-	23	0	55
.	13	0	56
/	22	2	57
0	24	2	60
1	24	2	61
2	24	2	62
3	24	2	63
4	24	2	64
5	24	2	65
6	24	2	66
7	24	2	67
8	24	2	70
9	24	2	71
:	11	0	72
;	11	0	73
<	25	2	74
=	26	0	75
>	25	2	76
?	21	2	77
@	41	2	100
A	32	2	101
B	31	2	102
C	31	2	103
D	32	2	104
E	29	2	105
F	27	2	106
Fi	30	0	0	xxx
Fl	30	0	0	xxx
G	35	2	107
H	37	2	110
I	18	2	111
J	24	2	112
K	33	2	113
L	29	2	114
M	41	2	115
N	33	2	116
O	34	2	117
P	28	2	120
Q	34	2	121
R	32	2	122
S	26	2	123
T	30	2	124
U	35	2	125
V	33	2	126
W	41	2	127
X	32	2	130
Y	31	2	131
Z	32	2	132
[	13	3	133
\	22	2	134
\-	0	0	0	xxx
\^	2	0	0
\|	6	0	0
]	14	3	135
^	26	0	136
_	33	0	137
`	12	2	140
a	22	0	141
aa	16	0	0
b	24	2	142
br	8	0	0
c	21	0	143
ce	0	0	0	xxx
ci	33	0	0
d	24	2	144
dg	0	0	0	xxx
e	21	0	145
em	23	0	0
en	23	0	0
f	19	2	146
ff	30	0	0	xxx
fi	30	0	0	xxx
fl	30	0	0	xxx
fm	16	0	0
g	23	1	147
ga	12	0	0
h	27	2	150
hy	23	0	0
i	14	2	151
j	17	3	152
k	26	2	153
l	14	2	154
l.	12	0	0
m	36	0	155
n	25	0	156
o	22	0	157
or	8	0	0
p	24	1	160
q	24	1	161
r	18	0	162
ru	35	0	0
s	18	0	163
t	16	2	164
u	24	0	165
ul	35	0	0
v	20	0	166
vr	8	0	0
w	32	0	167
x	24	0	170
y	23	1	171
z	20	0	172
{	16	3	173
|	8	3	174
}	17	3	175
~	30	0	176
!Funky!Stuff!