xref: /csrg-svn/old/vfilters/rvcat/rvcat.c (revision 33682)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #ifndef lint
14 char copyright[] =
15 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
16  All rights reserved.\n";
17 #endif /* not lint */
18 
19 #ifndef lint
20 static char sccsid[] = "@(#)rvcat.c	5.3 (Berkeley) 03/08/88";
21 #endif /* not lint */
22 
23 /*
24  * Cat Simulator for Versatec and Varian
25  * Modified for Varian with rotated fonts: wnj 5/30/80.
26  *
27  * Takes two extra special codes defined by rvsort:
28  *	0115 - break for new page, goto (0,0)
29  *	0116 - lead 64* following byte
30  */
31 
32 #include <stdio.h>
33 #include <sys/vcmd.h>
34 #include <vfont.h>
35 
36 int	prtmode[] = {VPRINT};
37 int	pltmode[] = {VPLOT};
38 
39 #define DISPATCHSIZE		256	/* must be a power of two */
40 #define CHARMASK		(DISPATCHSIZE-1)
41 #define NFONTS			25
42 #define SPECIALFONT		3
43 #define DSIZ			((sizeof *dispatch)*DISPATCHSIZE)
44 #define MAXF			4
45 
46 #define LOCAL_RAILMAG		".railmag"
47 #define GLOBAL_RAILMAG		"/usr/lib/vfont/railmag"
48 
49 /*
50  * Here we make up for the fact that we only have 2112
51  * bits vertically when we need 2200 (11''*200/in), by
52  * a 4% vertical size squashing.
53  */
54 #define CONVERT(n)		((n*(200./432.))*(2112./2200.))
55 #define RECONVERT(n)		((n*(432./200.))*(2200./2112.))
56 
57 #define NLINES			110
58 
59 #define	FF_LINES		1600	/* Scan lines to output before formfeeding. */
60 
61 #define	min(a,b)		(a<b ? a : b)
62 
63 char	buffer[NLINES * 264];	/* Big enough for varain */
64 char	*buf0p = &buffer[0];	/* Zero origin in circular buffer */
65 
66 char	*calloc();
67 char	*nalloc();
68 char	*allpanic();
69 
70 struct	header	header;
71 struct dispatch *dispatch;
72 
73 struct	fontdes {
74 	int	fnum;
75 	int	psize;
76 	struct	dispatch *disp;
77 	char	*bits;
78 } fontdes[NFONTS] = {
79 	-1,
80 	-1
81 };
82 
83 struct point_sizes {
84 	int	stupid_code;
85 	int	real_code;
86 } point_sizes[] = {
87 	010, 6,
88 	0, 7,
89 	01, 8,
90 	07, 9,
91 	02, 10,
92 	03, 11,
93 	04, 12,
94 	05, 14,
95 	0211, 16,
96 	06, 18,
97 	0212, 20,
98 	0213, 22,
99 	0214, 24,
100 	0215, 28,
101 	0216, 36,
102 	0, 0
103 };
104 
105 int	lines;
106 
107 int	vc = 1;			/* varian/versatec output file descriptor */
108 int	varian = 1;		/* 0 for versatec, 1 for varian. */
109 int	BYTES_PER_LINE = 264;	/* number of bytes per raster line. */
110 int	PAGE_LINES = 1700;	/* number of raster lines per page. */
111 int	BUFFER_SIZE = NLINES * 264;	/* buffer size. */
112 int	cfnum = -1;
113 int	cpsize = 10;
114 int	cfont = 1;
115 char	*bits;
116 int	nfontnum = -1;
117 int	fontwanted = 1;
118 int	npsize = 10;
119 int	last_ssize = 02;
120 int	xpos, ypos;
121 int	esc, lead, back, verd, mcase, railmag;
122 double	row, col;
123 char	*fontname[MAXF];
124 char	fnbuf[120];
125 char	*scanline;
126 int	linecount;
127 
128 char	asctab[128] = {
129 	'\0',	/*blank*/
130 	'h',	/*h*/
131 	't',	/*t*/
132 	'n',	/*n*/
133 	'm',	/*m*/
134 	'l',	/*l*/
135 	'i',	/*i*/
136 	'z',	/*z*/
137 	's',	/*s*/
138 	'd',	/*d*/
139 	'b',	/*b*/
140 	'x',	/*x*/
141 	'f',	/*f*/
142 	'j',	/*j*/
143 	'u',	/*u*/
144 	'k',	/*k*/
145 	'\0',	/*blank*/
146 	'p',	/*p*/
147 	'\06',	/*_ 3/4 em dash*/
148 	';',	/*;*/
149 	'\0',	/*blank*/
150 	'a',	/*a*/
151 	'\05',	/*rule*/
152 	'c',	/*c*/
153 	'`',	/*` open*/
154 	'e',	/*e*/
155 	'\'',	/*' close*/
156 	'o',	/*o*/
157 	'\021',	/*1/4*/
158 	'r',	/*r*/
159 	'\022',	/*1/2*/
160 	'v',	/*v*/
161 	'-',	/*- hyphen*/
162 	'w',	/*w*/
163 	'q',	/*q*/
164 	'/',	/*/*/
165 	'.',	/*.*/
166 	'g',	/*g*/
167 	'\023',	/*3/4*/
168 	',',	/*,*/
169 	'&',	/*&*/
170 	'y',	/*y*/
171 	'\0',	/*blank*/
172 	'%',	/*%*/
173 	'\0',	/*blank*/
174 	'Q',	/*Q*/
175 	'T',	/*T*/
176 	'O',	/*O*/
177 	'H',	/*H*/
178 	'N',	/*N*/
179 	'M',	/*M*/
180 	'L',	/*L*/
181 	'R',	/*R*/
182 	'G',	/*G*/
183 	'I',	/*I*/
184 	'P',	/*P*/
185 	'C',	/*C*/
186 	'V',	/*V*/
187 	'E',	/*E*/
188 	'Z',	/*Z*/
189 	'D',	/*D*/
190 	'B',	/*B*/
191 	'S',	/*S*/
192 	'Y',	/*Y*/
193 	'\0',	/*blank*/
194 	'F',	/*F*/
195 	'X',	/*X*/
196 	'A',	/*A*/
197 	'W',	/*W*/
198 	'J',	/*J*/
199 	'U',	/*U*/
200 	'K',	/*K*/
201 	'0',	/*0*/
202 	'1',	/*1*/
203 	'2',	/*2*/
204 	'3',	/*3*/
205 	'4',	/*4*/
206 	'5',	/*5*/
207 	'6',	/*6*/
208 	'7',	/*7*/
209 	'8',	/*8*/
210 	'9',	/*9*/
211 	'*',	/***/
212 	'\04',	/*minus*/
213 	'\01',	/*fi*/
214 	'\02',	/*fl*/
215 	'\03',	/*ff*/
216 	'\020',	/* cent sign */
217 	'\012',	/*ffl*/
218 	'\011',	/*ffi*/
219 	'(',	/*(*/
220 	')',	/*)*/
221 	'[',	/*[*/
222 	']',	/*]*/
223 	'\013',	/* degree */
224 	'\014',	/* dagger */
225 	'=',	/*=*/
226 	'\017',	/* registered */
227 	':',	/*:*/
228 	'+',	/*+*/
229 	'\0',	/*blank*/
230 	'!',	/*!*/
231 	'\07',	/* bullet */
232 	'?',	/*?*/
233 	'\015',	/*foot mark*/
234 	'|',	/*|*/
235 	'\0',	/*blank*/
236 	'\016',	/* copyright */
237 	'\010',	/* square */
238 	'$',	/*$*/
239 	'\0',
240 	'\0',
241 	'"',	/*"*/
242 	'#',	/*#*/
243 	'<',	/*<*/
244 	'>',	/*>*/
245 	'@',	/*@*/
246 	'\\',	/*\\*/
247 	'^',	/*^*/
248 	'{',	/*{*/
249 	'}',	/*}*/
250 	'~'	/*~*/
251 };
252 
253 char spectab[128] = {
254 	'\0',	/*blank*/
255 	'w',	/*psi*/
256 	'h',	/*theta*/
257 	'm',	/*nu*/
258 	'l',	/*mu*/
259 	'k',	/*lambda*/
260 	'i',	/*iota*/
261 	'f',	/*zeta*/
262 	'r',	/*sigma*/
263 	'd',	/*delta*/
264 	'b',	/*beta*/
265 	'n',	/*xi*/
266 	'g',	/*eta*/
267 	'u',	/*phi*/
268 	't',	/*upsilon*/
269 	'j',	/*kappa*/
270 	'\0',	/*blank*/
271 	'p',	/*pi*/
272 	'@',	/*at-sign*/
273 	'7',	/*down arrow*/
274 	'\0',	/*blank*/
275 	'a',	/*alpha*/
276 	'|',	/*or*/
277 	'v',	/*chi*/
278 	'"',	/*"*/
279 	'e',	/*epsilon*/
280 	'=',	/*=*/
281 	'o',	/*omicron*/
282 	'4',	/*left arrow*/
283 	'q',	/*rho*/
284 	'6',	/*up arrow*/
285 	's',	/*tau*/
286 	'_',	/*underrule*/
287 	'\\',	/*\*/
288 	'W',	/*Psi*/
289 	'\07',	/*bell system sign*/
290 	'\001',	/*infinity*/
291 	'c',	/*gamma*/
292 	'\002',	/*improper superset*/
293 	'\003',	/*proportional to*/
294 	'\004',	/*right hand*/
295 	'x',	/*omega*/
296 	'\0',	/*blank*/
297 	'(',	/*gradient*/
298 	'\0',	/*blank*/
299 	'U',	/*Phi*/
300 	'H',	/*Theta*/
301 	'X',	/*Omega*/
302 	'\005',	/*cup (union)*/
303 	'\006',	/*root en*/
304 	'\014',	/*terminal sigma*/
305 	'K',	/*Lambda*/
306 	'-',	/*minus*/
307 	'C',	/*Gamma*/
308 	'\015',	/*integral sign*/
309 	'P',	/*Pi*/
310 	'\032',	/*subset of*/
311 	'\033',	/*superset of*/
312 	'2',	/*approximates*/
313 	'y',	/*partial derivative*/
314 	'D',	/*Delta*/
315 	'\013',	/*square root*/
316 	'R',	/*Sigma*/
317 	'1',	/*approx =*/
318 	'\0',	/*blank*/
319 	'>',	/*>*/
320 	'N',	/*Xi*/
321 	'<',	/*<*/
322 	'\016',	/*slash (longer)*/
323 	'\034',	/*cap (intersection)*/
324 	'T',	/*Upsilon*/
325 	'\035',	/*not*/
326 	'\023',	/*right ceiling (rt of ")*/
327 	'\024',	/*left top (of big curly)*/
328 	'\017',	/*bold vertical*/
329 	'\030',	/*left center of big curly bracket*/
330 	'\025',	/*left bottom*/
331 	'\026',	/*right top*/
332 	'\031',	/*right center of big curly bracket*/
333 	'\027',	/*right bot*/
334 	'\021',	/*right floor (rb of ")*/
335 	'\020',	/*left floor (left bot of big sq bract)*/
336 	'\022',	/*left ceiling (lt of ")*/
337 	'*',	/*multiply*/
338 	'/',	/*divide*/
339 	'\010',	/*plus-minus*/
340 	'\011',	/*<=*/
341 	'\012',	/*>=*/
342 	'0',	/*identically equal*/
343 	'3',	/*not equal*/
344 	'{',	/*{*/
345 	'}',	/*}*/
346 	'\'',	/*' acute accent*/
347 	'\`',	/*` grave accent*/
348 	'^',	/*^*/
349 	'#',	/*sharp*/
350 	'\036',	/*left hand*/
351 	'\037',	/*member of*/
352 	'~',	/*~*/
353 	'z',	/*empty set*/
354 	'\0',	/*blank*/
355 	'Y',	/*dbl dagger*/
356 	'Z',	/*box rule*/
357 	'9',	/*asterisk*/
358 	'[',	/*improper subset*/
359 	']',	/*circle*/
360 	'\0',	/*blank*/
361 	'+',	/*eqn plus*/
362 	'5',	/*right arrow*/
363 	'8'	/*section mark*/
364 };
365 
366 main(argc, argv)
367 	int argc;
368 	char *argv[];
369 {
370 	char *namearg = NULL;
371 	char *hostarg = NULL;
372 	char *acctfile = NULL;
373 
374 	while (--argc) {
375 		if (*(*++argv) == '-')
376 			switch (argv[0][1]) {
377 			case 'x':
378 				BYTES_PER_LINE = atoi(&argv[0][2]) / 8;
379 				BUFFER_SIZE = NLINES * BYTES_PER_LINE;
380 				break;
381 
382 			case 'y':
383 				PAGE_LINES = atoi(&argv[0][2]);
384 				break;
385 
386 			case 'n':
387 				if (argc > 1) {
388 					argc--;
389 					namearg = *++argv;
390 				}
391 				break;
392 
393 			case 'h':
394 				if (argc > 1) {
395 					argc--;
396 					hostarg = *++argv;
397 				}
398 				break;
399 			}
400 		else
401 			acctfile = *argv;
402 	}
403 	ioctl(vc, VSETSTATE, pltmode);
404 	readrm();
405 	ofile();
406 	ioctl(vc, VSETSTATE, prtmode);
407 	if (varian)
408 		write(vc, "\f", 2);
409 	else
410 		write(vc, "\n\n\n\n\n", 6);
411 	account(namearg, hostarg, acctfile);
412 	exit(0);
413 }
414 
415 readrm()
416 {
417 	register int i;
418 	register char *cp;
419 	register int rmfd;
420 	char c;
421 
422 	if ((rmfd = open(LOCAL_RAILMAG, 0)) < 0)
423 		if ((rmfd = open(GLOBAL_RAILMAG, 0)) < 0) {
424 			fprintf(stderr, "rvcat: No railmag file\n");
425 			exit(2);
426 		}
427 	cp = fnbuf;
428 	for (i = 0; i < MAXF; i++) {
429 		fontname[i] = cp;
430 		while (read(rmfd, &c, 1) == 1 && c != '\n')
431 			*cp++ = c;
432 		*cp++ = '\0';
433 	}
434 	close(rmfd);
435 }
436 
437 ofile()
438 {
439 	register int c;
440 	register int i;
441 	double scol;
442 	static int initialized;
443 
444 	lines = 0;
445 	while ((c = getchar()) != EOF) {
446 		if (!c)
447 			continue;
448 		if (c & 0200) {
449 			esc += (~c) & 0177;
450 			continue;
451 		}
452 		if (esc) {
453 			if (back)
454 				esc = -esc;
455 			col += esc;
456 			esc = 0;
457 			i = CONVERT(col);
458 			while (i >= NLINES) {
459 				slop_lines(15);
460 				i = CONVERT(col);
461 			}
462 			ypos = i;
463 		}
464 		if ((c & 0377) < 0100)	/*  Purely for efficiency  */
465 			goto normal_char;
466 		switch (c) {
467 
468 		case 0100:
469 			esc = 0;
470 			lead = 0;
471 			linecount = 0;
472 			verd = 0;
473 			back = 0;
474 			mcase = 0;
475 			railmag = 0;
476 			if (loadfont(railmag, cpsize) < 0)
477 				fprintf(stderr, "rvcat: Can't load initial font\n");
478 			if (initialized)
479 				goto reset;
480 			initialized = 1;
481 			row = 0;
482 			xpos = CONVERT(row);
483 			for (c = 0; c < BUFFER_SIZE; c++)
484 				buffer[c] = 0;
485 			col = 0;
486 			ypos = 0;
487 			break;
488 
489 		case 0101:	/* lower rail */
490 			crail(railmag &= ~01);
491 			break;
492 
493 		case 0102:	/* upper rail */
494 			crail(railmag |= 01);
495 			break;
496 
497 		case 0103:	/* upper mag */
498 			crail(railmag |= 02);
499 			break;
500 
501 		case 0104:	/* lower mag */
502 			crail(railmag &= ~02);
503 			break;
504 
505 		case 0105:	/* lower case */
506 			mcase = 0;
507 			break;
508 
509 		case 0106:	/* upper case */
510 			mcase = 0100;
511 			break;
512 
513 		case 0107:	/* escape forward */
514 			back = 0;
515 			break;
516 
517 		case 0110:	/* escape backwards */
518 			back = 1;
519 			break;
520 
521 		case 0111:	/* stop */
522 			break;
523 
524 		case 0112:	/* lead forward */
525 			verd = 0;
526 			break;
527 
528 		case 0113:	/* undefined */
529 			break;
530 
531 		case 0114:	/* lead backward */
532 			verd = 1;
533 			break;
534 
535 		case 0115:	/* undefined */
536 reset:
537 			c = lines % PAGE_LINES;
538 			while (c < FF_LINES) {
539 				slop_lines(min(FF_LINES - c, NLINES));
540 				c = lines % PAGE_LINES;
541 			}
542 			new_page(PAGE_LINES - c);
543 			break;
544 
545 		case 0116:
546 			lead = (getchar() & 0377) * 64;
547 			goto leadin;
548 
549 		case 0117:
550 			break;
551 
552 		default:
553 			if ((c & 0340) == 0140)	/* leading */ {
554 				lead = (~c) & 037;
555 leadin:
556 				if (verd)
557 					lead = -lead;
558 				row += lead*3;	/*  Lead is 3 units  */
559 				xpos = CONVERT(row);
560 				continue;
561 			}
562 			if ((c & 0360) == 0120)	/* size change */ {
563 				loadfont(railmag, findsize(c & 017));
564 				continue;
565 			}
566 			if (c & 0300)
567 				continue;
568 
569 normal_char:
570 			if (row < 0 || CONVERT(row) >= BYTES_PER_LINE * 8)
571 				continue;
572 			c = (c & 077) | mcase;
573 			outc(c);
574 		}
575 	}
576 out:
577 	slop_lines(NLINES);
578 }
579 
580 findsize(code)
581 	register int code;
582 {
583 	register struct point_sizes *psp;
584 
585 	psp = point_sizes;
586 	while (psp->real_code != 0) {
587 		if ((psp->stupid_code & 017) == code)
588 			break;
589 		psp++;
590 	}
591 	code = 0;
592 	if (!(last_ssize & 0200) && (psp->stupid_code & 0200))
593 		code = -55;
594 	else if ((last_ssize & 0200) && !(psp->stupid_code & 0200))
595 		code = 55;
596 	if (back)
597 		code = -code;
598 	esc += code;
599 	last_ssize = psp->stupid_code;
600 	return(psp->real_code);
601 }
602 
603 account(who, from, acctfile)
604 	char *who, *from, *acctfile;
605 {
606 	register FILE *a;
607 
608 	if (who == NULL || acctfile == NULL)
609 		return;
610 	if (access(acctfile, 02) || (a = fopen(acctfile, "a")) == NULL)
611 		return;
612 	/*
613 	 * Varian accounting is done by 8.5 inch pages;
614 	 * Versatec accounting is by the (12 inch) foot.
615 	 */
616 	fprintf(a, "t%6.2f\t", (double)lines / (double)PAGE_LINES);
617 	if (from != NULL)
618 		fprintf(a, "%s:", from);
619 	fprintf(a, "%s\n", who);
620 	fclose(a);
621 }
622 
623 crail(nrail)
624 	register int nrail;
625 {
626 	register int psize;
627 
628 	psize = cpsize;
629 	if (fontwanted && psize != npsize)
630 		psize = npsize;
631 	loadfont(nrail, psize);
632 }
633 
634 
635 loadfont(fnum, size)
636 	register int fnum;
637 	register int size;
638 {
639 	register int i;
640 	char cbuf[80];
641 
642 	fontwanted = 0;
643 	if (fnum == cfnum && size == cpsize)
644 		return(0);
645 	for (i = 0; i < NFONTS; i++)
646 		if (fontdes[i].fnum == fnum && fontdes[i].psize == size) {
647 			cfnum = fontdes[i].fnum;
648 			cpsize = fontdes[i].psize;
649 			dispatch = &fontdes[i].disp[0];
650 			bits = fontdes[i].bits;
651 			cfont = i;
652 			return(0);
653 		}
654 	if (fnum < 0 || fnum >= MAXF) {
655 		fprintf(stderr, "rvcat: Internal error: illegal font\n");
656 		return(-1);
657 	}
658 	nfontnum = fnum;
659 	npsize = size;
660 	fontwanted++;
661 	return(0);
662 }
663 
664 
665 getfont()
666 {
667 	register int fnum, size, font;
668 	int d;
669 	char cbuf[BUFSIZ];
670 	char *cp = cbuf;
671 	char *dp;
672 
673 	if (!fontwanted)
674 		return(0);
675 	fnum = nfontnum;
676 	size = npsize;
677 	sprintf(cbuf, "%s.%dr", fontname[fnum], size);
678 	font = open(cbuf, 0);
679 	if (font == -1) {
680 		fprintf(stderr, "rvcat: ");
681 		perror(cbuf);
682 		fontwanted = 0;
683 		return(-1);
684 	}
685 	if (read(font, &header, sizeof header)!=sizeof header || header.magic!=0436)
686 		fprintf(stderr, "rvcat: %s: Bad font file", cbuf);
687 	else {
688 		cfont = relfont();
689 		if (((bits=nalloc(header.size+DSIZ+1,1))== NULL)
690 			&& ((bits=allpanic(header.size+DSIZ+1))== NULL)) {
691 				fprintf(stderr, "rvcat: %s: ran out of memory\n", cbuf);
692 				exit(2);
693 		} else {
694 			/*
695 			 * have allocated one chunk of mem for font, dispatch.
696 			 * get the dispatch addr, align to word boundary.
697 			 */
698 			d = (int) bits+header.size;
699 			d += 1;
700 			d &= ~1;
701 			if (read(font, d, DSIZ)!=DSIZ
702 			  || read(font, bits, header.size)!=header.size)
703 				fprintf(stderr, "rvcat: bad font header");
704 			else {
705 				close(font);
706 				cfnum = fontdes[cfont].fnum = fnum;
707 				cpsize = fontdes[cfont].psize = size;
708 				fontdes[cfont].bits = bits;
709 				fontdes[cfont].disp = (struct dispatch *) d;
710 				dispatch = &fontdes[cfont].disp[0];
711 				fontwanted = 0;
712 				return(0);
713 			}
714 		}
715 	}
716 	close(font);
717 	fontwanted = 0;
718 	return(-1);
719 }
720 
721 int lastloaded = -1;
722 
723 relfont()
724 {
725 	register int newfont;
726 
727 	newfont = lastloaded;
728 	/*
729 	 * optimization for special font.  since we think that usually
730 	 * there is only one character at a time from any special math
731 	 * font, make it the candidate for removal.
732 	 */
733 	if (fontdes[cfont].fnum != SPECIALFONT || fontdes[cfont].bits==0)
734 		if (++newfont>=NFONTS)
735 			newfont = 0;
736 	lastloaded = newfont;
737 	if ((int)fontdes[newfont].bits != -1 && fontdes[newfont].bits != 0)
738 		nfree(fontdes[newfont].bits);
739 	fontdes[newfont].bits = 0;
740 	return(newfont);
741 }
742 
743 char *
744 allpanic(nbytes)
745 	int nbytes;
746 {
747 	register int i;
748 
749 	for (i = 0; i <= NFONTS; i++)
750 		if (fontdes[i].bits != (char *)-1 && fontdes[i].bits != (char *)0)
751 			nfree(fontdes[i].bits);
752 	lastloaded = cfont;
753 	for (i = 0; i <= NFONTS; i++) {
754 		fontdes[i].fnum = fontdes[i].psize = -1;
755 		fontdes[i].bits = 0;
756 		cfnum = cpsize = -1;
757 	}
758 	return(nalloc(nbytes,1));
759 }
760 
761 int	M[] = { 0xffffffff, 0xfefefefe, 0xfcfcfcfc, 0xf8f8f8f8,
762 		0xf0f0f0f0, 0xe0e0e0e0, 0xc0c0c0c0, 0x80808080, 0x0 };
763 int	N[] = { 0x00000000, 0x01010101, 0x03030303, 0x07070707,
764 		0x0f0f0f0f, 0x1f1f1f1f, 0x3f3f3f3f, 0x7f7f7f7f, 0xffffffff };
765 int	strim[] = { 0xffffffff, 0xffffff00, 0xffff0000, 0xff000000, 0 };
766 
767 outc(code)
768 	int code;
769 {
770 	char c;				/* character to print */
771 	register struct dispatch *d;	/* ptr to character font record */
772 	register char *addr;		/* addr of font data */
773 	int llen;			/* length of each font line */
774 	int nlines;			/* number of font lines */
775 	register char *scanp;		/* ptr to output buffer */
776 	int scanp_inc;			/* increment to start of next buffer */
777 	int offset;			/* bit offset to start of font data */
778 	int i;				/* loop counter */
779 	register int count;		/* font data ptr */
780 	register unsigned fontdata;	/* font data temporary */
781 	register int off8;		/* offset + 8 */
782 	int b0poff;			/* bit offset back towards buf0p */
783 
784 	if (fontwanted)
785 		getfont();
786 	if (railmag == SPECIALFONT) {
787 		if ((c = spectab[code]) < 0)
788 			return(0);
789 	} else if ((c = asctab[code]) < 0)
790 		return(0);
791 	d = dispatch+c;
792 	if (d->nbytes) {
793 		addr = bits+d->addr;
794 		llen = (d->down+d->up+7)/8;
795 		nlines = d->left+d->right;
796 		if (ypos+d->right >= NLINES)
797 			slop_lines(ypos+d->right-NLINES+6);
798 		b0poff = BYTES_PER_LINE*8 - 1 - (xpos+d->down);
799 		scanp = ((ypos-d->left-1)*BYTES_PER_LINE+b0poff/8)+buf0p;
800 		if (scanp < &buffer[0])
801 			scanp += BUFFER_SIZE;
802 		scanp_inc = BYTES_PER_LINE-llen;
803 		offset = -(b0poff&07);
804 		off8 = offset+8;
805 		for (i = 0; i < nlines; i++) {
806 			if (scanp >= &buffer[BUFFER_SIZE])
807 				scanp -= BUFFER_SIZE;
808 			count = llen;
809 			if (scanp + count <= &buffer[BUFFER_SIZE])
810 				do {
811 					fontdata = *(unsigned *)addr;
812 					addr += 4;
813 					if (count < 4)
814 						fontdata &= ~strim[count];
815 					*(unsigned *)scanp |= (fontdata << offset) &~ M[off8];
816 					scanp++;
817 					*(unsigned *)scanp |= (fontdata << off8) &~ N[off8];
818 					scanp += 3;
819 					count -= 4;
820 				} while (count > 0);
821 			scanp += scanp_inc+count;
822 			addr += count;
823 		}
824 		return(1);
825 	}
826 	return(0);
827 }
828 
829 slop_lines(ncols)
830 	int ncols;
831 {
832 	register int i, rcols;
833 
834 	lines += ncols;
835 	rcols = (&buffer[BUFFER_SIZE] - buf0p) / BYTES_PER_LINE;
836 	if (rcols < ncols) {
837 		if (write(vc, buf0p, BYTES_PER_LINE * rcols) < 0)
838 			exit(1);
839 		bzero(buf0p, rcols * BYTES_PER_LINE);
840 		buf0p = buffer;
841 		ncols -= rcols;
842 		ypos -= rcols;
843 		col -= RECONVERT(rcols);
844 	}
845 	if (write(vc, buf0p, BYTES_PER_LINE * ncols) < 0)
846 		exit(1);
847 	bzero(buf0p, BYTES_PER_LINE * ncols);
848 	buf0p += BYTES_PER_LINE * ncols;
849 	if (buf0p >= &buffer[BUFFER_SIZE])
850 		buf0p -= BUFFER_SIZE;
851 	ypos -= ncols;
852 	col -= RECONVERT(ncols);
853 }
854 
855 /* Start a new page by formfeeding, resetting buffer and column counters. */
856 new_page(lines_left)
857 	int lines_left;		/* ... on page. */
858 {
859 	lines += lines_left;
860 	buf0p = buffer;		/* Clear out buffer and reset pointers. */
861 	bzero(buf0p, BYTES_PER_LINE * NLINES);
862 	row = 0;
863 	col = 0;
864 	xpos = CONVERT(row);
865 	ypos = 0;
866 	ioctl(vc, VSETSTATE, prtmode);
867 	write (vc, "\f", 2);
868 	ioctl(vc, VSETSTATE, pltmode);
869 }
870 
871 char *
872 nalloc(i, j)
873 	int i, j;
874 {
875 	register char *cp;
876 
877 	cp = calloc(i, j);
878 	return(cp);
879 }
880 
881 nfree(cp)
882 	char *cp;
883 {
884 	free(cp);
885 }
886