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