1 /*	dvar.c	1.15	85/08/05
2  *
3  * Varian driver for the new troff
4  *
5  * Authors:	BWK(BELL)
6  *		VCAT(berkley)
7  *		Richard L. Hyde, Perdue University
8  *		and David Slattengren, U.C. Berkeley
9  */
10 
11 
12 /*******************************************************************************
13 
14     output language from troff:
15     all numbers are character strings
16 
17 #..\n	comment
18 sn	size in points
19 fn	font as number from 1 to n
20 in	stipple `font' as number from 1 to n
21 cx	ascii character x
22 Cxyz	funny char \(xyz. terminated by white space
23 Hn	go to absolute horizontal position n
24 Vn	go to absolute vertical position n (down is positive)
25 hn	go n units horizontally (relative)
26 vn	ditto vertically
27 nnc	move right nn, then print c (exactly 2 digits!)
28 		(this wart is an optimization that shrinks output file size
29 		 about 35% and run-time about 15% while preserving ascii-ness)
30 p	new page begins -- set v to 0
31 nb a	end of line (information only -- no action needed)
32 	b = space before line, a = after
33 w	paddable word space -- no action needed
34 
35 Dt ..\n	draw operation 't':
36 	Dt d		set line thickness to d
37 	Ds d		set line style (mask) to d
38 	Dl x y		line from here by x,y
39 	Dc d		circle of diameter d with left side here
40 	De x y		ellipse of axes x,y with left side here
41 	Da x y r	arc counter-clockwise by x,y of radius r
42 	D~ x y x y ...	B-spline curve by x,y then x,y ...
43 	Dg x y x y ...	gremlin spline curve by x,y then x,y ...
44 	Dp s x y ...	polygon by x,y then ... filled with stipple s
45 
46 x ..\n	device control functions:
47      x i	init
48      x T s	name of device is s
49      x r n h v	resolution is n/inch h = min horizontal motion, v = min vert
50      x p	pause (can restart)
51      x s	stop -- done for ever
52      x t	generate trailer
53      x f n s	font position n contains font s
54      x H n	set character height to n
55      x S n	set slant to N
56 
57 	Subcommands like "i" are often spelled out like "init".
58 
59 *******************************************************************************/
60 
61 
62 #include <stdio.h>
63 #include <ctype.h>
64 #include <sys/vcmd.h>
65 #include "dev.h"
66 
67 
68 /* #define DEBUGABLE		/* No, not debugable... */
69 #define DRIVER  		/* Yes, we're driving directly */
70 /* #define FULLPAGE		/* No, don't output full pages */
71 #define	NFONTS	65		/* total number of fonts useable */
72 #define	MAXSTATE 6		/* number of environments rememberable */
73 #define OPENREAD 0		/* mode for openning files */
74 #define RESTART	1		/* upon exit, return either RESTART */
75 #define ABORT	2		/*     or ABORT */
76 #define	FATAL	1		/* type of error */
77 #define	BMASK	0377		/* byte grabber */
78 #ifndef FONTDIR
79 #define FONTDIR	"/usr/lib/font"	/* default place to find font descriptions */
80 #endif
81 #ifndef BITDIR
82 #define BITDIR "/usr/lib/vfont" /* default place to look for font rasters */
83 #endif
84 #define MAXWRIT 4096		/* max characters allowed to write at once */
85 
86 #define  hmot(n)	hgoto(hpos + n)
87 #define  vmot(n)	vgoto(vpos + n)
88 
89 
90 char	SccsId[]= "dvar.c	1.15	85/08/05";
91 
92 int	output	= 0;	/* do we do output at all? */
93 int	nolist	= 0;	/* output page list if > 0 */
94 int	olist[20];	/* pairs of page numbers */
95 int	spage	= 9999;	/* stop every spage pages */
96 int	scount	= 0;
97 struct	dev	dev;
98 struct	font	*fontbase[NFONTS+1];
99 short *	pstab;		/* point size table pointer */
100 int	nsizes;		/* number of sizes device is capable of printing */
101 int	nfonts;		/* number of fonts device is capable of printing */
102 int	nstips;		/* number of stipple fonts device can print */
103 int	nchtab;
104 char *	chname;
105 short *	chtab;
106 char *	fitab[NFONTS+1];	/* font inclusion table - maps ascii to ch # */
107 char *	widtab[NFONTS+1];	/* width table for each font */
108 char *	codetab[NFONTS+1];	/* device codes */
109 char *	fontdir = FONTDIR;	/* place to find devxxx directories */
110 char *	bitdir = BITDIR;	/* place to find raster fonts and fontmap */
111 char *	fontname[NFONTS+1];	/* table of what font is on what position */
112 struct {			/* table of what font */
113 	char fname[3];		/*   name maps to what */
114 	char *ffile;		/*   filename in bitdirectory */
115 } fontmap[NFONTS+1];
116 
117 
118 #ifdef DEBUGABLE
119 int	dbg	= 0;
120 #endif
121 int	size	= -1;	/* current point size (internal pstable index) */
122 int	font	= -1;	/* current font - not using any to start with */
123 int	stip	= -1;	/* current stipple font - not using any to start with */
124 int	stipmem	= 0;	/* current member to use from stipple font */
125 int	hpos;		/* horizontal position we are to be at next; left = 0 */
126 int	vpos;		/* current vertical position (down positive) */
127 extern	linethickness;	/* thickness (in pixels) of any drawn object */
128 extern	linmod;		/* line style (a bit mask - dotted, etc.) of objects */
129 int	lastw;		/* width of last character printed */
130 
131 
132 #define DISPATCHSIZE	256		/* must be a power of two */
133 #define CHARMASK	(DISPATCHSIZE-1)
134 #define DSIZ		((sizeof *dispatch)*DISPATCHSIZE)
135 #define OUTFILE 	fileno (stdout)
136 #define	RES		200		/* resolution of the device (dots/in) */
137 
138 #define RASTER_LENGTH	2112			/* device line length */
139 #define BYTES_PER_LINE	(RASTER_LENGTH/8)
140 #ifndef FULLPAGE
141 #	define NLINES	1600			/* page width, 8 inches */
142 #endif
143 #ifdef FULLPAGE
144 #	define NLINES	1700			/* page width, 8.5 inches */
145 #endif
146 #define BUFFER_SIZE	(NLINES*BYTES_PER_LINE)	/* number of chars in picture */
147 
148 
149 int	pltmode[] = { VPLOT };
150 int	prtmode[] = { VPRINT };
151 char	buffer1[BUFFER_SIZE];	/* Big line buffers  */
152 char	buffer2[BUFFER_SIZE];
153 char *	fill = &buffer1[0];	/* Zero origin in filling buffer */
154 char *	empty = &buffer2[0];	/* Zero origin in emptying buffer */
155 char *	elevel = &buffer2[0];	/* current position in emptying buffer */
156 int	emptypos = NLINES;	/* amount of emptying done (initially "done") */
157 
158 
159 char *	calloc();
160 char *	nalloc();
161 char *	allpanic();
162 char *	operand();
163 
164 struct header {
165 	short	magic;
166 	unsigned short	size;
167 	short	maxx;
168 	short	maxy;
169 	short	xtnd;
170 } header;
171 
172 struct	dispatch{
173 	unsigned short	addr;
174 	short	nbytes;
175 	char	up;
176 	char	down;
177 	char	left;
178 	char	right;
179 	short	width;
180 };
181 
182 struct	fontdes {
183 	int	fnum;		/* if == -1, then this position is empty */
184 	int	psize;
185 	struct	dispatch *disp;
186 	char	*bits;
187 } fontdes[NFONTS+1];		/* initialized at program start */
188 
189 struct dispatch *dispatch;
190 struct dispatch *stip_disp;
191 int	cfnum = -1;
192 int	cpsize = 10;
193 int	cfont = 1;
194 char	*bits;
195 char	*stip_bits;
196 int	bordered = 1;		/* flag:  "do polygons get bordered?" */
197 int	fontwanted = 1;		/* flag:  "has a new font been requested?" */
198 int	nfontnum = -1;
199 int	npsize = 10;
200 
201 
202 
203 main(argc, argv)
204 char *argv[];
205 {
206 	register FILE *fp;
207 	register int i;
208 
209 	for (i = 0; i <= NFONTS; fontdes[i++].fnum = -1);
210 	while (--argc > 0 && **++argv == '-') {
211 		switch ((*argv)[1]) {
212 		case 'F':
213 			bitdir = operand(&argc, &argv);
214 			break;
215 		case 'f':
216 			fontdir = operand(&argc, &argv);
217 			break;
218 		case 'o':
219 			outlist(operand(&argc, &argv));
220 			break;
221 #ifdef DEBUGABLE
222 		case 'd':
223 			dbg = atoi(operand(&argc, &argv));
224 			if (dbg == 0) dbg = 1;
225 			break;
226 #endif
227 		case 's':
228 			spage = atoi(operand(&argc, &argv));
229 			if (spage <= 0)
230 				spage = 9999;
231 			break;
232 		}
233 	}
234 
235 #ifdef DRIVER
236 	ioctl(OUTFILE, VSETSTATE, pltmode);
237 #endif
238 
239 	if (argc < 1)
240 		conv(stdin);
241 	else
242 		while (argc--) {
243 			if (strcmp(*argv, "-") == 0)
244 				fp = stdin;
245 			else if ((fp = fopen(*argv, "r")) == NULL)
246 				error(FATAL, "can't open %s", *argv);
247 			conv(fp);
248 			fclose(fp);
249 			argv++;
250 		}
251 	exit(0);
252 }
253 
254 
255 /*----------------------------------------------------------------------------*
256  | Routine:	char  * operand (& argc,  & argv)
257  |
258  | Results:	returns address of the operand given with a command-line
259  |		option.  It uses either "-Xoperand" or "-X operand", whichever
260  |		is present.  The program is terminated if no option is present.
261  |
262  | Side Efct:	argc and argv are updated as necessary.
263  *----------------------------------------------------------------------------*/
264 
265 char *operand(argcp, argvp)
266 int * argcp;
267 char ***argvp;
268 {
269 	if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */
270 	if ((--*argcp) <= 0)			/* no operand */
271 	    error (FATAL, "command-line option operand missing.\n");
272 	return(*(++(*argvp)));			/* operand next word */
273 }
274 
275 
276 outlist(s)	/* process list of page numbers to be printed */
277 char *s;
278 {
279 	int n1, n2, i;
280 
281 	nolist = 0;
282 	while (*s) {
283 		n1 = 0;
284 		if (isdigit(*s))
285 			do
286 				n1 = 10 * n1 + *s++ - '0';
287 			while (isdigit(*s));
288 		else
289 			n1 = -9999;
290 		n2 = n1;
291 		if (*s == '-') {
292 			s++;
293 			n2 = 0;
294 			if (isdigit(*s))
295 				do
296 					n2 = 10 * n2 + *s++ - '0';
297 				while (isdigit(*s));
298 			else
299 				n2 = 9999;
300 		}
301 		olist[nolist++] = n1;
302 		olist[nolist++] = n2;
303 		if (*s != '\0')
304 			s++;
305 	}
306 	olist[nolist] = 0;
307 #ifdef DEBUGABLE
308 	if (dbg)
309 		for (i=0; i<nolist; i += 2)
310 			fprintf(stderr,"%3d %3d\n", olist[i], olist[i+1]);
311 #endif
312 }
313 
314 conv(fp)
315 register FILE *fp;
316 {
317 	register int c, k;
318 	int m, n, n1, m1;
319 	char str[100], buf[300];
320 
321 	while ((c = getc(fp)) != EOF) {
322 		switch (c) {
323 		case '\n':	/* when input is text */
324 		case ' ':
325 		case 0:		/* occasional noise creeps in */
326 			break;
327 		case '{':	/* push down current environment */
328 			t_push();
329 			break;
330 		case '}':
331 			t_pop();
332 			break;
333 		case '0': case '1': case '2': case '3': case '4':
334 		case '5': case '6': case '7': case '8': case '9':
335 			/* two motion digits plus a character */
336 			hmot((c-'0')*10 + getc(fp)-'0');
337 			put1(getc(fp));
338 			break;
339 		case 'c':	/* single ascii character */
340 			put1(getc(fp));
341 			break;
342 		case 'C':
343 			fscanf(fp, "%s", str);
344 			put1s(str);
345 			break;
346 		case 't':	/* straight text */
347 			fgets(buf, sizeof(buf), fp);
348 			t_text(buf);
349 			break;
350 		case 'D':	/* draw function */
351 			if (fgets(buf, sizeof(buf), fp) == NULL)
352 			    error(FATAL, "unexpected end of input");;
353 			switch (buf[0]) {
354 			case 'l':	/* draw a line */
355 			    sscanf(buf+1, "%d %d", &n, &m);
356 			    drawline(n, m);
357 			    break;
358 			case 'c':	/* circle */
359 			    sscanf(buf+1, "%d", &n);
360 			    drawcirc(n);
361 			    break;
362 			case 'e':	/* ellipse */
363 			    sscanf(buf+1, "%d %d", &m, &n);
364 			    drawellip(m, n);
365 			    break;
366 			case 'a':	/* arc */
367 			    sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
368 			    drawarc(n, m, n1, m1);
369 			    break;
370 			case 'P':	/* unbordered polygon */
371 			    bordered = 0;		/* unset border flag */
372 			case 'p':	/* polygon */
373 			    sscanf(buf+1, "%d", &m);	/* get stipple */
374 			    n = 1;			/* number first */
375 			    while (buf[++n] == ' ');
376 			    while (isdigit(buf[++n]));
377 			    setfill(m);			/* set up stipple */
378 			    drawwig(buf+n, fp, -1);	/* draw polygon */
379 			    bordered = 1;		/* ALWAYS set after */
380 			    break;
381 			case '~':	/* wiggly line */
382 			    drawwig(buf+1, fp, 1);
383 			    break;
384 			case 'g':	/* gremlin spline */
385 			    drawwig(buf+1, fp, 0);
386 			    break;
387 			case 't':	/* line thickness */
388 			    sscanf(buf+1, "%d", &n);
389 			    drawthick(n);
390 			    break;
391 			case 's':	/* line style */
392 			    sscanf(buf+1, "%d", &n);
393 			    drawstyle(n);
394 			    break;
395 			default:
396 			    error(FATAL, "unknown drawing function %s", buf);
397 			    break;
398 			}
399 			break;
400 		case 's':
401 			fscanf(fp, "%d", &n);	/* ignore fractional sizes */
402 			setsize(t_size(n));
403 			break;
404 		case 'f':
405 			fscanf(fp, "%s", str);
406 			setfont(t_font(str));
407 			break;
408 		case 'i':
409 			fscanf(fp, "%d", &n);
410 			setstip(n);
411 			break;
412 		case 'H':	/* absolute horizontal motion */
413 			/* fscanf(fp, "%d", &n); */
414 			while ((c = getc(fp)) == ' ')
415 				;
416 			k = 0;
417 			do {
418 				k = 10 * k + c - '0';
419 			} while (isdigit(c = getc(fp)));
420 			ungetc(c, fp);
421 			hgoto(k);
422 			break;
423 		case 'h':	/* relative horizontal motion */
424 			while ((c = getc(fp)) == ' ')
425 				;
426 			k = 0;
427 			do {
428 				k = 10 * k + c - '0';
429 			} while (isdigit(c = getc(fp)));
430 			ungetc(c, fp);
431 			hmot(k);
432 			break;
433 		case 'w':	/* word space */
434 			break;
435 		case 'V':
436 			fscanf(fp, "%d", &n);
437 			vgoto(n);
438 			break;
439 		case 'v':
440 			fscanf(fp, "%d", &n);
441 			vmot(n);
442 			break;
443 		case 'p':	/* new page */
444 			fscanf(fp, "%d", &n);
445 			t_page(n);
446 			break;
447 		case 'n':	/* end of line */
448 			t_newline();
449 
450 		case '#':	/* comment */
451 			do
452 				c = getc(fp);
453 			while (c != '\n' && c != EOF);
454 			break;
455 		case 'x':	/* device control */
456 			if (devcntrl(fp)) return;
457 			break;
458 		default:
459 			error(FATAL, "unknown input character %o %c", c, c);
460 		}
461 		if (emptypos < NLINES) {	/* for each input operation */
462 			slop_lines(1);		/* put out an output line */
463 #ifdef DRIVER
464 			if (emptypos == NLINES) {
465 				ioctl(OUTFILE, VSETSTATE, prtmode);
466 				if (write(OUTFILE, "\f", 2) != 2)
467 					exit(RESTART);
468 				ioctl(OUTFILE, VSETSTATE, pltmode);
469 			}
470 #endif
471 		}
472 	}
473 }
474 
475 int devcntrl(fp)	/* interpret device control functions */
476 FILE *fp;		/* returns -1 upon "stop" command */
477 {
478         char str[20], str1[50], buf[50];
479 	int c, n;
480 
481 	fscanf(fp, "%s", str);
482 	switch (str[0]) {	/* crude for now */
483 	case 'i':	/* initialize */
484 		fileinit();
485 		t_init();
486 		break;
487 	case 't':	/* trailer */
488 		break;
489 	case 'p':	/* pause -- can restart */
490 		t_reset('p');
491 		break;
492 	case 's':	/* stop */
493 		t_reset('s');
494 		return -1;
495 	case 'r':	/* resolution assumed when prepared */
496 		fscanf(fp, "%d", &n);
497 		if (n!=RES) error(FATAL,"Input computed for wrong printer");
498 		break;
499 	case 'f':	/* font used */
500 		fscanf(fp, "%d %s", &n, str);
501 		fgets(buf, sizeof buf, fp);	/* in case there's a filename */
502 		ungetc('\n', fp);		/* fgets goes too far */
503 		str1[0] = 0;			/* in case nothing comes in */
504 		sscanf(buf, "%s", str1);
505 		loadfont(n, str, str1);
506 		break;
507 						/* these don't belong here... */
508 	case 'H':	/* char height */
509 		fscanf(fp, "%d", &n);
510 		t_charht(n);
511 		break;
512 	case 'S':	/* slant */
513 		fscanf(fp, "%d", &n);
514 		t_slant(n);
515 		break;
516 	}
517 	while ((c = getc(fp)) != '\n')	/* skip rest of input line */
518 		if (c == EOF)
519 			return -1;
520 	return 0;
521 }
522 
523 /* fileinit:	read in font and code files, etc.
524 		Must open table for device, read in resolution,
525 		size info, font info, etc. and set params.
526 		Also read in font name mapping.
527 */
528 
529 fileinit()
530 {
531 	register int i;
532 	register int fin;
533 	register int nw;
534 	register char *filebase;
535 	register char *p;
536 	register FILE *fp;
537 	char	temp[100];
538 
539 		/* first, read in font map file.  The file must be of Format:
540 			XX  FILENAME  (XX = troff font name)
541 			with one entry per text line of the file.
542 		   Extra stuff after FILENAME is ignored */
543 
544 	sprintf(temp, "%s/fontmap", bitdir);
545 	if ((fp = fopen(temp, "r")) == NULL)
546 		error(FATAL, "Can't open %s", temp);
547 	for (i = 0; i <= NFONTS && fgets(temp, 100, fp) != NULL; i++) {
548 		sscanf(temp, "%2s", fontmap[i].fname);
549 		p = &temp[0];
550 		while (*p != ' ' && *p != '	') p++;
551 		while (*p == ' ' || *p == '	') p++;
552 		filebase = p;
553 		for (nw = 1; *p != '\n' && *p != ' ' && *p != '\t'; p++) nw++;
554 		fontmap[i].ffile = nalloc(1, nw);
555 		sscanf(filebase, "%s", fontmap[i].ffile);
556 	}
557 	fontmap[++i].fname[0] = '0';		/* finish off with zeros */
558 	fontmap[i].ffile = (char *) 0;
559 	fclose(fp);
560 #ifdef DEBUGABLE
561 	if(dbg) {
562 	    fprintf(stderr, "font map:\n");
563 	    for (i = 0; fontmap[i].ffile; i++)
564 		fprintf(stderr,"%s = %s\n", fontmap[i].fname, fontmap[i].ffile);
565 	}
566 #endif
567 
568 	sprintf(temp, "%s/devva/DESC.out", fontdir);
569 	if ((fin = open(temp, 0)) < 0)
570 		error(FATAL, "can't open tables for %s", temp);
571 	read(fin, &dev, sizeof(struct dev));
572 	nfonts = dev.nfonts;
573 	nstips = dev.nstips;
574 	nsizes = dev.nsizes;
575 	nchtab = dev.nchtab;
576 	filebase = calloc(1, dev.filesize);	/* enough room for whole file */
577 	read(fin, filebase, dev.filesize);	/* all at once */
578 	pstab = (short *) filebase;
579 	chtab = pstab + nsizes + 1;
580 	chname = (char *) (chtab + dev.nchtab);
581 	p = chname + dev.lchname;
582 	for (i = 1; i <= nfonts; i++) {
583 		fontbase[i] = (struct font *) p;
584 		nw = *p & BMASK;		/* 1st thing is width count */
585 		p += sizeof(struct font);
586 		widtab[i] = p;
587 		codetab[i] = p + 2 * nw;
588 		fitab[i] = p + 3 * nw;
589 		p += 3 * nw + dev.nchtab + 128 - 32;
590 		t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
591 #ifdef DEBUGABLE
592 		if (dbg > 1) fontprint(i);
593 #endif
594 	}
595 	for (i = 1; i <= nstips; i++) {		/* add in stipple "filenames" */
596 		if (nfonts + i <= NFONTS)
597 			t_fp(nfonts + i, p, (char *)0);
598 		p += strlen(p) + 1;
599 	}
600 	fontbase[0] = (struct font *)
601 		calloc(1,3*255 + dev.nchtab + (128-32) + sizeof (struct font));
602 	widtab[0] = (char *) fontbase[0] + sizeof (struct font);
603 	fontbase[0]->nwfont = 255;
604 	close(fin);
605 
606 }
607 
608 
609 #ifdef DEBUGABLE
610 fontprint(i)	/* debugging print of font i (0,...) */
611 {
612 	int j, n;
613 	char *p;
614 
615 	fprintf(stderr,"font %d:\n", i);
616 	p = (char *) fontbase[i];
617 	n = fontbase[i]->nwfont & BMASK;
618 	fprintf(stderr,
619 	    "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",p,
620 	    n,fontbase[i]->specfont,fontbase[i]->namefont,widtab[i],fitab[i]);
621 	fprintf(stderr,"widths:\n");
622 	for (j=0; j <= n; j++) {
623 		fprintf(stderr," %2d", widtab[i][j] & BMASK);
624 		if (j % 20 == 19) fprintf(stderr,"\n");
625 	}
626 	fprintf(stderr,"\ncodetab:\n");
627 	for (j=0; j <= n; j++) {
628 		fprintf(stderr," %2d", codetab[i][j] & BMASK);
629 		if (j % 20 == 19) fprintf(stderr,"\n");
630 	}
631 	fprintf(stderr,"\nfitab:\n");
632 	for (j=0; j <= dev.nchtab + 128-32; j++) {
633 		fprintf(stderr," %2d", fitab[i][j] & BMASK);
634 		if (j % 20 == 19) fprintf(stderr,"\n");
635 	}
636 	fprintf(stderr,"\n");
637 }
638 #endif
639 
640 
641 loadfont(n, s, s1)	/* load font info for font s on position n (0...) */
642 int n;
643 char *s, *s1;
644 {
645 	char temp[60];
646 	register int fin;
647 	register int nw;
648 	register int norig;
649 
650 	if (n < 0 || n > NFONTS)
651 		error(FATAL, "illegal fp command %d %s", n, s);
652 	if (strcmp(s, fontbase[n]->namefont) == 0)
653 		return;
654 
655 	for (fin = 1; fin <= NFONTS; fin++)	/* first check to see if the */
656 	    if (strcmp(s, fontbase[fin]->namefont) == 0) {  /* font is loaded */
657 		register char *c;			    /* somewhere else */
658 
659 #define ptrswap(x, y) { c = (char*) (x); x = y; y = c; }
660 #define ptrfswap(x, y) { c = (char*) (x); x = y; y = (struct font *) c; }
661 
662 		ptrfswap(fontbase[n], fontbase[fin]);
663 		ptrswap(codetab[n], codetab[fin]);
664 		ptrswap(widtab[n], widtab[fin]);
665 		ptrswap(fitab[n], fitab[fin]);
666 		t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
667 		t_fp(fin, fontbase[fin]->namefont, fontbase[fin]->intname);
668 		return;
669 	    }
670 
671 	if (s1 == NULL || s1[0] == '\0')
672 		sprintf(temp, "%s/devva/%s.out", fontdir, s);
673 	else
674 		sprintf(temp, "%s/%s.out", s1, s);
675 	if ((fin = open(temp, 0)) < 0)
676 		error(FATAL, "can't open font table %s", temp);
677 	norig = fontbase[n]->nwfont & BMASK;
678 	read(fin, fontbase[n], 3*norig + nchtab+128-32 + sizeof(struct font));
679 	if ((fontbase[n]->nwfont & BMASK) > norig)
680 		error(FATAL, "Font %s too big for position %d", s, n);
681 	close(fin);
682 	nw = fontbase[n]->nwfont & BMASK;
683 	widtab[n] = (char *) fontbase[n] + sizeof(struct font);
684 	codetab[n] = (char *) widtab[n] + 2 * nw;
685 	fitab[n] = (char *) widtab[n] + 3 * nw;
686 	t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
687 	fontbase[n]->nwfont = norig;	/* to later use full original size */
688 #ifdef DEBUGABLE
689 	if (dbg > 1) fontprint(n);
690 #endif
691 }
692 
693 
694 /*VARARGS1*/
695 error(f, s, a1, a2, a3, a4, a5, a6, a7) {
696 	fprintf(stderr, "dvar: ");
697 	fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
698 	fprintf(stderr, "\n");
699 	if (f) exit(ABORT);
700 }
701 
702 
703 t_init()	/* initialize device */
704 {
705 	int i;
706 
707 	hpos = vpos = 0;
708 
709 	setsize(t_size(10));	/* start somewhere */
710 	setfont(1);
711 }
712 
713 
714 struct state {
715 	int	ssize;
716 	int	sfont;
717 	int	shpos;
718 	int	svpos;
719 	int	sstyle;
720 	int	sthick;
721 };
722 struct	state	state[MAXSTATE];
723 struct	state	*statep = state;
724 
725 t_push()	/* begin a new block */
726 {
727 	statep->ssize = size;
728 	statep->sfont = font;
729 	statep->sstyle = linmod;
730 	statep->sthick = linethickness;
731 	statep->shpos = hpos;
732 	statep->svpos = vpos;
733 	if (statep++ >= state+MAXSTATE)
734 		error(FATAL, "{ nested too deep");
735 }
736 
737 t_pop()	/* pop to previous state */
738 {
739 	if (--statep < state)
740 		error(FATAL, "extra }");
741 	size = statep->ssize;
742 	font = statep->sfont;
743 	hpos = statep->shpos;
744 	vpos = statep->svpos;
745 	linmod = statep->sstyle;
746 	linethickness = statep->sthick;
747 }
748 
749 t_page(n)	/* do whatever new page functions */
750 {
751 	int i;
752 
753 
754 	if (emptypos < NLINES) {		/* finish off last page, if */
755 		slop_lines(NLINES - emptypos);	/* it's not done yet */
756 #ifdef DRIVER
757 		ioctl(OUTFILE, VSETSTATE, prtmode);
758 		if (write(OUTFILE, "\f", 2) != 2)
759 			exit(RESTART);
760 		ioctl(OUTFILE, VSETSTATE, pltmode);
761 #endif
762 	}
763 	if (output) {
764 		emptypos = 0;		/* set emptying to be started */
765 		elevel = fill;		/* swap buffer pointers */
766 		fill = empty;
767 		empty = elevel;
768 	}
769 
770 	vpos = 0;
771 	output = 1;
772 	if (nolist == 0)
773 		return;		/* no -o specified */
774 	output = 0;
775 	for (i = 0; i < nolist; i += 2)
776 		if (n >= olist[i] && n <= olist[i+1]) {
777 			output = 1;
778 			break;
779 		}
780 }
781 
782 t_newline()	/* do whatever for the end of a line */
783 {
784 	hpos = 0;	/* because we're now back at the left margin */
785 }
786 
787 t_size(n)	/* convert integer to internal size number*/
788 int n;
789 {
790 	int i;
791 
792 	if (n <= pstab[0])
793 		return(0);
794 	else if (n >= pstab[nsizes - 1])
795 		return(nsizes - 1);
796 	for (i = 0; n > pstab[i]; i++)
797 		;
798 	return(i);
799 }
800 
801 t_charht(n)	/* set character height to n */
802 int n;
803 {
804 #ifdef DEBUGABLE
805 	if (dbg) error(!FATAL, "can't set height on varian");
806 #endif
807 }
808 
809 t_slant(n)	/* set slant to n */
810 int n;
811 {
812 #ifdef DEBUGABLE
813 	if (dbg) error(!FATAL, "can't set slant on varian");
814 #endif
815 }
816 
817 t_font(s)	/* convert string to internal font number */
818 char *s;
819 {
820 	int n;
821 
822 	n = atoi(s);
823 	if (n < 0 || n > nfonts)
824 		n = 1;
825 	return(n);
826 }
827 
828 t_text(s)	/* print string s as text */
829 char *s;
830 {
831 	int c;
832 	char str[100];
833 
834 	if (!output)
835 		return;
836 	while (c = *s++) {
837 		if (c == '\\') {
838 			switch (c = *s++) {
839 			case '\\':
840 			case 'e':
841 				put1('\\');
842 				break;
843 			case '(':
844 				str[0] = *s++;
845 				str[1] = *s++;
846 				str[2] = '\0';
847 				put1s(str);
848 				break;
849 			}
850 		} else {
851 			put1(c);
852 		}
853 		hmot(lastw);
854 #ifdef DEBUGABLE
855 		if (dbg) fprintf(stderr,"width = %d\n", lastw);
856 #endif
857 	}
858 }
859 
860 
861 t_reset(c)
862 {
863 	if (c == 's') {
864 		t_page();
865 		output = 0;
866 		t_page();
867 #ifdef DRIVER
868 		ioctl(OUTFILE, VSETSTATE, prtmode);
869 		if (write(OUTFILE, "\f", 2) != 2)
870 			exit(RESTART);
871 #endif
872 	}
873 }
874 
875 
876 /*----------------------------------------------------------------------------*
877  | Routine:	hgoto (horizontal_spot)
878  |
879  | Results:	hpos is set to n.  If n overlaps in either direction, it wraps
880  |		around to the other end of the page.
881  *----------------------------------------------------------------------------*/
882 
883 hgoto(n)
884 int n;
885 {
886     if (n < 0)
887 	n += NLINES;
888     else if (n >= NLINES)
889 	n -= NLINES;
890     hpos = n;
891 }
892 
893 
894 /*----------------------------------------------------------------------------*
895  | Routine:	vgoto (vertical_spot)
896  |
897  | Results:	vpos is set to n.  If n overlaps in either direction, it wraps
898  |		around to the other end of the page.
899  *----------------------------------------------------------------------------*/
900 
901 vgoto(n)
902 int n;
903 {
904     if (n < 0)
905 	n += RASTER_LENGTH;
906     else if (n > RASTER_LENGTH)
907 	n -= RASTER_LENGTH;
908     vpos = n;
909 }
910 
911 put1s(s)	/* s is a funny char name */
912 char *s;
913 {
914 	int i;
915 
916 	if (!output)
917 		return;
918 #ifdef DEBUGABLE
919 	if (dbg) fprintf(stderr,"%s ", s);
920 #endif
921 	for (i = 0; i < nchtab; i++)
922 		if (strcmp(&chname[chtab[i]], s) == 0)
923 			break;
924 	if (i < nchtab)
925 		put1(i + 128);
926 }
927 
928 put1(c)	/* output char c */
929 int c;
930 {
931 	char *pw;
932 	register char *p;
933 	register int i, k;
934 	int j, ofont, code;
935 
936 	if (!output)
937 		return;
938 	c -= 32;
939 	if (c <= 0) {
940 #ifdef DEBUGABLE
941 		if (dbg) fprintf(stderr,"non-exist 0%o\n", c + 32);
942 #endif
943  		lastw = (widtab[font][0] * pstab[size] + dev.unitwidth/2)
944 								/ dev.unitwidth;
945 		return;
946 	}
947 	k = ofont = font;
948 	i = fitab[font][c] & BMASK;
949 	if (i != 0) {			/* it's on this font */
950 		p = codetab[font];	/* get the printing value of ch */
951 		pw = widtab[font];	/* get the width */
952 	} else {		/* on another font - run down the font list */
953 		for (j=0; j++ <= nfonts; k = (k+1) % (nfonts+1)) {
954 			if (fitab[k] == 0)
955 				continue;
956 			if ((i=fitab[k][c] & BMASK) != 0) {
957 				p = codetab[k];
958 				pw = widtab[k];
959 				setfont(k);
960 				break;
961 			}
962 		}
963 	}
964 
965 	if (i == 0) {
966 #ifdef DEBUGABLE
967 		if (dbg) fprintf(stderr,"not found 0%o\n", c+32);
968 #endif
969 		return;
970 	}
971 	code = p[i] & BMASK;
972 #ifdef DEBUGABLE
973 	if (dbg) {
974 		if (isprint(c+32))
975 			fprintf(stderr,"%c %d\n", c+32, code);
976 		else
977 			fprintf(stderr,"%03o %d\n", c+32, code);
978 	}
979 #endif
980 	outc(code);	/* character is < 254 */
981 	if (font != ofont)
982 		setfont(ofont);
983 	lastw = ((pw[i]&077) * pstab[size] + dev.unitwidth/2) / dev.unitwidth;
984 }
985 
986 
987 
988 setsize(n)	/* set point size to n (internal) */
989 int n;
990 {
991 
992 	if (n == size)
993 		return;	/* already there */
994 	if (vloadfont(font, pstab[n]) != -1)
995 		size = n;
996 }
997 
998 t_fp(n, s, si)	/* font position n now contains font s, intname si */
999 int n;		/* internal name is ignored */
1000 char *s, *si;
1001 {
1002 	register int i;
1003 
1004 
1005 			/* first convert s to filename if possible */
1006 	for (i = 0; fontmap[i].ffile != (char *) 0; i++) {
1007 #ifdef DEBUGABLE
1008 		if(dbg>1)fprintf(stderr,"testing :%s:%s:\n",s,fontmap[i].fname);
1009 #endif
1010 		if (strcmp(s, fontmap[i].fname) == 0) {
1011 			s = fontmap[i].ffile;
1012 #ifdef DEBUGABLE
1013 			if(dbg)fprintf(stderr, "found :%s:\n",fontmap[i].ffile);
1014 #endif
1015 			break;
1016 		}
1017 	}
1018 	fontname[n] = s;
1019 	for(i = 0;i <= NFONTS;i++)	/* free the bits of that font */
1020 		if (fontdes[i].fnum == n){
1021 			nfree(fontdes[i].bits);
1022 			fontdes[i].fnum = -1;
1023 		}
1024 }
1025 
1026 
1027 setfont(n)	/* set font to n */
1028 int n;
1029 {
1030 	if (n < 0 || n > nfonts)
1031 		error(FATAL, "illegal font %d", n);
1032 	if (vloadfont(n,pstab[size]) != -1)
1033 		font = n;
1034 }
1035 
1036 
1037 setstip(n)	/* set stipple font to n */
1038 int n;
1039 {
1040 	if (n < 1 || n > nstips)
1041 		error(FATAL, "illegal stipple %d", n);
1042 	stip = n;
1043 }
1044 
1045 
1046 vloadfont(fnum, fsize)
1047 register int fnum;
1048 register int fsize;
1049 {
1050 	register int i;
1051 
1052 	fontwanted = 0;
1053 	if (fnum == cfnum && fsize == cpsize)
1054 		return(0);
1055 	for (i = 0; i < NFONTS; i++) {
1056 		if (fontdes[i].fnum == fnum && fontdes[i].psize == fsize) {
1057 			cfnum = fontdes[i].fnum;
1058 			cpsize = fontdes[i].psize;
1059 			dispatch = &fontdes[i].disp[0];
1060 			bits = fontdes[i].bits;
1061 			cfont = i;
1062 			return (0);
1063 		}
1064 	}
1065 		/* this is a new font */
1066 	if (fnum < 0 || fnum > NFONTS || fontname[fnum] == 0) {
1067 	    error(!FATAL,"error: illegal font %d, size %d\n", fnum, fsize);
1068 	    return(-1);
1069 	}
1070 		/* Need to verify the existance of that font/size here*/
1071 	nfontnum = fnum;
1072 	npsize = fsize;
1073 	fontwanted++;
1074 	return (0);
1075 }
1076 
1077 
1078 getfont()
1079 {
1080 	register int fnum;
1081 	register int fsize;
1082 	register int fontd;
1083 	register int d;
1084 	register int sizehunt = size;
1085 	char cbuf[BUFSIZ];
1086 
1087 	fnum = nfontnum;
1088 	fsize = npsize;
1089 			/* try to open font file - if unsuccessful, hunt for */
1090 			/* a file of same style, different size to substitute */
1091 	d = -1;	 /* direction to look in pstab (smaller first) */
1092 	do {
1093 	    sprintf(cbuf, "%s/%s.%dr", bitdir, fontname[fnum], fsize);
1094 	    fontd = open(cbuf, OPENREAD);
1095 	    if (fontd == -1) {		/* File wasn't found. Try another ps */
1096 		sizehunt += d;
1097 		if (sizehunt < 0) {	/* past beginning - look higher */
1098 		    d = 1;
1099 		    sizehunt = size + 1;
1100 		}
1101 		if (sizehunt > nsizes) {	/* past top - forget it */
1102 		    d = 0;
1103 		} else {
1104 		    fsize = pstab[sizehunt];
1105 		}
1106 	    }
1107 	} while (fontd == -1 && d != 0);
1108 
1109 	if (fontd == -1) {		/* completely unsuccessful */
1110 	    perror(cbuf);
1111 	    error(!FATAL,"fnum = %d, psize = %d, name = %s",
1112 		fnum, npsize, fontname[fnum]);
1113 	    fontwanted = 0;
1114 	    return (-1);
1115 	}
1116 	if (read(fontd, &header, sizeof  (header)) != sizeof (header)
1117 						|| header.magic != 0436)
1118 		fprintf(stderr, "%s: Bad font file", cbuf);
1119 	else {
1120 		cfont = relfont();
1121 		if ((bits=nalloc(header.size+DSIZ+1,1))== NULL)
1122 			if ((bits=allpanic(header.size+DSIZ+1))== NULL) {
1123 				error(FATAL,"%s: ran out of memory", cbuf);
1124 			}
1125 
1126 			/*
1127 			 * have allocated one chunk of mem for font, dispatch.
1128 			 * get the dispatch addr, align to word boundary.
1129 			 */
1130 
1131 		d = (int) bits+header.size;
1132 		d += 1;
1133 		d &= ~1;
1134 		if (read (fontd, d, DSIZ) != DSIZ
1135 			    || read (fontd, bits, header.size) != header.size)
1136 			fprintf(stderr, "bad font header");
1137 		else {
1138 			close(fontd);
1139 			cfnum = fontdes[cfont].fnum = fnum;
1140 			cpsize = fontdes[cfont].psize = fsize;
1141 			fontdes [cfont].bits = bits;
1142 			fontdes [cfont].disp = (struct dispatch *) d;
1143 			dispatch = &fontdes[cfont].disp[0];
1144 			fontwanted = 0;
1145 			return (0);
1146 		}
1147 	}
1148 	close(fontd);
1149 	fontwanted = 0;
1150 	return(-1);
1151 }
1152 
1153 /*
1154  * "release" a font position - find an empty one, if possible
1155  */
1156 
1157 relfont()
1158 {
1159     register int newfont;
1160 
1161     for (newfont = 0; newfont < NFONTS; newfont++)
1162 	if (fontdes [newfont].fnum == -1)
1163 	    break;
1164     if (fontdes [newfont].fnum != -1) {
1165 	nfree (fontdes [newfont].bits);
1166 #ifdef DEBUGABLE
1167 	if (dbg) fprintf (stderr, "freeing position %d\n", newfont);
1168     } else {
1169 	if (dbg)
1170 	    fprintf (stderr, "taking, not freeing, position %d\n", newfont);
1171 #endif
1172     }
1173     fontdes[newfont].fnum = -1;
1174     return (newfont);
1175 }
1176 
1177 char *allpanic (nbytes)
1178 int nbytes;
1179 {
1180 	register int i;
1181 
1182 	for (i = 0; i <= NFONTS; i++) {
1183 		if (fontdes[i].fnum != -1) nfree(fontdes[i].bits);
1184 		fontdes[i].fnum = -1;
1185 		cfnum = cpsize = -1;
1186 	}
1187 	return(nalloc(nbytes,1));
1188 }
1189 
1190 int	M[] = { 0xffffffff, 0xfefefefe, 0xfcfcfcfc, 0xf8f8f8f8,
1191 		0xf0f0f0f0, 0xe0e0e0e0, 0xc0c0c0c0, 0x80808080, 0x0 };
1192 int	N[] = { 0x00000000, 0x01010101, 0x03030303, 0x07070707,
1193 		0x0f0f0f0f, 0x1f1f1f1f, 0x3f3f3f3f, 0x7f7f7f7f, 0xffffffff };
1194 int	strim[] = { 0xffffffff, 0xffffff00, 0xffff0000, 0xff000000, 0 };
1195 
1196 outc(code)
1197 int code;		/* character to print */
1198 {
1199     register struct dispatch *dis; /* ptr to character font record */
1200     register char *addr;	/* addr of font data */
1201     int llen;			/* length of each font line */
1202     int nlines;			/* number of font lines */
1203     register char *scanp;	/* ptr to output buffer */
1204     int scanp_inc;		/* increment to start of next buffer */
1205     int offset;			/* bit offset to start of font data */
1206     register int i;		/* loop counter */
1207     register int count;		/* font data ptr */
1208     register unsigned fontdata;	/* font data temporary */
1209     register int off8;		/* offset + 8 */
1210 
1211     if (fontwanted)
1212 	getfont();
1213     dis = dispatch + code;
1214     if (dis->nbytes) {
1215 	addr = bits + dis->addr;
1216 	llen = (dis->up + dis->down + 7) >> 3;
1217 	nlines = dis->right + dis->left;
1218 	scanp = fill + (hpos + 1 - dis->left) * BYTES_PER_LINE
1219 			- (1 + ((dis->down + vpos - 1) >> 3));
1220 	if (scanp < fill)
1221 	    scanp += BUFFER_SIZE;
1222 	scanp_inc = BYTES_PER_LINE - llen;
1223 	off8 = ((dis->down + vpos - 1) &07);
1224 	offset = off8 - 8;
1225 	for (i = 0; i < nlines; i++) {
1226 	    if (scanp >= fill + BUFFER_SIZE)
1227 		scanp -= BUFFER_SIZE;
1228 	    count = llen;
1229 	    if (scanp + count < fill + BUFFER_SIZE) {
1230 		do {
1231 		    fontdata = *(unsigned *)addr;
1232 		    addr += 4;
1233 		    if (count < 4)
1234 			fontdata &= ~strim[count];
1235 		    *(unsigned*)scanp |=(fontdata << offset) & ~M[off8];
1236 		    scanp++;
1237 		    *(unsigned*)scanp |=(fontdata << off8) & ~N[off8];
1238 		    scanp += 3;
1239 		    count -= 4;
1240 		} while (count > 0);
1241 	    }
1242 	    scanp += scanp_inc+count;
1243 	    addr += count;
1244 	}
1245 	return;
1246     }
1247     return;
1248 }
1249 
1250 
1251 /*----------------------------------------------------------------------------*
1252  | Routine:	setfill(stipple_number)
1253  |
1254  | Results:	sets the fill-pattern pointers (stip_disp and
1255  |		stip_bits) for a particular stipple.  Takes stipple
1256  |		font from current "stip" number.
1257  *----------------------------------------------------------------------------*/
1258 
1259 setfill(number)
1260 int number;
1261 {
1262 	int curfont;		/* places to save current text font */
1263 	int cursize;
1264 
1265 					/* set global stipmem for polygon */
1266 	if (number < 0 || number >= DISPATCHSIZE)
1267 		stipmem = 0;
1268 	else
1269 		stipmem = number;
1270 
1271 	curfont = cfnum;		/* get pointers to */
1272 	cursize = cpsize;		/* the inuse font */
1273 	if (vloadfont(nfonts + stip, 0)) {
1274 	    stip_disp = (struct dispatch *) NULL;	/* stipple not here */
1275 	} else {
1276 	    if (fontwanted) {
1277 		if (getfont()) {
1278 		    stip_disp = (struct dispatch *) NULL;
1279 		} else {
1280 		    stip_disp = dispatch;	/* save for polygon routine */
1281 		    stip_bits = bits;
1282 		}
1283 	    } else {
1284 		stip_disp = dispatch;	/* save for polygon routine */
1285 		stip_bits = bits;
1286 	    }
1287 	}
1288 	if (curfont >= 0) vloadfont(curfont, cursize);
1289 }
1290 
1291 
1292 slop_lines(nlines)
1293 int nlines;
1294 
1295 /* Output "nlines" lines from the buffer, and clear that section of the  */
1296 /* buffer.	Also updates the pointers to the emptying buffer */
1297 
1298 {
1299 	unsigned usize;
1300 
1301 	usize = BYTES_PER_LINE * nlines;
1302 	vwrite(elevel, usize);
1303 	vclear(elevel, usize);
1304 	elevel += usize;
1305 	emptypos += nlines;
1306 }
1307 
1308 vwrite(buf,usize)
1309 char *buf;
1310 unsigned usize;
1311 {
1312 	register int tsize = 0;
1313 
1314 	while (usize){
1315 		buf += tsize;
1316 		tsize = usize > MAXWRIT ? MAXWRIT : usize;
1317 #ifdef DEBUGABLE
1318 		if (dbg)fprintf(stderr,"buf = %d size = %d\n",buf,tsize);
1319 #endif
1320 		if ((tsize = write(OUTFILE, buf, tsize)) < 0) {
1321 			perror("dvar: write failed");
1322 			exit(RESTART);
1323 		}
1324 		usize -= tsize;
1325 	}
1326 }
1327 
1328 vclear (ptr, nbytes)
1329 char	*ptr;
1330 unsigned nbytes;
1331 {
1332     register tsize = 0;
1333 
1334     while (nbytes){
1335 	if ((unsigned)(16*1024) < nbytes) {
1336 	    tsize = 16 * 1024;
1337 	} else
1338 	    tsize = nbytes;
1339 	nbytes -= tsize;
1340 #ifdef DEBUGABLE
1341 	if (dbg) fprintf(stderr,"clearing ptr = %d size = %d\n",ptr,tsize);
1342 #endif
1343 	clear(ptr,tsize);
1344 	ptr += tsize;
1345     }
1346 }
1347 
1348 /*ARGSUSED*/
1349 clear(lp, nbytes)
1350 int *lp;
1351 int nbytes;
1352 {
1353 #ifdef vax
1354 	asm("movc5 $0,(sp),$0,8(ap),*4(ap)");
1355 #else
1356 	register int i = nbytes;
1357 	register int *cp = lp;
1358 
1359 	while (i-- > 0)
1360 		*(cp++) = 0;
1361 #endif
1362 }
1363 
1364 char *
1365 nalloc(i, j)
1366 int i, j;
1367 {
1368 	register char *cp;
1369 
1370 	cp = calloc(i, j);
1371 #ifdef DEBUGABLE
1372 	if (dbg) fprintf(stderr, "allocated %d bytes at %x\n", i * j, cp);
1373 #endif
1374 	return(cp);
1375 }
1376 
1377 nfree(cp)
1378 char *cp;
1379 {
1380 #ifdef DEBUGABLE
1381 	if (dbg) fprintf(stderr, "freeing at %x\n", cp);
1382 #endif
1383 	free(cp);
1384 }
1385 
1386 
1387 /*
1388  * Points should be in the range 0 <= x < RASTER_LENGTH, 0 <= y < NLINES.
1389  * The origin is the top left-hand corner with increasing x towards the
1390  * right and increasing y going down.  X and Y should be sent as (0,0) being
1391  * at the bottom left.  The output array is NLINES x BYTES_PER_LINE pixels.
1392  */
1393 point(x, y)
1394 register int x;
1395 register int y;
1396 {
1397     if ((unsigned)(y=(RASTER_LENGTH-1)-y)<RASTER_LENGTH && (unsigned)x<NLINES) {
1398 	*(fill + x * BYTES_PER_LINE + (y >> 3)) |= 1 << (7 - (y & 07));
1399     }
1400 }
1401 
1402 
1403 #define pv(x)	((polyvector *)x)
1404 
1405 typedef struct poly {
1406 	struct poly *next;	/* doublely-linked lists of vectors */
1407 	struct poly *prev;
1408 	int param;	/* bressenham line algorithm parameter */
1409 	short dy;	/* delta-y for calculating line */
1410 	short dx;	/* delta-x for calculating line */
1411 	short curry;	/* current y in this vector */
1412 	short endx;	/* where vector ends */
1413 } polyvector;
1414 
1415 
1416 /*----------------------------------------------------------------------------*
1417  | Routine:	polygon ( x_coordinates, y_coordinates, num_of_points )
1418  |
1419  | Results:	draws a polygon starting at (x[1], y[1]) going through
1420  |		each of (x_coordinates, y_coordinates), and fills it
1421  |		with a stipple pattern from stip_disp and stip_bits,
1422  |		which point to the stipple font.  The pattern is defined
1423  |		by "stip" and "stipmem".
1424  |
1425  |		The scan-line algorithm implemented scans from left to
1426  |		right (low x to high x).  It also scans, within a line,
1427  |		from bottom to top (high y to low y).
1428  |
1429  |		polygons are clipped to page boundary.
1430  |
1431  | Bugs:	stipple pattern MUST be a power of two bytes "wide" and
1432  |		square.  The square restriction comes from the fact that
1433  |		the varian and versatec are respectively rotated.
1434  *----------------------------------------------------------------------------*/
1435 
1436 polygon(x, y, npts)
1437 int x[];
1438 int y[];
1439 int npts;
1440 {
1441     int nextx;			/* at what x value the next vector starts */
1442     int maxx, minx, maxy, miny;		/* finds bounds of polygon */
1443     polyvector *activehead;		/* doing fill, is active edge list */
1444     polyvector *waitinghead;		/* edges waiting to be active */
1445     register polyvector *vectptr;	/* random vector */
1446     register int i;			/* random register */
1447 
1448     char *topstipple;		/* points to beginning of stipple glyph */
1449     char *leftstipple;		/* points to beginning of line of stipple */
1450     char *bottompage;		/* points to the edge of a raster line */
1451     int bytewidth;		/* glyph width in bytes */
1452     int mask;			/* mask to pick off pixel index into stipple */
1453     int bytemask;		/* mask to pick off byte index into stipple */
1454 
1455 
1456     if (bordered) {
1457 	for (i = 1; i < npts; i++)		/* first draw outlines */
1458 	    HGtline(x[i], y[i], x[i+1], y[i+1]);
1459     }
1460 
1461 						/* if no stipple, don't fill */
1462     if (stip_disp == (struct dispatch *) NULL || stip_bits == (char *) NULL)
1463 	return;
1464 
1465     stip_disp += stipmem;			/* set up parameters for */
1466     if (!stip_disp->nbytes) {			/* tiling with the stipple */
1467 #ifdef DEBUGABLE
1468 	error(!FATAL, "member not found: member %d, stipple %d", stipmem, stip);
1469 #endif
1470 	return;
1471     }
1472     topstipple = stip_bits + stip_disp->addr;
1473     bytewidth = stip_disp->up + stip_disp->down;
1474     for (i = 1 << 30; i && i != bytewidth; i = i >> 1)
1475 	;
1476     if (i==0 || bytewidth<8 || bytewidth != stip_disp->right+stip_disp->left) {
1477 	error(!FATAL, "invalid stipple: number %d, member %d", stip, stipmem);
1478 	return;
1479     }
1480     mask = bytewidth - 1;
1481     bytewidth = bytewidth >> 3;
1482     bytemask = bytewidth - 1;
1483 
1484 				/* allocate space for raster-fill algorithm*/
1485     if ((vectptr = pv( nalloc(sizeof(polyvector), npts + 6) )) == NULL) {
1486 	error(!FATAL, "unable to allocate space for polygon");
1487 	return;
1488     }
1489 #ifdef DEBUGABLE
1490     if (dbg) fprintf(stderr, "polygon, %d points\n", npts);
1491 #endif
1492 
1493     waitinghead = vectptr;
1494     minx = maxx = x[1];
1495     miny = maxy = y[1];
1496     (vectptr++)->prev = pv( NULL );	/* put dummy entry at start */
1497     waitinghead->next = vectptr;
1498     vectptr->prev = waitinghead;
1499     i = 1;					/* starting point of coords */
1500     if (y[1] != y[npts] || x[1] != x[npts]) {
1501 	y[0] = y[npts];				/* close polygon if it's not */
1502 	x[0] = x[npts];
1503 	i = 0;
1504     }
1505     while (i < npts) {		/* set up the vectors */
1506 	register int j;			/* indexes to work off of */
1507 	register int k;
1508 
1509 	if (miny > y[i]) miny = y[i];		/* remember limits */
1510 	else if (maxy < y[i]) maxy = y[i];
1511 	if (maxx < x[i]) maxx = x[i];
1512 	else if (minx > x[i]) minx = x[i];
1513 
1514 	j = i;			/* j "points" to the higher (lesser) point */
1515 	k = ++i;
1516 	if (x[j] == x[k])		/* ignore vertical lines */
1517 	    continue;
1518 
1519 	if (x[j] > x[k]) {
1520 	    j++;
1521 	    k--;
1522 	}
1523 	vectptr->next = vectptr + 1;
1524 	vectptr->param = x[j];		/* starting point of vector */
1525 	vectptr->dy = y[k] - y[j];	/* line-calculating parameters */
1526 	vectptr->dx = x[k] - x[j];
1527 	vectptr->curry = y[j];		/* starting point */
1528 	(vectptr++)->endx = x[k];	/* ending point */
1529 	vectptr->prev = vectptr - 1;
1530     }
1531 				/* set now because we didn't know minx before */
1532     leftstipple = topstipple + (minx & mask) * bytewidth;
1533     bottompage = fill + minx * BYTES_PER_LINE;
1534     waitinghead->param = minx - 1;
1535 					/* if no useable vectors, quit */
1536     if (vectptr == waitinghead + 1)
1537 	goto leavepoly;
1538 
1539     vectptr->param = maxx + 1;		/* dummy entry at end, too */
1540     vectptr->next = pv( NULL );
1541 
1542     activehead = ++vectptr;		/* two dummy entries for active list */
1543     vectptr->curry = maxy + 1;		/* head */
1544     vectptr->endx = maxx + 1;
1545     vectptr->param = vectptr->dx = vectptr->dy = 0;
1546     activehead->next = ++vectptr;
1547     activehead->prev = vectptr;
1548 
1549     vectptr->prev = activehead;		/* tail */
1550     vectptr->next = activehead;
1551     vectptr->curry = miny - 1;
1552     vectptr->endx = maxx + 1;
1553     vectptr->param = vectptr->dx = vectptr->dy = 0;
1554 
1555 
1556 			/* main loop -- gets vectors off the waiting list, */
1557 			/* then displays spans while updating the vectors in */
1558 			/* the active list */
1559     while (minx <= maxx) {
1560 	i = maxx + 1;		/* this is the NEXT time to get a new vector */
1561 	for (vectptr = waitinghead->next; vectptr != pv( NULL ); ) {
1562 	    if (minx == vectptr->param) {
1563 				/* the entry in waiting list (vectptr) is */
1564 				/*   ready to go into active list.  Need to */
1565 				/*   convert some vector stuff and sort the */
1566 				/*   entry into the list. */
1567 		register polyvector *p;	/* random vector pointers */
1568 		register polyvector *v;
1569 
1570 							/* convert this */
1571 		if (vectptr->dy < 0)			/* entry to active */
1572 		    vectptr->param = (vectptr->dy >> 1) - (vectptr->dx >> 1);
1573 		else
1574 		    vectptr->param = -((vectptr->dx >> 1) + (vectptr->dy >> 1));
1575 
1576 		p = vectptr;			/* remove from the */
1577 		vectptr = vectptr->next;	/* waiting list */
1578 		vectptr->prev = p->prev;
1579 		p->prev->next = vectptr;
1580 						/* find where it goes */
1581 						/* in the active list */
1582 						/* (sorted greatest first) */
1583 		for (v = activehead->next; v->curry > p->curry; v = v->next)
1584 		    ;
1585 		p->next = v;		/* insert into active list */
1586 		p->prev = v->prev;	/* before the one it stopped on */
1587 		v->prev = p;
1588 		p->prev->next = p;
1589 	    } else {
1590 		if (i > vectptr->param) {
1591 		    i = vectptr->param;
1592 		}
1593 		vectptr = vectptr->next;
1594 	    }
1595 	}
1596 	nextx = i;
1597 
1598 					/* print the polygon while there */
1599 					/* are no more vectors to add */
1600 	while (minx < nextx) {
1601 					/* remove any finished vectors */
1602 	    vectptr = activehead->next;
1603 	    do {
1604 		if (vectptr->endx <= minx) {
1605 		    vectptr->prev->next = vectptr->next;
1606 		    vectptr->next->prev = vectptr->prev;
1607 		}
1608 	    } while ((vectptr = vectptr->next) != activehead);
1609 
1610 					/* draw the span */
1611 	    if (((unsigned) minx) < NLINES) {
1612 	      vectptr = activehead->next;
1613 	      while (vectptr->next != activehead) {
1614 		register int start;	/* get the beginning */
1615 		register int length;	/*   and the end of span */
1616 		register char *glyph;
1617 		register char *raster;
1618 
1619 		start = (RASTER_LENGTH - 1) - vectptr->curry;
1620 		vectptr = vectptr->next;
1621 		length = RASTER_LENGTH - vectptr->curry;
1622 		vectptr = vectptr->next;
1623 
1624 					/* bound the polygon to the page */
1625 		if (start >= RASTER_LENGTH)
1626 		    break;
1627 		if (start < 0) start = 0;
1628 		if (length > RASTER_LENGTH) length = RASTER_LENGTH;
1629 		length -= start;		/* length is in pixels */
1630 
1631 		i = start & 7;
1632 		start = start >> 3;		/* start is in bytes */
1633 		raster = bottompage + start;
1634 		glyph = leftstipple + (start & bytemask);
1635 
1636 		if (i) {			/* do any piece of byte */
1637 		    register char data;		/* that hangs on the front */
1638 
1639 		    data = (*(glyph++)) & (0x7f >> --i);
1640 		    length -= 7 - i;
1641 		    if (length < 0) {		/* less than one byte wide? */
1642 			data &= 0xff << -length;
1643 			length = 0;	/* force clean stoppage */
1644 		    }
1645 		    *(raster++) |= data;
1646 					/* update glyph ptr after first byte */
1647 		    if (!(++start & bytemask))
1648 			glyph = leftstipple;
1649 		}
1650 						/* fill the line of raster */
1651 		while ((length -= 8) >= 0) {
1652 		    *(raster++) |= *(glyph++);
1653 		    if (!(++start & bytemask))
1654 			glyph = leftstipple;
1655 		}
1656 		if (length & 7) {	/* add any part hanging off the end */
1657 		    *raster |= (*glyph) & (0xff << -length);
1658 		}
1659 	      }
1660 	    }
1661 
1662 #ifdef DEBUGABLE
1663 	    if (dbg) {
1664 		vectptr = activehead;
1665 		do {
1666 		    fprintf (stderr, "%d ", vectptr->curry);
1667 		    vectptr = vectptr->next;
1668 		} while (vectptr != activehead);
1669 	    }
1670 #endif
1671 					/* update the vectors */
1672 	    vectptr = activehead->next;
1673 	    do {
1674 		if (vectptr->dy > 0) {
1675 		    while (vectptr->param >= 0) {
1676 			vectptr->param -= vectptr->dx;
1677 			vectptr->curry++;
1678 		    }
1679 		    vectptr->param += vectptr->dy;
1680 		} else if (vectptr->dy < 0) {
1681 		    while (vectptr->param >= 0) {
1682 			vectptr->param -= vectptr->dx;
1683 			vectptr->curry--;
1684 		    }
1685 		    vectptr->param -= vectptr->dy;
1686 		}
1687 					/* must sort the vectors if updates */
1688 					/* caused them to cross */
1689 					/* also move to next vector here */
1690 		if (vectptr->curry > vectptr->prev->curry) {
1691 		    register polyvector *v;		/* vector to move */
1692 		    register polyvector *p;	/* vector to put it after */
1693 
1694 		    v = vectptr;
1695 		    p = v->prev;
1696 		    while (v->curry > p->curry)	/* find the */
1697 			p = p->prev;		/* right vector */
1698 
1699 		    vectptr = vectptr->next;	/* remove from spot */
1700 		    vectptr->prev = v->prev;
1701 		    v->prev->next = vectptr;
1702 
1703 		    v->prev = p;		/* put in new spot */
1704 		    v->next = p->next;
1705 		    p->next = v;
1706 		    v->next->prev = v;
1707 		} else {
1708 		    vectptr = vectptr->next;
1709 		}
1710 	    } while (vectptr != activehead);
1711 #ifdef DEBUGABLE
1712 	    if (dbg) fprintf(stderr, "line done\n");
1713 #endif
1714 
1715 	    if (++minx & mask) {
1716 		leftstipple += bytewidth;
1717 	    } else {
1718 		leftstipple = topstipple;
1719 	    }
1720 	    bottompage += BYTES_PER_LINE;
1721 	} /* while (minx < nextx) */
1722     } /* while (minx <= maxx) */
1723 
1724 leavepoly:
1725     nfree(waitinghead);
1726 }  /* polygon function */
1727