xref: /csrg-svn/local/transcript/src/psdit.c (revision 37310)
1*37310Sedward /*	@(#)psdit.c	1.6 04/03/89	*/
230594Ssam #ifndef lint
330594Ssam static char Notice[] = "Copyright (c) 1984, 1985 Adobe Systems Incorporated";
432179Sedward static char *RCSID = "$Header: psdit.c,v 2.1 85/11/24 11:50:41 shore Rel $";
530594Ssam #endif
630595Ssam # define XMOD
732179Sedward /*
832179Sedward  * Changed by Edward Wang (edward@ucbarpa.berkeley.edu) to handle graphics,
932179Sedward  * 17 Feb, 87, with code provided by John Coker (john@renoir.berkeley.edu)
1032179Sedward  * and Peehong Chen (phc@renoir.berkeley.edu).
1132179Sedward  */
1230594Ssam /* psdit.c
1330594Ssam  *
1430594Ssam  * Copyright (c) 1984, 1985 Adobe Systems Incorporated
1530594Ssam  *
1630594Ssam  * ditroff intermediate file to PostScript translator
1730594Ssam  *
1830594Ssam  * Original Version: Barry Hayes spring/summer 1984
1930594Ssam  * Edit History:
2030594Ssam  * Andrew Shore: Sat Nov 23 20:05:26 1985
2130594Ssam  * End Edit History.
2230594Ssam  *
2330594Ssam  * RCSLOG:
2430594Ssam  * $Log:	psdit.c,v $
2530594Ssam  * Revision 2.1  85/11/24  11:50:41  shore
2630594Ssam  * Product Release 2.0
2732179Sedward  *
2830594Ssam  * Revision 1.8  85/11/23  20:09:44  shore
2930594Ssam  * test for termination of included PostScript was bad
3032179Sedward  *
3130594Ssam  * Revision 1.7  85/11/21  14:23:56  shore
3230594Ssam  * added envget check for PSLIBDIR
3332179Sedward  *
3430594Ssam  * Revision 1.6  85/11/20  00:43:43  shore
3530594Ssam  * support for included PostScript
3630594Ssam  * big rework on FlushShow, word "breaks"
3730594Ssam  * removed FlushFont and made them instant
3830594Ssam  * Still no Gremlin support yet
3932179Sedward  *
4030594Ssam  * Revision 1.5  85/10/03  10:48:09  shore
4130594Ssam  * added FlushShow to xf fix !
4232179Sedward  *
4330594Ssam  * Revision 1.4  85/10/02  16:20:32  shore
4432179Sedward  * fixed xf bug
4530594Ssam  * mounting a font causes a font switch!
4632179Sedward  *
4730594Ssam  * Revision 1.3  85/07/09  13:10:20  shore
4830594Ssam  * added fclose on map file
4932179Sedward  *
5030594Ssam  * Revision 1.2  85/05/14  11:24:23  shore
5130594Ssam  * added flush to trailer
5230594Ssam  * fixed read bug when mounting fonts
5330594Ssam  */
5430594Ssam 
5532179Sedward /*
5630594Ssam output language from troff:
5730594Ssam all numbers are character strings
5830594Ssam 
5930594Ssam sn	size in points
6030594Ssam fn	font as number from 1-n
6130594Ssam cx	ascii character x
6230594Ssam Cxyz	funny char xyz. terminated by white space
6330594Ssam Hn	go to absolute horizontal position n
6430594Ssam Vn	go to absolute vertical position n (down is positive)
6530594Ssam hn	go n units horizontally (relative)
6630594Ssam vn	ditto vertically
6730594Ssam nnc	move right nn, then print c (exactly 2 digits!)
6830594Ssam 		(this wart is an optimization that shrinks output file size
6930594Ssam 		 about 35% and run-time about 15% while preserving ascii-ness)
7030594Ssam Dt ...\n	draw operation 't':
7130594Ssam 	Dl x y		line from here by x,y
7230594Ssam 	Dc d		circle of diameter d with left side here
7330594Ssam 	De x y		ellipse of axes x,y with left side here
7430594Ssam 	Da x y r	arc counter-clockwise by x,y of radius r
7532179Sedward 	Dp ...		bordered polygon
7632179Sedward 	DP ...		unbordered polygon
7732179Sedward 	D~ x y x y ...	b-spline by x,y then x,y ...
7832179Sedward 	Dg ...		gremlin curve
7932179Sedward 	Dz ...		bezier curve
8030594Ssam nb a	end of line (information only -- no action needed)
8130594Ssam 	a = space before line, a = after
8230594Ssam w	paddable word space -- no action needed
8330594Ssam pn	new page begins -- set v to 0
8430594Ssam {	push current environment (font info & location)
8530594Ssam }	pop a saved environment
8630594Ssam txxxx	print string xxxx using natural widths
8730594Ssam #...\n	comment
8830594Ssam x ...\n	device control functions:
8930594Ssam 	x i[nit]	init
9030594Ssam 	x T s		name of device is s
9130594Ssam 	x r[es] n h v	resolution is n/inch
9230594Ssam 			h = min horizontal motion, v = min vert
9330594Ssam 	x p[ause]	pause (can restart)
9430594Ssam 	x s[top]	stop -- done for ever
9530594Ssam 	x t[railer]	generate trailer
9630594Ssam 	x f[font] n s	font position n contains font s
9730594Ssam 	x H[eight] n	set character height to n
9830594Ssam 	x S[slant] n	set slant to N
9930594Ssam 
10030594Ssam Adobe Extension for included PostScript:
10130594Ssam %
10230594Ssam (raw postscript...)
10330594Ssam .\n
10430594Ssam 
10530594Ssam */
10630594Ssam 
10730594Ssam #include <stdio.h>
10830594Ssam #include <ctype.h>
10930594Ssam #include <signal.h>
11030594Ssam #include <pwd.h>
11130594Ssam #ifdef SYSV
11230594Ssam extern struct passwd *getpwuid();
11330594Ssam #endif
11430594Ssam #include "transcript.h"
11530594Ssam 
11630594Ssam #include "dev.h"
11730594Ssam 
11830594Ssam char *malloc();
11930594Ssam 
12030594Ssam #define	NFONT	10
12130594Ssam 
12230594Ssam /* DIT state consists of: */
12332179Sedward int	hpos;		/* current horizontal position */
12432179Sedward int	vpos;		/* current vertical position */
12532179Sedward int	fontsize;	/* current font size */
12632179Sedward int	fontheight;	/* current character height */
12732179Sedward int	fontslant;	/* current font slant */
12832179Sedward int	font;		/* current font */
12932179Sedward int	resolution;	/* device resolution */
13032179Sedward int	minhoriz;	/* minimum horizontal motion */
13132179Sedward int	minvert;	/* minimum vertical motion */
13234804Sedward int	stipplefont;	/* current stipple font */
13330594Ssam 
13432179Sedward int	onspecial;
13532179Sedward int	specfont;
13632179Sedward int	prevfont;
13732179Sedward int 	pfont;
13830594Ssam 
13930594Ssam /* {} push/pop stack */
14030594Ssam #define DSTACK 10
14132179Sedward struct ditstack {
14232179Sedward 	int hpos, vpos, fontsize, fontheight, fontslant, font;
14330594Ssam } ditstack[DSTACK];
14432179Sedward int dlevel = 0;
14530594Ssam 
14630594Ssam #define ErrorTolerance 48
14730594Ssam #define PSWID 0x00000FFF
14830594Ssam #define ISPSPROC 0x000FF000
14930594Ssam 
15030594Ssam /* PSscale is equivalent to (x * PSmag / 72000) + 0.5 */
15130594Ssam #define PSmag 16
15232179Sedward #define PSscale(x) (((x) + 2250) / 4500)
15330594Ssam 
15430594Ssam /* we maintain PS coords with PSmag times the precision */
15530594Ssam /* current PS state is: */
15630594Ssam 
15732179Sedward int	PSx;		/* current horizontal position */
15832179Sedward int	PSy;		/* current vertical position */
15932179Sedward int	savex, savey;	/* position of start of current show string */
16030594Ssam 
16130594Ssam /* ps move types -- note that XMOVE|YMOVE == XYMOVE ! */
16232179Sedward #define NONE	0
16332179Sedward #define XMOVE	1
16432179Sedward #define YMOVE	2
16532179Sedward #define XYMOVE	3
16630594Ssam 
16732179Sedward int movepending = NONE;
16830594Ssam 
16930594Ssam /* buffer string for show -- save up adjacent chars */
17030594Ssam #define SHOWSIZE 400
17132179Sedward char showbuf[SHOWSIZE + 3]; /* extras are for quoting */
17232179Sedward int showind = 0;	/* index into string of next available byte */
17332179Sedward int PSshowlen = 0;	/* size in big units of buffered string */
17432179Sedward int nshow = 0;		/* actual number of show chars in showbuf */
17532179Sedward int startx;		/* troff starting pos of current string */
17632179Sedward int thisw;
17730594Ssam 
17830594Ssam /* #define NONE 0 */
17932179Sedward #define HMOT	1
18032179Sedward #define VMOT	2
18132179Sedward #define CPUT	4
18232179Sedward #define BRK	8
18332179Sedward #define FNT	16
18432179Sedward int lastcmd;
18530594Ssam 
18632179Sedward int	output = 0;	/* do we do output at all? */
18732179Sedward int	nolist = 0;	/* output page list if > 0 */
18832179Sedward int	olist[20];	/* pairs of page numbers */
18932179Sedward int	spage = 9999;	/* stop every spage pages */
19032179Sedward int	scount = 0;
19132179Sedward int	stopped = 0;
19232179Sedward int	pageno = 0;
19332179Sedward int	firstpage = TRUE;
19430594Ssam 
19532179Sedward struct dev dev;
19632179Sedward struct font *fontbase[NFONT+1];
19732179Sedward short	*pstab;
19832179Sedward int	dres;	/* resolution from DESC */
19932179Sedward int	nsizes; /* number of point sizes from DESC */
20032179Sedward int	nfonts; /* number of fonts from DESC */
20132179Sedward int	smnt;	/* index of first special font */
20232179Sedward int	nchtab;
20332179Sedward char	*chname;
20432179Sedward short	*chtab;
20532179Sedward char	*fitab[NFONT+1];
20632179Sedward char	*widthtab[NFONT+1];	/* widtab would be a better name */
20732179Sedward char	*codetab[NFONT+1];	/* device codes */
20830594Ssam 
20932179Sedward int	*pswidths[NFONT+1]; /* ps width tables */
21032179Sedward int	fontdelta[NFONT+1]; /* nonzero if xf overwrites font i */
21130594Ssam 
21230594Ssam /* font position info: */
21332179Sedward struct {
21430594Ssam 	char *name;
21530594Ssam 	int number;
21630594Ssam } fontname[NFONT+1];
21730594Ssam 
21830594Ssam #define	FATAL	1
21930594Ssam #define	BMASK	0377
22030594Ssam 
22130594Ssam #ifdef DEBUG
22232179Sedward int	dbg = 0;
22330594Ssam int	fdbg = 0;
22432179Sedward #define debugp(xxx) (dbg != 0 ? (dbg--, printf xxx, fflush(stdout)) : 0)
22530594Ssam #else
22630594Ssam #define debugp(x)
22730594Ssam #endif
22830594Ssam 
22932179Sedward char	devname[20] = "psc";
23030594Ssam 
23132179Sedward char	*infilename = "stdin"; /* input file name */
23232179Sedward char	*prologfile = PSDITPRO;
23332179Sedward char	*ditdir = DitDir;
23430594Ssam 
23532179Sedward char	*prog;		/* argv[0] - program name */
23630594Ssam 
23734009Sedward 	/* for curve and polygon drawing */
23832179Sedward #define MAXPOINTS	200
23934009Sedward double x[MAXPOINTS], y[MAXPOINTS];
24034009Sedward int numpoints;
24132179Sedward 
main(argc,argv)24230594Ssam main(argc, argv)
24332179Sedward 	int argc;
24432179Sedward 	char *argv[];
24530594Ssam {
24632179Sedward 	FILE *fp;
24732179Sedward 	int done();
24830594Ssam 
24932179Sedward 	prog = argv[0];
25032179Sedward 	while (argc > 1 && argv[1][0] == '-') {
25132179Sedward 		switch (argv[1][1]) {
25232179Sedward 		case 'f':
25332179Sedward 		case 'F':
25432179Sedward 			if (argv[1][2])
25532179Sedward 				ditdir = &argv[1][2];
25632179Sedward 			else {
25732179Sedward 				ditdir = argv[2];
25832179Sedward 				argv++;
25932179Sedward 				argc--;
26032179Sedward 			}
26132179Sedward 			break;
26232179Sedward 		case 'p':
26332179Sedward 			if (argv[1][2])
26432179Sedward 				prologfile = &argv[1][2];
26532179Sedward 			break;
26632179Sedward 		case 'o':
26732179Sedward 			outlist(&argv[1][2]);
26832179Sedward 			break;
26932179Sedward 		case 'd':
27032179Sedward #ifdef DEBUG
27132179Sedward 			dbg = atoi(&argv[1][2]);
27232179Sedward 			if (dbg == 0)
27332179Sedward 				dbg = 1;
27432179Sedward #endif DEBUG
27532179Sedward 			break;
27632179Sedward 		case 'b': 		/* ignore busy */
27732179Sedward 			break;
27832179Sedward 		case 'w': 		/* ignore wait */
27932179Sedward 			break;
28032179Sedward 		case 's':
28132179Sedward 			spage = atoi(&argv[1][2]);
28232179Sedward 			if (spage <= 0)
28332179Sedward 				spage = 9999;
28432179Sedward 			break;
28530594Ssam 		}
28632179Sedward 		argc--;
28732179Sedward 		argv++;
28830594Ssam 	}
28930594Ssam 
29032179Sedward 	if (signal(SIGINT, done) == SIG_IGN) {
29132179Sedward 		signal(SIGINT, SIG_IGN);
29232179Sedward 		signal(SIGQUIT, SIG_IGN);
29332179Sedward 		signal(SIGHUP, SIG_IGN);
29432179Sedward 	} else {
29532179Sedward 		signal(SIGQUIT, done);
29632179Sedward 		signal(SIGHUP, done);
29732179Sedward 	}
29832179Sedward 	signal(SIGTERM, done);
29930594Ssam 
30032179Sedward 	preface();
30130594Ssam 
30232179Sedward 	if (argc <= 1)
30332179Sedward 		conv(stdin);
30432179Sedward 	else
30532179Sedward 		while (--argc > 0) {
30632179Sedward 			if (strcmp(*++argv, "-") == 0)
30732179Sedward 				fp = stdin;
30832179Sedward 			else if ((fp = fopen(*argv, "r")) == NULL) {
30932179Sedward 				fprintf(stderr, "%s: can't open %s\n",
31032179Sedward 					prog, *argv);
31132179Sedward 				pexit(prog, 2);
31232179Sedward 			}
31332179Sedward 			infilename = *argv;
31432179Sedward 			conv(fp);
31532179Sedward 			(void) fclose(fp);
31632179Sedward 		}
31732179Sedward 	done();
31830594Ssam }
31930594Ssam 
32032179Sedward /* process list of page numbers to be printed */
outlist(s)32132179Sedward outlist(s)
32232179Sedward 	register char *s;
32330594Ssam {
32432179Sedward 	int n1, n2, i;
32530594Ssam 
32632179Sedward 	nolist = 0;
32732179Sedward 	while (*s) {
32832179Sedward 		n1 = 0;
32932179Sedward 		if (isdigit (*s))
33032179Sedward 			do
33132179Sedward 				n1 = 10 * n1 + *s++ - '0';
33232179Sedward 			while (isdigit(*s));
33332179Sedward 		else
33432179Sedward 			n1 = -9999;
33532179Sedward 		n2 = n1;
33632179Sedward 		if (*s == '-') {
33732179Sedward 			s++;
33832179Sedward 			n2 = 0;
33932179Sedward 			if (isdigit(*s))
34032179Sedward 				do
34132179Sedward 					n2 = 10 * n2 + *s++ - '0';
34232179Sedward 				while (isdigit(*s));
34332179Sedward 			else
34432179Sedward 				n2 = 9999;
34530594Ssam 		}
34632179Sedward 		olist[nolist++] = n1;
34732179Sedward 		olist[nolist++] = n2;
34832179Sedward 		if (*s != '\0')
34932179Sedward 			s++;
35030594Ssam 	}
35132179Sedward 	olist[nolist] = 0;
35230594Ssam #ifdef DEBUG
35332179Sedward 	if (dbg)
35432179Sedward 		for (i = 0; i < nolist; i += 2)
35532179Sedward 			printf("%3d %3d\n", olist[i], olist[i + 1]);
35632179Sedward #endif
35730594Ssam }
35830594Ssam 
conv(fp)35932179Sedward conv(fp)	/* convert a file */
36032179Sedward 	register FILE *fp;
36130594Ssam {
36232179Sedward 	register int c, k;
36332179Sedward 	int m, n, n1, m1;
364*37310Sedward 	char str[100], buf[1024];
36530594Ssam 
36632179Sedward 	while ((c = getc(fp)) != EOF)
36732179Sedward 		switch (c) {
36832179Sedward 		case '\n': case ' ': case '\0':
36930594Ssam 			break;
37032179Sedward 		case '{': 		/* push down current environment */
37132179Sedward 			t_push();
37230594Ssam 			break;
37332179Sedward 		case '}':
37432179Sedward 			t_pop();
37530594Ssam 			break;
37632179Sedward 		case '0': case '1': case '2': case '3': case '4':
37732179Sedward 		case '5': case '6': case '7': case '8': case '9':
37832179Sedward 			/* two motion digits plus a character */
37932179Sedward 			hmot((c - '0') * 10 + getc(fp) - '0');
38032179Sedward 			lastcmd = HMOT;
38132179Sedward 			put1(getc(fp), (char *) 0);
38232179Sedward 			lastcmd = CPUT;
38330594Ssam 			break;
38432179Sedward 		case 'c': 		/* single ascii character */
38532179Sedward 			put1(getc(fp), (char *) 0);
38632179Sedward 			lastcmd = CPUT;
38730594Ssam 			break;
38832179Sedward 		case 'C':
38932179Sedward 			fscanf(fp, "%s", str);
39032179Sedward 			put1s(str);
39132179Sedward 			lastcmd = CPUT;
39232179Sedward 			break;
39332179Sedward 		case 't': 		/* straight text */
39432179Sedward 			fgets(buf, sizeof buf, fp);
39532179Sedward 			t_text(buf);
39632179Sedward 			lastcmd = CPUT;
39732179Sedward 			break;
39832179Sedward 		case 'D': 		/* draw function */
39932179Sedward 			fgets(buf, sizeof buf, fp);
40032179Sedward 			switch (buf[0]) {
40132179Sedward 			case 'l': 	/* draw a line */
40232179Sedward 				sscanf(buf + 1, "%d %d", &n, &m);
40332179Sedward 				drawline(n, m);
40432179Sedward 				break;
40532179Sedward 			case 'c': 	/* circle */
40632179Sedward 				sscanf(buf + 1, "%d", &n);
40732179Sedward 				drawcirc(n);
40832179Sedward 				break;
40932179Sedward 			case 'e': 	/* ellipse */
41032179Sedward 				sscanf(buf + 1, "%d %d", &m, &n);
41132179Sedward 				drawellip(m, n);
41232179Sedward 				break;
41332179Sedward 			case 'a': 	/* arc */
41432179Sedward 				sscanf(buf + 1, "%d %d %d %d",
41532179Sedward 					&n, &m, &n1, &m1);
41632179Sedward 				drawarc(n, m, n1, m1);
41732179Sedward 				break;
41832179Sedward 			case '~': 	/* b-spline */
41932179Sedward 			case 'g': 	/* gremlin curve */
42032179Sedward 			case 'z': 	/* bezier cubic */
42134009Sedward 				drawcurve(buf);
42232179Sedward 				break;
42332179Sedward 			case 'p': 	/* filled polygon */
42432179Sedward 			case 'P': 	/* bordered filled polygon */
42534009Sedward 				drawpoly(buf);
42632179Sedward 				break;
42732179Sedward 			case 't': 	/* line thickness */
42832179Sedward 			case 's': 	/* line style */
42932179Sedward 				sscanf(buf + 1, "%d", &n);
43032179Sedward 				printf("%d D%c\n", n, buf[0]);
43132179Sedward 				break;
43232179Sedward 			default:
43332179Sedward 				fprintf(stderr,
43432179Sedward 					"%s: unknown drawing function %s\n",
43532179Sedward 					prog, buf);
43632179Sedward 				exit(2);
43732179Sedward 			}
43832179Sedward 			break;
43932179Sedward 		case 'i':
44034804Sedward 			fscanf(fp, "%d", &stipplefont);
44134804Sedward 			printf("%d i\n", stipplefont);
44232179Sedward 			break;
44332179Sedward 		case 's':
44432179Sedward 			fscanf(fp, "%d", &n);
44532179Sedward 			t_size(n);
44632179Sedward 			lastcmd = FNT;
44732179Sedward 			break;
44832179Sedward 		case 'f':
44932179Sedward 			fscanf(fp, "%s", str);
45032179Sedward 			setfont(t_font(str));
45132179Sedward 			lastcmd = FNT;
45232179Sedward 			break;
45332179Sedward 		case 'H': 		/* absolute horizontal motion */
45432179Sedward 			while ((c = getc(fp)) == ' ')
45532179Sedward 				;
45632179Sedward 			k = 0;
45732179Sedward 			do
45832179Sedward 				k = 10 * k + c - '0';
45932179Sedward 			while (isdigit(c = getc(fp)));
46032179Sedward 			ungetc(c, fp);
46132179Sedward 			hgoto(k);
46232179Sedward 			lastcmd = HMOT;
46332179Sedward 			break;
46432179Sedward 		case 'h': 		/* relative horizontal motion */
46532179Sedward 			while ((c = getc(fp)) == ' ')
46632179Sedward 				;
46732179Sedward 			k = 0;
46832179Sedward 			do
46932179Sedward 				k = 10 * k + c - '0';
47032179Sedward 			while (isdigit(c = getc(fp)));
47132179Sedward 			ungetc(c, fp);
47232179Sedward 			hmot(k);
47332179Sedward 			lastcmd = HMOT;
47432179Sedward 			break;
47532179Sedward 		case 'w':
47632179Sedward 			FlushShow(1);
47732179Sedward 			lastcmd = BRK;
47832179Sedward 			break;
47932179Sedward 		case 'V':
48032179Sedward 			fscanf(fp, "%d", &n);
48132179Sedward 			vgoto(n);
48232179Sedward 			lastcmd = VMOT;
48332179Sedward 			break;
48432179Sedward 		case 'v':
48532179Sedward 			fscanf(fp, "%d", &n);
48632179Sedward 			vmot(n);
48732179Sedward 			lastcmd = VMOT;
48832179Sedward 			break;
48932179Sedward 		case 'p': 		/* new page */
49032179Sedward 			fscanf(fp, "%d", &n);
49132179Sedward 			t_page(n);
49232179Sedward 			lastcmd = NONE;
49332179Sedward 			break;
49432179Sedward 		case 'n': 		/* end of line -- ignore */
49532179Sedward 			while (getc(fp) != '\n')
49632179Sedward 				;
49732179Sedward 			FlushShow(1);
49832179Sedward 			lastcmd = BRK;
49932179Sedward 			break;
50032179Sedward 		case '#': 		/* comment */
50132179Sedward 			/* maybe should pass through as a PS comment */
50232179Sedward 			while (getc(fp) != '\n')
50332179Sedward 				;
50432179Sedward 			break;
50532179Sedward 		case 'x': 		/* device control */
50632179Sedward 			devcntrl(fp);
50732179Sedward 			break;
50832179Sedward 		case '%':		/* imbedded PostScript */
50932179Sedward 			/* copy everything up to but NOT including a line */
51032179Sedward 			/* with at single "." */
51132179Sedward 			FlushShow(0);
51232179Sedward 			MoveTo();
51332179Sedward 			DoMove();
51432179Sedward 			printf("\n%% included PostScript\n");
51532179Sedward 			while (fgets(buf, sizeof buf, fp) != NULL) {
51632179Sedward 				if (strcmp(".\n", buf) == 0)
51732179Sedward 					break;
51832179Sedward 				fputs(buf, stdout);
51932179Sedward 			}
52032179Sedward 			break;
52132179Sedward 		default:
52232179Sedward 			fprintf(stderr, "%s: bad input char \\%03o (%c)\n",
52332179Sedward 				prog, c, c);
52430594Ssam 			exit(2);
52530594Ssam 		}
52630594Ssam }
52730594Ssam 
52830594Ssam /* put in PostScript prolog */
preface()52932179Sedward preface()
53030594Ssam {
53132179Sedward 	register FILE *prolog;
53232179Sedward 	char hostname[256];
53332179Sedward 	char tempfile[512];
53432179Sedward 	struct passwd *pswd;
53532179Sedward 	long clock;
53632179Sedward 	char *libdir;
53730594Ssam 
53832179Sedward 	printf("%%!%s\n", COMMENTVERSION);
53932179Sedward 	pswd = getpwuid(getuid());
54032179Sedward 	(void) gethostname(hostname, sizeof hostname);
54132179Sedward 	printf("%%%%Creator: %s:%s (%s)\n", hostname,
54232179Sedward 		pswd->pw_name, pswd->pw_gecos);
54332179Sedward 	printf("%%%%Title: %s (ditroff)\n", infilename);
54432179Sedward 	printf("%%%%CreationDate: %s", (time(&clock), ctime(&clock)));
54532179Sedward 	printf("%%%%EndComments\n");
54632179Sedward 	if ((libdir = envget("PSLIBDIR")) == NULL)
54732179Sedward 		libdir = LibDir;
54832179Sedward 	mstrcat(tempfile, libdir, prologfile, sizeof tempfile);
54932179Sedward 	if (copyfile(tempfile, stdout) != 0) {
55032179Sedward 		fprintf(stderr, "%s: can't copy prolog file %s\n",
55132179Sedward 			prog, tempfile);
55232179Sedward 		exit(2);
55332179Sedward 	}
55432179Sedward 	printf("ditstart\n");
55530594Ssam }
55630594Ssam 
devcntrl(fp)55732179Sedward devcntrl(fp)	/* interpret device control functions */
55832179Sedward 	FILE *fp;
55930594Ssam {
56032179Sedward 	char str[20], str1[50], buf[50];
56132179Sedward 	int c, n, res, minh, minv;
56230594Ssam 
56332179Sedward 	fscanf(fp, "%s", str);
56432179Sedward 	switch (str[0]) {		/* crude for now */
56530594Ssam 	case 'i': 		/* initialize */
56632179Sedward 		fileinit();
56732179Sedward 		t_init();
56832179Sedward 		lastcmd = NONE;
56932179Sedward 		break;
57030594Ssam 	case 'T': 		/* device name */
57132179Sedward 		/*
57232179Sedward 		fscanf(fp, "%s", devname);
57332179Sedward 		if (strcmp(devname, "psc")) {
57432179Sedward 			fprintf(stderr, "%s: device not psc\n", prog);
57532179Sedward 			exit(2);
57632179Sedward 		}
57732179Sedward 		*/
57832179Sedward 		printf("(%s)xT\n", devname);
57932179Sedward 		lastcmd = NONE;
58032179Sedward 		break;
58130594Ssam 	case 't': 		/* trailer */
58232179Sedward 		t_trailer();
58332179Sedward 		lastcmd = NONE;
58432179Sedward 		break;
58530594Ssam 	case 'p': 		/* pause -- can restart */
58632179Sedward 		t_reset('p');
58732179Sedward 		lastcmd = NONE;
58832179Sedward 		break;
58930594Ssam 	case 's': 		/* stop */
59032179Sedward 		t_reset('s');
59132179Sedward 		lastcmd = NONE;
59232179Sedward 		break;
59330594Ssam 	case 'r': 		/* resolution assumed when prepared */
59432179Sedward 		fscanf(fp, "%d %d %d", &res, &minh, &minv);
59532179Sedward 		t_res(res, minh, minv);
59632179Sedward 		lastcmd = NONE;
59732179Sedward 		break;
59830594Ssam 	case 'f': 		/* font used */
59932179Sedward 		fscanf(fp, "%d %s", &n, str);
60032179Sedward 		fgets(buf, sizeof buf, fp);	/* in case theres a filename */
60132179Sedward 		ungetc('\n', fp);		/* fgets goes too far */
60232179Sedward 		str1[0] = 0;	/* in case there is nothing to come in */
60332179Sedward 		sscanf(buf, "%s", str1);
60432179Sedward 		loadfont(n, str, str1);
60532179Sedward 		lastcmd = FNT;
60632179Sedward 		break;
60730594Ssam 	case 'H': 		/* char height */
60832179Sedward 		fscanf(fp, "%d", &n);
60932179Sedward 		t_charht(n);
61032179Sedward 		lastcmd = FNT;
61132179Sedward 		break;
61230594Ssam 	case 'S': 		/* slant */
61332179Sedward 		fscanf(fp, "%d", &n);
61432179Sedward 		t_slant(n);
61532179Sedward 		lastcmd = FNT;
61632179Sedward 		break;
61730595Ssam #ifdef XMOD
61830595Ssam 	case 'X': {		/* \X command from ditroff */
61930595Ssam             int last;
62030595Ssam 	    char largebuf[128];
62130595Ssam 	    fscanf (fp, "%1s", str);
62230595Ssam 	    switch (str[0]) {
62330595Ssam 		case 'p' :
62430595Ssam 		    FlushShow(0);MoveTo();DoMove();
62530595Ssam 		    fgets(largebuf, sizeof(largebuf), fp);
62630595Ssam 		    last = strlen(largebuf) - 1;
62730595Ssam 		    if (last >= 0 && largebuf[last] == '\n') {
62830595Ssam 			ungetc('\n', fp);
62930595Ssam 			largebuf[last] = ' ';
63030595Ssam 		    }
63132179Sedward 		    puts(largebuf);
63230595Ssam 		    break;
63330595Ssam 		case 'f' :
63430595Ssam 		    FlushShow(0);MoveTo();DoMove();
63530595Ssam 		    if (fscanf(fp, "%s", largebuf) == 1) {
63630595Ssam 			char *nl = (char *) index(largebuf, '\n');
63730595Ssam 			if (nl) *nl = '\0';
63830595Ssam 			includefile(largebuf);
63930595Ssam 		    } else
64030595Ssam 			fprintf(stderr, "warning - include cmd w/o path.\n");
64130595Ssam 		    break;
64230595Ssam 	    }
64330595Ssam 	}
64430595Ssam 	break;
64530595Ssam #endif
64632179Sedward 	}
64732179Sedward 	/* skip rest of input line */
64832179Sedward 	while ((c = getc(fp)) != '\n' && c != EOF)
64932179Sedward 		;
65030594Ssam }
65130594Ssam 
65230595Ssam #ifdef XMOD
includefile(filenm)65330595Ssam includefile(filenm)
65432179Sedward 	char *filenm;
65532179Sedward {
65630595Ssam 	FILE *inf;
65730595Ssam 	int ch, c1, c2, firstch = 0;
65830595Ssam 
65930595Ssam 	if (!(inf = fopen(filenm, "r"))) {
66030595Ssam 		fprintf(stderr, "psdit: fopen(%s): ", filenm);
66130595Ssam 		perror();
66230595Ssam 		exit(1);
66330595Ssam 	}
66430595Ssam 	c1 = fgetc(inf); c2 = fgetc(inf);
66530595Ssam 	if (c1 != '%' || c2 != '!')
66630595Ssam 		fprintf(stderr, "psdit: %s not a postscript file.\n", filenm),
66730595Ssam 		exit(1);
66830595Ssam 
66932179Sedward 	fputs("%!", stdout);
67030595Ssam 	while ((ch = fgetc(inf)) != EOF) {
67132179Sedward 		putchar(ch);
67230595Ssam 		if (firstch && ch == '%') {
67330595Ssam 			/* we have to double leading '%'s */
67432179Sedward 			putchar('%');
67530595Ssam 		}
67630595Ssam 		firstch = (ch == '\n');
67734009Sedward 	}
67830595Ssam 	fclose(inf);
67930595Ssam }
68030595Ssam #endif
68132179Sedward 
fileinit()68232179Sedward fileinit()	/* read in font and code files, etc. */
68330594Ssam {
68432179Sedward 	int i, fin, nw;
68532179Sedward 	char *filebase, *p;
68632179Sedward 	char temp[60];
68732179Sedward 	unsigned msize;
68830594Ssam 
68932179Sedward 	/*
69032179Sedward 	 * Open table for device,
69132179Sedward 	 * read in resolution, size info, font info, etc., and set params.
69232179Sedward 	 */
69332179Sedward 	sprintf(temp, "%s/dev%s/DESC.out", ditdir, devname);
69432179Sedward 	if ((fin = open(temp, 0)) < 0) {
69532179Sedward 		fprintf(stderr, "%s: can't open %s - %s\n",
69632179Sedward 			prog, devname, temp);
69732179Sedward 		pexit(prog, 2);
69832179Sedward 	}
69932179Sedward 	if (read(fin, (char *) &dev, sizeof (struct dev)) !=
70032179Sedward 			sizeof (struct dev)) {
70132179Sedward 		fprintf(stderr, "%s: can't read %s\n", prog, temp);
70232179Sedward 		pexit(prog, 2);
70332179Sedward 	}
70432179Sedward 	dres = dev.res;
70532179Sedward 	nfonts = dev.nfonts;
70632179Sedward 	nsizes = dev.nsizes;
70732179Sedward 	nchtab = dev.nchtab;
70832179Sedward 	/* enough room for whole file */
70932179Sedward 	filebase = malloc((unsigned) dev.filesize);
71032179Sedward 	if (read(fin, filebase, dev.filesize) != dev.filesize) {
71132179Sedward 		fprintf(stderr, "%s: trouble reading %s\n", prog, temp);
71232179Sedward 		pexit(prog, 2);
71332179Sedward 	}
71432179Sedward 	pstab = (short *) filebase;		/* point size table */
71532179Sedward 	chtab = pstab + nsizes + 1;		/* char index table */
71632179Sedward 	chname = (char *) (chtab + dev.nchtab);	/* char name table */
71732179Sedward 	p = chname + dev.lchname;		/* end of char name table */
71832179Sedward 	/* parse the preloaded font tables */
71932179Sedward 	for (i = 1; i <= nfonts; i++) {
72032179Sedward 		fontdelta[i] = 0;
72132179Sedward 		fontbase[i] = (struct font *) p;
72232179Sedward 		nw = *p & BMASK;	/* number of width entries */
72332179Sedward 		if ((smnt == 0) && (fontbase[i]->specfont == 1))
72432179Sedward 			smnt = i;		/* first special font */
72532179Sedward 		p += sizeof (struct font); /* skip header */
72632179Sedward 		widthtab[i] = p;		/* width table */
72732179Sedward 		/* kern table is next */
72832179Sedward 		codetab[i] = p + 2 * nw;	/* device codes */
72932179Sedward 		fitab[i] = p + 3 * nw;		/* font index table */
73032179Sedward 		p += 3 * nw + dev.nchtab + (128 - 32);	/* next font */
73132179Sedward 		t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
73232179Sedward 		loadpswidths(i, fontbase[i]->namefont);
73332179Sedward 		sayload(i, fontbase[i]->namefont, (char *) 0);
73430594Ssam #ifdef DEBUG
73532179Sedward 		if (fdbg > 1)
73632179Sedward 			fontprint(i);
73730594Ssam #endif
73832179Sedward 	}
73932179Sedward 	fontdelta[0] = 0;
74032179Sedward 	msize = 3*255 + dev.nchtab + (128 - 32) + sizeof (struct font);
74132179Sedward 	fontbase[0] = (struct font *) malloc(msize);
74232179Sedward 	widthtab[0] = (char *) fontbase[0] + sizeof (struct font);
74332179Sedward 	fontbase[0]->nwfont = 255;
74432179Sedward 	close(fin);
74530594Ssam }
74630594Ssam 
loadpswidths(i,name)74732179Sedward loadpswidths(i, name)
74832179Sedward 	int i;
74932179Sedward 	char *name;
75030594Ssam {
75132179Sedward 	char temp[60];
75232179Sedward 	register FILE *auxin;
75332179Sedward 	register int j;
75432179Sedward 	int cc, wid, funny;
75530594Ssam 
75632179Sedward 	sprintf(temp, "%s/dev%s/%s.aux", ditdir, devname, name);
75732179Sedward 	auxin = fopen(temp, "r");
75832179Sedward 	/* allocate table */
75932179Sedward 	if (pswidths[i] == NULL)
76032179Sedward 		pswidths[i] = (int *) malloc(256 * (sizeof (int)));
76132179Sedward 	/* initialize to not-there */
76232179Sedward 	for (j = 0; j <= 255; pswidths[i][j++] = -1)
76332179Sedward 		;
76432179Sedward 	/* read them in */
76532179Sedward 	while (fscanf(auxin, "%d %d %d", &cc, &wid, &funny) != EOF)
76632179Sedward 		pswidths[i][cc] = wid | (funny << 12);
76732179Sedward 	(void) fclose(auxin);
76830594Ssam }
76930594Ssam 
77030594Ssam #ifdef DEBUG
fontprint(i)77132179Sedward fontprint(i)	/* debugging print of font i (0, ...) */
77230594Ssam int i;
77330594Ssam {
77432179Sedward 	int j, n;
77532179Sedward 	char *p;
77630594Ssam 
77732179Sedward 	printf("font %d:\n", i);
77832179Sedward 	p = (char *) fontbase[i];
77932179Sedward 	n = fontbase[i]->nwfont & BMASK;
78032179Sedward 	printf("base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
78132179Sedward 		p, n, fontbase[i]->specfont,
78232179Sedward 		fontbase[i]->namefont, widthtab[i], fitab[i]);
78332179Sedward 	printf("widths:\n");
78432179Sedward 	for (j = 0; j <= n; j++) {
78532179Sedward 		printf(" %2d", widthtab[i][j] & BMASK);
78632179Sedward 		if (j % 20 == 19)
78732179Sedward 			printf("\n");
78832179Sedward 	}
78932179Sedward 	printf("\ncodetab:\n");
79032179Sedward 	for (j = 0; j <= n; j++) {
79132179Sedward 		printf(" %2d", codetab[i][j] & BMASK);
79232179Sedward 		if (j % 20 == 19)
79332179Sedward 			printf("\n");
79432179Sedward 	}
79532179Sedward 	printf("\nfitab:\n");
79632179Sedward 	for (j = 0; j <= dev.nchtab + 128 - 32; j++) {
79732179Sedward 		printf(" %2d", fitab[i][j] & BMASK);
79832179Sedward 		if (j % 20 == 19)
79932179Sedward 			printf("\n");
80032179Sedward 	}
80132179Sedward 	printf("\n");
80230594Ssam }
80330594Ssam #endif
80430594Ssam 
loadfont(n,s,s1)80532179Sedward loadfont(n, s, s1) /* load font info for font s on position n */
80632179Sedward 	int n;
80732179Sedward 	char *s, *s1;
80830594Ssam {
80932179Sedward 	char temp[60];
81032179Sedward 	int fin, nw, norig;
81132179Sedward 	int bcount;
81230594Ssam 
81332179Sedward 	if (n < 0 || n > NFONT) {
81432179Sedward 		fprintf(stderr, "%s: illegal fp command %d %s\n", prog, n, s);
81532179Sedward 		exit(2);
81632179Sedward 	}
81732179Sedward 	if (strcmp(s, fontbase[n]->namefont) == 0)
81832179Sedward 		return;
81932179Sedward 	if (fontbase[n]->namefont != 0)
82032179Sedward 		fontdelta[n] = 1;
82132179Sedward 	if (s1 == NULL || s1[0] == '\0')
82232179Sedward 		sprintf(temp, "%s/dev%s/%s.out", ditdir, devname, s);
82332179Sedward 	else
82432179Sedward 		sprintf(temp, "%s/%s.out", s1, s);
82532179Sedward 	if ((fin = open(temp, 0)) < 0) {
82632179Sedward 		fprintf(stderr, "%s: can't open font table %s\n", prog, temp);
82732179Sedward 		pexit(prog, 2);
82832179Sedward 	}
82932179Sedward 	norig = fontbase[n]->nwfont & BMASK;
83032179Sedward 	bcount = 3 * norig + nchtab + 128 - 32 + sizeof (struct font);
83132179Sedward 	(void) read(fin, (char *) fontbase[n], bcount);
83232179Sedward 	if ((fontbase[n]->nwfont & BMASK) > norig) {
83332179Sedward 		fprintf(stderr, "%s: Font %s too big for position %d\n",
83432179Sedward 			prog, s, n);
83532179Sedward 		exit(2);
83632179Sedward 	}
83732179Sedward 	close(fin);
83832179Sedward 	nw = fontbase[n]->nwfont & BMASK;
83932179Sedward 	widthtab[n] = (char *) fontbase[n] + sizeof (struct font);
84032179Sedward 	codetab[n] = (char *) widthtab[n] + 2 * nw;
84132179Sedward 	fitab[n] = (char *) widthtab[n] + 3 * nw;
84232179Sedward 	t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
84332179Sedward 	loadpswidths(n, fontbase[n]->namefont);
84432179Sedward 	sayload(n, s, s1);
84532179Sedward 	fontbase[n]->nwfont = norig; /* so can later use full original size */
84630594Ssam #ifdef DEBUG
84732179Sedward 	if (fdbg > 1)
84832179Sedward 		fontprint(n);
84930594Ssam #endif
85030594Ssam }
85130594Ssam 
sayload(n,s,s1)85232179Sedward sayload(n, s, s1)	/* position n contains font s (internal s1) */
85332179Sedward 	int n;
85432179Sedward 	char *s, *s1;
85530594Ssam {
85632179Sedward 	char pass[60];
85732179Sedward 	FILE *ptrfile;
85832179Sedward 	char Adobefont[60];
85930594Ssam 
86032179Sedward 	if (s1 == NULL || s1[0] == '\0')
86132179Sedward 		sprintf(pass, "%s/dev%s/%s.map", ditdir, devname, s);
86232179Sedward 	else
86332179Sedward 		sprintf(pass, "%s/%s.map", s1, s);
86432179Sedward 	if ((ptrfile = fopen(pass, "r")) == NULL) {
86532179Sedward 		fprintf(stderr, "%s: can't open font map file %s\n",
86632179Sedward 			prog, pass);
86732179Sedward 		pexit(prog, 2);
86832179Sedward 	}
86932179Sedward 	fscanf(ptrfile, "%s", Adobefont);
87032179Sedward 	FlushShow(0);
87132179Sedward 	printf("%d(%s)xf %d f\n", n, Adobefont, n);
87232179Sedward 	font = n;
87332179Sedward 	(void) fclose(ptrfile);
87430594Ssam }
87530594Ssam 
done()87632179Sedward done()
87730594Ssam {
87832179Sedward 	t_reset('s');
87932179Sedward 	exit(0);
88030594Ssam }
88130594Ssam 
t_init()88232179Sedward t_init()	/* "x i" - initialize device */
88330594Ssam {
88432179Sedward 	movepending = NONE;
88532179Sedward 	savex = savey = 0;
88630594Ssam 
88732179Sedward 	t_size(10);		/* start somewhere */
88832179Sedward 	t_slant(0);
88932179Sedward 	setfont(1);		/* set font */
89034804Sedward 	stipplefont = 1;
89132179Sedward 	printf("xi\n");
89232179Sedward 	printf("%%%%EndProlog\n");
89330594Ssam }
89430594Ssam 
t_push()89532179Sedward t_push()	/* begin a new block */
89630594Ssam {
89732179Sedward 	FlushShow(1);
89832179Sedward 	MoveTo();
89932179Sedward 	DoMove();
90032179Sedward 	if (dlevel == DSTACK) {
90132179Sedward 		fprintf(stderr, "%s: ditroff push/pop overflow!\n", prog);
90232179Sedward 		exit(2);
90332179Sedward 	}
90432179Sedward 	ditstack[dlevel].hpos = hpos;
90532179Sedward 	ditstack[dlevel].vpos = vpos;
90632179Sedward 	ditstack[dlevel].fontsize = fontsize;
90732179Sedward 	ditstack[dlevel].fontheight = fontheight;
90832179Sedward 	ditstack[dlevel].fontslant = fontslant;
90932179Sedward 	ditstack[dlevel].font = font;
91032179Sedward 	dlevel++;
91132179Sedward 	printf("\nditpush\n");
91230594Ssam }
91330594Ssam 
t_pop()91432179Sedward t_pop()	/* pop to previous state */
91530594Ssam {
91632179Sedward 	FlushShow(1);
91732179Sedward 	MoveTo();
91832179Sedward 	DoMove();
91932179Sedward 	if (dlevel == 0) {
92032179Sedward 		fprintf(stderr, "%s: ditroff push/pop underflow!\n", prog);
92132179Sedward 		exit(2);
92232179Sedward 	}
92332179Sedward 	dlevel--;
92432179Sedward 	hpos = ditstack[dlevel].hpos;
92532179Sedward 	vpos = ditstack[dlevel].vpos;
92632179Sedward 	fontsize = ditstack[dlevel].fontsize;
92732179Sedward 	fontheight = ditstack[dlevel].fontheight;
92832179Sedward 	fontslant = ditstack[dlevel].fontslant;
92932179Sedward 	font = ditstack[dlevel].font;
93032179Sedward 	printf("%d s %d xH %d xS %d f\n",
93132179Sedward 		fontsize, fontheight, fontslant, font);
93232179Sedward 	startx = savex = hpos;
93332179Sedward 	savey = vpos;
93432179Sedward 	PSx = hpos * PSmag;
93532179Sedward 	PSy = vpos * PSmag;
93632179Sedward 	printf("%d %d MXY\n", savex, savey);
93732179Sedward 	movepending = NONE;
93832179Sedward 	printf("\nditpop\n");
93930594Ssam }
94030594Ssam 
t_page(n)94132179Sedward t_page(n)	/* do whatever new page functions */
94230594Ssam {
94332179Sedward 	register int i;
94430594Ssam 
94532179Sedward 	if (output && ++scount >= spage) {
94632179Sedward 		t_reset('p');
94732179Sedward 		scount = 0;
94830594Ssam 	}
94932179Sedward 	output = 1;
95032179Sedward 	FlushShow(0);
95132179Sedward 	if (!firstpage)
95232179Sedward 		printf("\n%d p", n);
95332179Sedward 	firstpage = FALSE;
95432179Sedward 	printf("\n%%%%Page: %d %d\n", n, ++pageno, n);
95532179Sedward 	for (i = 0; i <= nfonts; i++)
95632179Sedward 		if (fontdelta[i] != 0)
95732179Sedward 			sayload(i, fontname[i].name, (char *) 0);
95832179Sedward 	vpos = 0;
95932179Sedward 	PSy = 0;
96034804Sedward 	printf("%d s %d xH %d xS %d f %d i\n",
96134804Sedward 		fontsize, fontheight, fontslant, font, stipplefont);
96232179Sedward 	if (nolist == 0)
96332179Sedward 		return;
96432179Sedward 	output = 0;
96532179Sedward 	for (i = 0; i < nolist; i += 2)
96632179Sedward 		if (n >= olist[i] && n <= olist[i + 1]) {
96732179Sedward 			output = 1;
96832179Sedward 			break;
96932179Sedward 		}
97030594Ssam }
97130594Ssam 
t_size(n)97232179Sedward t_size(n)	/* convert integer to internal size number*/
97332179Sedward 	int n;
97430594Ssam {
97532179Sedward 	FlushShow(1);
97632179Sedward 	if (fontsize != n) {
97732179Sedward 		fontsize = n;
97830595Ssam #ifdef XMOD
97932179Sedward 		fontheight = n;
98030595Ssam #endif
98132179Sedward 		printf("%d s\n", fontsize);
98232179Sedward 	}
98330594Ssam }
98430594Ssam 
t_charht(n)98532179Sedward t_charht(n)	/* set character height to n */
98632179Sedward 	int n;
98730594Ssam {
98832179Sedward 	FlushShow(1);
98932179Sedward 	if (fontheight != n) {
99032179Sedward 		fontheight = n;
99132179Sedward 		printf("%d xH\n", fontheight);
99232179Sedward 	}
99330594Ssam }
99430594Ssam 
t_slant(n)99532179Sedward t_slant(n)	/* set slant to n */
99632179Sedward 	int n;
99730594Ssam {
99832179Sedward 	FlushShow(1);
99932179Sedward 	if (fontslant != n) {
100032179Sedward 		fontslant = n;
100132179Sedward 		printf("%d xS\n", fontslant);
100232179Sedward 	}
100330594Ssam }
100430594Ssam 
t_font(s)100532179Sedward t_font(s)	/* convert string to internal font number */
100632179Sedward 	char *s;
100730594Ssam {
100832179Sedward 	int n;
100930594Ssam 
101032179Sedward 	n = atoi(s);
101132179Sedward 	return n < 0 || n > nfonts ? 1 : n;
101230594Ssam }
101330594Ssam 
t_text(s)101432179Sedward t_text(s)	/* print string s as text??? */
101532179Sedward 	char *s;
101630594Ssam {
101732179Sedward 	fprintf(stderr, "%s: ditroff t <%s> unimplemented!\n", prog, s);
101830594Ssam }
101930594Ssam 
t_reset(c)102032179Sedward t_reset(c)
102130594Ssam {
102232179Sedward 	output = 1;			/* by God */
102332179Sedward 	if (c == 'p')
102432179Sedward 		printf("\nxp\n");
102532179Sedward 	else if (!stopped) {
102632179Sedward 		printf("\nxs\n");
102732179Sedward 		stopped = 1;
102832179Sedward 	}
102932179Sedward 	fflush(stdout);
103030594Ssam }
103130594Ssam 
t_res(res,minh,minv)103232179Sedward t_res(res, minh, minv)
103332179Sedward 	int res, minh, minv;
103430594Ssam {
103532179Sedward 	resolution = res;
103632179Sedward 	minhoriz = minh;
103732179Sedward 	minvert = minv;
103832179Sedward 	printf("%d %d %d xr\n", res, minh, minv);
103930594Ssam }
104030594Ssam 
t_trailer()104132179Sedward t_trailer()
104230594Ssam {
104332179Sedward 	FlushShow(0);
104432179Sedward 	printf("\n%d p", pageno);
104532179Sedward 	printf("\n%%%%Trailer\n");
104632179Sedward 	printf("xt\n");
104730594Ssam }
104830594Ssam 
put1s(s)104932179Sedward put1s(s)	/* s is a funny char name */
105030594Ssam char *s;
105130594Ssam {
105232179Sedward 	int i;
105330594Ssam 
105432179Sedward 	if (!output)
105532179Sedward 		return;
105632179Sedward 	debugp(("%s ", s));
105730594Ssam 
105832179Sedward 	/* search for s in the funny char name table */
105932179Sedward 	for (i = 0; i < nchtab; i++)
106032179Sedward 		if (strcmp(&chname[chtab[i]], s) == 0)
106132179Sedward 			break;
106232179Sedward 	if (i < nchtab)
106332179Sedward 		put1(i + 128, s);
106432179Sedward 	else {
106532179Sedward 		debugp(("not found "));
106632179Sedward 		putnf(0, s);
106732179Sedward 	}
106830594Ssam }
106930594Ssam 
107032179Sedward #define needsescape(c) ((c) == '\\' || (c) == '(' || (c) == ')')
107130594Ssam 
put1(c,s)107232179Sedward put1(c, s)	/* output char c */
107332179Sedward 	int c;
107432179Sedward 	char *s;
107530594Ssam {
107632179Sedward 	char *pw;
107732179Sedward 	register char *p;
107832179Sedward 	register int i, k;
107932179Sedward 	register int cc;
108032179Sedward 	int ofont, code;
108132179Sedward 	int psinfo, pswid, tw;
108230594Ssam 
108332179Sedward 	if (!output)
108432179Sedward 		return;
108532179Sedward 	if (c == ' ') {
108632179Sedward 		thisw = 0;
108732179Sedward 		FlushShow(0);
108832179Sedward 		return;
108932179Sedward 	}
109032179Sedward 	if (c < ' ') {
109132179Sedward 		debugp(("non-exist 0%o\n", c));
109232179Sedward 		return;
109332179Sedward 	}
109432179Sedward 	c -= 32;	/* offset char code */
109532179Sedward 	k = ofont = pfont = font;
109632179Sedward 	if (onspecial)
109732179Sedward 		pfont = prevfont;
109832179Sedward 	if ((i = fitab[pfont][c] & BMASK) != 0) {	/* char on this font */
109932179Sedward 		p = codetab[pfont];
110032179Sedward 		pw = widthtab[pfont];
110132179Sedward 		if (onspecial) {
110232179Sedward 			setfont(prevfont);
110332179Sedward 			thisw = 0;
110432179Sedward 			onspecial = 0;
110532179Sedward 		}
110632179Sedward 	} else if (smnt > 0) {			/* on special (we hope) */
110732179Sedward 		for (k = smnt; k <= nfonts; k += 1)
110832179Sedward 			if ((i = fitab[k][c] & BMASK) != 0) {
110932179Sedward 				p = codetab[k];
111032179Sedward 				pw = widthtab[k];
111132179Sedward 				prevfont = pfont;
111232179Sedward 				if (onspecial && k == specfont)
111332179Sedward 					break;
111432179Sedward 				setfont(k);
111532179Sedward 				thisw = 0;
111632179Sedward 				onspecial = 1;
111732179Sedward 				specfont = k;
111832179Sedward 				break;
111932179Sedward 			}
112032179Sedward 	}
112132179Sedward 	if (i == 0 || k > nfonts || (code = p[i] & BMASK) == 0) {
112232179Sedward 		debugp(("not found 0%o\n", c + 32));
112332179Sedward 		putnf(c + 32, s);
112432179Sedward 		return;
112532179Sedward 	}
112632179Sedward 	/*
112732179Sedward 	 * when we get here,
112832179Sedward 	 *  c == biased character code
112932179Sedward 	 *	k == font number
113032179Sedward 	 *  i == index into codetab and widthtab for this character
113132179Sedward 	 *  p == codetab for this font
113232179Sedward 	 *  pw == width tab for this font
113332179Sedward 	 *  code == character code for this char
113432179Sedward 	 */
113532179Sedward 	cc = c + 32;
113632179Sedward 	debugp(((isascii(cc) && isprint(cc)) ? "%c %d\n":"%03o %d\n",
113732179Sedward 		cc, code));
113832179Sedward 	psinfo = pswidths[font][code];	/* PS specific char info */
113932179Sedward 	pswid = psinfo & PSWID;		/* PS character width */
114032179Sedward 	thisw = pw[i] & BMASK;		/* troff char width */
114132179Sedward 	tw = thisw = (thisw * fontsize + dev.unitwidth / 2) / dev.unitwidth;
114230594Ssam 
114332179Sedward 	if (psinfo & ISPSPROC && psinfo != -1) {
114432179Sedward 		/* character is implemented by a PostScript proc */
114532179Sedward 		showspecial(s, code, pswid);
114632179Sedward 		if (pswid > 0)
114732179Sedward 			PSx += PSscale(pswid * fontsize * dres);
114832179Sedward 		thisw = 0;
114932179Sedward 	} else {
115032179Sedward 		showchar(code);
115132179Sedward 		if (pswid > 0)
115232179Sedward 			PSshowlen += PSscale(pswid * fontsize * dres);
115332179Sedward 	}
115430594Ssam 
115532179Sedward 	/*
115632179Sedward 	if (font != ofont) {
115732179Sedward 		setfont(ofont);
115832179Sedward 		startx = hpos + tw;
115930594Ssam 		thisw = 0;
116032179Sedward 		lastcmd = FNT;
116130594Ssam 	}
116232179Sedward 	*/
116332179Sedward 	debugp(("...width (%d)\n", pw[i] & BMASK));
116432179Sedward }
116530594Ssam 
putnf(c,s)116632179Sedward putnf(c, s)	/* note that a character wasnt found */
116732179Sedward 	int c;
116832179Sedward 	char *s;
116932179Sedward {
117032179Sedward 	FlushShow(0);
117130594Ssam 	thisw = 0;
117232179Sedward 	if (s == NULL || *s == '\0')
1173*37310Sedward 		printf("(%3o)cb\n", c);
117432179Sedward 	else if (strcmp(s, "\\|") == 0 || strcmp(s, "\\^") == 0 ||
117532179Sedward 		 strcmp(s, "\\&") == 0)
117632179Sedward 		return;
117732179Sedward 	else
117832179Sedward 		printf("(%s)cb\n", s);
117930594Ssam }
118030594Ssam 
t_fp(n,s,si)118132179Sedward t_fp(n, s, si)	/* font position n now contains font s, intname si */
118232179Sedward 	int n;		/* position */
118332179Sedward 	char *s;	/* font (ditname) */
118432179Sedward 	char *si;	/* font (intname = number) */
118532179Sedward {
118632179Sedward 	fontname[n].name = s;
118732179Sedward 	fontname[n].number = atoi(si);
118832179Sedward }
118930594Ssam 
setfont(n)119032179Sedward setfont(n)	/* set font to n */
119132179Sedward 	int n;
119230594Ssam {
119332179Sedward 	FlushShow(1);
119432179Sedward 	if (n < 0 || n > NFONT)
119532179Sedward 		fprintf(stderr, "%s: illegal font %d\n", prog, n);
119632179Sedward 	if (font != n) {
119732179Sedward 		font = n;
119832179Sedward 		printf("%d f\n", font);
119932179Sedward 	}
120032179Sedward 	onspecial = 0;
120132179Sedward }
120230594Ssam 
drawline(dx,dy)120332179Sedward drawline(dx, dy)	/* draw line from here to dx, dy */
120432179Sedward 	int dx, dy;
120532179Sedward {
120632179Sedward 	FlushShow(0);
120732179Sedward 	MoveTo();
120832179Sedward 	DoMove();
120932179Sedward 	printf("%d %d Dl\n", dx, dy);
121032179Sedward 	hpos += dx;
121132179Sedward 	PSx = hpos * PSmag;
121232179Sedward 	vpos += dy;
121332179Sedward 	PSy = vpos * PSmag;
121430594Ssam }
121530594Ssam 
drawcurve(line)121632179Sedward drawcurve(line)
121732179Sedward 	char *line;
121832179Sedward {
121932179Sedward 	FlushShow(0);
122032179Sedward 	MoveTo();
122132179Sedward 	DoMove();
122234009Sedward 	getpoints(line + 1);
122334009Sedward 	/* hpos and vpos won't be changed by curve drawing code */
122434009Sedward 	hpos = x[numpoints];
122534009Sedward 	vpos = y[numpoints];
122634009Sedward 	switch (*line) {
122734009Sedward 	case 'g':
122834009Sedward 		IS_Initialize();
122934009Sedward 		IS_Convert();
123034009Sedward 		break;
123134009Sedward 	case '~':
123234009Sedward 		BS_Initialize();
123334009Sedward 		BS_Convert();
123434009Sedward 		break;
123534009Sedward 	case 'z':
123634009Sedward 		BZ_Offsets();
123734009Sedward 		BZ_Convert();
123834009Sedward 		break;
123934009Sedward 	}
124034009Sedward 	printf("Dstroke\n");
124132179Sedward }
124232179Sedward 
drawpoly(line)124334009Sedward drawpoly(line)
124432179Sedward 	char *line;
124530594Ssam {
124632179Sedward 	int stipple;
124732179Sedward 	register i;
124834009Sedward 	register char *p;
124932179Sedward 	int minx, miny, maxx, maxy;
125032179Sedward 
125132179Sedward 	FlushShow(0);
125232179Sedward 	MoveTo();
125332179Sedward 	DoMove();
125434009Sedward 	for (p = line + 1; isspace(*p); p++)
125532179Sedward 		;
125634009Sedward 	for (stipple = 0; isdigit(*p);
125734009Sedward 	     stipple = stipple * 10 + *p++ - '0')
125832179Sedward 		;
125934009Sedward 	getpoints(p);
126032179Sedward 	minx = maxx = hpos;
126132179Sedward 	miny = maxy = vpos;
126234009Sedward 	for (i = 1; i <= numpoints; i++) {
126334009Sedward 		printf(" %lg %lg lineto\n", x[i], y[i]);
126434009Sedward 		if (x[i] > maxx)
126534009Sedward 			maxx = x[i];
126634009Sedward 		if (x[i] < minx)
126734009Sedward 			minx = x[i];
126834009Sedward 		if (y[i] > maxy)
126934009Sedward 			maxy = y[i];
127034009Sedward 		if (y[i] < miny)
127134009Sedward 			miny = y[i];
127232179Sedward 	}
127332179Sedward 	printf("closepath %d %d %d %d %d D%c\n",
127434009Sedward 	       stipple, minx, miny, maxx, maxy, *line);
127534009Sedward 	/* XXX, hpos and vpos not changed? */
127634009Sedward 	PSx = x[numpoints] * PSmag;
127734009Sedward 	PSy = y[numpoints] * PSmag;
127830594Ssam }
127930594Ssam 
getpoints(s)128034009Sedward getpoints(s)
128132179Sedward 	register char *s;
128230594Ssam {
128332179Sedward 	int h = hpos, v = vpos;
128432179Sedward 
128534009Sedward 	numpoints = 0;
128632179Sedward 	for (;;) {
128734009Sedward 		int dh, dv, neg;
128834009Sedward 
128934009Sedward 		numpoints++;
129034009Sedward 		x[numpoints] = h;
129134009Sedward 		y[numpoints] = v;
129234009Sedward 		if (numpoints >= MAXPOINTS - 2)	/* -2 for good measure */
129332179Sedward 			break;
129432179Sedward 		for (; isspace(*s); s++)
129532179Sedward 			;
129632179Sedward 		if (neg = *s == '-')
129732179Sedward 			s++;
129832179Sedward 		if (!isdigit(*s))
129932179Sedward 			break;
130034009Sedward 		for (dh = 0; isdigit(*s); dh = dh * 10 + *s++ - '0')
130132179Sedward 			;
130232179Sedward 		if (neg)
130334009Sedward 			dh = - dh;
130432179Sedward 		for (; isspace(*s); s++)
130532179Sedward 			;
130632179Sedward 		if (neg = *s == '-')
130732179Sedward 			s++;
130832179Sedward 		if (!isdigit(*s))
130932179Sedward 			break;
131034009Sedward 		for (dv = 0; isdigit(*s); dv = dv * 10 + *s++ - '0')
131132179Sedward 			;
131232179Sedward 		if (neg)
131334009Sedward 			dv = - dv;
131434009Sedward 		h += dh;
131534009Sedward 		v += dv;
131632179Sedward 	}
131730594Ssam }
131830594Ssam 
drawcirc(d)131932179Sedward drawcirc(d)
132032179Sedward 	int d;
132130594Ssam {
132232179Sedward 	FlushShow(0);
132332179Sedward 	MoveTo();
132432179Sedward 	DoMove();
132532179Sedward 	printf("%d Dc\n", d);
132630594Ssam }
132730594Ssam 
drawarc(dx1,dy1,dx2,dy2)132832179Sedward drawarc(dx1, dy1, dx2, dy2)
132932179Sedward 	int dx1, dy1, dx2, dy2;
133030594Ssam {
133132179Sedward 	FlushShow(0);
133232179Sedward 	MoveTo();
133332179Sedward 	DoMove();
133432179Sedward 	printf("%d %d %d %d Da\n", dx1, dy1, dx2, dy2);
133532179Sedward 	hpos += dx1 + dx2;
133632179Sedward 	PSx = hpos * PSmag;
133732179Sedward 	vpos += dy1 + dy2;
133832179Sedward 	PSy = vpos * PSmag;
133930594Ssam }
134030594Ssam 
drawellip(a,b)134132179Sedward drawellip(a, b)
134232179Sedward 	int a, b;
134330594Ssam {
134432179Sedward 	FlushShow(0);
134532179Sedward 	MoveTo();
134632179Sedward 	DoMove();
134732179Sedward 	printf("%d %d De\n", a, b);
134830594Ssam }
134930594Ssam 
hmot(a)135032179Sedward hmot(a)	/* relative horizontal motion */
135132179Sedward 	int a;
135230594Ssam {
135332179Sedward 	register int aa;
135432179Sedward 
135532179Sedward 	aa = abs(a);
135632179Sedward 	if (aa < 8 || aa > 10 * thisw || a >= 100 ||
135732179Sedward 	    thisw != 0 && abs(thisw - a) > 4)
135832179Sedward 		FlushShow(1);
135932179Sedward 	hpos += a;
136032179Sedward 	if (lastcmd != CPUT)
136132179Sedward 		startx = hpos;
136230594Ssam }
136330594Ssam 
hgoto(a)136432179Sedward hgoto(a) /* absolute horizontal motion */
136532179Sedward 	int a;
136630594Ssam {
136732179Sedward 	FlushShow(1);
136832179Sedward 	startx = hpos = a;
136932179Sedward 	thisw = 0;
137030594Ssam }
137130594Ssam 
vmot(a)137232179Sedward vmot(a) /* relative vertical motion */
137332179Sedward 	int a;
137430594Ssam {
137532179Sedward 	FlushShow(1);
137632179Sedward 	vpos += a;
137732179Sedward 	thisw = 0;
137830594Ssam }
137930594Ssam 
vgoto(a)138032179Sedward vgoto(a) /* absolute vertical motion */
138132179Sedward 	int a;
138230594Ssam {
138332179Sedward 	FlushShow(1);
138432179Sedward 	vpos = a;
138532179Sedward 	thisw = 0;
138630594Ssam }
138730594Ssam 
showspecial(s,cc,wid)138832179Sedward showspecial(s, cc, wid)
138932179Sedward 	char *s;
139032179Sedward 	int cc;
139132179Sedward 	int wid;
139230594Ssam {
139332179Sedward 	char *sp;
139430594Ssam 
139532179Sedward 	FlushShow(0);
139632179Sedward 	MoveTo();
139732179Sedward 	DoMove();
139832179Sedward 	putchar('(');
139932179Sedward 	for (sp = s; *sp != '\0'; sp++) {
140032179Sedward 		if (needsescape(*sp))
140132179Sedward 			putchar('\\');
140232179Sedward 		putchar(*sp);
140330594Ssam 	}
140432179Sedward 	printf(")%d %d oc\n", cc, wid);
140530594Ssam }
140630594Ssam 
showchar(c)140732179Sedward showchar(c)
140832179Sedward 	int c;
140930594Ssam {
141032179Sedward 	if (showind == 0)
141132179Sedward 		MoveTo();
141232179Sedward 	else if (vpos * PSmag != PSy) {
141332179Sedward 		FlushShow(0);
141432179Sedward 		MoveTo();
141530594Ssam 	}
141632179Sedward 	if (showind >= SHOWSIZE)
141732179Sedward 		FlushShow(0);
141832179Sedward 	if (isascii(c) && isprint(c))
141932179Sedward 		switch (c) {
142032179Sedward 		case '\\':
142132179Sedward 		case '(':
142232179Sedward 		case ')':
142332179Sedward 			showbuf[showind++] = '\\';
142432179Sedward 			/* fall through */
142532179Sedward 		default:
142632179Sedward 			showbuf[showind++] = c;
142732179Sedward 		}
142832179Sedward 	else {
142932179Sedward 		showbuf[showind++] = '\\';
143032179Sedward 		showbuf[showind++] = ((c >> 6) & 03) + '0';
143132179Sedward 		showbuf[showind++] = ((c >> 3) & 07) + '0';
143232179Sedward 		showbuf[showind++] = (c & 07) + '0';
143332179Sedward 	}
143432179Sedward 	showbuf[showind] = '\0';
143532179Sedward 	nshow++;
143630594Ssam }
143730594Ssam 
MoveTo()143832179Sedward MoveTo()
143932179Sedward {
144032179Sedward 	int x, y;
144130594Ssam 
144232179Sedward 	x = hpos * PSmag;
144332179Sedward 	y = vpos * PSmag;
144432179Sedward 	if (x != PSx) {
144532179Sedward 		startx = savex = hpos;
144632179Sedward 		PSx = x;
144732179Sedward 		movepending |= XMOVE;
144832179Sedward 	}
144932179Sedward 	if (y != PSy) {
145032179Sedward 		savey = vpos;
145132179Sedward 		PSy = y;
145232179Sedward 		movepending |= YMOVE;
145332179Sedward 	}
145430594Ssam }
145530594Ssam 
FlushMove()145632179Sedward FlushMove()
145732179Sedward {
145832179Sedward 	switch (movepending) {
145930594Ssam 	case NONE:
146032179Sedward 		break;
146130594Ssam 	case XMOVE:
146232179Sedward 		printf("%d", savex);
146332179Sedward 		break;
146430594Ssam 	case YMOVE:
146532179Sedward 		printf("%d", savey);
146632179Sedward 		break;
146730594Ssam 	case XYMOVE:
146832179Sedward 		printf("%d %d", savex, savey);
146932179Sedward 		break;
147030594Ssam 	default:
147132179Sedward 		fprintf(stderr, "%s: invalid move code %d\n",
147232179Sedward 			prog, movepending);
147332179Sedward 		exit(2);
147432179Sedward 	}
147530594Ssam }
147630594Ssam 
147732179Sedward char *movecmds[] = { "MX", "MY", "MXY" };
147832179Sedward 
DoMove()147932179Sedward DoMove()
148032179Sedward {
148132179Sedward 	FlushMove();
148232179Sedward 	if (movepending != NONE) {
148332179Sedward 		printf(" %s\n", movecmds[movepending - 1]);
148432179Sedward 		movepending = NONE;
148532179Sedward 	}
148630594Ssam }
148730594Ssam 
148832179Sedward char showops[] = "SXYN";
148930594Ssam 
FlushShow(t)149032179Sedward FlushShow(t)
149132179Sedward 	int t;
149232179Sedward {
149332179Sedward 	long err, tlen;
149432179Sedward 	float cerror;
149532179Sedward 
149632179Sedward 	if (showind == 0) {
149732179Sedward 		thisw = 0;
149832179Sedward 		return;
149932179Sedward 	}
150032179Sedward 	if (movepending != NONE)
150132179Sedward 		FlushMove();
150232179Sedward 	tlen = hpos - startx;
150332179Sedward 	if (lastcmd == CPUT)
150432179Sedward 		tlen += thisw;
150532179Sedward 	err = tlen * PSmag - PSshowlen;
150632179Sedward 	if (nshow != 1 && abs(err) > ErrorTolerance) {
150732179Sedward 		cerror = (float) err / ((nshow - 1) * PSmag);
150830594Ssam #ifdef DEBUG
150932179Sedward 		fprintf(stderr, "F%d lc %d thisw %d ", t, lastcmd, thisw);
151032179Sedward 		fprintf(stderr, "x %ld h %ld tn %ld %ld ",
151132179Sedward 			startx, hpos, tlen*PSmag, PSshowlen);
151232179Sedward 		fprintf(stderr, "error %d %.4f %s\n", nshow, cerror, showbuf);
151332179Sedward 		fflush(stderr);
151430594Ssam #endif
151532179Sedward 		printf(" %.4f(%s)A%c\n", cerror, showbuf, showops[movepending]);
151632179Sedward 	} else
151732179Sedward 		printf("(%s)%c\n", showbuf, showops[movepending]);
151832179Sedward 	showind = 0;
151932179Sedward 	nshow = 0;
152032179Sedward 	showbuf[showind] = '\0';
152132179Sedward 	PSx += PSshowlen;
152232179Sedward 	PSshowlen = 0;
152332179Sedward 	startx = hpos;
152432179Sedward 	if (lastcmd == CPUT)
152532179Sedward 		startx += thisw;
152632179Sedward 	thisw = 0;
152732179Sedward 	movepending = NONE;
152832179Sedward }
152930594Ssam 
153032179Sedward /* The following stolen (with modifications) from ... */
153132179Sedward /*
153232179Sedward  * This program is part of gr2ps.  It converts Gremlin's curve output to
153332179Sedward  * control vertices of Bezier Cubics, as supported by PostScript.
153432179Sedward  * Gremlin currently supports three kinds of curves:
153532179Sedward  *	(1) cubic interpolated spline with
153632179Sedward  *	     i) periodic end condition, if two end points coincide
153732179Sedward  *	    ii) natural end condition, otherwise
153832179Sedward  *	(2) uniform cubic B-spline with
153932179Sedward  *	     i) closed curve (no vertex interpolated), if end vertices coincide
154032179Sedward  *	    ii) end vertex interpolation, otherwise
154132179Sedward  *	(3) Bezier cubics
154232179Sedward  *
154332179Sedward  * The basic idea of the conversion algorithm for the first two is
154432179Sedward  *	(1) take each curve segment's two end points as Bezier end vertices.
154532179Sedward  *	(2) find two intermediate points in the orginal curve segment
154632179Sedward  *	    (with u=1/4 and u=1/2, for example).
154732179Sedward  *	(3) solve for the two intermediate control vertices.
154832179Sedward  * The conversion between Bezier Cubics of Gremlin and that of PostScript
154932179Sedward  * is straightforward.
155032179Sedward  *
155132179Sedward  * Author: Peehong Chen (phc@renoir.berkeley.edu)
155232179Sedward  * Date: 9/17/1986
155332179Sedward  */
155432179Sedward #include <math.h>
155532179Sedward 
155632179Sedward #define BezierMax	5
155732179Sedward #define BC1		1.0/9		/* coefficient of Bezier conversion */
155832179Sedward #define BC2		4*BC1
155932179Sedward #define BC3		3*BC2
156032179Sedward #define BC4		8*BC2
156132179Sedward 
156234009Sedward double Qx, Qy, h[MAXPOINTS], dx[MAXPOINTS],
156332179Sedward 	dy[MAXPOINTS], d2x[MAXPOINTS], d2y[MAXPOINTS], d3x[MAXPOINTS],
156432179Sedward 	d3y[MAXPOINTS];
156532179Sedward 
156632179Sedward /*
156732179Sedward  * This routine converts each segment of a curve, P1, P2, P3, and P4
156832179Sedward  * to a set of two intermediate control vertices, V2 and V3, in a Bezier
156932179Sedward  * segment, plus a third vertex of the end point P4 (assuming the current
157032179Sedward  * position is P1), and then writes a PostScript command "V2 V3 V4 curveto"
157132179Sedward  * to the output file.
157232179Sedward  * The two intermediate vertices are obtained using
157332179Sedward  *    Q(u) = V1 * (1-u)^3 + V2 * 3u(1-u)^2 + V3 * 3(1-u)u^2 + V4 * u^3
157432179Sedward  * with u=1/4, and u=1/2,
157532179Sedward  *	Q(1/4) = Q2 = (x2, y2)
157632179Sedward  *	Q(1/2) = Q3 = (x3, y3)
157732179Sedward  *	V1 = P1
157832179Sedward  *	V4 = P4
157932179Sedward  * and
158032179Sedward  *	V2 = (32/9)*Q2 - (4/3)*(Q3 + V1) + (1/9)*V4
158132179Sedward  *	V3 = -(32/9)*Q2 + 4*Q3 + V1 - (4/9)*V4
158232179Sedward  */
BezierSegment(x1,y1,x2,y2,x3,y3,x4,y4)158332179Sedward BezierSegment(x1, y1, x2, y2, x3, y3, x4, y4)
158432179Sedward 	double x1, y1, x2, y2, x3, y3, x4, y4;
158532179Sedward {
158632179Sedward 	double V2x, V2y, V3x, V3y;
158732179Sedward 
158832179Sedward 	V2x = BC4 * x2 - BC3 * (x3 + x1) + BC1 * x4;
158932179Sedward 	V2y = BC4 * y2 - BC3 * (y3 + y1) + BC1 * y4;
159032179Sedward 	V3x = -BC4 * x2 + 4 * x3 +  x1 - BC2 * x4;
159132179Sedward 	V3y = -BC4 * y2 + 4 * y3 +  y1 - BC2 * y4;
159232179Sedward 
159332179Sedward 	printf(" %lg %lg %lg %lg %lg %lg curveto\n",
159432179Sedward 		V2x, V2y, V3x, V3y, x4, y4);
159534009Sedward 	PSx = x4 * PSmag;
159634009Sedward 	PSy = y4 * PSmag;
159732179Sedward } /* end BezierSegment */
159832179Sedward 
159932179Sedward /*
160032179Sedward  * This routine calculates parameteric values for use in calculating
160132179Sedward  * curves.  The values are an approximation of cumulative arc lengths
160232179Sedward  * of the curve (uses cord * length).  For additional information,
160332179Sedward  * see paper cited below.
160432179Sedward  *
160532179Sedward  * This is from Gremlin (called Paramaterize in gremlin),
160632179Sedward  * with minor modifications (elimination of param list)
160732179Sedward  */
IS_Parameterize()160832179Sedward IS_Parameterize()
160932179Sedward {
161032179Sedward 	register i, j;
161132179Sedward 	double t1, t2;
161232179Sedward 	double u[MAXPOINTS];
161332179Sedward 
161432179Sedward 	for (i = 1; i <= numpoints; i++) {
161532179Sedward 		u[i] = 0.0;
161632179Sedward 		for (j = 1; j < i; j++) {
161732179Sedward 			t1 = x[j + 1] - x[j];
161832179Sedward 			t2 = y[j + 1] - y[j];
161934009Sedward 			u[i] += sqrt(t1 * t1 + t2 * t2);
162032179Sedward 		}
162132179Sedward 	}
162232179Sedward 	for (i = 1; i < numpoints; i++)
162332179Sedward 		h[i] = u[i + 1] - u[i];
162432179Sedward }  /* end IS_Parameterize */
162532179Sedward 
162632179Sedward /*
162732179Sedward  * This routine solves for the cubic polynomial to fit a spline
162832179Sedward  * curve to the the points  specified by the list of values.
162932179Sedward  * The curve generated is periodic.  The alogrithms for this
163032179Sedward  * curve are from the "Spline Curve Techniques" paper cited below.
163132179Sedward  *
163232179Sedward  * This is from Gremlin (called PeriodicSpline in gremlin)
163332179Sedward  *
163432179Sedward  */
IS_PeriodicEnd(h,z,dz,d2z,d3z)163532179Sedward IS_PeriodicEnd(h, z, dz, d2z, d3z)
163632179Sedward 	double h[MAXPOINTS];		/* Parameterizeaterization */
163732179Sedward 	double z[MAXPOINTS];		/* point list */
163832179Sedward 	double dz[MAXPOINTS];		/* to return the 1st derivative */
163932179Sedward 	double d2z[MAXPOINTS];		/* 2nd derivative */
164032179Sedward 	double d3z[MAXPOINTS];		/* and 3rd derivative */
164132179Sedward {
164232179Sedward 	double a[MAXPOINTS];
164332179Sedward 	double b[MAXPOINTS];
164432179Sedward 	double c[MAXPOINTS];
164532179Sedward 	double d[MAXPOINTS];
164632179Sedward 	double deltaz[MAXPOINTS];
164732179Sedward 	double r[MAXPOINTS];
164832179Sedward 	double s[MAXPOINTS];
164932179Sedward 	double ftmp;
165032179Sedward 	register i;
165132179Sedward 
165232179Sedward 	/* step 1 */
165332179Sedward 	for (i = 1; i < numpoints; i++)
165432179Sedward 		if (h[i] != 0)
165532179Sedward 			deltaz[i] = (z[i + 1] - z[i]) / h[i];
165632179Sedward 		else
165732179Sedward 			deltaz[i] = 0;
165832179Sedward 	h[0] = h[numpoints - 1];
165932179Sedward 	deltaz[0] = deltaz[numpoints - 1];
166032179Sedward 
166132179Sedward 	/* step 2 */
166232179Sedward 	for (i = 1; i < numpoints - 1; i++)
166332179Sedward 		d[i] = deltaz[i + 1] - deltaz[i];
166432179Sedward 	d[0] = deltaz[1] - deltaz[0];
166532179Sedward 
166632179Sedward 	/* step 3a */
166732179Sedward 	a[1] = 2 * (h[0] + h[1]);
166832179Sedward 	if (a[1] == 0)
166932179Sedward 		return (-1);  /* 3 consecutive knots at same point */
167032179Sedward 	b[1] = d[0];
167132179Sedward 	c[1] = h[0];
167232179Sedward 
167332179Sedward 	for (i = 2; i < numpoints - 1; i++) {
167432179Sedward 		ftmp = h[i - 1];
167532179Sedward 		a[i] = ftmp + ftmp + h[i] + h[i] - ftmp * ftmp / a[i - 1];
167632179Sedward 		if (a[i] == 0)
167732179Sedward 			return (-1);  /* 3 consec knots at same point */
167832179Sedward 		b[i] = d[i - 1] - ftmp * b[i - 1] / a[i - 1];
167932179Sedward 		c[i] = - ftmp * c[i - 1]/a[i - 1];
168032179Sedward 	}
168132179Sedward 
168232179Sedward 	/* step 3b */
168332179Sedward 	r[numpoints - 1] = 1;
168432179Sedward 	s[numpoints - 1] = 0;
168532179Sedward 	for (i = numpoints - 2; i > 0; i--) {
168632179Sedward 		r[i] = - (h[i] * r[i + 1] + c[i]) / a[i];
168732179Sedward 		s[i] = (6 * b[i] - h[i] * s[i + 1]) / a[i];
168832179Sedward 	}
168932179Sedward 
169032179Sedward 	/* step 4 */
169132179Sedward 	d2z[numpoints - 1] = (6 * d[numpoints - 2] - h[0] * s[1]
169232179Sedward 			- h[numpoints - 1] * s[numpoints - 2])
169332179Sedward 		/ (h[0] * r[1] + h[numpoints - 1] * r[numpoints - 2]
169432179Sedward 			+ 2 * (h[numpoints - 2] + h[0]));
169532179Sedward 	for (i = 1; i < numpoints - 1; i++)
169632179Sedward 		d2z[i] = r[i] * d2z[numpoints - 1] + s[i];
169732179Sedward 	d2z[numpoints] = d2z[1];
169832179Sedward 
169932179Sedward 	/* step 5 */
170032179Sedward 	for (i = 1; i < numpoints; i++) {
170132179Sedward 		dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
170232179Sedward 		if (h[i] != 0)
170332179Sedward 			d3z[i] = (d2z[i + 1] - d2z[i]) / h[i];
170432179Sedward 		else
170532179Sedward 			d3z[i] = 0;
170632179Sedward 	}
170732179Sedward 
170832179Sedward 	return (0);
170932179Sedward }  /* end IS_PeriodicEnd */
171032179Sedward 
171132179Sedward /*
171232179Sedward  * This routine solves for the cubic polynomial to fit a spline
171332179Sedward  * curve from the points specified by the list of values.  The alogrithms for
171432179Sedward  * this curve are from the "Spline Curve Techniques" paper cited below.
171532179Sedward  *
171632179Sedward  * This is from Gremlin (called NaturalEndSpline in gremlin)
171732179Sedward  */
IS_NaturalEnd(h,z,dz,d2z,d3z)171832179Sedward IS_NaturalEnd(h, z, dz, d2z, d3z)
171932179Sedward 	double h[MAXPOINTS];		/* parameterization */
172032179Sedward 	double z[MAXPOINTS];		/* point list */
172132179Sedward 	double dz[MAXPOINTS];		/* to return the 1st derivative */
172232179Sedward 	double d2z[MAXPOINTS];		/* 2nd derivative */
172332179Sedward 	double d3z[MAXPOINTS];		/* and 3rd derivative */
172432179Sedward {
172532179Sedward 	double a[MAXPOINTS];
172632179Sedward 	double b[MAXPOINTS];
172732179Sedward 	double d[MAXPOINTS];
172832179Sedward 	double deltaz[MAXPOINTS];
172932179Sedward 	double ftmp;
173032179Sedward 	register i;
173132179Sedward 
173232179Sedward 	/* step 1 */
173332179Sedward 	for (i = 1; i < numpoints; i++)
173432179Sedward 		if (h[i] != 0)
173532179Sedward 			deltaz[i] = (z[i + 1] - z[i]) / h[i];
173632179Sedward 		else
173732179Sedward 			deltaz[i] = 0;
173832179Sedward 	deltaz[0] = deltaz[numpoints - 1];
173932179Sedward 
174032179Sedward 	/* step 2 */
174132179Sedward 	for (i = 1; i < numpoints - 1; i++)
174232179Sedward 		d[i] = deltaz[i + 1] - deltaz[i];
174332179Sedward 	d[0] = deltaz[1] - deltaz[0];
174432179Sedward 
174532179Sedward 	/* step 3 */
174632179Sedward 	a[0] = 2 * (h[2] + h[1]);
174732179Sedward 	if (a[0] == 0)		/* 3 consec knots at same point */
174832179Sedward 		return (-1);
174932179Sedward 	b[0] = d[1];
175032179Sedward 
175132179Sedward 	for (i = 1; i < numpoints - 2; i++) {
175232179Sedward 		ftmp = h[i + 1];
175332179Sedward 		a[i] = ftmp + ftmp + h[i + 2] + h[i + 2] -
175432179Sedward 			(ftmp * ftmp) / a[i - 1];
175532179Sedward 		if (a[i] == 0)		/* 3 consec knots at same point */
175632179Sedward 			return (-1);
175732179Sedward 		b[i] = d[i + 1] - ftmp * b[i - 1] / a[i - 1];
175832179Sedward 	}
175932179Sedward 
176032179Sedward 	/* step 4 */
176132179Sedward 	d2z[numpoints] = d2z[1] = 0;
176232179Sedward 	for (i = numpoints - 1; i > 1; i--)
176332179Sedward 		d2z[i] = (6 * b[i - 2] - h[i] * d2z[i + 1]) / a[i - 2];
176432179Sedward 
176532179Sedward 	/* step 5 */
176632179Sedward 	for (i = 1; i < numpoints; i++) {
176732179Sedward 		dz[i] = deltaz[i] - h[i] * (2 * d2z[i] + d2z[i + 1]) / 6;
176832179Sedward 		if (h[i] != 0)
176932179Sedward 			d3z[i] = (d2z[i + 1] - d2z[i]) / h[i];
177032179Sedward 		else
177132179Sedward 			d3z[i] = 0;
177232179Sedward 	}
177332179Sedward 
177432179Sedward 	return (0);
177532179Sedward }  /* end IS_NaturalEnd */
177632179Sedward 
177732179Sedward /*
177832179Sedward  * Use the same algorithm Gremlin uses to interpolate a given
177932179Sedward  * set of points, as described in ``Spline Curve Techniques,''
178032179Sedward  * by Pattrick Baudelaire, Robert M. Flegal, and Robert F. Sproull,
178132179Sedward  * Xerox PARC Tech Report No. 78CSL-059.
178232179Sedward  */
IS_Initialize()178334009Sedward IS_Initialize()
178432179Sedward {
178532179Sedward 	IS_Parameterize();
178632179Sedward 
178732179Sedward 	/* Solve for derivatives of the curve at each point
178832179Sedward 	   separately for x and y (parametric). */
178932179Sedward 
179032179Sedward 	if (x[1] == x[numpoints] && y[1] == y[numpoints]) { /* closed curve */
179132179Sedward 		IS_PeriodicEnd(h, x, dx, d2x, d3x);
179232179Sedward 		IS_PeriodicEnd(h, y, dy, d2y, d3y);
179332179Sedward 	} else {
179432179Sedward 		IS_NaturalEnd(h, x, dx, d2x, d3x);
179532179Sedward 		IS_NaturalEnd(h, y, dy, d2y, d3y);
179632179Sedward 	}
179730594Ssam }
179832179Sedward 
179932179Sedward /*
180032179Sedward  * This routine converts cubic interpolatory spline to Bezier control vertices
180132179Sedward  */
IS_Convert()180232179Sedward IS_Convert()
180332179Sedward {
180432179Sedward 	double t, t2, t3, x2, y2, x3, y3;
180532179Sedward 	register j, j1;
180632179Sedward 
180732179Sedward 	for (j = 1; j < numpoints; j++) {
180832179Sedward 		t = .25 * h[j];
180932179Sedward 		t2 = t * t;
181032179Sedward 		t3 = t2 * t;
181132179Sedward 		x2 = x[j] + t * dx[j] + t2 * d2x[j] / 2.0 + t3 * d3x[j] / 6.0;
181232179Sedward 		y2 = y[j] + t * dy[j] + t2 * d2y[j] / 2.0 + t3 * d3y[j] / 6.0;
181332179Sedward 
181432179Sedward 		t = 2 * t;
181532179Sedward 		t2 = t * t;
181632179Sedward 		t3 = t2 * t;
181732179Sedward 		x3 = x[j] + t * dx[j] + t2 * d2x[j] / 2.0 + t3 * d3x[j] / 6.0;
181832179Sedward 		y3 = y[j] + t * dy[j] + t2 * d2y[j] / 2.0 + t3 * d3y[j] / 6.0;
181932179Sedward 
182032179Sedward 		j1 = j + 1;
182132179Sedward 		BezierSegment(x[j], y[j], x2, y2, x3, y3, x[j1], y[j1]);
182232179Sedward 	}
182332179Sedward } /* end IS_Convert */
182432179Sedward 
182532179Sedward /*
182632179Sedward  * This routine computes a point in B-spline segment, given i, and u.
182732179Sedward  * Details of this algorithm can be found in the tech. report cited below.
182832179Sedward  */
BS_ComputePoint(i,u,xp,yp)182934009Sedward BS_ComputePoint(i, u, xp, yp)
183032179Sedward 	int i;
183132179Sedward 	float u;
183234009Sedward 	double *xp, *yp;
183332179Sedward {
183432179Sedward 	float u2, u3, b_2, b_1, b0, b1;
183532179Sedward 	register i1, i_2, i_1;
183632179Sedward 
183732179Sedward 	i1  = i + 1;
183832179Sedward 	i_1 = i - 1;
183932179Sedward 	i_2 = i - 2;
184032179Sedward 
184132179Sedward 	u2 = u * u;
184232179Sedward 	u3 = u2 * u;
184332179Sedward 	b_2 = (1 - 3 * u + 3 * u2 - u3) / 6.0;
184432179Sedward 	b_1 = (4 - 6 * u2 + 3 * u3) / 6.0;
184532179Sedward 	b0  = (1 + 3 * u + 3 * u2 - 3 * u3) / 6.0;
184632179Sedward 	b1  = u3 / 6.0;
184732179Sedward 
184834009Sedward 	*xp = b_2 * x[i_2] + b_1 * x[i_1] + b0 * x[i] + b1 * x[i1];
184934009Sedward 	*yp = b_2 * y[i_2] + b_1 * y[i_1] + b0 * y[i] + b1 * y[i1];
185032179Sedward } /* end BS_ComputePoint */
185132179Sedward 
185232179Sedward /*
185332179Sedward  * This routine initializes the array of control vertices
185432179Sedward  * We consider two end conditions here:
185532179Sedward  *   (1) closed curve -- C2 continuation and end vertex not interpolated, i.e.
185632179Sedward  *		V[0] = V[n-1], and
185732179Sedward  *		V[n+1] = V[2].
185832179Sedward  *   (2) open curve -- end vertex interpolation, i.e.
185932179Sedward  *		V[0] = 2*V[1] - V[2], and
186032179Sedward  *		V[n+1] = 2*V[n] - V[n-1].
186132179Sedward  * Details of uniform cubic B-splines, including other end conditions
186232179Sedward  * and important properties can be found in Chapters 4-5 of
186332179Sedward  * Richard H. Bartels and Brian A. Barsky,
186432179Sedward  * "An Introduction to the Use of Splines in Computer Graphics",
186532179Sedward  * Tech. Report CS-83-136, Computer Science Division,
186632179Sedward  * University of California, Berkeley, 1984.
186732179Sedward  */
BS_Initialize()186834009Sedward BS_Initialize()
186932179Sedward {
187032179Sedward 	register n_1, n1;
187132179Sedward 
187232179Sedward 	n_1 = numpoints - 1;
187332179Sedward 	n1  = numpoints + 1;
187432179Sedward 	if (x[1] == x[numpoints] && y[1] == y[numpoints]) { /* closed curve */
187532179Sedward 		x[0] = x[n_1];				/* V[0] */
187632179Sedward 		y[0] = y[n_1];
187732179Sedward 		x[n1] = x[2];				/* V[n+1] */
187832179Sedward 		y[n1] = y[2];
187932179Sedward 	} else {				/* end vertex interpolation */
188034009Sedward 		x[0] = 2 * x[1] - x[2];			/* V[0] */
188134009Sedward 		y[0] = 2 * y[1] - y[2];
188234009Sedward 		x[n1] = 2 * x[numpoints] - x[n_1];	/* V[n+1] */
188334009Sedward 		y[n1] = 2 * y[numpoints] - y[n_1];
188432179Sedward 	}
188532179Sedward } /* end BS_Initialize */
188632179Sedward 
188732179Sedward /*
188832179Sedward  * This routine converts uniform cubic B-spline to Bezier control vertices
188932179Sedward  */
BS_Convert()189032179Sedward BS_Convert()
189132179Sedward {
189234009Sedward 	double x1, y1, x2, y2, x3, y3, x4, y4;
189332179Sedward 	register i;
189432179Sedward 
189532179Sedward 	for (i = 2; i <= numpoints; i++) {
189634009Sedward 		BS_ComputePoint(i, 0.0, &x1, &y1);
189734009Sedward 		BS_ComputePoint(i, 0.25, &x2, &y2);
189834009Sedward 		BS_ComputePoint(i, 0.5, &x3, &y3);
189934009Sedward 		BS_ComputePoint(i, 1.0, &x4, &y4);
190034009Sedward 		if (i == 2)
190134009Sedward 			printf("%lg %lg moveto\n", x1, y1);
190234009Sedward 		BezierSegment(x1, y1, x2, y2, x3, y3, x4, y4);
190332179Sedward 	}
190432179Sedward } /* end BS_Convert */
190532179Sedward 
190632179Sedward /*
190732179Sedward  * This routine copies the offset between two consecutive control points
190832179Sedward  * into an array.  That is,
190932179Sedward  * 	O[i] = (x[i], y[i]) = V[i+1] - V[i],
191032179Sedward  * for i=1 to N-1, where N is the number of points given.
191132179Sedward  * The starting end point (V[1]) is saved in (Qx, Qy).
191232179Sedward  */
BZ_Offsets()191334009Sedward BZ_Offsets()
191432179Sedward {
191532179Sedward 	register i;
191632179Sedward 
191732179Sedward 	/* Assign offsets btwn points to array for convenience of processing */
191834009Sedward 	Qx = x[1];
191934009Sedward 	Qy = y[1];
192034009Sedward 	for (i = 1; i < numpoints; i++) {
192134009Sedward 		x[i] = x[i + 1] - x[i];
192234009Sedward 		y[i] = y[i + 1] - y[i];
192332179Sedward 	}
192432179Sedward }
192532179Sedward 
192632179Sedward /*
192732179Sedward  * This routine contructs paths of piecewise continuous Bezier cubics
192832179Sedward  * in PostScript based on the given set of control vertices.
192934009Sedward  * Given 2 points, a straight line is drawn.
193032179Sedward  * Given 3 points V[1], V[2], and V[3], a Bezier cubic segment
193132179Sedward  * of (V[1], (V[1]+V[2])/2, (V[2]+V[3])/2, V[3]) is drawn.
193232179Sedward  * In the case when N (N >= 4) points are given, N-2 Bezier segments will
193332179Sedward  * be drawn, each of which (for i=1 to N-2) is translated to PostScript as
193432179Sedward  *	Q+O[i]/3  Q+(3*O[i]+O[i+1])/6  K+O[i+1]/2  curveto,
193532179Sedward  * where
193632179Sedward  *	Q is the current point,
193732179Sedward  *	K is the continuation offset = Qinitial + Sigma(1, i)(O[i])
193832179Sedward  * Note that when i is 1, the initial point
193932179Sedward  *	Q = V[1].
194032179Sedward  * and when i is N-2, the terminating point
194132179Sedward  *	K+O[i+1]/2 = V[N].
194232179Sedward  */
BZ_Convert()194332179Sedward BZ_Convert()
194432179Sedward {
194532179Sedward 	register i, i1;
194632179Sedward 	double x1, y1, x2, y2, x3, y3, Kx, Ky;
194732179Sedward 
194832179Sedward 	if (numpoints == 2) {
194932179Sedward 		printf(" %lg %lg rlineto\n", x[1], y[1]);
195034009Sedward 		PSx += x[1] * PSmag;
195134009Sedward 		PSy += y[1] * PSmag;
195232179Sedward 		return;
195332179Sedward 	}
195432179Sedward 	if (numpoints == 3) {
195532179Sedward 		x1 = Qx + x[1];
195632179Sedward 		y1 = Qy + y[1];
195732179Sedward 		x2 = x1 + x[2];
195832179Sedward 		y2 = y1 + y[2];
195932179Sedward 		printf(" %lg %lg %lg %lg %lg %lg curveto\n",
196032179Sedward 		       (Qx + x1) / 2.0, (Qy + y1) / 2.0, (x1 + x2) / 2.0,
196132179Sedward 		       (y1 + y2) / 2.0, x2, y2);
196234009Sedward 		PSx = x2 * PSmag;
196334009Sedward 		PSy = y2 * PSmag;
196432179Sedward 		return;
196532179Sedward 	}
196632179Sedward 	/* numpoints >= 4 */
196732179Sedward 	Kx = Qx + x[1];
196832179Sedward 	Ky = Qy + y[1];
196934009Sedward 	x[1] *= 2;
197034009Sedward 	y[1] *= 2;
197134009Sedward 	x[numpoints - 1] *= 2;
197234009Sedward 	y[numpoints - 1] *= 2;
197334009Sedward 	for (i = 1; i <= numpoints - 2; i++) {
197434009Sedward 		i1 = i + 1;
197534009Sedward 		x1 = Qx + x[i] / 3;
197634009Sedward 		y1 = Qy + y[i] / 3;
197734009Sedward 		x2 = Qx + (3 * x[i] + x[i1]) / 6;
197834009Sedward 		y2 = Qy + (3 * y[i] + y[i1]) / 6;
197934009Sedward 		x3 = Kx + x[i1] / 2;
198034009Sedward 		y3 = Ky + y[i1] / 2;
198132179Sedward 		printf(" %lg %lg %lg %lg %lg %lg curveto\n",
198232179Sedward 			x1, y1, x2, y2, x3, y3);
198332179Sedward 		Qx = x3;
198432179Sedward 		Qy = y3;
198534009Sedward 		Kx += x[i1];
198634009Sedward 		Ky += y[i1];
198732179Sedward 	}
198834009Sedward 	PSx = x3 * PSmag;
198934009Sedward 	PSy = y3 * PSmag;
199032179Sedward } /* end BZ_Convert */
1991