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