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