fix includes
[unix-history] / usr / src / usr.bin / deroff / deroff.c
CommitLineData
2958d0fe 1#ifndef lint
78d90aa3 2static char sccsid[] = "@(#)deroff.c 4.4 (Berkeley) 83/04/29";
2958d0fe
RH
3#endif not lint
4
2958d0fe
RH
5#include <stdio.h>
6
ae8977bb
RH
7/*
8 * Deroff command -- strip troff, eqn, and Tbl sequences from
9 * a file. Has two flags argument, -w, to cause output one word per line
10 * rather than in the original format.
11 * -mm (or -ms) causes the corresponding macro's to be interpreted
12 * so that just sentences are output
13 * -ml also gets rid of lists.
14 * Deroff follows .so and .nx commands, removes contents of macro
15 * definitions, equations (both .EQ ... .EN and $...$),
16 * Tbl command sequences, and Troff backslash constructions.
17 *
18 * All input is through the Cget macro;
19 * the most recently read character is in c.
20 *
21 * Modified by Robert Henry to process -me and -man macros.
22 */
23
24#define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
25#define C1get ( (c=getc(infile)) == EOF ? eof() : c)
26
27#ifdef DEBUG
28# define C _C()
29# define C1 _C1()
30#else not DEBUG
31# define C Cget
32# define C1 C1get
33#endif not DEBUG
34
2958d0fe
RH
35#define SKIP while(C != '\n')
36#define SKIP_TO_COM SKIP; SKIP; pc=c; while(C != '.' || pc != '\n' || C > 'Z')pc=c
37
ae8977bb
RH
38#define YES 1
39#define NO 0
40#define MS 0 /* -ms */
41#define MM 1 /* -mm */
42#define ME 2 /* -me */
43#define MA 3 /* -man */
44
45#ifdef DEBUG
46char *mactab[] = {"-ms", "-mm", "-me", "-ma"};
47#endif DEBUG
48
49#define ONE 1
50#define TWO 2
2958d0fe
RH
51
52#define NOCHAR -2
53#define SPECIAL 0
54#define APOS 1
280efb10
RH
55#define PUNCT 2
56#define DIGIT 3
57#define LETTER 4
2958d0fe 58
ae8977bb
RH
59int wordflag;
60int msflag; /* processing a source written using a mac package */
61int mac; /* which package */
62int disp;
63int parag;
64int inmacro;
65int intable;
66int keepblock; /* keep blocks of text; normally false when msflag */
2958d0fe 67
280efb10 68char chars[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
2958d0fe
RH
69
70char line[512];
71char *lp;
72
73int c;
74int pc;
ae8977bb
RH
75int ldelim;
76int rdelim;
2958d0fe
RH
77
78
79int argc;
80char **argv;
81
82char fname[50];
83FILE *files[15];
84FILE **filesp;
85FILE *infile;
ae8977bb
RH
86FILE *opn();
87/*
88 * Flags for matching conditions other than
89 * the macro name
90 */
91#define NONE 0
92#define FNEST 1 /* no nested files */
93#define NOMAC 2 /* no macro */
94#define MAC 3 /* macro */
95#define PARAG 4 /* in a paragraph */
96#define MSF 5 /* msflag is on */
97#define NBLK 6 /* set if no blocks to be kept */
98
99/*
100 * Return codes from macro minions, determine where to jump,
101 * how to repeat/reprocess text
102 */
103#define COMX 1 /* goto comx */
104#define COM 2 /* goto com */
105\f
2958d0fe
RH
106main(ac, av)
107int ac;
108char **av;
109{
280efb10 110 register int i;
ae8977bb
RH
111 int errflg = 0;
112 register optchar;
280efb10 113 FILE *opn();
ae8977bb
RH
114 int kflag = NO;
115 char *p;
116
117 wordflag = NO;
118 msflag = NO;
119 mac = ME;
120 disp = NO;
121 parag = NO;
122 inmacro = NO;
123 intable = NO;
124 ldelim = NOCHAR;
125 rdelim = NOCHAR;
126 keepblock = YES;
127
128 for(argc = ac - 1, argv = av + 1;
129 ( (argc > 0)
130 && (argv[0][0] == '-')
131 && (argv[0][1] != '\0') );
132 --argc, ++argv
133 ){
134 for(p = argv[0]+1; *p; ++p) {
135 switch(*p) {
136 case 'p':
137 parag=YES;
138 break;
139 case 'k':
140 kflag = YES;
141 break;
142 case 'w':
143 wordflag = YES;
144 kflag = YES;
145 break;
146 case 'm':
147 msflag = YES;
148 keepblock = NO;
149 switch(p[1]){
150 case 'm': mac = MM; p++; break;
151 case 's': mac = MS; p++; break;
152 case 'e': mac = ME; p++; break;
153 case 'a': mac = MA; p++; break;
154 case 'l': disp = YES; p++; break;
155 default: errflg++; break;
156 }
157 break;
158 default:
159 errflg++;
160 }
161 }
2958d0fe 162 }
ae8977bb
RH
163
164 if (kflag)
165 keepblock = YES;
280efb10 166 if (errflg)
ae8977bb
RH
167 fatal("usage: deroff [ -w ] [ -k] [ -m (a e m s l) ] [ file ] ... \n",
168 (char *) NULL);
169
170#ifdef DEBUG
171 printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n",
172 msflag, mactab[mac], keepblock, disp);
173#endif DEBUG
174 if (argc == 0){
280efb10 175 infile = stdin;
ae8977bb
RH
176 } else {
177 infile = opn(argv[0]);
178 --argc;
179 ++argv;
180 }
181
182
280efb10
RH
183 files[0] = infile;
184 filesp = &files[0];
185
186 for(i='a'; i<='z' ; ++i)
187 chars[i] = LETTER;
188 for(i='A'; i<='Z'; ++i)
189 chars[i] = LETTER;
190 for(i='0'; i<='9'; ++i)
191 chars[i] = DIGIT;
192 chars['\''] = APOS;
193 chars['&'] = APOS;
194 chars['.'] = PUNCT;
195 chars[','] = PUNCT;
196 chars[';'] = PUNCT;
197 chars['?'] = PUNCT;
198 chars[':'] = PUNCT;
199 work();
200}
201char *calloc();
2958d0fe 202
2958d0fe
RH
203skeqn()
204{
280efb10
RH
205 while((c = getc(infile)) != rdelim)
206 if(c == EOF)
207 c = eof();
208 else if(c == '"')
209 while( (c = getc(infile)) != '"')
210 if(c == EOF)
2958d0fe 211 c = eof();
280efb10
RH
212 else if(c == '\\')
213 if((c = getc(infile)) == EOF)
214 c = eof();
215 if(msflag)return(c='x');
216 return(c = ' ');
2958d0fe
RH
217}
218
2958d0fe
RH
219FILE *opn(p)
220register char *p;
221{
280efb10 222 FILE *fd;
2958d0fe 223
78d90aa3
KM
224 if( (fd = fopen(p, "r")) == NULL) {
225 fprintf(stderr, "Deroff: ");
226 perror(p);
227 exit(1);
228 }
2958d0fe 229
280efb10 230 return(fd);
2958d0fe
RH
231}
232
2958d0fe
RH
233eof()
234{
280efb10
RH
235 if(infile != stdin)
236 fclose(infile);
237 if(filesp > files)
238 infile = *--filesp;
ae8977bb
RH
239 else if (argc > 0) {
240 infile = opn(argv[0]);
241 --argc;
242 ++argv;
243 } else
280efb10 244 exit(0);
280efb10 245 return(C);
2958d0fe
RH
246}
247
2958d0fe
RH
248getfname()
249{
280efb10
RH
250 register char *p;
251 struct chain {
252 struct chain *nextp;
253 char *datap;
254 } *chainblock;
255 register struct chain *q;
256 static struct chain *namechain = NULL;
257 char *copys();
258
259 while(C == ' ') ;
260
261 for(p = fname ; (*p=c)!= '\n' && c!=' ' && c!='\t' && c!='\\' ; ++p)
262 C;
263 *p = '\0';
264 while(c != '\n')
265 C;
266
267 /* see if this name has already been used */
268
269 for(q = namechain ; q; q = q->nextp)
270 if( ! strcmp(fname, q->datap))
2958d0fe 271 {
280efb10
RH
272 fname[0] = '\0';
273 return;
2958d0fe
RH
274 }
275
280efb10
RH
276 q = (struct chain *) calloc(1, sizeof(*chainblock));
277 q->nextp = namechain;
278 q->datap = copys(fname);
279 namechain = q;
2958d0fe
RH
280}
281
2958d0fe
RH
282fatal(s,p)
283char *s, *p;
284{
280efb10
RH
285 fprintf(stderr, "Deroff: ");
286 fprintf(stderr, s, p);
287 exit(1);
2958d0fe 288}
280efb10 289
ae8977bb
RH
290/*ARGSUSED*/
291textline(str, const)
292 char *str;
293 int const;
2958d0fe 294{
ae8977bb
RH
295 if (wordflag) {
296 msputwords(0);
297 return;
298 }
299 puts(str);
300}
2958d0fe 301
ae8977bb
RH
302work()
303{
280efb10 304 for( ;; )
2958d0fe 305 {
ae8977bb
RH
306 C;
307#ifdef FULLDEBUG
308 printf("Starting work with `%c'\n", c);
309#endif FULLDEBUG
310 if(c == '.' || c == '\'')
280efb10
RH
311 comline();
312 else
ae8977bb 313 regline(textline, TWO);
2958d0fe
RH
314 }
315}
316
ae8977bb
RH
317regline(pfunc, const)
318 int (*pfunc)();
319 int const;
2958d0fe 320{
280efb10
RH
321 line[0] = c;
322 lp = line;
323 for( ; ; )
2958d0fe 324 {
ae8977bb 325 if(c == '\\') {
280efb10
RH
326 *lp = ' ';
327 backsl();
2958d0fe 328 }
ae8977bb
RH
329 if(c == '\n')
330 break;
331 if(intable && c=='T') {
280efb10 332 *++lp = C;
ae8977bb 333 if(c=='{' || c=='}') {
280efb10
RH
334 lp[-1] = ' ';
335 *lp = C;
2958d0fe 336 }
ae8977bb
RH
337 } else {
338 *++lp = C;
2958d0fe 339 }
2958d0fe
RH
340 }
341
280efb10 342 *lp = '\0';
2958d0fe 343
280efb10 344 if(line[0] != '\0')
ae8977bb 345 (*pfunc)(line, const);
2958d0fe
RH
346}
347
2958d0fe
RH
348macro()
349{
280efb10
RH
350 if(msflag){
351 do {
352 SKIP;
353 } while(C!='.' || C!='.' || C=='.'); /* look for .. */
354 if(c != '\n')SKIP;
355 return;
356 }
357 SKIP;
358 inmacro = YES;
2958d0fe
RH
359}
360
2958d0fe
RH
361tbl()
362{
280efb10
RH
363 while(C != '.');
364 SKIP;
365 intable = YES;
2958d0fe
RH
366}
367stbl()
368{
280efb10
RH
369 while(C != '.');
370 SKIP_TO_COM;
371 if(c != 'T' || C != 'E'){
372 SKIP;
373 pc=c;
374 while(C != '.' || pc != '\n' || C != 'T' || C != 'E')pc=c;
375 }
2958d0fe
RH
376}
377
378eqn()
379{
280efb10
RH
380 register int c1, c2;
381 register int dflg;
382 char last;
2958d0fe 383
280efb10
RH
384 last=0;
385 dflg = 1;
386 SKIP;
2958d0fe 387
280efb10 388 for( ;;)
2958d0fe 389 {
280efb10 390 if(C1 == '.' || c == '\'')
2958d0fe 391 {
280efb10
RH
392 while(C1==' ' || c=='\t')
393 ;
394 if(c=='E' && C1=='N')
2958d0fe 395 {
280efb10
RH
396 SKIP;
397 if(msflag && dflg){
398 putchar('x');
399 putchar(' ');
400 if(last){
401 putchar(last);
402 putchar('\n');
403 }
404 }
405 return;
2958d0fe
RH
406 }
407 }
280efb10 408 else if(c == 'd') /* look for delim */
2958d0fe 409 {
280efb10
RH
410 if(C1=='e' && C1=='l')
411 if( C1=='i' && C1=='m')
2958d0fe 412 {
280efb10
RH
413 while(C1 == ' ');
414 if((c1=c)=='\n' || (c2=C1)=='\n'
415 || (c1=='o' && c2=='f' && C1=='f') )
416 {
417 ldelim = NOCHAR;
418 rdelim = NOCHAR;
419 }
420 else {
421 ldelim = c1;
422 rdelim = c2;
423 }
2958d0fe 424 }
2958d0fe
RH
425 dflg = 0;
426 }
427
280efb10
RH
428 if(c != '\n') while(C1 != '\n'){
429 if(chars[c] == PUNCT)last = c;
430 else if(c != ' ')last = 0;
431 }
2958d0fe
RH
432 }
433}
434
2958d0fe
RH
435backsl() /* skip over a complete backslash construction */
436{
280efb10 437 int bdelim;
2958d0fe 438
280efb10
RH
439sw:
440 switch(C)
2958d0fe
RH
441 {
442 case '"':
443 SKIP;
444 return;
445 case 's':
446 if(C == '\\') backsl();
447 else {
448 while(C>='0' && c<='9') ;
449 ungetc(c,infile);
450 c = '0';
280efb10 451 }
2958d0fe
RH
452 --lp;
453 return;
454
455 case 'f':
456 case 'n':
2958d0fe
RH
457 case '*':
458 if(C != '(')
459 return;
460
461 case '(':
280efb10
RH
462 if(msflag){
463 if(C == 'e'){
464 if(C == 'm'){
465 *lp = '-';
466 return;
467 }
468 }
469 else if(c != '\n')C;
470 return;
471 }
2958d0fe
RH
472 if(C != '\n') C;
473 return;
474
475 case '$':
476 C; /* discard argument number */
477 return;
478
479 case 'b':
480 case 'x':
481 case 'v':
482 case 'h':
483 case 'w':
484 case 'o':
485 case 'l':
486 case 'L':
487 if( (bdelim=C) == '\n')
488 return;
489 while(C!='\n' && c!=bdelim)
490 if(c == '\\') backsl();
491 return;
492
493 case '\\':
494 if(inmacro)
495 goto sw;
496 default:
497 return;
498 }
499}
500
2958d0fe
RH
501char *copys(s)
502register char *s;
503{
280efb10 504 register char *t, *t0;
2958d0fe 505
280efb10
RH
506 if( (t0 = t = calloc( (unsigned)(strlen(s)+1), sizeof(*t) ) ) == NULL)
507 fatal("Cannot allocate memory", (char *) NULL);
2958d0fe 508
280efb10
RH
509 while( *t++ = *s++ )
510 ;
511 return(t0);
2958d0fe 512}
ae8977bb
RH
513
514sce()
515{
280efb10
RH
516 register char *ap;
517 register int n, i;
518 char a[10];
2958d0fe
RH
519 for(ap=a;C != '\n';ap++){
520 *ap = c;
521 if(ap == &a[9]){
522 SKIP;
523 ap=a;
524 break;
525 }
526 }
527 if(ap != a)n = atoi(a);
528 else n = 1;
529 for(i=0;i<n;){
530 if(C == '.'){
531 if(C == 'c'){
532 if(C == 'e'){
533 while(C == ' ');
280efb10
RH
534 if(c == '0'){
535 SKIP;
536 break;
537 }
2958d0fe
RH
538 else SKIP;
539 }
540 else SKIP;
541 }
280efb10
RH
542 else if(c == 'P' || C == 'P'){
543 if(c != '\n')SKIP;
544 break;
545 }
546 else if(c != '\n')SKIP;
2958d0fe
RH
547 }
548 else {
549 SKIP;
550 i++;
551 }
552 }
553}
ae8977bb 554
280efb10
RH
555refer(c1)
556{
557 register int c2;
558 if(c1 != '\n')
559 SKIP;
560 while(1){
561 if(C != '.')
562 SKIP;
563 else {
564 if(C != ']')
565 SKIP;
566 else {
567 while(C != '\n')
568 c2=c;
569 if(chars[c2] == PUNCT)putchar(c2);
570 return;
571 }
572 }
573 }
574}
ae8977bb
RH
575
576inpic()
577{
280efb10
RH
578 register int c1;
579 register char *p1;
580 SKIP;
581 p1 = line;
582 c = '\n';
583 while(1){
584 c1 = c;
585 if(C == '.' && c1 == '\n'){
586 if(C != 'P'){
587 if(c == '\n')continue;
588 else { SKIP; c='\n'; continue;}
589 }
590 if(C != 'E'){
591 if(c == '\n')continue;
592 else { SKIP; c='\n';continue; }
593 }
594 SKIP;
595 return;
596 }
597 else if(c == '\"'){
598 while(C != '\"'){
599 if(c == '\\'){
600 if(C == '\"')continue;
601 ungetc(c,infile);
602 backsl();
603 }
604 else *p1++ = c;
605 }
606 *p1++ = ' ';
607 }
608 else if(c == '\n' && p1 != line){
609 *p1 = '\0';
ae8977bb 610 if(wordflag)msputwords(NO);
280efb10
RH
611 else {
612 puts(line);
613 putchar('\n');
614 }
615 p1 = line;
616 }
617 }
618}
ae8977bb
RH
619
620#ifdef DEBUG
621_C1()
622{
623 return(C1get);
624}
625_C()
626{
627 return(Cget);
628}
629#endif DEBUG
630\f
631/*
632 * Macro processing
633 *
634 * Macro table definitions
635 */
636#define reg register
637typedef int pacmac; /* compressed macro name */
638int argconcat = 0; /* concat arguments together (-me only) */
639
640#define tomac(c1, c2) ((((c1) & 0xFF) << 8) | ((c2) & 0xFF))
641#define frommac(src, c1, c2) (((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF))
642
643struct mactab{
644 int condition;
645 pacmac macname;
646 int (*func)();
647};
648struct mactab troffmactab[];
649struct mactab ppmactab[];
650struct mactab msmactab[];
651struct mactab mmmactab[];
652struct mactab memactab[];
653struct mactab manmactab[];
654/*
655 * macro table initialization
656 */
657#define M(cond, c1, c2, func) {cond, tomac(c1, c2), func}
658
659/*
660 * Put out a macro line, using ms and mm conventions.
661 */
662msputmac(s, const)
663 register char *s;
664 int const;
665{
666 register char *t;
667 register found;
668 int last;
669 found = 0;
670
671 if (wordflag) {
672 msputwords(YES);
673 return;
674 }
675 while(*s)
676 {
677 while(*s==' ' || *s=='\t')
678 putchar(*s++);
679 for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t)
680 ;
681 if(*s == '\"')s++;
682 if(t>s+const && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER){
683 while(s < t)
684 if(*s == '\"')s++;
685 else
686 putchar(*s++);
687 last = *(t-1);
688 found++;
689 }
690 else if(found && chars[ s[0] ] == PUNCT && s[1] == '\0')
691 putchar(*s++);
692 else{
693 last = *(t-1);
694 s = t;
695 }
696 }
697 putchar('\n');
698 if(msflag && chars[last] == PUNCT){
699 putchar(last);
700 putchar('\n');
701 }
702}
703/*
704 * put out words (for the -w option) with ms and mm conventions
705 */
706msputwords(macline)
707 int macline; /* is this is a macro line */
708{
709 register char *p, *p1;
710 int i, nlet;
711
712 for(p1 = line ; ;) {
713 /*
714 * skip initial specials ampersands and apostrophes
715 */
716 while( chars[*p1] < DIGIT)
717 if(*p1++ == '\0') return;
718 nlet = 0;
719 for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
720 if(i == LETTER) ++nlet;
721
722 if ( (macline && nlet > 1)
723 || (!macline && nlet > 2
724 && chars[p1[0]] == LETTER
725 && chars[p1[1]] == LETTER) )
726 {
727 /*
728 * delete trailing ampersands and apostrophes
729 */
730 while( (p[-1]=='\'')
731 || (p[-1]=='&')
732 || (chars[p[-1]] == PUNCT) ){
733 --p;
734 }
735 while(p1 < p)
736 putchar(*p1++);
737 putchar('\n');
738 } else {
739 p1 = p;
740 }
741 }
742}
743/*
744 * put out a macro using the me conventions
745 */
746#define SKIPBLANK(cp) while(*cp == ' ' || *cp == '\t') { cp++; }
747#define SKIPNONBLANK(cp) while(*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
748
749meputmac(cp, const)
750 reg char *cp;
751 int const;
752{
753 reg char *np;
754 int found;
755 int argno;
756 int last;
757 int inquote;
758
759 if (wordflag) {
760 meputwords(YES);
761 return;
762 }
763 for (argno = 0; *cp; argno++){
764 SKIPBLANK(cp);
765 inquote = (*cp == '"');
766 if (inquote)
767 cp++;
768 for (np = cp; *np; np++){
769 switch(*np){
770 case '\n':
771 case '\0': break;
772 case '\t':
773 case ' ': if (inquote) {
774 continue;
775 } else {
776 goto endarg;
777 }
778 case '"': if(inquote && np[1] == '"'){
779 strcpy(np, np + 1);
780 np++;
781 continue;
782 } else {
783 *np = ' '; /* bye bye " */
784 goto endarg;
785 }
786 default: continue;
787 }
788 }
789 endarg: ;
790 /*
791 * cp points at the first char in the arg
792 * np points one beyond the last char in the arg
793 */
794 if ((argconcat == 0) || (argconcat != argno)) {
795 putchar(' ');
796 }
797#ifdef FULLDEBUG
798 {
799 char *p;
800 printf("[%d,%d: ", argno, np - cp);
801 for (p = cp; p < np; p++) {
802 putchar(*p);
803 }
804 printf("]");
805 }
806#endif FULLDEBUG
807 /*
808 * Determine if the argument merits being printed
809 *
810 * const is the cut off point below which something
811 * is not a word.
812 */
813 if ( ( (np - cp) > const)
814 && ( inquote
815 || (chars[cp[0]] == LETTER)) ){
816 for (cp = cp; cp < np; cp++){
817 putchar(*cp);
818 }
819 last = np[-1];
820 found++;
821 } else
822 if(found && (np - cp == 1) && chars[*cp] == PUNCT){
823 putchar(*cp);
824 } else {
825 last = np[-1];
826 }
827 cp = np;
828 }
829 if(msflag && chars[last] == PUNCT)
830 putchar(last);
831 putchar('\n');
832}
833/*
834 * put out words (for the -w option) with ms and mm conventions
835 */
836meputwords(macline)
837 int macline;
838{
839 msputwords(macline);
840}
841/*
842 *
843 * Skip over a nested set of macros
844 *
845 * Possible arguments to noblock are:
846 *
847 * fi end of unfilled text
848 * PE pic ending
849 * DE display ending
850 *
851 * for ms and mm only:
852 * KE keep ending
853 *
854 * NE undocumented match to NS (for mm?)
855 * LE mm only: matches RL or *L (for lists)
856 *
857 * for me:
858 * ([lqbzcdf]
859 */
860
861noblock(a1, a2)
862 char a1, a2;
863{
864 register int c1,c2;
865 register int eqnf;
866 int lct;
867 lct = 0;
868 eqnf = 1;
869 SKIP;
870 while(1){
871 while(C != '.')
872 if(c == '\n')
873 continue;
874 else
875 SKIP;
876 if((c1=C) == '\n')
877 continue;
878 if((c2=C) == '\n')
879 continue;
880 if(c1==a1 && c2 == a2){
881 SKIP;
882 if(lct != 0){
883 lct--;
884 continue;
885 }
886 if(eqnf)
887 putchar('.');
888 putchar('\n');
889 return;
890 } else if(a1 == 'L' && c2 == 'L'){
891 lct++;
892 SKIP;
893 }
894 /*
895 * equations (EQ) nested within a display
896 */
897 else if(c1 == 'E' && c2 == 'Q'){
898 if ( (mac == ME && a1 == ')')
899 || (mac != ME && a1 == 'D') ) {
900 eqn();
901 eqnf=0;
902 }
903 }
904 /*
905 * turning on filling is done by the paragraphing
906 * macros
907 */
908 else if(a1 == 'f') { /* .fi */
909 if ( (mac == ME && (c2 == 'h' || c2 == 'p'))
910 ||(mac != ME && (c1 == 'P' || c2 == 'P')) ) {
911 SKIP;
912 return;
913 }
914 } else {
915 SKIP;
916 }
917 }
918}
919
920EQ()
921{
922 eqn();
923 return(0);
924}
925domacro()
926{
927 macro();
928 return(0);
929}
930PS()
931{
932 if (!msflag) {
933 inpic();
934 } else {
935 noblock('P', 'E');
936 }
937 return(0);
938}
939
940skip()
941{
942 SKIP;
943 return(0);
944}
945
946intbl()
947{
948 if(msflag){
949 stbl();
950 }
951 else tbl();
952 return(0);
953}
954
955outtbl(){ intable = NO; }
956
957so()
958{
959 getfname();
960 if( fname[0] )
961 infile = *++filesp = opn( fname );
962 return(0);
963}
964nx()
965{
966 getfname();
967 if(fname[0] == '\0') exit(0);
968 if(infile != stdin)
969 fclose(infile);
970 infile = *filesp = opn(fname);
971 return(0);
972}
973skiptocom(){ SKIP_TO_COM; return(COMX); }
974
975PP(c12)
976 pacmac c12;
977{
978 int c1, c2;
979
980 frommac(c12, c1, c2);
981 printf(".%c%c",c1,c2);
982 while(C != '\n')putchar(c);
983 putchar('\n');
984 return(0);
985}
986AU()
987{
988 if(mac==MM) {
989 return(0);
990 } else {
991 SKIP_TO_COM;
992 return(COMX);
993 }
994}
995
996SH(c12)
997 pacmac c12;
998{
999 int c1, c2;
1000
1001 frommac(c12, c1, c2);
1002
1003 if(parag){
1004 printf(".%c%c",c1,c2);
1005 while(C != '\n')putchar(c);
1006 putchar(c);
1007 putchar('!');
1008 while(1){
1009 while(C != '\n')putchar(c);
1010 putchar('\n');
1011 if(C == '.')
1012 return(COM);
1013 putchar('!');
1014 putchar(c);
1015 }
1016 /*NOTREACHED*/
1017 } else {
1018 SKIP_TO_COM;
1019 return(COMX);
1020 }
1021}
1022
1023UX()
1024{
1025 if(wordflag)
1026 printf("UNIX\n");
1027 else
1028 printf("UNIX ");
1029 return(0);
1030}
1031
1032MMHU(c12)
1033 pacmac c12;
1034{
1035 int c1, c2;
1036
1037 frommac(c12, c1, c2);
1038 if(parag){
1039 printf(".%c%c",c1,c2);
1040 while(C != '\n')putchar(c);
1041 putchar('\n');
1042 } else {
1043 SKIP;
1044 }
1045 return(0);
1046}
1047
1048mesnblock(c12)
1049 pacmac c12;
1050{
1051 int c1, c2;
1052
1053 frommac(c12, c1, c2);
1054 noblock(')',c2);
1055 return(0);
1056}
1057mssnblock(c12)
1058 pacmac c12;
1059{
1060 int c1, c2;
1061
1062 frommac(c12, c1, c2);
1063 noblock(c1,'E');
1064 return(0);
1065}
1066nf()
1067{
1068 noblock('f','i');
1069 return(0);
1070}
1071
1072ce()
1073{
1074 sce();
1075 return(0);
1076}
1077
1078meip(c12)
1079 pacmac c12;
1080{
1081 if(parag)
1082 mepp(c12);
1083 else if (wordflag) /* save the tag */
1084 regline(meputmac, ONE);
1085 else {
1086 SKIP;
1087 }
1088 return(0);
1089}
1090/*
1091 * only called for -me .pp or .sh, when parag is on
1092 */
1093mepp(c12)
1094 pacmac c12;
1095{
1096 PP(c12); /* eats the line */
1097 return(0);
1098}
1099/*
1100 * Start of a section heading; output the section name if doing words
1101 */
1102mesh(c12)
1103 pacmac c12;
1104{
1105 if (parag)
1106 mepp(c12);
1107 else if (wordflag)
1108 defcomline(c12);
1109 else {
1110 SKIP;
1111 }
1112 return(0);
1113}
1114/*
1115 * process a font setting
1116 */
1117mefont(c12)
1118 pacmac c12;
1119{
1120 argconcat = 1;
1121 defcomline(c12);
1122 argconcat = 0;
1123 return(0);
1124}
1125manfont(c12)
1126 pacmac c12;
1127{
1128 return(mefont(c12));
1129}
1130manpp(c12)
1131 pacmac c12;
1132{
1133 return(mepp(c12));
1134}
1135
1136defcomline(c12)
1137 pacmac c12;
1138{
1139 int c1, c2;
1140
1141 frommac(c12, c1, c2);
1142 if(msflag && mac==MM && c2=='L'){
1143 if(disp || c1 == 'R') {
1144 noblock('L','E');
1145 } else {
1146 SKIP;
1147 putchar('.');
1148 }
1149 }
1150 else if(c1=='.' && c2=='.'){
1151 if(msflag){
1152 SKIP;
1153 return;
1154 }
1155 while(C == '.')
1156 /*VOID*/;
1157 }
1158 ++inmacro;
1159 /*
1160 * Process the arguments to the macro
1161 */
1162 switch(mac){
1163 default:
1164 case MM:
1165 case MS:
1166 if(c1 <= 'Z' && msflag)
1167 regline(msputmac, ONE);
1168 else
1169 regline(msputmac, TWO);
1170 break;
1171 case ME:
1172 regline(meputmac, ONE);
1173 break;
1174 }
1175 --inmacro;
1176}
1177
1178comline()
1179{
1180 reg int c1;
1181 reg int c2;
1182 pacmac c12;
1183 reg int mid;
1184 int lb, ub;
1185 int hit;
1186 static int tabsize = 0;
1187 static struct mactab *mactab = (struct mactab *)0;
1188 reg struct mactab *mp;
1189
1190 if (mactab == 0){
1191 buildtab(&mactab, &tabsize);
1192 }
1193com:
1194 while(C==' ' || c=='\t')
1195 ;
1196comx:
1197 if( (c1=c) == '\n')
1198 return;
1199 c2 = C;
1200 if(c1=='.' && c2 !='.')
1201 inmacro = NO;
1202 if(msflag && c1 == '['){
1203 refer(c2);
1204 return;
1205 }
1206 if(parag && mac==MM && c1 == 'P' && c2 == '\n'){
1207 printf(".P\n");
1208 return;
1209 }
1210 if(c2 == '\n')
1211 return;
1212 /*
1213 * Single letter macro
1214 */
1215 if (mac == ME && (c2 == ' ' || c2 == '\t') )
1216 c2 = ' ';
1217 c12 = tomac(c1, c2);
1218 /*
1219 * binary search through the table of macros
1220 */
1221 lb = 0;
1222 ub = tabsize - 1;
1223 while(lb <= ub){
1224 mid = (ub + lb) / 2;
1225 mp = &mactab[mid];
1226 if (mp->macname < c12)
1227 lb = mid + 1;
1228 else if (mp->macname > c12)
1229 ub = mid - 1;
1230 else {
1231 hit = 1;
1232#ifdef FULLDEBUG
1233 printf("preliminary hit macro %c%c ", c1, c2);
1234#endif FULLDEBUG
1235 switch(mp->condition){
1236 case NONE: hit = YES; break;
1237 case FNEST: hit = (filesp == files); break;
1238 case NOMAC: hit = !inmacro; break;
1239 case MAC: hit = inmacro; break;
1240 case PARAG: hit = parag; break;
1241 case NBLK: hit = !keepblock; break;
1242 default: hit = 0;
1243 }
1244 if (hit) {
1245#ifdef FULLDEBUG
1246 printf("MATCH\n");
1247#endif FULLDEBUG
1248 switch( (*(mp->func))(c12) ) {
1249 default: return;
1250 case COMX: goto comx;
1251 case COM: goto com;
1252 }
1253 }
1254#ifdef FULLDEBUG
1255 printf("FAIL\n");
1256#endif FULLDEBUG
1257 break;
1258 }
1259 }
1260 defcomline(c12);
1261}
1262
1263int macsort(p1, p2)
1264 struct mactab *p1, *p2;
1265{
1266 return(p1->macname - p2->macname);
1267}
1268
1269int sizetab(mp)
1270 reg struct mactab *mp;
1271{
1272 reg int i;
1273 i = 0;
1274 if (mp){
1275 for (; mp->macname; mp++, i++)
1276 /*VOID*/ ;
1277 }
1278 return(i);
1279}
1280
1281struct mactab *macfill(dst, src)
1282 reg struct mactab *dst;
1283 reg struct mactab *src;
1284{
1285 if (src) {
1286 while(src->macname){
1287 *dst++ = *src++;
1288 }
1289 }
1290 return(dst);
1291}
1292
1293buildtab(r_back, r_size)
1294 struct mactab **r_back;
1295 int *r_size;
1296{
1297 int size;
1298
1299 struct mactab *p, *p1, *p2;
1300 struct mactab *back;
1301
1302 size = sizetab(troffmactab);
1303 size += sizetab(ppmactab);
1304 p1 = p2 = (struct mactab *)0;
1305 if (msflag){
1306 switch(mac){
1307 case ME: p1 = memactab; break;
1308 case MM: p1 = msmactab;
1309 p2 = mmmactab; break;
1310
1311 case MS: p1 = msmactab; break;
1312 case MA: p1 = manmactab; break;
1313 default: break;
1314 }
1315 }
1316 size += sizetab(p1);
1317 size += sizetab(p2);
1318 back = (struct mactab *)calloc(size+2, sizeof(struct mactab));
1319
1320 p = macfill(back, troffmactab);
1321 p = macfill(p, ppmactab);
1322 p = macfill(p, p1);
1323 p = macfill(p, p2);
1324
1325 qsort(back, size, sizeof(struct mactab), macsort);
1326 *r_size = size;
1327 *r_back = back;
1328}
1329
1330/*
1331 * troff commands
1332 */
1333struct mactab troffmactab[] = {
1334 M(NONE, '\\','"', skip), /* comment */
1335 M(NOMAC, 'd','e', domacro), /* define */
1336 M(NOMAC, 'i','g', domacro), /* ignore till .. */
1337 M(NOMAC, 'a','m', domacro), /* append macro */
1338 M(NBLK, 'n','f', nf), /* filled */
1339 M(NBLK, 'c','e', ce), /* centered */
1340
1341 M(NONE, 's','o', so), /* source a file */
1342 M(NONE, 'n','x', nx), /* go to next file */
1343
1344 M(NONE, 't','m', skip), /* print string on tty */
1345 M(NONE, 'h','w', skip), /* exception hyphen words */
1346 M(NONE, 0,0, 0)
1347};
1348/*
1349 * Preprocessor output
1350 */
1351struct mactab ppmactab[] = {
1352 M(FNEST, 'E','Q', EQ), /* equation starting */
1353 M(FNEST, 'T','S', intbl), /* table starting */
1354 M(FNEST, 'T','C', intbl), /* alternative table? */
1355 M(FNEST, 'T','&', intbl), /* table reformatting */
1356 M(NONE, 'T','E', outtbl),/* table ending */
1357 M(NONE, 'P','S', PS), /* picture starting */
1358 M(NONE, 0,0, 0)
1359};
1360/*
1361 * Particular to ms and mm
1362 */
1363struct mactab msmactab[] = {
1364 M(NONE, 'T','L', skiptocom), /* title follows */
1365 M(NONE, 'F','S', skiptocom), /* start footnote */
1366 M(NONE, 'O','K', skiptocom), /* Other kws */
1367
1368 M(NONE, 'N','R', skip), /* undocumented */
1369 M(NONE, 'N','D', skip), /* use supplied date */
1370
1371 M(PARAG, 'P','P', PP), /* begin parag */
1372 M(PARAG, 'I','P', PP), /* begin indent parag, tag x */
1373 M(PARAG, 'L','P', PP), /* left blocked parag */
1374
1375 M(NONE, 'A','U', AU), /* author */
1376 M(NONE, 'A','I', AU), /* authors institution */
1377
1378 M(NONE, 'S','H', SH), /* section heading */
1379 M(NONE, 'S','N', SH), /* undocumented */
1380 M(NONE, 'U','X', UX), /* unix */
1381
1382 M(NBLK, 'D','S', mssnblock), /* start display text */
1383 M(NBLK, 'K','S', mssnblock), /* start keep */
1384 M(NBLK, 'K','F', mssnblock), /* start float keep */
1385 M(NONE, 0,0, 0)
1386};
1387
1388struct mactab mmmactab[] = {
1389 M(NONE, 'H',' ', MMHU), /* -mm ? */
1390 M(NONE, 'H','U', MMHU), /* -mm ? */
1391 M(PARAG, 'P',' ', PP), /* paragraph for -mm */
1392 M(NBLK, 'N','S', mssnblock), /* undocumented */
1393 M(NONE, 0,0, 0)
1394};
1395
1396struct mactab memactab[] = {
1397 M(PARAG, 'p','p', mepp),
1398 M(PARAG, 'l','p', mepp),
1399 M(PARAG, 'n','p', mepp),
1400 M(NONE, 'i','p', meip),
1401
1402 M(NONE, 's','h', mesh),
1403 M(NONE, 'u','h', mesh),
1404
1405 M(NBLK, '(','l', mesnblock),
1406 M(NBLK, '(','q', mesnblock),
1407 M(NBLK, '(','b', mesnblock),
1408 M(NBLK, '(','z', mesnblock),
1409 M(NBLK, '(','c', mesnblock),
1410
1411 M(NBLK, '(','d', mesnblock),
1412 M(NBLK, '(','f', mesnblock),
1413 M(NBLK, '(','x', mesnblock),
1414
1415 M(NONE, 'r',' ', mefont),
1416 M(NONE, 'i',' ', mefont),
1417 M(NONE, 'b',' ', mefont),
1418 M(NONE, 'u',' ', mefont),
1419 M(NONE, 'q',' ', mefont),
1420 M(NONE, 'r','b', mefont),
1421 M(NONE, 'b','i', mefont),
1422 M(NONE, 'b','x', mefont),
1423 M(NONE, 0,0, 0)
1424};
1425
1426
1427struct mactab manmactab[] = {
1428 M(PARAG, 'B','I', manfont),
1429 M(PARAG, 'B','R', manfont),
1430 M(PARAG, 'I','B', manfont),
1431 M(PARAG, 'I','R', manfont),
1432 M(PARAG, 'R','B', manfont),
1433 M(PARAG, 'R','I', manfont),
1434
1435 M(PARAG, 'P','P', manpp),
1436 M(PARAG, 'L','P', manpp),
1437 M(PARAG, 'H','P', manpp),
1438 M(NONE, 0,0, 0)
1439};