xref: /illumos-gate/usr/src/cmd/troff/troff.d/ta.c (revision 5e989a96186a37eb528fb7bb4d28a150874ec799)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 /*
43  *	drive hp2621 terminal
44  *	just to see stuff quickly. like troff -a
45  */
46 
47 /*
48 output language from troff:
49 all numbers are character strings
50 
51 sn	size in points
52 fn	font as number from 1-n
53 cx	ascii character x
54 Cxyz	funny char xyz. terminated by white space
55 Hn	go to absolute horizontal position n
56 Vn	go to absolute vertical position n (down is positive)
57 hn	go n units horizontally (relative)
58 vn	ditto vertically
59 nnc	move right nn (exactly 2 digits!), then print c
60 		(this wart is an optimization that shrinks output file size
61 		 about 35% and run-time about 15% while preserving ascii-ness)
62 w	paddable word space - no action needed
63 nb a	end of line (information only -- no action needed)
64 	b = space before line, a = after
65 pn	begin page n
66 #...\n	comment
67 Dt ...\n	draw operation 't':
68 	Dl x y		line from here by x,y
69 	Dc d		circle of diameter d with left side here
70 	De x y		ellipse of axes x,y with left side here
71 	Da x y u v	arc counter-clockwise from here to u,v from center
72 				with center x,y from here
73 	D~ x y x y ...	wiggly line by x,y then x,y ...
74 x ...\n	device control functions:
75 	x i	init
76 	x T s	name of device is s
77 	x r n h v	resolution is n/inch
78 		h = min horizontal motion, v = min vert
79 	x p	pause (can restart)
80 	x s	stop -- done for ever
81 	x t	generate trailer
82 	x f n s	font position n contains font s
83 	x H n	set character height to n
84 	x S n	set character slant to n
85 
86 	Subcommands like "i" are often spelled out like "init".
87 */
88 
89 #include	<stdio.h>
90 #include	<signal.h>
91 #include	<ctype.h>
92 
93 #include "dev.h"
94 #define	NFONT	10
95 
96 int	output	= 0;	/* do we do output at all? */
97 int	nolist	= 0;	/* output page list if > 0 */
98 int	olist[20];	/* pairs of page numbers */
99 
100 int	erase	= 1;
101 float	aspect	= 1.5;	/* default aspect ratio */
102 int	wflag	= 0;	/* wait, looping, for new input if on */
103 void	(*sigint)();
104 void	(*sigquit)();
105 void	done();
106 
107 struct dev dev;
108 struct font *fontbase[NFONT];
109 short	psizes[]	={ 11, 16, 22, 36, 0};	/* approx sizes available */
110 short	*pstab		= psizes;
111 int	nsizes	= 1;
112 int	nfonts;
113 int	smnt;	/* index of first special font */
114 int	nchtab;
115 char	*chname;
116 short	*chtab;
117 char	*fitab[NFONT];
118 char	*widthtab[NFONT];	/* widtab would be a better name */
119 char	*codetab[NFONT];	/* device codes */
120 
121 #define	FATAL	1
122 #define	BMASK	0377
123 int	dbg	= 0;
124 int	res	= 972;		/* input assumed computed according to this resolution */
125 				/* initial value to avoid 0 divide */
126 FILE	*tf	= stdout;	/* output file */
127 char	*fontdir	= "/usr/lib/font";
128 extern char devname[];
129 
130 FILE *fp = stdin;	/* input file pointer */
131 
132 int	nowait = 0;	/* 0 => wait at bottom of each page */
133 
134 int
135 main(int argc, char **argv)
136 {
137 	char buf[BUFSIZ];
138 
139 	setbuf(stdout, buf);
140 	while (argc > 1 && argv[1][0] == '-') {
141 		switch (argv[1][1]) {
142 		case 'a':
143 			aspect = atof(&argv[1][2]);
144 			break;
145 		case 'e':
146 			erase = 0;
147 			break;
148 		case 'o':
149 			outlist(&argv[1][2]);
150 			break;
151 		case 'd':
152 			dbg = atoi(&argv[1][2]);
153 			if (dbg == 0) dbg = 1;
154 			break;
155 		case 'w':	/* no wait at bottom of page */
156 			nowait = 1;
157 			break;
158 		}
159 		argc--;
160 		argv++;
161 	}
162 
163 	if (argc <= 1)
164 		conv(stdin);
165 	else
166 		while (--argc > 0) {
167 			if (strcmp(*++argv, "-") == 0)
168 				fp = stdin;
169 			else if ((fp = fopen(*argv, "r")) == NULL)
170 				error(FATAL, "can't open %s", *argv);
171 			conv(fp);
172 			fclose(fp);
173 		}
174 	done();
175 
176 	return (0);
177 }
178 
179 int
180 outlist(s)	/* process list of page numbers to be printed */
181 char *s;
182 {
183 	int n1, n2, i;
184 
185 	nolist = 0;
186 	while (*s) {
187 		n1 = 0;
188 		if (isdigit((unsigned char)*s))
189 			do
190 				n1 = 10 * n1 + *s++ - '0';
191 			while (isdigit((unsigned char)*s));
192 		else
193 			n1 = -9999;
194 		n2 = n1;
195 		if (*s == '-') {
196 			s++;
197 			n2 = 0;
198 			if (isdigit((unsigned char)*s))
199 				do
200 					n2 = 10 * n2 + *s++ - '0';
201 				while (isdigit((unsigned char)*s));
202 			else
203 				n2 = 9999;
204 		}
205 		olist[nolist++] = n1;
206 		olist[nolist++] = n2;
207 		if (*s != '\0')
208 			s++;
209 	}
210 	olist[nolist] = 0;
211 	if (dbg)
212 		for (i=0; i<nolist; i += 2)
213 			printf("%3d %3d\n", olist[i], olist[i+1]);
214 
215 	return (0);
216 }
217 
218 int
219 in_olist(n)	/* is n in olist? */
220 int n;
221 {
222 	int i;
223 
224 	if (nolist == 0)
225 		return(1);	/* everything is included */
226 	for (i = 0; i < nolist; i += 2)
227 		if (n >= olist[i] && n <= olist[i+1])
228 			return(1);
229 	return(0);
230 }
231 
232 int
233 conv(fp)
234 FILE *fp;
235 {
236 	int c, k;
237 	int m, n, i, n1, m1;
238 	char str[100], buf[300];
239 
240 	while ((c = getc(fp)) != EOF) {
241 		switch (c) {
242 		case '\n':	/* when input is text */
243 		case ' ':
244 		case 0:		/* occasional noise creeps in */
245 			break;
246 		case '{':	/* push down current environment */
247 			t_push();
248 			break;
249 		case '}':
250 			t_pop();
251 			break;
252 		case '0': case '1': case '2': case '3': case '4':
253 		case '5': case '6': case '7': case '8': case '9':
254 			/* two motion digits plus a character */
255 			hmot((c-'0')*10 + getc(fp)-'0');
256 			put1(getc(fp));
257 			break;
258 		case 'c':	/* single ascii character */
259 			put1(getc(fp));
260 			break;
261 		case 'C':
262 			fscanf(fp, "%s", str);
263 			put1s(str);
264 			break;
265 		case 't':	/* straight text */
266 			fgets(buf, sizeof(buf), fp);
267 			t_text(buf);
268 			break;
269 		case 'D':	/* draw function */
270 			fgets(buf, sizeof(buf), fp);
271 			switch (buf[0]) {
272 			case 'l':	/* draw a line */
273 				sscanf(buf+1, "%d %d", &n, &m);
274 				drawline(n, m, ".");
275 				break;
276 			case 'c':	/* circle */
277 				sscanf(buf+1, "%d", &n);
278 				drawcirc(n);
279 				break;
280 			case 'e':	/* ellipse */
281 				sscanf(buf+1, "%d %d", &m, &n);
282 				drawellip(m, n);
283 				break;
284 			case 'a':	/* arc */
285 				sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
286 				drawarc(n, m, n1, m1);
287 				break;
288 			case '~':	/* wiggly line */
289 				drawwig(buf+1);
290 				break;
291 			default:
292 				error(FATAL, "unknown drawing function %s\n", buf);
293 				break;
294 			}
295 			break;
296 		case 's':
297 			fscanf(fp, "%d", &n);	/* ignore fractional sizes */
298 			setsize(t_size(n));
299 			break;
300 		case 'f':
301 			fscanf(fp, "%s", str);
302 			setfont(t_font(str));
303 			break;
304 		case 'H':	/* absolute horizontal motion */
305 			/* fscanf(fp, "%d", &n); */
306 			while ((c = getc(fp)) == ' ')
307 				;
308 			k = 0;
309 			do {
310 				k = 10 * k + c - '0';
311 			} while (isdigit(c = getc(fp)));
312 			ungetc(c, fp);
313 			hgoto(k);
314 			break;
315 		case 'h':	/* relative horizontal motion */
316 			/* fscanf(fp, "%d", &n); */
317 			while ((c = getc(fp)) == ' ')
318 				;
319 			k = 0;
320 			do {
321 				k = 10 * k + c - '0';
322 			} while (isdigit(c = getc(fp)));
323 			ungetc(c, fp);
324 			hmot(k);
325 			break;
326 		case 'w':	/* word space */
327 			putc(' ', stdout);
328 			break;
329 		case 'V':
330 			fscanf(fp, "%d", &n);
331 			vgoto(n);
332 			break;
333 		case 'v':
334 			fscanf(fp, "%d", &n);
335 			vmot(n);
336 			break;
337 		case 'p':	/* new page */
338 			fscanf(fp, "%d", &n);
339 			t_page(n);
340 			break;
341 		case 'n':	/* end of line */
342 			while (getc(fp) != '\n')
343 				;
344 			t_newline();
345 			break;
346 		case '#':	/* comment */
347 			while (getc(fp) != '\n')
348 				;
349 			break;
350 		case 'x':	/* device control */
351 			devcntrl(fp);
352 			break;
353 		default:
354 			error(!FATAL, "unknown input character %o %c\n", c, c);
355 			done();
356 		}
357 	}
358 
359 	return (0);
360 }
361 
362 int
363 devcntrl(fp)	/* interpret device control functions */
364 FILE *fp;
365 {
366 	char str[20];
367 	int c, n;
368 
369 	fscanf(fp, "%s", str);
370 	switch (str[0]) {	/* crude for now */
371 	case 'i':	/* initialize */
372 		fileinit();
373 		t_init(0);
374 		break;
375 	case 'T':	/* device name */
376 		fscanf(fp, "%s", devname);
377 		break;
378 	case 't':	/* trailer */
379 		t_trailer();
380 		break;
381 	case 'p':	/* pause -- can restart */
382 		t_reset('p');
383 		break;
384 	case 's':	/* stop */
385 		t_reset('s');
386 		break;
387 	case 'r':	/* resolution assumed when prepared */
388 		fscanf(fp, "%d", &res);
389 		break;
390 	case 'f':	/* font used */
391 		fscanf(fp, "%d %s", &n, str);
392 		loadfont(n, str);
393 		break;
394 	}
395 	while (getc(fp) != '\n')	/* skip rest of input line */
396 		;
397 
398 	return (0);
399 }
400 
401 int
402 fileinit()	/* read in font and code files, etc. */
403 {
404 	return (0);
405 }
406 
407 int
408 fontprint(i)	/* debugging print of font i (0,...) */
409 {
410 	return (0);
411 }
412 
413 int
414 loadcode(n, nw)	/* load codetab on position n (0...); #chars is nw */
415 int n, nw;
416 {
417 	return (0);
418 }
419 
420 int
421 loadfont(n, s)	/* load font info for font s on position n (1...) */
422 int n;
423 char *s;
424 {
425 	return (0);
426 }
427 
428 int
429 error(f, s, a1, a2, a3, a4, a5, a6, a7)
430 char *s;
431 {
432 	fprintf(stderr, "ta: ");
433 	fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
434 	fprintf(stderr, "\n");
435 	if (f)
436 		exit(1);
437 
438 	return (0);
439 }
440 
441 
442 /*
443 	Here beginneth all the stuff that really depends
444 	on the 202 (we hope).
445 */
446 
447 
448 char	devname[20]	= "hp2621";
449 
450 #define	ESC	033
451 #define	HOME	'H'
452 #define	CLEAR	'J'
453 #define	FF	014
454 
455 int	size	= 1;
456 int	font	= 1;		/* current font */
457 int	hpos;		/* horizontal position where we are supposed to be next (left = 0) */
458 int	vpos;		/* current vertical position (down positive) */
459 
460 int	horig;		/* h origin of current block; hpos rel to this */
461 int	vorig;		/* v origin of current block; vpos rel to this */
462 
463 int	DX	= 10;	/* step size in x for drawing */
464 int	DY	= 10;	/* step size in y for drawing */
465 int	drawdot	= '.';	/* draw with this character */
466 int	drawsize = 1;	/* shrink by this factor when drawing */
467 
468 int
469 t_init(reinit)	/* initialize device */
470 int reinit;
471 {
472 	int i, j;
473 
474 	fflush(stdout);
475 	hpos = vpos = 0;
476 
477 	return (0);
478 }
479 
480 #define	MAXSTATE	5
481 
482 struct state {
483 	int	ssize;
484 	int	sfont;
485 	int	shpos;
486 	int	svpos;
487 	int	shorig;
488 	int	svorig;
489 };
490 struct	state	state[MAXSTATE];
491 struct	state	*statep = state;
492 
493 int
494 t_push()	/* begin a new block */
495 {
496 	hflush();
497 	statep->ssize = size;
498 	statep->sfont = font;
499 	statep->shorig = horig;
500 	statep->svorig = vorig;
501 	statep->shpos = hpos;
502 	statep->svpos = vpos;
503 	horig = hpos;
504 	vorig = vpos;
505 	hpos = vpos = 0;
506 	if (statep++ >= state+MAXSTATE)
507 		error(FATAL, "{ nested too deep");
508 	hpos = vpos = 0;
509 
510 	return (0);
511 }
512 
513 int
514 t_pop()	/* pop to previous state */
515 {
516 	if (--statep < state)
517 		error(FATAL, "extra }");
518 	size = statep->ssize;
519 	font = statep->sfont;
520 	hpos = statep->shpos;
521 	vpos = statep->svpos;
522 	horig = statep->shorig;
523 	vorig = statep->svorig;
524 
525 	return (0);
526 }
527 
528 int	np;	/* number of pages seen */
529 int	npmax;	/* high-water mark of np */
530 int	pgnum[40];	/* their actual numbers */
531 long	pgadr[40];	/* their seek addresses */
532 
533 int
534 t_page(n)	/* do whatever new page functions */
535 {
536 	long ftell();
537 	int c, m, i;
538 	char buf[100], *bp;
539 
540 	pgnum[np++] = n;
541 	pgadr[np] = ftell(fp);
542 	if (np > npmax)
543 		npmax = np;
544 	if (output == 0) {
545 		output = in_olist(n);
546 		t_init(1);
547 		return (0);
548 	}
549 	/* have just printed something, and seen p<n> for next one */
550 	putpage();
551 	fflush(stdout);
552 	if (nowait)
553 		return (0);
554 
555   next:
556 	for (bp = buf; (*bp = readch()); )
557 		if (*bp++ == '\n')
558 			break;
559 	*bp = 0;
560 	switch (buf[0]) {
561 	case 0:
562 		done();
563 		break;
564 	case '\n':
565 		output = in_olist(n);
566 		t_init(1);
567 		return (0);
568 	case '!':
569 		callunix(&buf[1]);
570 		fputs("!\n", stderr);
571 		break;
572 	case 'e':
573 		erase = 1 - erase;
574 		break;
575 	case 'w':
576 		wflag = 1 - wflag;
577 		break;
578 	case 'a':
579 		aspect = atof(&buf[1]);
580 		break;
581 	case '-':
582 	case 'p':
583 		m = atoi(&buf[1]) + 1;
584 		if (fp == stdin) {
585 			fputs("you can't; it's not a file\n", stderr);
586 			break;
587 		}
588 		if (np - m <= 0) {
589 			fputs("too far back\n", stderr);
590 			break;
591 		}
592 		np -= m;
593 		fseek(fp, pgadr[np], 0);
594 		output = 1;
595 		t_init(1);
596 		return (0);
597 	case '0': case '1': case '2': case '3': case '4':
598 	case '5': case '6': case '7': case '8': case '9':
599 		m = atoi(&buf[0]);
600 		for (i = 0; i < npmax; i++)
601 			if (m == pgnum[i])
602 				break;
603 		if (i >= npmax || fp == stdin) {
604 			fputs("you can't\n", stderr);
605 			break;
606 		}
607 		np = i + 1;
608 		fseek(fp, pgadr[np], 0);
609 		output = 1;
610 		t_init(1);
611 		return (0);
612 	case 'o':
613 		outlist(&buf[1]);
614 		output = 0;
615 		t_init(1);
616 		return (0);
617 	case '?':
618 		fputs("!cmd	unix cmd\n", stderr);
619 		fputs("p	print this page again\n", stderr);
620 		fputs("-n	go back n pages\n", stderr);
621 		fputs("n	print page n (previously printed)\n", stderr);
622 		fputs("o...	set the -o output list to ...\n", stderr);
623 		fputs("en	n=0 -> don't erase; n=1 -> erase\n", stderr);
624 		fputs("an	sets aspect ratio to n\n", stderr);
625 		break;
626 	default:
627 		fputs("?\n", stderr);
628 		break;
629 	}
630 	goto next;
631 }
632 
633 int
634 putpage()
635 {
636 	int i, j, k;
637 
638 	fflush(stdout);
639 
640 	return (0);
641 }
642 
643 int
644 t_newline()	/* do whatever for the end of a line */
645 {
646 	printf("\n");
647 	hpos = 0;
648 
649 	return (0);
650 }
651 
652 int
653 t_size(n)	/* convert integer to internal size number*/
654 int n;
655 {
656 	return (0);
657 }
658 
659 int
660 t_font(s)	/* convert string to internal font number */
661 char *s;
662 {
663 	return (0);
664 }
665 
666 int
667 t_text(s)	/* print string s as text */
668 char *s;
669 {
670 	int c, w=0;
671 	char str[100];
672 
673 	if (!output)
674 		return (0);
675 	while ((c = *s++) != '\n') {
676 		if (c == '\\') {
677 			switch (c = *s++) {
678 			case '\\':
679 			case 'e':
680 				put1('\\');
681 				break;
682 			case '(':
683 				str[0] = *s++;
684 				str[1] = *s++;
685 				str[2] = '\0';
686 				put1s(str);
687 				break;
688 			}
689 		} else {
690 			put1(c);
691 		}
692 		hmot(w);
693 	}
694 
695 	return (0);
696 }
697 
698 int
699 t_reset(c)
700 {
701 	int n;
702 
703 	output = 1;
704 	fflush(stdout);
705 	if (c == 's')
706 		t_page(9999);
707 
708 	return (0);
709 }
710 
711 int
712 t_trailer()
713 {
714 	return (0);
715 }
716 
717 int
718 hgoto(n)
719 {
720 	hpos = n;	/* this is where we want to be */
721 			/* before printing a character, */
722 			/* have to make sure it's true */
723 
724 	return (0);
725 }
726 
727 int
728 hmot(n)	/* generate n units of horizontal motion */
729 int n;
730 {
731 	hgoto(hpos + n);
732 
733 	return (0);
734 }
735 
736 int
737 hflush()	/* actual horizontal output occurs here */
738 {
739 	return (0);
740 }
741 
742 int
743 vgoto(n)
744 {
745 	vpos = n;
746 
747 	return (0);
748 }
749 
750 int
751 vmot(n)	/* generate n units of vertical motion */
752 int n;
753 {
754 	vgoto(vpos + n);	/* ignores rounding */
755 
756 	return (0);
757 }
758 
759 int
760 put1s(s)	/* s is a funny char name */
761 char *s;
762 {
763 	int i;
764 	char *p;
765 	extern char *spectab[];
766 	static char prev[10] = "";
767 	static int previ;
768 
769 	if (!output)
770 		return (0);
771 	if (strcmp(s, prev) != 0) {
772 		previ = -1;
773 		for (i = 0; spectab[i] != 0; i += 2)
774 			if (strcmp(spectab[i], s) == 0) {
775 				strcpy(prev, s);
776 				previ = i;
777 				break;
778 			}
779 	}
780 	if (previ >= 0) {
781 		for (p = spectab[previ+1]; *p; p++)
782 			putc(*p, stdout);
783 	} else
784 		prev[0] = 0;
785 
786 	return (0);
787 }
788 
789 int
790 put1(c)	/* output char c */
791 int c;
792 {
793 	if (!output)
794 		return (0);
795 	putc(c, stdout);
796 
797 	return (0);
798 }
799 
800 int
801 setsize(n)	/* set point size to n (internal) */
802 int n;
803 {
804 	return (0);
805 }
806 
807 int
808 t_fp(n, s)	/* font position n now contains font s */
809 int n;
810 char *s;
811 {
812 	return (0);
813 }
814 
815 int
816 setfont(n)	/* set font to n */
817 int n;
818 {
819 	return (0);
820 }
821 
822 void done()
823 {
824 	output = 1;
825 	putpage();
826 	fflush(stdout);
827 	exit(0);
828 }
829 
830 int
831 callunix(line)
832 char line[];
833 {
834 	int rc, status, unixpid;
835 	if( (unixpid=fork())==0 ) {
836 		signal(SIGINT,sigint); signal(SIGQUIT,sigquit);
837 		close(0); dup(2);
838 		execl("/bin/sh", "-sh", "-c", line, 0);
839 		exit(255);
840 	}
841 	else if(unixpid == -1)
842 		return (0);
843 	else{	signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN);
844 		while( (rc = wait(&status)) != unixpid && rc != -1 ) ;
845 		signal(SIGINT,(void(*)())done); signal(SIGQUIT,(void(*)())sigquit);
846 	}
847 
848 	return (0);
849 }
850 
851 int
852 readch(){
853 	char c;
854 	if (read(2,&c,1)<1) c=0;
855 	return(c);
856 }
857 
858 char *spectab[] ={
859 	"em", "-",
860 	"hy", "-",
861 	"en", "-",
862 	"ru", "_",
863 	"l.", ".",
864 	"br", "|",
865 	"vr", "|",
866 	"fm", "'",
867 	"or", "|",
868 	0, 0,
869 };
870