end-macro processing fix; bug report 4.3BSD/usr.bin/24
[unix-history] / usr / src / usr.bin / deroff / deroff.c
CommitLineData
2958d0fe 1#ifndef lint
f77d5ae4 2static char sccsid[] = "@(#)deroff.c 4.5 (Berkeley) 84/12/18";
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
f77d5ae4 722 if (nlet > 1 && chars[p1[0]] == LETTER) {
ae8977bb
RH
723 /*
724 * delete trailing ampersands and apostrophes
725 */
f77d5ae4 726 while( (i=chars[p[-1]]) == PUNCT || i == APOS )
ae8977bb 727 --p;
ae8977bb
RH
728 while(p1 < p)
729 putchar(*p1++);
730 putchar('\n');
731 } else {
732 p1 = p;
733 }
734 }
735}
736/*
737 * put out a macro using the me conventions
738 */
739#define SKIPBLANK(cp) while(*cp == ' ' || *cp == '\t') { cp++; }
740#define SKIPNONBLANK(cp) while(*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; }
741
742meputmac(cp, const)
743 reg char *cp;
744 int const;
745{
746 reg char *np;
747 int found;
748 int argno;
749 int last;
750 int inquote;
751
752 if (wordflag) {
753 meputwords(YES);
754 return;
755 }
756 for (argno = 0; *cp; argno++){
757 SKIPBLANK(cp);
758 inquote = (*cp == '"');
759 if (inquote)
760 cp++;
761 for (np = cp; *np; np++){
762 switch(*np){
763 case '\n':
764 case '\0': break;
765 case '\t':
766 case ' ': if (inquote) {
767 continue;
768 } else {
769 goto endarg;
770 }
771 case '"': if(inquote && np[1] == '"'){
772 strcpy(np, np + 1);
773 np++;
774 continue;
775 } else {
776 *np = ' '; /* bye bye " */
777 goto endarg;
778 }
779 default: continue;
780 }
781 }
782 endarg: ;
783 /*
784 * cp points at the first char in the arg
785 * np points one beyond the last char in the arg
786 */
787 if ((argconcat == 0) || (argconcat != argno)) {
788 putchar(' ');
789 }
790#ifdef FULLDEBUG
791 {
792 char *p;
793 printf("[%d,%d: ", argno, np - cp);
794 for (p = cp; p < np; p++) {
795 putchar(*p);
796 }
797 printf("]");
798 }
799#endif FULLDEBUG
800 /*
801 * Determine if the argument merits being printed
802 *
803 * const is the cut off point below which something
804 * is not a word.
805 */
806 if ( ( (np - cp) > const)
807 && ( inquote
808 || (chars[cp[0]] == LETTER)) ){
809 for (cp = cp; cp < np; cp++){
810 putchar(*cp);
811 }
812 last = np[-1];
813 found++;
814 } else
815 if(found && (np - cp == 1) && chars[*cp] == PUNCT){
816 putchar(*cp);
817 } else {
818 last = np[-1];
819 }
820 cp = np;
821 }
822 if(msflag && chars[last] == PUNCT)
823 putchar(last);
824 putchar('\n');
825}
826/*
827 * put out words (for the -w option) with ms and mm conventions
828 */
829meputwords(macline)
830 int macline;
831{
832 msputwords(macline);
833}
834/*
835 *
836 * Skip over a nested set of macros
837 *
838 * Possible arguments to noblock are:
839 *
840 * fi end of unfilled text
841 * PE pic ending
842 * DE display ending
843 *
844 * for ms and mm only:
845 * KE keep ending
846 *
847 * NE undocumented match to NS (for mm?)
848 * LE mm only: matches RL or *L (for lists)
849 *
850 * for me:
851 * ([lqbzcdf]
852 */
853
854noblock(a1, a2)
855 char a1, a2;
856{
857 register int c1,c2;
858 register int eqnf;
859 int lct;
860 lct = 0;
861 eqnf = 1;
862 SKIP;
863 while(1){
864 while(C != '.')
865 if(c == '\n')
866 continue;
867 else
868 SKIP;
869 if((c1=C) == '\n')
870 continue;
871 if((c2=C) == '\n')
872 continue;
873 if(c1==a1 && c2 == a2){
874 SKIP;
875 if(lct != 0){
876 lct--;
877 continue;
878 }
879 if(eqnf)
880 putchar('.');
881 putchar('\n');
882 return;
883 } else if(a1 == 'L' && c2 == 'L'){
884 lct++;
885 SKIP;
886 }
887 /*
888 * equations (EQ) nested within a display
889 */
890 else if(c1 == 'E' && c2 == 'Q'){
891 if ( (mac == ME && a1 == ')')
892 || (mac != ME && a1 == 'D') ) {
893 eqn();
894 eqnf=0;
895 }
896 }
897 /*
898 * turning on filling is done by the paragraphing
899 * macros
900 */
901 else if(a1 == 'f') { /* .fi */
902 if ( (mac == ME && (c2 == 'h' || c2 == 'p'))
903 ||(mac != ME && (c1 == 'P' || c2 == 'P')) ) {
904 SKIP;
905 return;
906 }
907 } else {
908 SKIP;
909 }
910 }
911}
912
913EQ()
914{
915 eqn();
916 return(0);
917}
918domacro()
919{
920 macro();
921 return(0);
922}
923PS()
924{
925 if (!msflag) {
926 inpic();
927 } else {
928 noblock('P', 'E');
929 }
930 return(0);
931}
932
933skip()
934{
935 SKIP;
936 return(0);
937}
938
939intbl()
940{
941 if(msflag){
942 stbl();
943 }
944 else tbl();
945 return(0);
946}
947
948outtbl(){ intable = NO; }
949
950so()
951{
952 getfname();
953 if( fname[0] )
954 infile = *++filesp = opn( fname );
955 return(0);
956}
957nx()
958{
959 getfname();
960 if(fname[0] == '\0') exit(0);
961 if(infile != stdin)
962 fclose(infile);
963 infile = *filesp = opn(fname);
964 return(0);
965}
966skiptocom(){ SKIP_TO_COM; return(COMX); }
967
968PP(c12)
969 pacmac c12;
970{
971 int c1, c2;
972
973 frommac(c12, c1, c2);
974 printf(".%c%c",c1,c2);
975 while(C != '\n')putchar(c);
976 putchar('\n');
977 return(0);
978}
979AU()
980{
981 if(mac==MM) {
982 return(0);
983 } else {
984 SKIP_TO_COM;
985 return(COMX);
986 }
987}
988
989SH(c12)
990 pacmac c12;
991{
992 int c1, c2;
993
994 frommac(c12, c1, c2);
995
996 if(parag){
997 printf(".%c%c",c1,c2);
998 while(C != '\n')putchar(c);
999 putchar(c);
1000 putchar('!');
1001 while(1){
1002 while(C != '\n')putchar(c);
1003 putchar('\n');
1004 if(C == '.')
1005 return(COM);
1006 putchar('!');
1007 putchar(c);
1008 }
1009 /*NOTREACHED*/
1010 } else {
1011 SKIP_TO_COM;
1012 return(COMX);
1013 }
1014}
1015
1016UX()
1017{
1018 if(wordflag)
1019 printf("UNIX\n");
1020 else
1021 printf("UNIX ");
1022 return(0);
1023}
1024
1025MMHU(c12)
1026 pacmac c12;
1027{
1028 int c1, c2;
1029
1030 frommac(c12, c1, c2);
1031 if(parag){
1032 printf(".%c%c",c1,c2);
1033 while(C != '\n')putchar(c);
1034 putchar('\n');
1035 } else {
1036 SKIP;
1037 }
1038 return(0);
1039}
1040
1041mesnblock(c12)
1042 pacmac c12;
1043{
1044 int c1, c2;
1045
1046 frommac(c12, c1, c2);
1047 noblock(')',c2);
1048 return(0);
1049}
1050mssnblock(c12)
1051 pacmac c12;
1052{
1053 int c1, c2;
1054
1055 frommac(c12, c1, c2);
1056 noblock(c1,'E');
1057 return(0);
1058}
1059nf()
1060{
1061 noblock('f','i');
1062 return(0);
1063}
1064
1065ce()
1066{
1067 sce();
1068 return(0);
1069}
1070
1071meip(c12)
1072 pacmac c12;
1073{
1074 if(parag)
1075 mepp(c12);
1076 else if (wordflag) /* save the tag */
1077 regline(meputmac, ONE);
1078 else {
1079 SKIP;
1080 }
1081 return(0);
1082}
1083/*
1084 * only called for -me .pp or .sh, when parag is on
1085 */
1086mepp(c12)
1087 pacmac c12;
1088{
1089 PP(c12); /* eats the line */
1090 return(0);
1091}
1092/*
1093 * Start of a section heading; output the section name if doing words
1094 */
1095mesh(c12)
1096 pacmac c12;
1097{
1098 if (parag)
1099 mepp(c12);
1100 else if (wordflag)
1101 defcomline(c12);
1102 else {
1103 SKIP;
1104 }
1105 return(0);
1106}
1107/*
1108 * process a font setting
1109 */
1110mefont(c12)
1111 pacmac c12;
1112{
1113 argconcat = 1;
1114 defcomline(c12);
1115 argconcat = 0;
1116 return(0);
1117}
1118manfont(c12)
1119 pacmac c12;
1120{
1121 return(mefont(c12));
1122}
1123manpp(c12)
1124 pacmac c12;
1125{
1126 return(mepp(c12));
1127}
1128
1129defcomline(c12)
1130 pacmac c12;
1131{
1132 int c1, c2;
1133
1134 frommac(c12, c1, c2);
1135 if(msflag && mac==MM && c2=='L'){
1136 if(disp || c1 == 'R') {
1137 noblock('L','E');
1138 } else {
1139 SKIP;
1140 putchar('.');
1141 }
1142 }
1143 else if(c1=='.' && c2=='.'){
1144 if(msflag){
1145 SKIP;
1146 return;
1147 }
1148 while(C == '.')
1149 /*VOID*/;
1150 }
1151 ++inmacro;
1152 /*
1153 * Process the arguments to the macro
1154 */
1155 switch(mac){
1156 default:
1157 case MM:
1158 case MS:
1159 if(c1 <= 'Z' && msflag)
1160 regline(msputmac, ONE);
1161 else
1162 regline(msputmac, TWO);
1163 break;
1164 case ME:
1165 regline(meputmac, ONE);
1166 break;
1167 }
1168 --inmacro;
1169}
1170
1171comline()
1172{
1173 reg int c1;
1174 reg int c2;
1175 pacmac c12;
1176 reg int mid;
1177 int lb, ub;
1178 int hit;
1179 static int tabsize = 0;
1180 static struct mactab *mactab = (struct mactab *)0;
1181 reg struct mactab *mp;
1182
1183 if (mactab == 0){
1184 buildtab(&mactab, &tabsize);
1185 }
1186com:
1187 while(C==' ' || c=='\t')
1188 ;
1189comx:
1190 if( (c1=c) == '\n')
1191 return;
1192 c2 = C;
1193 if(c1=='.' && c2 !='.')
1194 inmacro = NO;
1195 if(msflag && c1 == '['){
1196 refer(c2);
1197 return;
1198 }
1199 if(parag && mac==MM && c1 == 'P' && c2 == '\n'){
1200 printf(".P\n");
1201 return;
1202 }
1203 if(c2 == '\n')
1204 return;
1205 /*
1206 * Single letter macro
1207 */
1208 if (mac == ME && (c2 == ' ' || c2 == '\t') )
1209 c2 = ' ';
1210 c12 = tomac(c1, c2);
1211 /*
1212 * binary search through the table of macros
1213 */
1214 lb = 0;
1215 ub = tabsize - 1;
1216 while(lb <= ub){
1217 mid = (ub + lb) / 2;
1218 mp = &mactab[mid];
1219 if (mp->macname < c12)
1220 lb = mid + 1;
1221 else if (mp->macname > c12)
1222 ub = mid - 1;
1223 else {
1224 hit = 1;
1225#ifdef FULLDEBUG
1226 printf("preliminary hit macro %c%c ", c1, c2);
1227#endif FULLDEBUG
1228 switch(mp->condition){
1229 case NONE: hit = YES; break;
1230 case FNEST: hit = (filesp == files); break;
1231 case NOMAC: hit = !inmacro; break;
1232 case MAC: hit = inmacro; break;
1233 case PARAG: hit = parag; break;
1234 case NBLK: hit = !keepblock; break;
1235 default: hit = 0;
1236 }
1237 if (hit) {
1238#ifdef FULLDEBUG
1239 printf("MATCH\n");
1240#endif FULLDEBUG
1241 switch( (*(mp->func))(c12) ) {
1242 default: return;
1243 case COMX: goto comx;
1244 case COM: goto com;
1245 }
1246 }
1247#ifdef FULLDEBUG
1248 printf("FAIL\n");
1249#endif FULLDEBUG
1250 break;
1251 }
1252 }
1253 defcomline(c12);
1254}
1255
1256int macsort(p1, p2)
1257 struct mactab *p1, *p2;
1258{
1259 return(p1->macname - p2->macname);
1260}
1261
1262int sizetab(mp)
1263 reg struct mactab *mp;
1264{
1265 reg int i;
1266 i = 0;
1267 if (mp){
1268 for (; mp->macname; mp++, i++)
1269 /*VOID*/ ;
1270 }
1271 return(i);
1272}
1273
1274struct mactab *macfill(dst, src)
1275 reg struct mactab *dst;
1276 reg struct mactab *src;
1277{
1278 if (src) {
1279 while(src->macname){
1280 *dst++ = *src++;
1281 }
1282 }
1283 return(dst);
1284}
1285
1286buildtab(r_back, r_size)
1287 struct mactab **r_back;
1288 int *r_size;
1289{
1290 int size;
1291
1292 struct mactab *p, *p1, *p2;
1293 struct mactab *back;
1294
1295 size = sizetab(troffmactab);
1296 size += sizetab(ppmactab);
1297 p1 = p2 = (struct mactab *)0;
1298 if (msflag){
1299 switch(mac){
1300 case ME: p1 = memactab; break;
1301 case MM: p1 = msmactab;
1302 p2 = mmmactab; break;
1303
1304 case MS: p1 = msmactab; break;
1305 case MA: p1 = manmactab; break;
1306 default: break;
1307 }
1308 }
1309 size += sizetab(p1);
1310 size += sizetab(p2);
1311 back = (struct mactab *)calloc(size+2, sizeof(struct mactab));
1312
1313 p = macfill(back, troffmactab);
1314 p = macfill(p, ppmactab);
1315 p = macfill(p, p1);
1316 p = macfill(p, p2);
1317
1318 qsort(back, size, sizeof(struct mactab), macsort);
1319 *r_size = size;
1320 *r_back = back;
1321}
1322
1323/*
1324 * troff commands
1325 */
1326struct mactab troffmactab[] = {
1327 M(NONE, '\\','"', skip), /* comment */
1328 M(NOMAC, 'd','e', domacro), /* define */
1329 M(NOMAC, 'i','g', domacro), /* ignore till .. */
1330 M(NOMAC, 'a','m', domacro), /* append macro */
1331 M(NBLK, 'n','f', nf), /* filled */
1332 M(NBLK, 'c','e', ce), /* centered */
1333
1334 M(NONE, 's','o', so), /* source a file */
1335 M(NONE, 'n','x', nx), /* go to next file */
1336
1337 M(NONE, 't','m', skip), /* print string on tty */
1338 M(NONE, 'h','w', skip), /* exception hyphen words */
1339 M(NONE, 0,0, 0)
1340};
1341/*
1342 * Preprocessor output
1343 */
1344struct mactab ppmactab[] = {
1345 M(FNEST, 'E','Q', EQ), /* equation starting */
1346 M(FNEST, 'T','S', intbl), /* table starting */
1347 M(FNEST, 'T','C', intbl), /* alternative table? */
1348 M(FNEST, 'T','&', intbl), /* table reformatting */
1349 M(NONE, 'T','E', outtbl),/* table ending */
1350 M(NONE, 'P','S', PS), /* picture starting */
1351 M(NONE, 0,0, 0)
1352};
1353/*
1354 * Particular to ms and mm
1355 */
1356struct mactab msmactab[] = {
1357 M(NONE, 'T','L', skiptocom), /* title follows */
1358 M(NONE, 'F','S', skiptocom), /* start footnote */
1359 M(NONE, 'O','K', skiptocom), /* Other kws */
1360
1361 M(NONE, 'N','R', skip), /* undocumented */
1362 M(NONE, 'N','D', skip), /* use supplied date */
1363
1364 M(PARAG, 'P','P', PP), /* begin parag */
1365 M(PARAG, 'I','P', PP), /* begin indent parag, tag x */
1366 M(PARAG, 'L','P', PP), /* left blocked parag */
1367
1368 M(NONE, 'A','U', AU), /* author */
1369 M(NONE, 'A','I', AU), /* authors institution */
1370
1371 M(NONE, 'S','H', SH), /* section heading */
1372 M(NONE, 'S','N', SH), /* undocumented */
1373 M(NONE, 'U','X', UX), /* unix */
1374
1375 M(NBLK, 'D','S', mssnblock), /* start display text */
1376 M(NBLK, 'K','S', mssnblock), /* start keep */
1377 M(NBLK, 'K','F', mssnblock), /* start float keep */
1378 M(NONE, 0,0, 0)
1379};
1380
1381struct mactab mmmactab[] = {
1382 M(NONE, 'H',' ', MMHU), /* -mm ? */
1383 M(NONE, 'H','U', MMHU), /* -mm ? */
1384 M(PARAG, 'P',' ', PP), /* paragraph for -mm */
1385 M(NBLK, 'N','S', mssnblock), /* undocumented */
1386 M(NONE, 0,0, 0)
1387};
1388
1389struct mactab memactab[] = {
1390 M(PARAG, 'p','p', mepp),
1391 M(PARAG, 'l','p', mepp),
1392 M(PARAG, 'n','p', mepp),
1393 M(NONE, 'i','p', meip),
1394
1395 M(NONE, 's','h', mesh),
1396 M(NONE, 'u','h', mesh),
1397
1398 M(NBLK, '(','l', mesnblock),
1399 M(NBLK, '(','q', mesnblock),
1400 M(NBLK, '(','b', mesnblock),
1401 M(NBLK, '(','z', mesnblock),
1402 M(NBLK, '(','c', mesnblock),
1403
1404 M(NBLK, '(','d', mesnblock),
1405 M(NBLK, '(','f', mesnblock),
1406 M(NBLK, '(','x', mesnblock),
1407
1408 M(NONE, 'r',' ', mefont),
1409 M(NONE, 'i',' ', mefont),
1410 M(NONE, 'b',' ', mefont),
1411 M(NONE, 'u',' ', mefont),
1412 M(NONE, 'q',' ', mefont),
1413 M(NONE, 'r','b', mefont),
1414 M(NONE, 'b','i', mefont),
1415 M(NONE, 'b','x', mefont),
1416 M(NONE, 0,0, 0)
1417};
1418
1419
1420struct mactab manmactab[] = {
1421 M(PARAG, 'B','I', manfont),
1422 M(PARAG, 'B','R', manfont),
1423 M(PARAG, 'I','B', manfont),
1424 M(PARAG, 'I','R', manfont),
1425 M(PARAG, 'R','B', manfont),
1426 M(PARAG, 'R','I', manfont),
1427
1428 M(PARAG, 'P','P', manpp),
1429 M(PARAG, 'L','P', manpp),
1430 M(PARAG, 'H','P', manpp),
1431 M(NONE, 0,0, 0)
1432};