1 /*	dver.c	1.8	83/08/19
2  *
3  * 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 cx	ascii character x
21 Cxyz	funny char \(xyz. terminated by white space
22 Hn	go to absolute horizontal position n
23 Vn	go to absolute vertical position n (down is positive)
24 hn	go n units horizontally (relative)
25 vn	ditto vertically
26 nnc	move right nn, then print c (exactly 2 digits!)
27 		(this wart is an optimization that shrinks output file size
28 		 about 35% and run-time about 15% while preserving ascii-ness)
29 pn	new page begins (number n) -- set v to 0
30 P	spread ends -- output it.
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 	Dl x y		line from here by x,y
37 	Dc d		circle of diameter d with left side here
38 	De x y		ellipse of axes x,y with left side here
39 	Da x y r	arc counter-clockwise by x,y of radius r
40 	D~ x y x y ...	B-spline curve by x,y then x,y ...
41 
42 x ..\n	device control functions:
43      x i	init
44      x T s	name of device is s
45      x r n h v	resolution is n/inch h = min horizontal motion, v = min vert
46      x p	pause (can restart)
47      x s	stop -- done for ever
48      x t	generate trailer
49      x f n s	font position n contains font s
50      x H n	set character height to n
51      x S n	set slant to N
52 
53 	Subcommands like "i" are often spelled out like "init".
54 
55 *******************************************************************************/
56 
57 
58 #include <stdio.h>
59 #include <ctype.h>
60 #include <sys/vcmd.h>
61 #include "dev.h"
62 
63 
64 #define DEBUGABLE		/* Yes, debugable... */
65 #define	NFONTS	60		/* total number of fonts useable */
66 #define	MAXSTATE 6		/* number of environments rememberable */
67 #define OPENREAD 0		/* mode for openning files */
68 #define RESTART	1		/* upon exit, return either RESTART */
69 #define ABORT	2		/*     or ABORT */
70 #define	FATAL	1		/* type of error */
71 #define	BMASK	0377		/* byte grabber */
72 #define FONTDIR	"/usr/lib/font"	/* default place to find font descriptions */
73 #define BITDIR "/usr/lib/vfont" /* default place to look for font rasters */
74 #define MAXWRIT 4096		/* max characters allowed to write at once */
75 
76 #define  hmot(n)	hpos += n
77 #define  hgoto(n)	hpos = n
78 #define  vmot(n)	vgoto(vpos + (n))
79 
80 
81 char	SccsId[]= "dver.c	1.8	83/08/19";
82 
83 int	output	= 0;	/* do we do output at all? */
84 int	nolist	= 0;	/* output page list if > 0 */
85 int	olist[20];	/* pairs of page numbers */
86 int	spage	= 9999;	/* stop every spage pages */
87 int	scount	= 0;
88 struct	dev	dev;
89 struct	font	*fontbase[NFONTS+1];
90 short *	pstab;		/* point size table pointer */
91 int	nsizes;		/* number of sizes device is capable of printing */
92 int	nfonts;		/* number of fonts device is capable of printing */
93 int	smnt;		/* index of first special font */
94 int	nchtab;
95 char *	chname;
96 short *	chtab;
97 char *	fitab[NFONTS+1];	/* font inclusion table - maps ascii to ch # */
98 char *	widtab[NFONTS+1];	/* width table for each font */
99 char *	codetab[NFONTS+1];	/* device codes */
100 char *	fontdir = FONTDIR;	/* place to find devxxx directories */
101 char *	bitdir = BITDIR;	/* place to find raster fonts and fontmap */
102 
103 struct {			/* table of what font */
104 	char *name;		/*   name is on what */
105 	int number;		/*   position in font tables */
106 } fontname[NFONTS+1];
107 struct {			/* table of what font */
108 	char fname[3];		/*   name maps to what */
109 	char *ffile;		/*   filename in bitdirectory */
110 } fontmap[NFONTS+1];
111 
112 #ifdef DEBUGABLE
113 int	dbg	= 0;
114 #endif
115 int	size	= 1;	/* current point size (internal pstable index) */
116 int	font	= 1;	/* current font - assume reasonable starting font */
117 int	hpos;		/* horizontal position we are to be at next; left = 0 */
118 int	vpos;		/* current vertical position (down positive) */
119 int	maxv;		/* farthest down the page we've been */
120 extern	linethickness;	/* thickness (in pixels) of any drawn object */
121 extern	linmod;		/* line style (a bit mask - dotted, etc.) of objects */
122 int	lastw;		/* width of last character printed */
123 
124 
125 #define DISPATCHSIZE	256		/* must be a power of two */
126 #define CHARMASK	(DISPATCHSIZE-1)
127 #define DSIZ		((sizeof *dispatch)*DISPATCHSIZE)
128 #define OUTFILE 	fileno (stdout)
129 
130 #define	RES		200		/* resolution of the device (dots/in) */
131 #define RASTER_LENGTH	7040		/* device line length */
132 #define BYTES_PER_LINE	(RASTER_LENGTH/8)
133 #define BAND		3			/* length of a band in inches */
134 #define NLINES		(int)(BAND * RES)	/* 3" long bands */
135 #define BUFFER_SIZE	(NLINES*BYTES_PER_LINE)	/* number of chars in picture */
136 
137 #define BUFTOP		(&buffer[0])
138 #define BUFBOTTOM	(&buffer[BUFFER_SIZE] - 1)
139 #define PAGEEND		1			/* flags to "outband" to tell */
140 #define OVERBAND	0			/* whether to fill out a page */
141 
142 
143 int	pltmode[] = { VPLOT };
144 int	prtmode[] = { VPRINT };
145 char	buffer[BUFFER_SIZE];	/* versatec-wide NLINES buffer */
146 char *	buf0p = BUFTOP;		/* vorigin in circular buffer */
147 int	vorigin = 0;		/* where on the page startbuf maps to */
148 int	pagelen = 0;		/* how long the current "page" has printed */
149 
150 char *	calloc();
151 char *	nalloc();
152 char *	allpanic();
153 
154 struct header {
155 	short	magic;
156 	unsigned short	size;
157 	short	maxx;
158 	short	maxy;
159 	short	xtnd;
160 } header;
161 
162 struct	dispatch{
163 	unsigned short	addr;
164 	short	nbytes;
165 	char	up;
166 	char	down;
167 	char	left;
168 	char	right;
169 	short	width;
170 };
171 
172 struct	fontdes {
173 	int	fnum;
174 	int	psize;
175 	struct	dispatch *disp;
176 	char	*bits;
177 } fontdes[NFONTS] = {
178 	-1,
179 	-1
180 };
181 
182 struct dispatch *dispatch;
183 int	cfnum = -1;
184 int	cpsize = 10;
185 int	cfont = 1;
186 char	*bits;
187 int	fontwanted = 1;		/* flag:  "has a new font been requested?" */
188 int	nfontnum = -1;
189 int	npsize = 10;
190 
191 
192 
193 main(argc, argv)
194 char *argv[];
195 {
196 	FILE *fp;
197 
198 	while (argc > 1 && argv[1][0] == '-') {
199 		switch (argv[1][1]) {
200 		case 'F':
201 			bitdir = &argv[1][2];
202 			break;
203 		case 'f':
204 			fontdir = &argv[1][2];
205 			break;
206 		case 'o':
207 			outlist(&argv[1][2]);
208 			break;
209 #ifdef DEBUGABLE
210 		case 'd':
211 			dbg = atoi(&argv[1][2]);
212 			if (dbg == 0) dbg = 1;
213 			break;
214 #endif
215 		case 's':
216 			spage = atoi(&argv[1][2]);
217 			if (spage <= 0)
218 				spage = 9999;
219 			break;
220 		}
221 		argc--;
222 		argv++;
223 	}
224 
225 /*nov	ioctl(OUTFILE, VSETSTATE, pltmode);  */
226 
227 	if (argc <= 1)
228 		conv(stdin);
229 	else
230 		while (--argc > 0) {
231 			if (strcmp(*++argv, "-") == 0)
232 				fp = stdin;
233 			else if ((fp = fopen(*argv, "r")) == NULL)
234 				error(FATAL, "can't open %s", *argv);
235 			conv(fp);
236 			fclose(fp);
237 		}
238 	exit(0);
239 }
240 
241 outlist(s)	/* process list of page numbers to be printed */
242 char *s;
243 {
244 	int n1, n2, i;
245 
246 	nolist = 0;
247 	while (*s) {
248 		n1 = 0;
249 		if (isdigit(*s))
250 			do
251 				n1 = 10 * n1 + *s++ - '0';
252 			while (isdigit(*s));
253 		else
254 			n1 = -9999;
255 		n2 = n1;
256 		if (*s == '-') {
257 			s++;
258 			n2 = 0;
259 			if (isdigit(*s))
260 				do
261 					n2 = 10 * n2 + *s++ - '0';
262 				while (isdigit(*s));
263 			else
264 				n2 = 9999;
265 		}
266 		olist[nolist++] = n1;
267 		olist[nolist++] = n2;
268 		if (*s != '\0')
269 			s++;
270 	}
271 	olist[nolist] = 0;
272 #ifdef DEBUGABLE
273 	if (dbg)
274 		for (i=0; i<nolist; i += 2)
275 			fprintf(stderr,"%3d %3d\n", olist[i], olist[i+1]);
276 #endif
277 }
278 
279 conv(fp)
280 register FILE *fp;
281 {
282 	register int c, k;
283 	int m, n, n1, m1;
284 	char str[100], buf[300];
285 
286 	while ((c = getc(fp)) != EOF) {
287 		switch (c) {
288 		case '\n':	/* when input is text */
289 		case ' ':
290 		case 0:		/* occasional noise creeps in */
291 			break;
292 		case '{':	/* push down current environment */
293 			t_push();
294 			break;
295 		case '}':
296 			t_pop();
297 			break;
298 		case '0': case '1': case '2': case '3': case '4':
299 		case '5': case '6': case '7': case '8': case '9':
300 			/* two motion digits plus a character */
301 			hmot((c-'0')*10 + getc(fp)-'0');
302 			put1(getc(fp));
303 			break;
304 		case 'c':	/* single ascii character */
305 			put1(getc(fp));
306 			break;
307 		case 'C':
308 			fscanf(fp, "%s", str);
309 			put1s(str);
310 			break;
311 		case 't':	/* straight text */
312 			fgets(buf, sizeof(buf), fp);
313 			t_text(buf);
314 			break;
315 		case 'D':	/* draw function */
316 			fgets(buf, sizeof(buf), fp);
317 			switch (buf[0]) {
318 			case 'l':	/* draw a line */
319 			    sscanf(buf+1, "%d %d", &n, &m);
320 			    drawline(n, m);
321 			    break;
322 			case 'c':	/* circle */
323 			    sscanf(buf+1, "%d", &n);
324 			    drawcirc(n);
325 			    break;
326 			case 'e':	/* ellipse */
327 			    sscanf(buf+1, "%d %d", &m, &n);
328 			    drawellip(m, n);
329 			    break;
330 			case 'a':	/* arc */
331 			    sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
332 			    drawarc(n, m, n1, m1);
333 			    break;
334 			case '~':	/* wiggly line */
335 			case 'g':	/* gremlin spline */
336 			    drawwig(buf+1, fp, buf[0] == '~');
337 			    break;
338 			case 't':	/* line thickness */
339 			    sscanf(buf+1, "%d", &n);
340 			    drawthick(n);
341 			    break;
342 			case 's':	/* line style */
343 			    sscanf(buf+1, "%d", &n);
344 			    drawstyle(n);
345 			    break;
346 			default:
347 			    error(FATAL, "unknown drawing function %s", buf);
348 			    break;
349 			}
350 			break;
351 		case 's':
352 			fscanf(fp, "%d", &n);	/* ignore fractional sizes */
353 			setsize(t_size(n));
354 			break;
355 		case 'f':
356 			fscanf(fp, "%s", str);
357 			setfont(t_font(str));
358 			break;
359 		case 'H':	/* absolute horizontal motion */
360 			/* fscanf(fp, "%d", &n); */
361 			while ((c = getc(fp)) == ' ')
362 				;
363 			k = 0;
364 			do {
365 				k = 10 * k + c - '0';
366 			} while (isdigit(c = getc(fp)));
367 			ungetc(c, fp);
368 			hgoto(k);
369 			break;
370 		case 'h':	/* relative horizontal motion */
371 			while ((c = getc(fp)) == ' ')
372 				;
373 			k = 0;
374 			do {
375 				k = 10 * k + c - '0';
376 			} while (isdigit(c = getc(fp)));
377 			ungetc(c, fp);
378 			hmot(k);
379 			break;
380 		case 'w':	/* word space */
381 			break;
382 		case 'V':
383 			fscanf(fp, "%d", &n);
384 			vgoto(n);
385 			break;
386 		case 'v':
387 			fscanf(fp, "%d", &n);
388 			vmot(n);
389 			break;
390 		case 'P':	/* new spread */
391 			outband(OVERBAND);
392 			break;
393 		case 'p':	/* new page */
394 			fscanf(fp, "%d", &n);
395 			t_page(n);
396 			break;
397 		case 'n':	/* end of line */
398 			while (getc(fp) != '\n')
399 				;
400 			t_newline();
401 			break;
402 		case '#':	/* comment */
403 			while (getc(fp) != '\n')
404 				;
405 			break;
406 		case 'x':	/* device control */
407 			devcntrl(fp);
408 			break;
409 		default:
410 			error(FATAL, "unknown input character %o %c", c, c);
411 		}
412 	}
413 }
414 
415 devcntrl(fp)	/* interpret device control functions */
416 FILE *fp;
417 {
418         char str[20], str1[50], buf[50];
419 	int c, n;
420 
421 	fscanf(fp, "%s", str);
422 	switch (str[0]) {	/* crude for now */
423 	case 'i':	/* initialize */
424 		fileinit();
425 		t_init();
426 		break;
427 	case 't':	/* trailer */
428 		break;
429 	case 'p':	/* pause -- can restart */
430 		t_reset('p');
431 		break;
432 	case 's':	/* stop */
433 		t_reset('s');
434 		break;
435 	case 'r':	/* resolution assumed when prepared */
436 		fscanf(fp, "%d", &n);
437 		if (n!=RES) error(FATAL,"Input computed with wrong resolution");
438 		break;
439 	case 'f':	/* font used */
440 		fscanf(fp, "%d %s", &n, str);
441 		fgets(buf, sizeof buf, fp);	/* in case there's a filename */
442 		ungetc('\n', fp);		/* fgets goes too far */
443 		str1[0] = 0;			/* in case nothing comes in */
444 		sscanf(buf, "%s", str1);
445 		loadfont(n, str, str1);
446 		break;
447 						/* these don't belong here... */
448 	case 'H':	/* char height */
449 		fscanf(fp, "%d", &n);
450 		t_charht(n);
451 		break;
452 	case 'S':	/* slant */
453 		fscanf(fp, "%d", &n);
454 		t_slant(n);
455 		break;
456 	}
457 	while ((c = getc(fp)) != '\n')	/* skip rest of input line */
458 		if (c == EOF)
459 			break;
460 }
461 
462 /* fileinit:	read in font and code files, etc.
463 		Must open table for device, read in resolution,
464 		size info, font info, etc. and set params.
465 		Also read in font name mapping.
466 */
467 fileinit()
468 {
469 	register int i;
470 	register int fin;
471 	register int nw;
472 	register char *filebase;
473 	register char *p;
474 	register FILE *fp;
475 	char	temp[100];
476 
477 
478 		/* first, read in font map file.  The file must be of Format:
479 			XX  FILENAME  (XX = troff font name)
480 			with one entry per text line of the file.
481 		   Extra stuff after FILENAME is ignored */
482 
483 	sprintf(temp, "%s/fontmap", bitdir);
484 	if ((fp = fopen(temp, "r")) == NULL)
485 		error(FATAL, "Can't open %s", temp);
486 	for (i = 0; i <= NFONTS && fgets(temp, 100, fp) != NULL; i++) {
487 		sscanf(temp, "%2s", fontmap[i].fname);
488 		p = &temp[0];
489 		while (*p != ' ' && *p != '	') p++;
490 		while (*p == ' ' || *p == '	') p++;
491 		filebase = p;
492 		for (nw = 1; *p != '\n' && *p != ' ' && *p != '\t'; p++) nw++;
493 		fontmap[i].ffile = nalloc(1, nw);
494 		sscanf(filebase, "%s", fontmap[i].ffile);
495 	}
496 	fontmap[++i].fname[0] = '0';		/* finish off with zeros */
497 	fontmap[i].ffile = (char *) 0;
498 	fclose(fp);
499 #ifdef DEBUGABLE
500 	if(dbg) {
501 	    fprintf(stderr, "font map:\n");
502 	    for (i = 0; fontmap[i].ffile; i++)
503 		fprintf(stderr,"%s = %s\n", fontmap[i].fname, fontmap[i].ffile);
504 	}
505 #endif
506 
507 
508 	sprintf(temp, "%s/devver/DESC.out", fontdir);
509 	if ((fin = open(temp, 0)) < 0)
510 		error(FATAL, "can't open tables for %s", temp);
511 	read(fin, &dev, sizeof(struct dev));
512 	nfonts = dev.nfonts;
513 	nsizes = dev.nsizes;
514 	nchtab = dev.nchtab;
515 	filebase = calloc(1, dev.filesize);	/* enough room for whole file */
516 	read(fin, filebase, dev.filesize);	/* all at once */
517 	pstab = (short *) filebase;
518 	chtab = pstab + nsizes + 1;
519 	chname = (char *) (chtab + dev.nchtab);
520 	p = chname + dev.lchname;
521 	for (i = 1; i <= nfonts; i++) {
522 		fontbase[i] = (struct font *) p;
523 		nw = *p & BMASK;		/* 1st thing is width count */
524 		if (smnt == 0 && fontbase[i]->specfont == 1)
525 			smnt = i;		/* first special font */
526 		p += sizeof(struct font);	/* that is on the beginning */
527 		widtab[i] = p;
528 		codetab[i] = p + 2 * nw;
529 		fitab[i] = p + 3 * nw;
530 		p += 3 * nw + dev.nchtab + 128 - 32;
531 		t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
532 #ifdef DEBUGABLE
533 		if (dbg > 1) fontprint(i);
534 #endif
535 	}
536 	fontbase[0] = (struct font *)
537 		calloc(1,3*255 + dev.nchtab + (128-32) + sizeof (struct font));
538 	widtab[0] = (char *) fontbase[0] + sizeof (struct font);
539 	fontbase[0]->nwfont = 255;
540 	close(fin);
541 }
542 
543 fontprint(i)	/* debugging print of font i (0,...) */
544 {
545 	int j, n;
546 	char *p;
547 
548 	fprintf(stderr,"font %d:\n", i);
549 	p = (char *) fontbase[i];
550 	n = fontbase[i]->nwfont & BMASK;
551 	fprintf(stderr,
552 	    "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",p,
553 	    n,fontbase[i]->specfont,fontbase[i]->namefont,widtab[i],fitab[i]);
554 	fprintf(stderr,"widths:\n");
555 	for (j=0; j <= n; j++) {
556 		fprintf(stderr," %2d", widtab[i][j] & BMASK);
557 		if (j % 20 == 19) fprintf(stderr,"\n");
558 	}
559 	fprintf(stderr,"\ncodetab:\n");
560 	for (j=0; j <= n; j++) {
561 		fprintf(stderr," %2d", codetab[i][j] & BMASK);
562 		if (j % 20 == 19) fprintf(stderr,"\n");
563 	}
564 	fprintf(stderr,"\nfitab:\n");
565 	for (j=0; j <= dev.nchtab + 128-32; j++) {
566 		fprintf(stderr," %2d", fitab[i][j] & BMASK);
567 		if (j % 20 == 19) fprintf(stderr,"\n");
568 	}
569 	fprintf(stderr,"\n");
570 }
571 
572 
573 loadfont(n, s, s1)	/* load font info for font s on position n (0...) */
574 int n;
575 char *s, *s1;
576 {
577 	char temp[60];
578 	int fin, nw, norig;
579 
580 	if (n < 0 || n > NFONTS)
581 		error(FATAL, "illegal fp command %d %s", n, s);
582 	if (strcmp(s, fontbase[n]->namefont) == 0)
583 		return;
584 	if (s1 == NULL || s1[0] == '\0')
585 		sprintf(temp, "%s/devver/%s.out", fontdir, s);
586 	else
587 		sprintf(temp, "%s/%s.out", s1, s);
588 	if ((fin = open(temp, 0)) < 0)
589 		error(FATAL, "can't open font table %s", temp);
590 	norig = fontbase[n]->nwfont & BMASK;
591 	read(fin, fontbase[n], 3*norig + nchtab+128-32 + sizeof(struct font));
592 	if ((fontbase[n]->nwfont & BMASK) > norig)
593 		error(FATAL, "Font %s too big for position %d", s, n);
594 	close(fin);
595 	nw = fontbase[n]->nwfont & BMASK;
596 	widtab[n] = (char *) fontbase[n] + sizeof(struct font);
597 	codetab[n] = (char *) widtab[n] + 2 * nw;
598 	fitab[n] = (char *) widtab[n] + 3 * nw;
599 	t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
600 	fontbase[n]->nwfont = norig;	/* to later use full original size */
601 #ifdef DEBUGABLE
602 	if (dbg > 1) fontprint(n);
603 #endif
604 }
605 
606 
607 /*VARARGS1*/
608 error(f, s, a1, a2, a3, a4, a5, a6, a7) {
609 	fprintf(stderr, "dver: ");
610 	fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
611 	fprintf(stderr, "\n");
612 	if (f)
613 		exit(1);
614 }
615 
616 
617 t_init()	/* initialize device */
618 {
619 	int i;
620 
621 	maxv = hpos = vpos = 0;
622 
623 	setsize(t_size(10));	/* start somewhere */
624 	setfont(1);
625 }
626 
627 
628 struct state {
629 	int	ssize;
630 	int	sfont;
631 	int	shpos;
632 	int	svpos;
633 	int	sstyle;
634 	int	sthick;
635 };
636 struct	state	state[MAXSTATE];
637 struct	state	*statep = state;
638 
639 t_push()	/* begin a new block */
640 {
641 	statep->ssize = size;
642 	statep->sfont = font;
643 	statep->sstyle = linmod;
644 	statep->sthick = linethickness;
645 	statep->shpos = hpos;
646 	statep->svpos = vpos;
647 	if (statep++ >= state+MAXSTATE)
648 		error(FATAL, "{ nested too deep");
649 }
650 
651 t_pop()	/* pop to previous state */
652 {
653 	if (--statep < state)
654 		error(FATAL, "extra }");
655 	size = statep->ssize;
656 	font = statep->sfont;
657 	hpos = statep->shpos;
658 	vpos = statep->svpos;
659 	linmod = statep->sstyle;
660 	linethickness = statep->sthick;
661 }
662 
663 
664 t_page(n)	/* do whatever new page functions */
665 {
666 	int i;
667 
668 
669 	if (output) {
670 		if (++scount >= spage) {
671 			scount = 0;
672 			t_reset('p');
673 		} else
674 			outband(PAGEEND);
675 	}
676 	maxv = vpos = 0;
677 
678 	output = 1;
679 	if (nolist == 0)
680 		return;		/* no -o specified */
681 	output = 0;
682 	for (i = 0; i < nolist; i += 2)
683 		if (n >= olist[i] && n <= olist[i+1]) {
684 			output = 1;
685 			break;
686 		}
687 }
688 
689 
690 outband(page)
691 int page;
692 {
693     register int outsize;
694 
695     if (page == PAGEEND) {		/* set to inch boundary */
696 	if ((outsize = maxv - ++pagelen) < 1) return;
697 	outsize = ((outsize + RES - 1) / RES) * RES * BYTES_PER_LINE;
698 	vwrite(buf0p, outsize);
699 	vclear(buf0p, outsize);
700 	vorigin = 0;
701 	pagelen = 0;
702     } else {
703 	vorigin += NLINES;
704 	pagelen += NLINES;
705 	vwrite(buf0p, BUFFER_SIZE);
706 	vclear(buf0p, BUFFER_SIZE);
707     }
708 }
709 
710 
711 t_newline()	/* do whatever for the end of a line */
712 {
713 	hpos = 0;	/* because we're now back at the left margin */
714 }
715 
716 t_size(n)	/* convert integer to internal size number*/
717 int n;
718 {
719 	int i;
720 
721 	if (n <= pstab[0])
722 		return(0);
723 	else if (n >= pstab[nsizes - 1])
724 		return(nsizes - 1);
725 	for (i = 0; n > pstab[i]; i++)
726 		;
727 	return(i);
728 }
729 
730 t_charht(n)	/* set character height to n */
731 int n;
732 {
733 #ifdef DEBUGABLE
734 	if (dbg) error(!FATAL, "can't set height on versatec");
735 #endif
736 }
737 
738 t_slant(n)	/* set slant to n */
739 int n;
740 {
741 #ifdef DEBUGABLE
742 	if (dbg) error(!FATAL, "can't set slant on versatec");
743 #endif
744 }
745 
746 t_font(s)	/* convert string to internal font number */
747 char *s;
748 {
749 	int n;
750 
751 	n = atoi(s);
752 	if (n < 0 || n > nfonts)
753 		n = 1;
754 	return(n);
755 }
756 
757 t_text(s)	/* print string s as text */
758 char *s;
759 {
760 	int c;
761 	char str[100];
762 
763 	if (!output)
764 		return;
765 	while (c = *s++) {
766 		if (c == '\\') {
767 			switch (c = *s++) {
768 			case '\\':
769 			case 'e':
770 				put1('\\');
771 				break;
772 			case '(':
773 				str[0] = *s++;
774 				str[1] = *s++;
775 				str[2] = '\0';
776 				put1s(str);
777 				break;
778 			}
779 		} else {
780 			put1(c);
781 		}
782 		hmot(lastw);
783 #ifdef DEBUGABLE
784 		if (dbg) fprintf(stderr,"width = %d\n", lastw);
785 #endif
786 	}
787 }
788 
789 
790 t_reset(c)
791 {
792 	output = 1;
793 	switch(c){
794 	case 'p':
795 		outband(PAGEEND);
796 		break;
797 	case 's':
798 		outband(PAGEEND);
799 /*nov		ioctl(OUTFILE, VSETSTATE, prtmode); */
800 		break;
801 	}
802 }
803 
804 
805 vgoto (n)
806 int n;
807 {
808 	vpos = n;
809 	if (vpos > maxv) maxv = vpos;
810 }
811 
812 
813 put1s(s)	/* s is a funny char name */
814 char *s;
815 {
816 	int i;
817 
818 	if (!output)
819 		return;
820 #ifdef DEBUGABLE
821 	if (dbg) fprintf(stderr,"%s ", s);
822 #endif
823 	for (i = 0; i < nchtab; i++)
824 		if (strcmp(&chname[chtab[i]], s) == 0)
825 			break;
826 	if (i < nchtab)
827 		put1(i + 128);
828 }
829 
830 put1(c)	/* output char c */
831 int c;
832 {
833 	char *pw;
834 	register char *p;
835 	register int i, k;
836 	int j, ofont, code;
837 
838 	if (!output)
839 		return;
840 	c -= 32;
841 	if (c <= 0) {
842 #ifdef DEBUGABLE
843 		if (dbg) fprintf(stderr,"non-exist 0%o\n", c + 32);
844 #endif
845  		lastw = (widtab[font][0] * pstab[size] + dev.unitwidth/2)
846 								/ dev.unitwidth;
847 		return;
848 	}
849 	k = ofont = font;
850 	i = fitab[font][c] & BMASK;
851 	if (i != 0) {			/* it's on this font */
852 		p = codetab[font];	/* get the printing value of ch */
853 		pw = widtab[font];	/* get the width */
854 	} else if (smnt > 0) {		/* on special (we hope) */
855 		for (k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1)){
856 			if (fitab[k] == 0)
857 				continue;
858 			if ((i = fitab[k][c] & BMASK) != 0) {
859 				p = codetab[k];
860 				pw = widtab[k];
861 				setfont(k);
862 				break;
863 			}
864 		}
865 	}
866 	if (i == 0 || (code = p[i] & BMASK) == 0 || k > nfonts) {
867 #ifdef DEBUGABLE
868 		if (dbg) fprintf(stderr,"not found 0%o\n", c+32);
869 #endif
870 		return;
871 	}
872 #ifdef DEBUGABLE
873 	if (dbg) {
874 		if (isprint(c+32))
875 			fprintf(stderr,"%c %d\n", c+32, code);
876 		else
877 			fprintf(stderr,"%03o %d\n", c+32, code);
878 	}
879 #endif
880 	outc(code);	/* character is < 254 */
881 	if (font != ofont)
882 		setfont(ofont);
883 	lastw = ((pw[i]&077) * pstab[size] + dev.unitwidth/2) / dev.unitwidth;
884 }
885 
886 
887 
888 setsize(n)	/* set point size to n (internal) */
889 int n;
890 {
891 
892 	if (n == size)
893 		return;	/* already there */
894 	if (vloadfont(font, pstab[n]) != -1)
895 		size = n;
896 }
897 
898 t_fp(n, s, si)	/* font position n now contains font s, intname si */
899 int n;
900 char *s, *si;
901 {
902 	register int i;
903 
904 			/* first convert s to filename if possible */
905 	for (i = 0; fontmap[i].ffile != (char *) 0; i++) {
906 #ifdef DEBUGABLE
907 		if(dbg>1)fprintf(stderr,"testing :%s:%s:\n",s,fontmap[i].fname);
908 #endif
909 		if (strcmp(s, fontmap[i].fname) == 0) {
910 			s = fontmap[i].ffile;
911 #ifdef DEBUGABLE
912 			if(dbg)fprintf(stderr, "found :%s:\n",fontmap[i].ffile);
913 #endif
914 			break;
915 		}
916 	}
917 
918 	fontname[n].name = s;
919 	fontname[n].number = atoi(si);
920 	for(i = 0;i < NFONTS;i++)	/* free the bits of that font */
921 		if (fontdes[i].fnum == n){
922 			nfree(fontdes[i].bits);
923 			fontdes[i].bits = 0;
924 			fontdes[i].fnum = -1;
925 		}
926 }
927 
928 setfont(n)	/* set font to n */
929 int n;
930 {
931 	if (n < 0 || n > NFONTS)
932 		error(FATAL, "illegal font %d", n);
933 	if (vloadfont(n,pstab[size]) != -1)
934 		font = n;
935 }
936 
937 vloadfont(fnum, fsize)
938 register int fnum;
939 register int fsize;
940 {
941 	register int i;
942 
943 	fontwanted = 0;
944 	if (fnum == cfnum && fsize == cpsize)
945 		return(0);
946 	for (i = 0; i < NFONTS; i++) {
947 		if (fontdes[i].fnum == fnum && fontdes[i].psize == fsize) {
948 			cfnum = fontdes[i].fnum;
949 			cpsize = fontdes[i].psize;
950 			dispatch = &fontdes[i].disp[0];
951 			bits = fontdes[i].bits;
952 			cfont = i;
953 			return (0);
954 		}
955 	}
956 		/* this is a new font */
957 	if (fnum < 0 || fnum > NFONTS || fontname[fnum].name == 0) {
958 #ifdef DEBUGABLE
959 	    if (dbg) error(!FATAL, "illegal font %d size %d", fnum, fsize);
960 #endif
961 	    return(-1);
962 	}
963 		/* Need to verify the existance of that font/size here*/
964 	nfontnum = fnum;
965 	npsize = fsize;
966 	fontwanted++;
967 	return (0);
968 }
969 
970 
971 getfont()
972 {
973 	register int fnum;
974 	register int fsize;
975 	register int fontd;
976 	register int d;
977 	register int savesize = size;
978 	char cbuf[BUFSIZ];
979 
980 
981 	fnum = nfontnum;
982 	fsize = npsize;
983 			/* try to open font file - if unsuccessful, hunt for */
984 			/* a file of same style, different size to substitute */
985 	d = -1;	/* direction to look in pstab (smaller first) */
986 	do {
987 	    sprintf(cbuf, "%s/%s.%d", bitdir, fontname[fnum].name, fsize);
988 	    fontd = open(cbuf, OPENREAD);
989 	    if (fontd == -1) {		/* File wasn't found. Try another ps */
990 		size += d;
991 		if (size < 0) {		/* past beginning - look higher */
992 		    d = 1;
993 		    size = savesize + 1;
994 		}
995 		if (size > nsizes) {	/* past top - forget it */
996 		    d = 0;
997 		} else {
998 		    fsize = pstab[size];
999 		}
1000 	    }
1001 	} while (fontd == -1 && d != 0);
1002 
1003 	if (fontd == -1) {		/* completely unsuccessful */
1004 	    perror(cbuf);
1005 	    error(!FATAL,"fnum = %d, psize = %d, name = %s",
1006 		fnum, npsize, fontname[fnum].name);
1007 	    fontwanted = 0;
1008 	    return (-1);
1009 	}
1010 	if (read(fontd, &header, sizeof  (header)) != sizeof (header)
1011 						|| header.magic != 0436)
1012 		fprintf(stderr, "%s: Bad font file", cbuf);
1013 	else {
1014 		cfont = relfont();
1015 		if ((bits=nalloc(header.size+DSIZ+1,1))== NULL)
1016 			if ((bits=allpanic(header.size+DSIZ+1))== NULL) {
1017 				fprintf(stderr,"%s: ran out of memory\n", cbuf);
1018 				exit(ABORT);
1019 			}
1020 
1021 			/*
1022 			 * have allocated one chunk of mem for font, dispatch.
1023 			 * get the dispatch addr, align to word boundary.
1024 			 */
1025 
1026 		d = (int) bits+header.size;
1027 		d += 1;
1028 		d &= ~1;
1029 		if (read (fontd, d, DSIZ) != DSIZ
1030 			    || read (fontd, bits, header.size) != header.size)
1031 			fprintf(stderr, "bad font header");
1032 		else {
1033 			close(fontd);
1034 			cfnum = fontdes[cfont].fnum = fnum;
1035 			cpsize = fontdes[cfont].psize = fsize;
1036 			fontdes [cfont].bits = bits;
1037 			fontdes [cfont].disp = (struct dispatch *) d;
1038 			dispatch = &fontdes[cfont].disp[0];
1039 			fontwanted = 0;
1040 			return (0);
1041 		}
1042 	}
1043 	close(fontd);
1044 	fontwanted = 0;
1045 	return(-1);
1046 }
1047 
1048 /*
1049  * "release" a font position - find an empty one, if possible
1050  */
1051 
1052 relfont()
1053 {
1054     register int newfont;
1055 
1056     for (newfont = 0; newfont < NFONTS; newfont++)
1057 	if (fontdes [newfont].bits == (char *) -1  ||  !fontdes [newfont].bits)
1058 	    break;
1059     if (fontdes [newfont].bits != (char *) -1  &&  fontdes [newfont].bits) {
1060 	nfree (fontdes [newfont].bits);
1061 	fontdes [newfont].bits = (char *)0;
1062 #ifdef DEBUGABLE
1063 	if (dbg) fprintf (stderr, "freeing position %d\n", newfont);
1064     } else {
1065 	if (dbg)
1066 	    fprintf (stderr, "taking, not freeing, position %d\n", newfont);
1067 #endif
1068     }
1069     fontdes[newfont].bits = 0;
1070     return (newfont);
1071 }
1072 
1073 char *allpanic (nbytes)
1074 int nbytes;
1075 {
1076 	register int i;
1077 
1078 	for (i = 0; i <= NFONTS; i++)
1079 	    if (fontdes[i].bits != (char *)-1 && fontdes[i].bits != (char *)0)
1080 		nfree(fontdes[i].bits);
1081 	for (i = 0; i <= NFONTS; i++) {
1082 		fontdes[i].fnum = fontdes[i].psize = -1;
1083 		fontdes[i].bits = 0;
1084 		cfnum = cpsize = -1;
1085 	}
1086 	return(nalloc(nbytes,1));
1087 }
1088 
1089 int	M[] = { 0xffffffff, 0xfefefefe, 0xfcfcfcfc, 0xf8f8f8f8,
1090 		0xf0f0f0f0, 0xe0e0e0e0, 0xc0c0c0c0, 0x80808080, 0x0 };
1091 int	N[] = { 0x00000000, 0x01010101, 0x03030303, 0x07070707,
1092 		0x0f0f0f0f, 0x1f1f1f1f, 0x3f3f3f3f, 0x7f7f7f7f, 0xffffffff };
1093 int	strim[] = { 0xffffffff, 0xffffff00, 0xffff0000, 0xff000000, 0 };
1094 
1095 outc(code)
1096 int code;		/* character to print */
1097 {
1098     register struct dispatch *dis; /* ptr to character font record */
1099     register char *addr;	/* addr of font data */
1100     int llen;			/* length of each font line */
1101     int nlines;			/* number of font lines */
1102     register char *scanp;	/* ptr to output buffer */
1103     int scanp_inc;		/* increment to start of next buffer */
1104     int offset;			/* bit offset to start of font data */
1105     register int i;		/* loop counter */
1106     register int count;		/* font data ptr */
1107     register unsigned fontdata;	/* font data temporary */
1108     register int off8;		/* offset + 8 */
1109 
1110     if (fontwanted)
1111 	getfont();
1112     dis = dispatch + code;
1113     if (dis->nbytes) {
1114 	addr = bits + dis->addr;
1115 	llen = (dis->left + dis->right + 7) / 8;
1116 	nlines = dis->up + dis->down;
1117 	if ((i = vpos + dis->down) > maxv) maxv = i;
1118 	scanp = buf0p + (vpos - (vorigin + dis->up + 1)) * BYTES_PER_LINE
1119 			+ (hpos - dis->left) / 8;
1120 	scanp_inc = BYTES_PER_LINE - llen;
1121 	offset = - ((hpos - dis->left) &07);
1122 	off8 = offset + 8;
1123 	for (i = 0; i < nlines; i++) {
1124 	    if (scanp + (count = llen) > BUFBOTTOM) return;
1125 	    if (scanp >= BUFTOP) {
1126 		do {
1127 		    fontdata = *(unsigned *)addr;
1128 		    addr += 4;
1129 		    if (count < 4)
1130 			fontdata &= ~strim[count];
1131 		    *(unsigned*)scanp |=(fontdata << offset) & ~M[off8];
1132 		    scanp++;
1133 		    *(unsigned*)scanp |=(fontdata << off8) & ~N[off8];
1134 		    scanp += 3;
1135 		    count -= 4;
1136 		} while (count > 0);
1137 	    }
1138 	    scanp += scanp_inc+count;
1139 	    addr += count;
1140 	}
1141 	return;
1142     }
1143     return;
1144 }
1145 
1146 
1147 vwrite(buf,usize)
1148 char *buf;
1149 unsigned usize;
1150 {
1151 	register int tsize = 0;
1152 
1153 	while (usize){
1154 		buf += tsize;
1155 		tsize = usize > MAXWRIT ? MAXWRIT : usize;
1156 #ifdef DEBUGABLE
1157 		if (dbg)fprintf(stderr,"buf = %d size = %d\n",buf,tsize);
1158 #endif
1159 		if ((tsize = write(OUTFILE, buf, tsize)) < 0) {
1160 			perror("dver: write failed");
1161 			exit(RESTART);
1162 		}
1163 		usize -= tsize;
1164 	}
1165 }
1166 
1167 vclear (ptr, nbytes)
1168 char	*ptr;
1169 unsigned nbytes;
1170 {
1171     register tsize = 0;
1172 
1173     while (nbytes){
1174 	if ((unsigned)(16*1024) < nbytes) {
1175 	    tsize = 16 * 1024;
1176 	} else
1177 	    tsize = nbytes;
1178 	nbytes -= tsize;
1179 #ifdef DEBUGABLE
1180 	if (dbg) fprintf(stderr,"clearing ptr = %d size = %d\n",ptr,tsize);
1181 #endif
1182 	clear(ptr,tsize);
1183 	ptr += tsize;
1184     }
1185 }
1186 
1187 /*ARGSUSED*/
1188 clear(lp, nbytes)
1189 int *lp;
1190 int nbytes;
1191 {
1192 	asm("movc5 $0,(sp),$0,8(ap),*4(ap)");
1193 }
1194 
1195 char *
1196 nalloc(i, j)
1197 int i, j;
1198 {
1199 	register char *cp;
1200 
1201 	cp = calloc(i, j);
1202 #ifdef DEBUGABLE
1203 	if (dbg) fprintf(stderr, "allocated %d bytes at %x\n", i * j, cp);
1204 #endif
1205 	return(cp);
1206 }
1207 
1208 nfree(cp)
1209 char *cp;
1210 {
1211 #ifdef DEBUGABLE
1212 	if (dbg) fprintf(stderr, "freeing at %x\n", cp);
1213 #endif
1214 	free(cp);
1215 }
1216 
1217 
1218 /*
1219  * Plot a dot at (x, y).  Points should be in the range 0 <= x < RASTER_LENGTH,
1220  * vorigin <= y < vorigin + NLINES.  If the point will not fit on the buffer,
1221  * it is left out.  Things outside the x boundary are wrapped around the end.
1222  */
1223 point(x, y)
1224 int x, y;
1225 {
1226     register char *ptr = buf0p + (y - vorigin) * BYTES_PER_LINE + (x >> 3);
1227 
1228     if (ptr <= BUFBOTTOM && ptr >= BUFTOP)	/* ignore it if it wraps over */
1229 	*ptr |= 1 << (7 - (x & 07));
1230 }
1231