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