1 /*	dip.c	1.12	(Berkeley)	85/10/29
2  *	dip
3  *	driver for impress/imagen canon laser printer
4  */
5 
6 /*
7 output language from troff:
8 all numbers are character strings
9 
10 sn	size in points
11 fn	font as number from 1-n
12 in	stipple `font' as number from 1-n
13 cx	ascii character x
14 Cxyz	funny char xyz. terminated by white space
15 Hn	go to absolute horizontal position n
16 Vn	go to absolute vertical position n (down is positive)
17 hn	go n units horizontally (relative)
18 vn	ditto vertically
19 nnc	move right nn, then print c (exactly 2 digits!)
20 		(this wart is an optimization that shrinks output file size
21 		 about 35% and run-time about 15% while preserving ascii-ness)
22 Dt ...\n	draw operation 't':
23 	Dt d		line thickness set to d
24 	Ds d		line style (coordinate bit map) set to d
25 	Dl x y		line from here by x,y
26 	Dc d		circle of diameter d with left side here
27 	De x y		ellipse of axes x,y with left side here
28 	Da x y r	arc counter-clockwise by x,y of radius r
29 	D~ x y x y ...	wiggly line by x,y then x,y ...
30 	Dg x y x y ...	gremlin spline by x,y then x,y ...
31 	Dp s x y ...	polygon filled with s by x,y then ...
32 	DP s x y ...	unbordered polygon filled with s by x,y then ...
33 nb a	end of line (information only -- no action needed)
34 	b = space before line, a = after
35 pn	new page begins -- set v to 0
36 #...\n	comment
37 x ...\n	device control functions:
38 	x i	init
39 	x T s	name of device is s
40 	x r n h v	resolution is n/inch
41 		h = min horizontal motion, v = min vert
42 	x p	pause (can restart)
43 	x s	stop -- done for ever
44 	x t	generate trailer
45 	x f n s	font position n contains font s
46 	x H n	set character height to n
47 	x S n	set slant to N
48 
49 	Subcommands like "i" are often spelled out like "init".
50 */
51 
52 #include	<stdio.h>
53 #include	<signal.h>
54 #include	<math.h>
55 #include	<ctype.h>
56 #include	"dev.h"
57 #include	"canon.h"
58 #include	"rst.h"
59 
60 
61 /* #define  DEBUGABLE	/* whether or not it'll accept the -d option */
62 #define  abs(n)		((n) >= 0 ? (n) : -(n))
63 #define  hmot(n)	hpos += n
64 #define  hgoto(n)	hpos = n
65 #define  vmot(n)	vpos += n
66 #define  vgoto(n)	vpos = n
67 
68 #define	FATAL	1
69 #define	BMASK	0377
70 #define	NFONT	35		/* maximum forever */
71 
72 #ifndef FONTDIR
73 #define FONTDIR	"/usr/lib/font";
74 #endif
75 #define BITDIR	"/usr/local/lib/ifontt";
76 
77 				/* BOTTOMTHRESH and DELTATHRESH are used to */
78 				/* search through the glyphs downloaded to */
79 				/* determine which ones to keep and which to */
80 				/* dump.  They're tested against BOTTOMTHRESH */
81 				/* first, then if THAT doesn't release enough */
82 				/* space, DELTATHRESH is added until it is. */
83 #define BOTTOMTHRESH	16
84 #define DELTATHRESH	16
85 #define MEMSIZE	70000		/* amount of memory inside imagen */
86 #define BUFFER	20000		/* imagen memory set aside for page buffer */
87 #define CHARRAY	128		/* size of character use count array */
88 
89 int	MAXX = (RES*8+RES/3);	/* size of the page... (not 8-1/2" x 11", */
90 int	MAXY = (RES*10+RES/2+RES/4);		/*  but 8-1/3" x 10-3/4") */
91 
92 int	output	= 0;		/* do we do output at all? */
93 int	pageno	= -1;		/* output page number */
94 int	nolist	= 0;		/* output page list if > 0 */
95 int	olist[20];		/* pairs of page numbers */
96 
97 struct dev dev;
98 struct font *fontbase[NFONT+1];
99 short *	pstab;
100 int	nsizes = 1;
101 int	nfonts;
102 int	nstips;
103 int	nchtab;
104 char *	chname;
105 short *	chtab;
106 unsigned char *	fitab[NFONT+1];		/* legal characters for each font */
107 unsigned char *	widtab[NFONT+1];	/* width table for each font */
108 unsigned char *	codetab[NFONT+1];	/* device code translation */
109 char *	fontname[NFONT+1];		/* what font is on what position? */
110 
111 #ifdef DEBUGABLE
112 int	dbg	= 0;
113 #endif
114 
115 FILE *	tf = stdout;		/* output file pointer */
116 char *	fontdir = FONTDIR;
117 char *	bitdir = BITDIR;
118 FILE *	fp = stdin;		/* input file pointer */
119 
120 int	totglyph= 0;		/* total space used by glyphs sent down */
121 int	maxglyph= MEMSIZE - BUFFER;		/* maximum space for glyphs */
122 
123 int	size = 1;
124 int	font = 1;
125 int	stip = 1;
126 int	family;
127 int	hpos;		/* current horizontal position (left = 0) */
128 int	vpos;		/* current vertical position (down positive) */
129 int	lastw	= 0;	/* width of last input character */
130 extern int polyborder;		/* flag to turn off borders around a polygon */
131 
132 typedef struct {
133 	int	font;
134 	int	size;
135 	short	first;
136 	short	last;
137 	unsigned char chused[CHARRAY];	/* test array - character downloaded? */
138 	glyph_dir *glyph;		/* array of character descriptions */
139 	unsigned char *cdp;		/* char data pointer */
140 } fontset;
141 
142 fontset	*fs;			/* A global pointer to the current family */
143 fontset fontdata[NFONT+1];	/* table of family data descripters */
144 
145 int	lastsize	= -1;
146 int	lastfont	= -1;
147 int	lastx		= -1;
148 int	lasty		= -1;
149 int	lastfam		= -1;
150 int	laststip	= -1;
151 int	laststipmem	= -1;
152 
153 
154 
main(argc,argv)155 main(argc, argv)
156 char *argv[];
157 {
158 	int i;
159 	char *mktemp();
160 	char *operand();
161 
162 	while (--argc > 0 && **++argv == '-') {
163 		switch ((*argv)[1]) {
164 		case 'X':
165 			MAXX = atoi(operand(&argc, &argv));
166 			break;
167 		case 'Y':
168 			MAXY = atoi(operand(&argc, &argv));
169 			break;
170 		case 'F':
171 			fontdir = operand(&argc, &argv);
172 			break;
173 		case 'f':
174 			bitdir = operand(&argc, &argv);
175 			break;
176 		case 'o':
177 			outlist(operand(&argc, &argv));
178 			break;
179 		case 'b':
180 			if ((i = atoi(operand(&argc, &argv))) < 1000) i = 1000;
181 			else if (i > MEMSIZE - 1000) i = MEMSIZE - 1000;
182 			maxglyph = MEMSIZE - i;
183 			break;
184 #ifdef DEBUGABLE
185 		case 'd':
186 			dbg = atoi(operand(&argc, &argv));
187 			if (dbg == 0) error (FATAL, "no debug value");
188 			break;
189 #endif
190 		}
191 	}
192 
193 	if (argc < 1)
194 		conv(stdin);
195 	else
196 		while (argc-- > 0) {
197 			if (strcmp(*argv, "-") == 0)
198 				fp = stdin;
199 			else if ((fp = fopen(*argv, "r")) == NULL)
200 				error(FATAL, "can't open %s", *argv);
201 			conv(fp);
202 			fclose(fp);
203 			argv++;
204 		}
205 
206 	t_wrapup();
207 	exit(0);
208 }
209 
210 
211 /*----------------------------------------------------------------------------*
212  | Routine:	char  * operand (& argc,  & argv)
213  |
214  | Results:	returns address of the operand given with a command-line
215  |		option.  It uses either "-Xoperand" or "-X operand", whichever
216  |		is present.  The program is terminated if no option is present.
217  |
218  | Side Efct:	argc and argv are updated as necessary.
219  *----------------------------------------------------------------------------*/
220 
operand(argcp,argvp)221 char *operand(argcp, argvp)
222 int * argcp;
223 char ***argvp;
224 {
225 	if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */
226 	if ((--*argcp) <= 0) {			/* no operand */
227 	    error (FATAL, "command-line option operand missing.");
228 	}
229 	return(*(++(*argvp)));			/* operand next word */
230 }
231 
232 
outlist(s)233 outlist(s)	/* process list of page numbers to be printed */
234 register char *s;
235 {
236 	register int n1, n2;
237 
238 	nolist = 0;
239 	while (*s) {
240 		n1 = 0;
241 		if (isdigit(*s))
242 			do
243 				n1 = 10 * n1 + *s++ - '0';
244 			while (isdigit(*s));
245 		else
246 			n1 = -9999;
247 		n2 = n1;
248 		if (*s == '-') {
249 			s++;
250 			n2 = 0;
251 			if (isdigit(*s))
252 				do
253 					n2 = 10 * n2 + *s++ - '0';
254 				while (isdigit(*s));
255 			else
256 				n2 = 9999;
257 		}
258 		olist[nolist++] = n1;
259 		olist[nolist++] = n2;
260 		if (*s != '\0')
261 			s++;
262 	}
263 	olist[nolist] = 0;
264 #ifdef DEBUGABLE
265 	if (dbg)
266 		for (i=0; i<nolist; i += 2)
267 			printf("%3d %3d\n", olist[i], olist[i+1]);
268 #endif
269 }
270 
271 
in_olist(n)272 in_olist(n)	/* is n in olist? */
273 int n;
274 {
275 	int i;
276 
277 	if (nolist == 0)
278 		return(1);	/* everything is included */
279 	for (i = 0; i < nolist; i += 2)
280 		if (n >= olist[i] && n <= olist[i+1])
281 			return(1);
282 	return(0);
283 }
284 
285 
conv(fp)286 conv(fp)
287 register FILE *fp;
288 {
289 	register int c;
290 	register int k;
291 	int m, n, n1, m1;
292 	char str[100], buf[300];
293 
294 	while ((c = getc(fp)) != EOF) {
295 		switch (c) {
296 		case '\n':	/* when input is text */
297 		case ' ':
298 		case 0:		/* occasional noise creeps in */
299 			break;
300 		case '0': case '1': case '2': case '3': case '4':
301 		case '5': case '6': case '7': case '8': case '9':
302 			/* two motion digits plus a character */
303 			hmot((c-'0')*10 + getc(fp)-'0');
304 			put1(getc(fp));
305 			break;
306 		case 'c':	/* single ascii character */
307 			put1(getc(fp));
308 			break;
309 		case 'C':
310 			fscanf(fp, "%s", str);
311 			put1s(str);
312 			break;
313 		case 'D':	/* draw function */
314 			if (fgets(buf, sizeof(buf), fp) == NULL)
315 			    error(FATAL, "unexpected end of input");
316 			switch (buf[0]) {
317 			case 'l':	/* draw a line */
318 				sscanf(buf+1, "%d %d", &n, &m);
319 				drawline(n, m, ".");
320 				break;
321 			case 'c':	/* circle */
322 				sscanf(buf+1, "%d", &n);
323 				drawcirc(n);
324 				break;
325 			case 'e':	/* ellipse */
326 				sscanf(buf+1, "%d %d", &m, &n);
327 				drawellip(m, n);
328 				break;
329 			case 'a':	/* arc */
330 				sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
331 				drawarc(n, m, n1, m1);
332 				break;
333 			case 'P':
334 				polyborder = 0;		/* borderless polygon */
335 			case 'p':	/* polygon */
336 				sscanf(buf+1, "%d", &m);/* get stipple */
337 				n = 1;			/* number first */
338 				while (buf[++n] == ' ');
339 				while (isdigit(buf[n])) n++;
340 				setfill(m);		/* set up stipple */
341 				drawwig(buf+n, fp, -1);	/* draw polygon */
342 				polyborder = 1;		/* assume polygons */
343 				break;			/*   all have borders */
344 
345 			case 'g':	/* gremlin curve */
346 				drawwig(buf+1, fp, 0);
347 				break;
348 			case '~':	/* wiggly line */
349 				drawwig(buf+1, fp, 1);
350 				break;
351 			case 't':	/* line-thickness */
352 				sscanf(buf+1, "%d", &n);
353 				drawthick(n);
354 				break;
355 			case 's':	/* line-style */
356 				sscanf(buf+1, "%d", &n);
357 				drawstyle(n);
358 				break;
359 			default:
360 				error(FATAL, "unknown drawing function %s",buf);
361 				break;
362 			}
363 			break;
364 		case 's':
365 			fscanf(fp, "%d", &n);	/* ignore fractional sizes */
366 			setsize(t_size(n));
367 			break;
368 		case 'f':
369 			fscanf(fp, "%s", str);
370 			setfont(t_font(str));
371 			break;
372 		case 'i':
373 			fscanf(fp, "%d", &n);
374 			setstip(n);
375 			break;
376 		case 'H':	/* absolute horizontal motion */
377 			/* fscanf(fp, "%d", &n); */
378 			while ((c = getc(fp)) == ' ')
379 				;
380 			k = 0;
381 			do {
382 				k = 10 * k + c - '0';
383 			} while (isdigit(c = getc(fp)));
384 			ungetc(c, fp);
385 			hgoto(k);
386 			break;
387 		case 'h':	/* relative horizontal motion */
388 			/* fscanf(fp, "%d", &n); */
389 			while ((c = getc(fp)) == ' ')
390 				;
391 			k = 0;
392 			do {
393 				k = 10 * k + c - '0';
394 			} while (isdigit(c = getc(fp)));
395 			ungetc(c, fp);
396 			hmot(k);
397 			break;
398 		case 'w':	/* word space */
399 			break;
400 		case 'V':
401 			fscanf(fp, "%d", &n);
402 			vgoto(n);
403 			break;
404 		case 'v':
405 			fscanf(fp, "%d", &n);
406 			vmot(n);
407 			break;
408 		case 'p':	/* new page */
409 			fscanf(fp, "%d", &n);
410 			t_page(n);
411 			break;
412 		case 'n':	/* end of line */
413 			hpos = 0;
414 
415 		case '#':	/* comment */
416 			do
417 				c = getc(fp);
418 			while (c != '\n' && c != EOF);
419 			break;
420 		case 'x':	/* device control */
421 			if (devcntrl(fp)) return;
422 			break;
423 		default:
424 			error(FATAL, "unknown input character %o %c", c, c);
425 		}
426 	}
427 }
428 
429 
devcntrl(fp)430 int devcntrl(fp)	/* interpret device control functions */
431 FILE *fp;		/* returns -1 upon "stop" command */
432 {
433         char str[20], str1[50], buf[50];
434 	int c, n;
435 
436 	fscanf(fp, "%s", str);
437 	switch (str[0]) {	/* crude for now */
438 	case 'i':	/* initialize */
439 		fileinit();
440 		t_init();
441 		break;
442 	case 'T':	/* device name */
443 	case 't':	/* trailer */
444 	case 'p':	/* pause -- can restart */
445 		break;
446 	case 's':	/* stop */
447 		return -1;
448 	case 'r':	/* resolution assumed when prepared */
449 		fscanf(fp, "%d", &n);
450 		if (n!=RES) error(FATAL,"Input computed for wrong printer");
451 		break;
452 	case 'f':	/* font used */
453 		fscanf(fp, "%d %s", &n, str);
454 		fgets(buf, sizeof buf, fp);	/* in case there's a filename */
455 		ungetc('\n', fp);	/* fgets goes too far */
456 		str1[0] = 0;	/* in case there's nothing to come in */
457 		sscanf(buf, "%s", str1);
458 		loadfont(n, str, str1);
459 		break;
460 	case 'H':	/* char height */
461 		fscanf(fp, "%d", &n);
462 		t_charht(n);
463 		break;
464 	case 'S':	/* slant */
465 		fscanf(fp, "%d", &n);
466 		t_slant(n);
467 		break;
468 	}
469 	while ((c = getc(fp)) != '\n')	/* skip rest of input line */
470 		if (c == EOF)
471 			return -1;
472 	return 0;
473 }
474 
475 
fileinit()476 fileinit()	/* read in font and code files, etc. */
477 {
478 	register int i;
479 	register int fin;
480 	register int nw;
481 	register unsigned char *filebase;
482 	register unsigned char *p;
483 	unsigned char *malloc();
484 	char temp[100];
485 
486 		/* open table for device,
487 		 * read in resolution, size info, font info, etc.
488 		 * and set params
489 		 */
490 
491 	sprintf(temp, "%s/devip/DESC.out", fontdir);
492 	if ((fin = open(temp, 0)) < 0)
493 		error(FATAL, "can't open tables for %s", temp);
494 	read(fin, &dev, sizeof(struct dev));
495 	nfonts = dev.nfonts;
496 	nstips = dev.nstips;
497 	nsizes = dev.nsizes;
498 	nchtab = dev.nchtab;
499 	filebase = malloc(dev.filesize);	/* enough room for whole file */
500 	read(fin, filebase, dev.filesize);	/* all at once */
501 	pstab = (short *) filebase;
502 	chtab = pstab + nsizes + 1;
503 	chname = (char *) (chtab + dev.nchtab);
504 	p = (unsigned char *) chname + dev.lchname;
505 	for (i = 1; i <= nfonts; i++) {
506 		fontbase[i] = (struct font *) p;
507 		nw = *p & BMASK;		/* 1st thing is width count */
508 		p += sizeof(struct font);
509 		widtab[i] = p;			/* then width table */
510 		codetab[i] = p + 2 * nw;	/* then code conversion table */
511 		fitab[i] = p + 3 * nw;		/* then font inclusion table */
512 		p += 3 * nw + dev.nchtab + 128 - 32;
513 		t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
514 #ifdef DEBUGABLE
515 		if (dbg > 1) fontprint(i);
516 #endif
517 	}
518 	for (i = 1; i <= nstips; i++) {		/* add in Stipple "filenames" */
519 		if (nfonts + i <= NFONT)
520 		    t_fp(nfonts + i, p, (char *)0);
521 		p += strlen(p) + 1;
522 	}
523 	fontbase[0] = NULL;
524 	close(fin);				/* no fonts loaded yet */
525 	for (i = 0; i <= NFONT; i++) fontdata[i].font = fontdata[i].size = -1;
526 }
527 
528 
529 #ifdef DEBUGABLE
fontprint(i)530 fontprint(i)	/* debugging print of font i (0,...) */
531 {
532 	int j, n;
533 	char *p;
534 
535 	printf("font %d:\n", i);
536 	p = (char *) fontbase[i];
537 	n = fontbase[i]->nwfont & BMASK;
538 	printf("base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
539 		p, n, fontbase[i]->specfont, fontbase[i]->namefont, widtab[i], fitab[i]);
540 	printf("widths:\n");
541 	for (j=0; j <= n; j++) {
542 		printf(" %2d", widtab[i][j] & BMASK);
543 		if (j % 20 == 19) printf("\n");
544 	}
545 	printf("\ncodetab:\n");
546 	for (j=0; j <= n; j++) {
547 		printf(" %2d", codetab[i][j] & BMASK);
548 		if (j % 20 == 19) printf("\n");
549 	}
550 	printf("\nfitab:\n");
551 	for (j=0; j <= dev.nchtab + 128-32; j++) {
552 		printf(" %2d", fitab[i][j] & BMASK);
553 		if (j % 20 == 19) printf("\n");
554 	}
555 	printf("\n");
556 }
557 #endif
558 
559 
loadfont(n,s,s1)560 loadfont(n, s, s1)	/* load font info for font s on position n (0...) */
561 int n;
562 char *s, *s1;
563 {
564 	char temp[60];
565 	int fin, nw;
566 
567 	if (n < 0 || n > NFONT)
568 		error(FATAL, "illegal fp command %d %s", n, s);
569 	if (fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0)
570 		return;
571 
572 	for (fin = 1; fin <= NFONT; fin++)	/* first check to see if the */
573 	    if (strcmp(s, fontbase[fin]->namefont) == 0) {  /* font is loaded */
574 		register unsigned char *c;		    /* somewhere else */
575 
576 #define ptrswap(x, y) { c = (unsigned char*) (x); x = y; y = c; }
577 #define ptrfswap(x, y) { c=(unsigned char*)(x); x = y; y = (struct font *) c; }
578 
579 		ptrfswap(fontbase[n], fontbase[fin]);
580 		ptrswap(codetab[n], codetab[fin]);
581 		ptrswap(widtab[n], widtab[fin]);
582 		ptrswap(fitab[n], fitab[fin]);
583 		t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
584 		t_fp(fin, fontbase[fin]->namefont, fontbase[fin]->intname);
585 		return;
586 	    }
587 
588 	if (s1 == NULL || s1[0] == '\0')
589 		sprintf(temp, "%s/devip/%s.out", fontdir, s);
590 	else
591 		sprintf(temp, "%s/%s.out", s1, s);
592 	if ((fin = open(temp, 0)) < 0) {
593 		error(!FATAL, "can't open font table %s", temp);
594 		return;
595 	}
596 	if (fontbase[n] != NULL)
597 		free(fontbase[n]);
598 	fontbase[n] = (struct font *) malloc(3*255 + dev.nchtab +
599 				(128-32) + sizeof(struct font));
600 	if (fontbase[n] == NULL)
601 		error(FATAL, "Out of space in loadfont %s", s);
602 	read(fin, fontbase[n], 3*255 + nchtab+128-32 + sizeof(struct font));
603 	close(fin);
604 	nw = fontbase[n]->nwfont & BMASK;
605 	widtab[n] = (unsigned char *) fontbase[n] + sizeof(struct font);
606 	codetab[n] = (unsigned char *) widtab[n] + 2 * nw;
607 	fitab[n] = (unsigned char *) widtab[n] + 3 * nw;
608 	t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
609 #ifdef DEBUGABLE
610 	if (dbg > 1) fontprint(n);
611 #endif
612 }
613 
614 
615 /*VARARGS2*/
error(f,s,a1,a2,a3,a4,a5,a6,a7)616 error(f, s, a1, a2, a3, a4, a5, a6, a7)
617 int f;
618 char *s;
619 {
620 	fprintf(stderr, "dip: ");
621 	fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
622 	fprintf(stderr, "\n");
623 	if (f)
624 		exit(2);
625 }
626 
627 
t_init()628 t_init()	/* initialize device */
629 {
630 	drawthick(3);		/* set the line thickness parameter */
631 	hpos = vpos = 0;
632 	setsize(t_size(10));	/* start somewhere */
633 }
634 
635 
636 /*----------------------------------------------------------------------------*
637  | Routine:	t_page ( page_number )
638  |
639  | Results:	mark this page done for printing.  If we think we've filled
640  |		the imagen too much, delete some of the info in the glyph cache.
641  |		This is a good time to do this since it's at the end of a page
642  |		and will get done every so often.
643  *----------------------------------------------------------------------------*/
644 
t_page(pg)645 t_page(pg)	/* do whatever new page functions */
646 {
647 	register int i;
648 	register int threshold;
649 
650 	pageno = pg;
651 #ifdef DEBUGABLE
652 	if(dbg)fprintf(stderr, "t_page %d, output=%d\n", pg, output);
653 #endif
654 	if (output != 0)
655 		putc(AEND, tf);
656 	output = in_olist(pg);
657 
658 	if (output) {
659 	    threshold = BOTTOMTHRESH;
660 	    while (totglyph >= maxglyph) {
661 		for (i = 0; i < NFONT; i++) {
662 		    if (fontdata[i].font != -1)
663 			clearglyphs(i, threshold);
664 		}
665 		threshold += DELTATHRESH;
666 	    }
667 	}
668 	lastx = lasty = -1;
669 	hpos = vpos = 0;
670 }
671 
672 
t_size(n)673 t_size(n)	/* convert integer to internal size number*/
674 int n;
675 {
676 	int i;
677 
678 	if (n <= pstab[0])
679 		return(0);
680 	else if (n >= pstab[nsizes-1])
681 		return(nsizes-1);
682 	for (i = 0; n > pstab[i]; i++)
683 		;
684 	return(i);
685 }
686 
687 
t_charht(n)688 t_charht(n)	/* set character height to n */
689 int n;
690 {
691 	/* punt for now */
692 }
693 
694 
t_slant(n)695 t_slant(n)	/* set slant to n */
696 int n;
697 {
698 	/* punt for now */
699 }
700 
701 
t_font(s)702 t_font(s)	/* convert string to internal font number */
703 char *s;
704 {
705 	int n;
706 
707 	n = atoi(s);
708 	if (n < 0 || n > nfonts)
709 		n = 1;
710 	return(n);
711 }
712 
713 
t_wrapup()714 t_wrapup()
715 {
716 	putc(AEND, tf);
717 	putc(AEOF, tf);
718 }
719 
720 
put1s(s)721 put1s(s)	/* s is a funny char name */
722 register char *s;
723 {
724 	static int i = 0;
725 
726 	if (!output)
727 		return;
728 #ifdef DEBUGABLE
729 	if (dbg) printf("%s ", s);
730 #endif
731 	if (strcmp(s, &chname[chtab[i]]) != 0)
732 		for (i = 0; i < nchtab; i++)
733 			if (strcmp(&chname[chtab[i]], s) == 0)
734 				break;
735 	if (i < nchtab)
736 		put1(i + 128);
737 	else
738 		i = 0;
739 }
740 
741 
put1(c)742 put1(c)	/* output char c */
743 register int c;
744 {
745 	register unsigned char *pw;
746 	register unsigned char *p;
747 	register int i;
748 	register int j;
749 	register int k;
750 	int ofont, code;
751 
752 	if (!output)
753 		return;
754 	c -= 32;
755 	if (c <= 0) {
756 #ifdef DEBUGABLE
757 		if (dbg) printf("non-exist 0%o\n", c+32);
758 #endif
759 		return;
760 	}
761 	ofont = font;
762 	i = fitab[font][c];
763 	if (i != 0) {	/* it's on this font */
764 		p = codetab[font];
765 		pw = widtab[font];
766 	} else {		/* on another font */
767 		k = font;	/* start with current, then run down the list */
768 		for (j=0; j++ <= nfonts; k = (k+1) % (nfonts+1))
769 			if (fontbase[k] != NULL && (i = fitab[k][c]) != 0) {
770 				p = codetab[k];
771 				pw = widtab[k];
772 				setfont(k);
773 				break;
774 			}
775 	}
776 	code = p[i] & BMASK;
777 	if (i == 0) {
778 #ifdef DEBUGABLE
779 		if (dbg) printf("not found 0%o\n", c+32);
780 #endif
781 		return;
782 	}
783 	lastw = (pw[i] * pstab[size] + dev.unitwidth/2) / dev.unitwidth;
784 #ifdef DEBUGABLE
785 	if (dbg) {
786 		if (isprint(c+32))
787 			printf("%c %d\n", c+32, code);
788 		else
789 			printf("%03o %d\n", c+32, code);
790 	} else
791 #endif
792 		if (output) xychar(code);
793 	if (font != ofont)
794 		setfont(ofont);
795 }
796 
797 
setsize(n)798 setsize(n)	/* set point size to n (internal) */
799 int n;
800 {
801 	size = n;
802 }
803 
804 
805 /*----------------------------------------------------------------------------*
806  | Routine:	t_fp ( number, string, string_internal )
807  |
808  | Results:	font position number now contains font 'string', internal
809  |		font name (number) is ignored.
810  |
811  | Side Efct:	any fonts loaded into fontdata with this font number are
812  |		removed.  And, to make sure they're not accessed, if lastfont
813  |		equals number, it is "disabled" by setting lastfont to -1.
814  *----------------------------------------------------------------------------*/
815 
t_fp(n,s,si)816 t_fp(n, s, si)
817 int n;
818 char *s, *si;
819 {
820 	register int i;
821 
822 	fontname[n] = s;
823 	for (i = 0; i <= NFONT; i++)		/* release any font files */
824 		if (fontdata[i].font == n) {	/* for this font */
825 			clearglyphs (i, 1000);
826 			putc(AFORCE, tf);
827 			free (fontdata[i].cdp);
828 			free (fontdata[i].glyph);
829 			fontdata[i].font = -1;
830 		}
831 	if (n == lastfont) lastfont = -1;
832 }
833 
834 
setfont(n)835 setfont(n)	/* set font to n */
836 int n;
837 {
838 	if (!output)
839 		return;
840 	if (n < 0 || n > nfonts)
841 		error(FATAL, "illegal font %d", n);
842 	font = n;
843 }
844 
845 
setstip(n)846 setstip(n)	/* set stipple "font" to n */
847 int n;
848 {
849 	if (!output)
850 		return;
851 	if (n < 1 || n > nstips)
852 		error(FATAL, "illegal stipple %d", n);
853 	stip = n;
854 }
855 
856 
857 /*----------------------------------------------------------------------------*
858  | Routine:	rd1, rd2, rd3, rd4 ( file_pointer )
859  |
860  | Results:	gets one, two three or four bytes from a file and interprets
861  |		them as integers.  Most significant bytes come first.
862  *----------------------------------------------------------------------------*/
863 
rd1(fp)864 int rd1(fp)
865 FILE *fp;
866 {
867     register int i;
868 
869     if((i = getc(fp)) == EOF) error(FATAL, "font file read error");
870     return i;
871 }
872 
rd2(fp)873 int rd2(fp)
874 FILE *fp;
875 {
876     register short i = rd1(fp) << 8;
877 
878     return i | rd1(fp);
879 }
880 
rd3(fp)881 int rd3(fp)
882 FILE *fp;
883 {
884     register int i = rd2(fp) << 8;
885 
886     return i | rd1(fp);
887 }
888 
rd4(fp)889 int rd4(fp)
890 FILE *fp;
891 {
892     register int i = rd2(fp) << 16;
893 
894     return i | rd2(fp);
895 }
896 
897 
898 /*----------------------------------------------------------------------------*
899  | Routine:	getfontdata ( font, size )
900  |
901  | Results:	returns the family number of the font/size found.  If the
902  |		particular point size requested is not found, other sizes are
903  |		searched for.  The font information pointer, fs, is set to
904  |		point to data for "font" at point size "size".  If no infor-
905  |		mation for that font is available, the info is read in from
906  |		the appropriate font file.  The table "fontdata" holds all the
907  |		fonts, and it is cleared of a random font/size if necessary.
908  *----------------------------------------------------------------------------*/
909 
getfontdata(f,s)910 int getfontdata(f, s)
911 int f;
912 int s;
913 {
914 	char name[100];
915 	register FILE *fd;
916 	register int i;
917 	register int fam;
918 	register int bitbase;
919 	register glyph_dir *maxgp;
920 	register glyph_dir *gp;
921 	preamble p;
922 
923 				/* first check if it's here already */
924 	for (fam = 0; fam <= NFONT; fam++)
925 	    if (fontdata[fam].font == f && fontdata[fam].size == s) {
926 		fs = &fontdata[fam];
927 		return (fam);
928 	    }
929 						/* find an empty slot */
930 	for (fam = 0; fam < NFONT && fontdata[fam].font != -1; fam++);
931 	fs = &fontdata[fam];
932 	if (fs->font != -1) {		/* clear a slot if not empty */
933 		clearglyphs(fam, 1000);		/* dumb version - always take */
934 		putc(AFORCE, tf);		/* the last one to replace */
935 		free(fs->glyph);
936 		free(fs->cdp);
937 	}
938 
939 	bitbase = s;
940 			/* try to open font file - if unsuccessful, hunt for */
941 			/* a file of same style, different size to substitute */
942 	i = -1;	 /* direction to look in pstab (smaller first) */
943 	do {
944 	    sprintf(name, "%s/%s.%d", bitdir, fontname[f], pstab[bitbase]);
945 	    fd = fopen(name, "r");
946 	    if (fd == NULL) {		/* File wasn't found. Try another ps */
947 		bitbase += i;
948 		if (bitbase < 0) {	/* past beginning - look higher */
949 		    i = 1;
950 		    bitbase = s + i;
951 		}
952 		if (bitbase > nsizes)	/* past top - forget it */
953 		    i = 0;
954 	    }
955 	} while (fd == NULL && i != 0);
956 
957 	if (fd == NULL)			/* completely unsuccessful */
958 		error(FATAL,"can't open %s/%s.%d",bitdir,fontname[f],pstab[s]);
959 						/* check for proper file mark */
960 	for(i = 0; i < FMARK; filemark[i++] = getc(fd));
961 	if (strncmp(filemark, "Rast", 4))
962 		error(FATAL, "bad File Mark in %s.", name);
963 					/* get preamble */
964 	p.p_size = rd2(fd);
965 	p.p_version = rd1(fd);
966 	if (p.p_version)
967 		error(FATAL, "wrong version of Font file: %s.", name);
968 	p.p_glyph = rd3(fd);
969 	fs->first = p.p_first = rd2(fd);
970 	fs->last = p.p_last = rd2(fd);
971 				/* skip rest of preamble */
972 	i = p.p_glyph - 18;
973 	while (i--) getc(fd);
974 	fs->glyph = (glyph_dir *)	/* allocate first */
975 		((char *) malloc((p.p_last - p.p_first + 1) * sizeof(glyph_dir))
976 		- (char *) (p.p_first * sizeof(glyph_dir)));
977 	maxgp = gp = &(fs->glyph[p.p_first]);
978 	bitbase = maxgp->g_bitp;
979 	for (i = p.p_first; i++ <= p.p_last; gp++) {
980 	    gp->g_height = rd2(fd);
981 	    gp->g_width = rd2(fd);
982 	    gp->g_up = rd2(fd);
983 	    gp->g_left = rd2(fd);
984 	    gp->g_pwidth = rd4(fd);
985 	    if ((gp->g_bitp = rd3(fd)) > maxgp->g_bitp)	/* find the glyphs */
986 		maxgp = gp;				/* farthest from and */
987 	    else if(gp->g_bitp < bitbase)		/* nearest to the */
988 		bitbase = gp->g_bitp;			/* start of the file */
989 	}
990 					/* remove file offset in bit pointers */
991 	for (gp = fs->glyph, i = p.p_first; i++ <= p.p_last; gp++)
992 	    gp->g_bitp -= bitbase;
993 
994 	i = maxgp->g_bitp + maxgp->g_height * ((maxgp->g_width + 7) / 8);
995 	fs->cdp = (unsigned char *) malloc(i);
996 	lseek(fileno(fd), (long) bitbase, 0);
997 	if (read(fileno (fd), fs->cdp, i) != i)
998 		error(FATAL, "can't read in %s", name);
999 	fclose(fd);
1000 
1001 	fs->size = s;
1002 	fs->font = f;
1003 	for (i = 0; i < CHARRAY; fs->chused[i++] = 0);
1004 	return (fam);
1005 }
1006 
1007 
1008 /*----------------------------------------------------------------------------*
1009  | Routine:	setfill(stipple_number)
1010  |
1011  | Results:	sends the appropriate command to set the fill-pattern
1012  |		for a particular stipple.  Sends the glyph if necessary,
1013  |		and does nothing if the pattern is the same.  Takes stipple
1014  |		font from current "stip" number.
1015  *----------------------------------------------------------------------------*/
1016 
setfill(number)1017 setfill(number)
1018 register int number;
1019 {
1020 	register int fam;
1021 	register int gsize;
1022 	register glyph_dir *par;
1023 	register unsigned char *p;
1024 	register fontset *savefs;
1025 
1026 	if (stip == laststip && number == laststipmem)
1027 		return;
1028 
1029 	savefs = fs;			/* getfontdata sets fs, so we have to */
1030 					/* save it before calling getfontdata */
1031 	fam = getfontdata(nfonts + stip, nsizes);
1032 	laststip = stip;
1033 	laststipmem = number;		/* must be set before call to polygon */
1034 
1035 	if (!number || number < fs->first || number > fs->last) {
1036 nostipbits:
1037 		fs = savefs;		/* forget it if it's out of range */
1038 		laststipmem = 0;	/* force NO stipple */
1039 		return;
1040 	}
1041 	if (fs->chused[number] == 0) {		/* stipple not down-loaded */
1042 		par = &(fs->glyph[number]);
1043 		if (!par->g_bitp)
1044 		    goto nostipbits;
1045 		totglyph += glspace(par);
1046 		putc(ABGLY, tf);
1047 		putint((fam << 7) | number, tf);
1048  		putint(par->g_pwidth, tf);
1049 		putint(par->g_width, tf);
1050 		putint(par->g_left, tf);
1051 		putint(par->g_height, tf);
1052 		putint(par->g_up, tf);
1053 		gsize = ((par->g_width + 7)/8) * par->g_height;
1054 		p = fs->cdp + par->g_bitp;
1055 		while (gsize--)
1056 			putc(*p++, tf);
1057 	}
1058 						/* mark that it's been used */
1059 	if (fs->chused[number] != BMASK)
1060 		fs->chused[number]++;
1061 	putc(ASTEXTURE, tf);			/* set the texture */
1062 	putint((fam << 7) | number, tf);
1063 	fs = savefs;				/* return fs to proper spot */
1064 }
1065 
1066 
xychar(c)1067 xychar(c)
1068 register int c;
1069 {
1070 	register unsigned char *p;
1071 	register glyph_dir *par;
1072 	register int gsize;
1073 
1074 
1075 	if (c >= CHARRAY) {
1076 #ifdef DEBUGABLE
1077 		if (dbg) error(!FATAL, "character out of range: %d 0%o", c, c);
1078 #endif
1079 		return;
1080 	}
1081 	if (font != lastfont || size != lastsize) {
1082 		family = getfontdata(font, size);
1083 		lastsize = size;
1084 		lastfont = font;
1085 	}
1086 	par = &(fs->glyph[c]);
1087 	p = fs->cdp + par->g_bitp;
1088 	if (family != lastfam) {
1089 		putc(AF, tf);
1090 		putc(lastfam = family ,tf);
1091 	}
1092 
1093 	if (fs->chused[c] == 0) {	/* 1st use of this character */
1094 		totglyph += glspace(par);
1095 		putc(ABGLY, tf);
1096 		putint((family << 7) | c, tf);
1097  		putint(lastw, tf);		/* use troff's width, not */
1098 		putint(par->g_width, tf);	/* the RST character width */
1099 		putint(par->g_left, tf);
1100 		putint(par->g_height, tf);
1101 		putint(par->g_up, tf);
1102 		gsize = ((par->g_width + 7)/8) * par->g_height;
1103 		while (gsize--)
1104 			putc(*p++, tf);
1105 	}
1106 					/* note that character's been used */
1107 	if (fs->chused[c] != BMASK)
1108 		fs->chused[c]++;
1109 	hvflush();
1110 	putc(c, tf);		/* guaranteed to be in range */
1111 	lastx += lastw;		/* take account of the automatic advance */
1112 }
1113 
1114 
1115 /*----------------------------------------------------------------------------*
1116  | Routine:	hvflush ( )
1117  |
1118  | Results:	force current position (hpos, vpos) on the imagen
1119  *----------------------------------------------------------------------------*/
1120 
hvflush()1121 hvflush()
1122 {
1123 	if (vpos != lasty) {
1124 		putc(ASETV, tf);
1125 		putint(lasty = vpos, tf);
1126 	}
1127 	if (hpos != lastx) {
1128 		putc(ASETH, tf);
1129 		putint(lastx = hpos, tf);
1130 	}
1131 }
1132 
1133 
1134 /*----------------------------------------------------------------------------*
1135  | Routine:	glspace ( glyph )
1136  |
1137  | Results:	returns how much space the glyph (defined by the glyph_dir
1138  |		entry) will take in the imagen's memory.
1139  *----------------------------------------------------------------------------*/
1140 
glspace(par)1141 glspace(par)
1142 glyph_dir *par;
1143 {
1144 	return 19 + ((par->g_width + 15) / 16 ) * (par->g_height);
1145 }
1146 
1147 
1148 /*----------------------------------------------------------------------------*
1149  | Routine:	clearglyphs ( index, limit )
1150  |
1151  | Results:	any glyphs downloaded into the imagen with a "chused" entry
1152  |		less than "limit" (and > 0) are marked for deletion and their
1153  |		space is "unrecorded" in totglyph.
1154  |
1155  | Bugs:	clearglyphs does NOT check index to make sure the family exists
1156  *----------------------------------------------------------------------------*/
1157 
clearglyphs(index,limit)1158 clearglyphs(index, limit)
1159 int index;
1160 int limit;
1161 {
1162 	register fontset *f = &fontdata[index];
1163 	register int j;
1164 
1165 #ifdef DEBUGABLE
1166 	if (dbg) fprintf(stderr, "clear %d family of %d (%d/%d) on page %d\n",
1167 			index, limit, totglyph, maxglyph, pageno);
1168 #endif
1169 	for (j = 0; j < CHARRAY; j++) {
1170 		if (f->chused[j] && f->chused[j] < limit) {
1171 			putc(ADELG, tf);
1172 			putint(index<<7 | j, tf);
1173 			totglyph -= glspace (&(f->glyph[j]));
1174 			f->chused[j] = 0;
1175 		}
1176 	}
1177 }
1178 
1179 
putint(n,f)1180 putint(n, f)
1181 int n;
1182 FILE *f;
1183 {
1184 	putc(n >> 8, f);
1185 	putc(n & 0377, f);
1186 }
1187