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