strmode doesn't allocate space anymore, just use the stack
[unix-history] / usr / src / usr.bin / deroff / deroff.c
CommitLineData
2958d0fe 1#ifndef lint
4e44ae42 2static char sccsid[] = "@(#)deroff.c 4.7 (Berkeley) 88/04/24";
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 290/*ARGSUSED*/
4e44ae42 291textline(str, constant)
ae8977bb 292 char *str;
4e44ae42 293 int constant;
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
4e44ae42 317regline(pfunc, constant)
ae8977bb 318 int (*pfunc)();
4e44ae42 319 int constant;
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')
4e44ae42 345 (*pfunc)(line, constant);
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 */
4e44ae42 662msputmac(s, constant)
ae8977bb 663 register char *s;
4e44ae42 664 int constant;
ae8977bb
RH
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++;
4e44ae42 682 if(t>s+constant && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER){
ae8977bb
RH
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
4e44ae42 742meputmac(cp, constant)
ae8977bb 743 reg char *cp;
4e44ae42 744 int constant;
ae8977bb
RH
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 *
4e44ae42 803 * constant is the cut off point below which something
ae8977bb
RH
804 * is not a word.
805 */
4e44ae42 806 if ( ( (np - cp) > constant)
ae8977bb
RH
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{
aec8209a
KB
925 for (C; c == ' ' || c == '\t'; C);
926 if (c == '<') { /* ".PS < file" -- don't expect a .PE */
927 SKIP;
928 return(0);
929 }
ae8977bb
RH
930 if (!msflag) {
931 inpic();
932 } else {
933 noblock('P', 'E');
934 }
935 return(0);
936}
937
938skip()
939{
940 SKIP;
941 return(0);
942}
943
944intbl()
945{
946 if(msflag){
947 stbl();
948 }
949 else tbl();
950 return(0);
951}
952
953outtbl(){ intable = NO; }
954
955so()
956{
957 getfname();
958 if( fname[0] )
959 infile = *++filesp = opn( fname );
960 return(0);
961}
962nx()
963{
964 getfname();
965 if(fname[0] == '\0') exit(0);
966 if(infile != stdin)
967 fclose(infile);
968 infile = *filesp = opn(fname);
969 return(0);
970}
971skiptocom(){ SKIP_TO_COM; return(COMX); }
972
973PP(c12)
974 pacmac c12;
975{
976 int c1, c2;
977
978 frommac(c12, c1, c2);
979 printf(".%c%c",c1,c2);
980 while(C != '\n')putchar(c);
981 putchar('\n');
982 return(0);
983}
984AU()
985{
986 if(mac==MM) {
987 return(0);
988 } else {
989 SKIP_TO_COM;
990 return(COMX);
991 }
992}
993
994SH(c12)
995 pacmac c12;
996{
997 int c1, c2;
998
999 frommac(c12, c1, c2);
1000
1001 if(parag){
1002 printf(".%c%c",c1,c2);
1003 while(C != '\n')putchar(c);
1004 putchar(c);
1005 putchar('!');
1006 while(1){
1007 while(C != '\n')putchar(c);
1008 putchar('\n');
1009 if(C == '.')
1010 return(COM);
1011 putchar('!');
1012 putchar(c);
1013 }
1014 /*NOTREACHED*/
1015 } else {
1016 SKIP_TO_COM;
1017 return(COMX);
1018 }
1019}
1020
1021UX()
1022{
1023 if(wordflag)
1024 printf("UNIX\n");
1025 else
1026 printf("UNIX ");
1027 return(0);
1028}
1029
1030MMHU(c12)
1031 pacmac c12;
1032{
1033 int c1, c2;
1034
1035 frommac(c12, c1, c2);
1036 if(parag){
1037 printf(".%c%c",c1,c2);
1038 while(C != '\n')putchar(c);
1039 putchar('\n');
1040 } else {
1041 SKIP;
1042 }
1043 return(0);
1044}
1045
1046mesnblock(c12)
1047 pacmac c12;
1048{
1049 int c1, c2;
1050
1051 frommac(c12, c1, c2);
1052 noblock(')',c2);
1053 return(0);
1054}
1055mssnblock(c12)
1056 pacmac c12;
1057{
1058 int c1, c2;
1059
1060 frommac(c12, c1, c2);
1061 noblock(c1,'E');
1062 return(0);
1063}
1064nf()
1065{
1066 noblock('f','i');
1067 return(0);
1068}
1069
1070ce()
1071{
1072 sce();
1073 return(0);
1074}
1075
1076meip(c12)
1077 pacmac c12;
1078{
1079 if(parag)
1080 mepp(c12);
1081 else if (wordflag) /* save the tag */
1082 regline(meputmac, ONE);
1083 else {
1084 SKIP;
1085 }
1086 return(0);
1087}
1088/*
1089 * only called for -me .pp or .sh, when parag is on
1090 */
1091mepp(c12)
1092 pacmac c12;
1093{
1094 PP(c12); /* eats the line */
1095 return(0);
1096}
1097/*
1098 * Start of a section heading; output the section name if doing words
1099 */
1100mesh(c12)
1101 pacmac c12;
1102{
1103 if (parag)
1104 mepp(c12);
1105 else if (wordflag)
1106 defcomline(c12);
1107 else {
1108 SKIP;
1109 }
1110 return(0);
1111}
1112/*
1113 * process a font setting
1114 */
1115mefont(c12)
1116 pacmac c12;
1117{
1118 argconcat = 1;
1119 defcomline(c12);
1120 argconcat = 0;
1121 return(0);
1122}
1123manfont(c12)
1124 pacmac c12;
1125{
1126 return(mefont(c12));
1127}
1128manpp(c12)
1129 pacmac c12;
1130{
1131 return(mepp(c12));
1132}
1133
1134defcomline(c12)
1135 pacmac c12;
1136{
1137 int c1, c2;
1138
1139 frommac(c12, c1, c2);
1140 if(msflag && mac==MM && c2=='L'){
1141 if(disp || c1 == 'R') {
1142 noblock('L','E');
1143 } else {
1144 SKIP;
1145 putchar('.');
1146 }
1147 }
1148 else if(c1=='.' && c2=='.'){
1149 if(msflag){
1150 SKIP;
1151 return;
1152 }
1153 while(C == '.')
1154 /*VOID*/;
1155 }
1156 ++inmacro;
1157 /*
1158 * Process the arguments to the macro
1159 */
1160 switch(mac){
1161 default:
1162 case MM:
1163 case MS:
1164 if(c1 <= 'Z' && msflag)
1165 regline(msputmac, ONE);
1166 else
1167 regline(msputmac, TWO);
1168 break;
1169 case ME:
1170 regline(meputmac, ONE);
1171 break;
1172 }
1173 --inmacro;
1174}
1175
1176comline()
1177{
1178 reg int c1;
1179 reg int c2;
1180 pacmac c12;
1181 reg int mid;
1182 int lb, ub;
1183 int hit;
1184 static int tabsize = 0;
1185 static struct mactab *mactab = (struct mactab *)0;
1186 reg struct mactab *mp;
1187
1188 if (mactab == 0){
1189 buildtab(&mactab, &tabsize);
1190 }
1191com:
1192 while(C==' ' || c=='\t')
1193 ;
1194comx:
1195 if( (c1=c) == '\n')
1196 return;
1197 c2 = C;
1198 if(c1=='.' && c2 !='.')
1199 inmacro = NO;
1200 if(msflag && c1 == '['){
1201 refer(c2);
1202 return;
1203 }
1204 if(parag && mac==MM && c1 == 'P' && c2 == '\n'){
1205 printf(".P\n");
1206 return;
1207 }
1208 if(c2 == '\n')
1209 return;
1210 /*
1211 * Single letter macro
1212 */
1213 if (mac == ME && (c2 == ' ' || c2 == '\t') )
1214 c2 = ' ';
1215 c12 = tomac(c1, c2);
1216 /*
1217 * binary search through the table of macros
1218 */
1219 lb = 0;
1220 ub = tabsize - 1;
1221 while(lb <= ub){
1222 mid = (ub + lb) / 2;
1223 mp = &mactab[mid];
1224 if (mp->macname < c12)
1225 lb = mid + 1;
1226 else if (mp->macname > c12)
1227 ub = mid - 1;
1228 else {
1229 hit = 1;
1230#ifdef FULLDEBUG
1231 printf("preliminary hit macro %c%c ", c1, c2);
1232#endif FULLDEBUG
1233 switch(mp->condition){
1234 case NONE: hit = YES; break;
1235 case FNEST: hit = (filesp == files); break;
1236 case NOMAC: hit = !inmacro; break;
1237 case MAC: hit = inmacro; break;
1238 case PARAG: hit = parag; break;
1239 case NBLK: hit = !keepblock; break;
1240 default: hit = 0;
1241 }
1242 if (hit) {
1243#ifdef FULLDEBUG
1244 printf("MATCH\n");
1245#endif FULLDEBUG
1246 switch( (*(mp->func))(c12) ) {
1247 default: return;
1248 case COMX: goto comx;
1249 case COM: goto com;
1250 }
1251 }
1252#ifdef FULLDEBUG
1253 printf("FAIL\n");
1254#endif FULLDEBUG
1255 break;
1256 }
1257 }
1258 defcomline(c12);
1259}
1260
1261int macsort(p1, p2)
1262 struct mactab *p1, *p2;
1263{
1264 return(p1->macname - p2->macname);
1265}
1266
1267int sizetab(mp)
1268 reg struct mactab *mp;
1269{
1270 reg int i;
1271 i = 0;
1272 if (mp){
1273 for (; mp->macname; mp++, i++)
1274 /*VOID*/ ;
1275 }
1276 return(i);
1277}
1278
1279struct mactab *macfill(dst, src)
1280 reg struct mactab *dst;
1281 reg struct mactab *src;
1282{
1283 if (src) {
1284 while(src->macname){
1285 *dst++ = *src++;
1286 }
1287 }
1288 return(dst);
1289}
1290
1291buildtab(r_back, r_size)
1292 struct mactab **r_back;
1293 int *r_size;
1294{
1295 int size;
1296
1297 struct mactab *p, *p1, *p2;
1298 struct mactab *back;
1299
1300 size = sizetab(troffmactab);
1301 size += sizetab(ppmactab);
1302 p1 = p2 = (struct mactab *)0;
1303 if (msflag){
1304 switch(mac){
1305 case ME: p1 = memactab; break;
1306 case MM: p1 = msmactab;
1307 p2 = mmmactab; break;
1308
1309 case MS: p1 = msmactab; break;
1310 case MA: p1 = manmactab; break;
1311 default: break;
1312 }
1313 }
1314 size += sizetab(p1);
1315 size += sizetab(p2);
1316 back = (struct mactab *)calloc(size+2, sizeof(struct mactab));
1317
1318 p = macfill(back, troffmactab);
1319 p = macfill(p, ppmactab);
1320 p = macfill(p, p1);
1321 p = macfill(p, p2);
1322
1323 qsort(back, size, sizeof(struct mactab), macsort);
1324 *r_size = size;
1325 *r_back = back;
1326}
1327
1328/*
1329 * troff commands
1330 */
1331struct mactab troffmactab[] = {
1332 M(NONE, '\\','"', skip), /* comment */
1333 M(NOMAC, 'd','e', domacro), /* define */
1334 M(NOMAC, 'i','g', domacro), /* ignore till .. */
1335 M(NOMAC, 'a','m', domacro), /* append macro */
1336 M(NBLK, 'n','f', nf), /* filled */
1337 M(NBLK, 'c','e', ce), /* centered */
1338
1339 M(NONE, 's','o', so), /* source a file */
1340 M(NONE, 'n','x', nx), /* go to next file */
1341
1342 M(NONE, 't','m', skip), /* print string on tty */
1343 M(NONE, 'h','w', skip), /* exception hyphen words */
1344 M(NONE, 0,0, 0)
1345};
1346/*
1347 * Preprocessor output
1348 */
1349struct mactab ppmactab[] = {
1350 M(FNEST, 'E','Q', EQ), /* equation starting */
1351 M(FNEST, 'T','S', intbl), /* table starting */
1352 M(FNEST, 'T','C', intbl), /* alternative table? */
1353 M(FNEST, 'T','&', intbl), /* table reformatting */
1354 M(NONE, 'T','E', outtbl),/* table ending */
1355 M(NONE, 'P','S', PS), /* picture starting */
1356 M(NONE, 0,0, 0)
1357};
1358/*
1359 * Particular to ms and mm
1360 */
1361struct mactab msmactab[] = {
1362 M(NONE, 'T','L', skiptocom), /* title follows */
1363 M(NONE, 'F','S', skiptocom), /* start footnote */
1364 M(NONE, 'O','K', skiptocom), /* Other kws */
1365
1366 M(NONE, 'N','R', skip), /* undocumented */
1367 M(NONE, 'N','D', skip), /* use supplied date */
1368
1369 M(PARAG, 'P','P', PP), /* begin parag */
1370 M(PARAG, 'I','P', PP), /* begin indent parag, tag x */
1371 M(PARAG, 'L','P', PP), /* left blocked parag */
1372
1373 M(NONE, 'A','U', AU), /* author */
1374 M(NONE, 'A','I', AU), /* authors institution */
1375
1376 M(NONE, 'S','H', SH), /* section heading */
1377 M(NONE, 'S','N', SH), /* undocumented */
1378 M(NONE, 'U','X', UX), /* unix */
1379
1380 M(NBLK, 'D','S', mssnblock), /* start display text */
1381 M(NBLK, 'K','S', mssnblock), /* start keep */
1382 M(NBLK, 'K','F', mssnblock), /* start float keep */
1383 M(NONE, 0,0, 0)
1384};
1385
1386struct mactab mmmactab[] = {
1387 M(NONE, 'H',' ', MMHU), /* -mm ? */
1388 M(NONE, 'H','U', MMHU), /* -mm ? */
1389 M(PARAG, 'P',' ', PP), /* paragraph for -mm */
1390 M(NBLK, 'N','S', mssnblock), /* undocumented */
1391 M(NONE, 0,0, 0)
1392};
1393
1394struct mactab memactab[] = {
1395 M(PARAG, 'p','p', mepp),
1396 M(PARAG, 'l','p', mepp),
1397 M(PARAG, 'n','p', mepp),
1398 M(NONE, 'i','p', meip),
1399
1400 M(NONE, 's','h', mesh),
1401 M(NONE, 'u','h', mesh),
1402
1403 M(NBLK, '(','l', mesnblock),
1404 M(NBLK, '(','q', mesnblock),
1405 M(NBLK, '(','b', mesnblock),
1406 M(NBLK, '(','z', mesnblock),
1407 M(NBLK, '(','c', mesnblock),
1408
1409 M(NBLK, '(','d', mesnblock),
1410 M(NBLK, '(','f', mesnblock),
1411 M(NBLK, '(','x', mesnblock),
1412
1413 M(NONE, 'r',' ', mefont),
1414 M(NONE, 'i',' ', mefont),
1415 M(NONE, 'b',' ', mefont),
1416 M(NONE, 'u',' ', mefont),
1417 M(NONE, 'q',' ', mefont),
1418 M(NONE, 'r','b', mefont),
1419 M(NONE, 'b','i', mefont),
1420 M(NONE, 'b','x', mefont),
1421 M(NONE, 0,0, 0)
1422};
1423
1424
1425struct mactab manmactab[] = {
1426 M(PARAG, 'B','I', manfont),
1427 M(PARAG, 'B','R', manfont),
1428 M(PARAG, 'I','B', manfont),
1429 M(PARAG, 'I','R', manfont),
1430 M(PARAG, 'R','B', manfont),
1431 M(PARAG, 'R','I', manfont),
1432
1433 M(PARAG, 'P','P', manpp),
1434 M(PARAG, 'L','P', manpp),
1435 M(PARAG, 'H','P', manpp),
1436 M(NONE, 0,0, 0)
1437};