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