|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)deroff.c 4.5 (Berkeley) 84/12/18";
3: #endif not lint
4:
5: #include <stdio.h>
6:
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:
35: #define SKIP while(C != '\n')
36: #define SKIP_TO_COM SKIP; SKIP; pc=c; while(C != '.' || pc != '\n' || C > 'Z')pc=c
37:
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
46: char *mactab[] = {"-ms", "-mm", "-me", "-ma"};
47: #endif DEBUG
48:
49: #define ONE 1
50: #define TWO 2
51:
52: #define NOCHAR -2
53: #define SPECIAL 0
54: #define APOS 1
55: #define PUNCT 2
56: #define DIGIT 3
57: #define LETTER 4
58:
59: int wordflag;
60: int msflag; /* processing a source written using a mac package */
61: int mac; /* which package */
62: int disp;
63: int parag;
64: int inmacro;
65: int intable;
66: int keepblock; /* keep blocks of text; normally false when msflag */
67:
68: char chars[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
69:
70: char line[512];
71: char *lp;
72:
73: int c;
74: int pc;
75: int ldelim;
76: int rdelim;
77:
78:
79: int argc;
80: char **argv;
81:
82: char fname[50];
83: FILE *files[15];
84: FILE **filesp;
85: FILE *infile;
86: FILE *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:
106: main(ac, av)
107: int ac;
108: char **av;
109: {
110: register int i;
111: int errflg = 0;
112: register optchar;
113: FILE *opn();
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: }
162: }
163:
164: if (kflag)
165: keepblock = YES;
166: if (errflg)
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){
175: infile = stdin;
176: } else {
177: infile = opn(argv[0]);
178: --argc;
179: ++argv;
180: }
181:
182:
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: }
201: char *calloc();
202:
203: skeqn()
204: {
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)
211: c = eof();
212: else if(c == '\\')
213: if((c = getc(infile)) == EOF)
214: c = eof();
215: if(msflag)return(c='x');
216: return(c = ' ');
217: }
218:
219: FILE *opn(p)
220: register char *p;
221: {
222: FILE *fd;
223:
224: if( (fd = fopen(p, "r")) == NULL) {
225: fprintf(stderr, "Deroff: ");
226: perror(p);
227: exit(1);
228: }
229:
230: return(fd);
231: }
232:
233: eof()
234: {
235: if(infile != stdin)
236: fclose(infile);
237: if(filesp > files)
238: infile = *--filesp;
239: else if (argc > 0) {
240: infile = opn(argv[0]);
241: --argc;
242: ++argv;
243: } else
244: exit(0);
245: return(C);
246: }
247:
248: getfname()
249: {
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))
271: {
272: fname[0] = '\0';
273: return;
274: }
275:
276: q = (struct chain *) calloc(1, sizeof(*chainblock));
277: q->nextp = namechain;
278: q->datap = copys(fname);
279: namechain = q;
280: }
281:
282: fatal(s,p)
283: char *s, *p;
284: {
285: fprintf(stderr, "Deroff: ");
286: fprintf(stderr, s, p);
287: exit(1);
288: }
289:
290: /*ARGSUSED*/
291: textline(str, const)
292: char *str;
293: int const;
294: {
295: if (wordflag) {
296: msputwords(0);
297: return;
298: }
299: puts(str);
300: }
301:
302: work()
303: {
304: for( ;; )
305: {
306: C;
307: #ifdef FULLDEBUG
308: printf("Starting work with `%c'\n", c);
309: #endif FULLDEBUG
310: if(c == '.' || c == '\'')
311: comline();
312: else
313: regline(textline, TWO);
314: }
315: }
316:
317: regline(pfunc, const)
318: int (*pfunc)();
319: int const;
320: {
321: line[0] = c;
322: lp = line;
323: for( ; ; )
324: {
325: if(c == '\\') {
326: *lp = ' ';
327: backsl();
328: }
329: if(c == '\n')
330: break;
331: if(intable && c=='T') {
332: *++lp = C;
333: if(c=='{' || c=='}') {
334: lp[-1] = ' ';
335: *lp = C;
336: }
337: } else {
338: *++lp = C;
339: }
340: }
341:
342: *lp = '\0';
343:
344: if(line[0] != '\0')
345: (*pfunc)(line, const);
346: }
347:
348: macro()
349: {
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;
359: }
360:
361: tbl()
362: {
363: while(C != '.');
364: SKIP;
365: intable = YES;
366: }
367: stbl()
368: {
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: }
376: }
377:
378: eqn()
379: {
380: register int c1, c2;
381: register int dflg;
382: char last;
383:
384: last=0;
385: dflg = 1;
386: SKIP;
387:
388: for( ;;)
389: {
390: if(C1 == '.' || c == '\'')
391: {
392: while(C1==' ' || c=='\t')
393: ;
394: if(c=='E' && C1=='N')
395: {
396: SKIP;
397: if(msflag && dflg){
398: putchar('x');
399: putchar(' ');
400: if(last){
401: putchar(last);
402: putchar('\n');
403: }
404: }
405: return;
406: }
407: }
408: else if(c == 'd') /* look for delim */
409: {
410: if(C1=='e' && C1=='l')
411: if( C1=='i' && C1=='m')
412: {
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: }
424: }
425: dflg = 0;
426: }
427:
428: if(c != '\n') while(C1 != '\n'){
429: if(chars[c] == PUNCT)last = c;
430: else if(c != ' ')last = 0;
431: }
432: }
433: }
434:
435: backsl() /* skip over a complete backslash construction */
436: {
437: int bdelim;
438:
439: sw:
440: switch(C)
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';
451: }
452: --lp;
453: return;
454:
455: case 'f':
456: case 'n':
457: case '*':
458: if(C != '(')
459: return;
460:
461: case '(':
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: }
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:
501: char *copys(s)
502: register char *s;
503: {
504: register char *t, *t0;
505:
506: if( (t0 = t = calloc( (unsigned)(strlen(s)+1), sizeof(*t) ) ) == NULL)
507: fatal("Cannot allocate memory", (char *) NULL);
508:
509: while( *t++ = *s++ )
510: ;
511: return(t0);
512: }
513:
514: sce()
515: {
516: register char *ap;
517: register int n, i;
518: char a[10];
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 == ' ');
534: if(c == '0'){
535: SKIP;
536: break;
537: }
538: else SKIP;
539: }
540: else SKIP;
541: }
542: else if(c == 'P' || C == 'P'){
543: if(c != '\n')SKIP;
544: break;
545: }
546: else if(c != '\n')SKIP;
547: }
548: else {
549: SKIP;
550: i++;
551: }
552: }
553: }
554:
555: refer(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: }
575:
576: inpic()
577: {
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';
610: if(wordflag)msputwords(NO);
611: else {
612: puts(line);
613: putchar('\n');
614: }
615: p1 = line;
616: }
617: }
618: }
619:
620: #ifdef DEBUG
621: _C1()
622: {
623: return(C1get);
624: }
625: _C()
626: {
627: return(Cget);
628: }
629: #endif DEBUG
630:
631: /*
632: * Macro processing
633: *
634: * Macro table definitions
635: */
636: #define reg register
637: typedef int pacmac; /* compressed macro name */
638: int 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:
643: struct mactab{
644: int condition;
645: pacmac macname;
646: int (*func)();
647: };
648: struct mactab troffmactab[];
649: struct mactab ppmactab[];
650: struct mactab msmactab[];
651: struct mactab mmmactab[];
652: struct mactab memactab[];
653: struct 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: */
662: msputmac(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: */
706: msputwords(macline)
707: int macline; /* is this is a macro line */
708: {
709: register char *p, *p1;
710: int i, nlet;
711:
712: for(p1 = line ; ;) {
713: /*
714: * skip initial specials ampersands and apostrophes
715: */
716: while( chars[*p1] < DIGIT)
717: if(*p1++ == '\0') return;
718: nlet = 0;
719: for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
720: if(i == LETTER) ++nlet;
721:
722: if (nlet > 1 && chars[p1[0]] == LETTER) {
723: /*
724: * delete trailing ampersands and apostrophes
725: */
726: while( (i=chars[p[-1]]) == PUNCT || i == APOS )
727: --p;
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:
742: meputmac(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: */
829: meputwords(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:
854: noblock(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:
913: EQ()
914: {
915: eqn();
916: return(0);
917: }
918: domacro()
919: {
920: macro();
921: return(0);
922: }
923: PS()
924: {
925: if (!msflag) {
926: inpic();
927: } else {
928: noblock('P', 'E');
929: }
930: return(0);
931: }
932:
933: skip()
934: {
935: SKIP;
936: return(0);
937: }
938:
939: intbl()
940: {
941: if(msflag){
942: stbl();
943: }
944: else tbl();
945: return(0);
946: }
947:
948: outtbl(){ intable = NO; }
949:
950: so()
951: {
952: getfname();
953: if( fname[0] )
954: infile = *++filesp = opn( fname );
955: return(0);
956: }
957: nx()
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: }
966: skiptocom(){ SKIP_TO_COM; return(COMX); }
967:
968: PP(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: }
979: AU()
980: {
981: if(mac==MM) {
982: return(0);
983: } else {
984: SKIP_TO_COM;
985: return(COMX);
986: }
987: }
988:
989: SH(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:
1016: UX()
1017: {
1018: if(wordflag)
1019: printf("UNIX\n");
1020: else
1021: printf("UNIX ");
1022: return(0);
1023: }
1024:
1025: MMHU(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:
1041: mesnblock(c12)
1042: pacmac c12;
1043: {
1044: int c1, c2;
1045:
1046: frommac(c12, c1, c2);
1047: noblock(')',c2);
1048: return(0);
1049: }
1050: mssnblock(c12)
1051: pacmac c12;
1052: {
1053: int c1, c2;
1054:
1055: frommac(c12, c1, c2);
1056: noblock(c1,'E');
1057: return(0);
1058: }
1059: nf()
1060: {
1061: noblock('f','i');
1062: return(0);
1063: }
1064:
1065: ce()
1066: {
1067: sce();
1068: return(0);
1069: }
1070:
1071: meip(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: */
1086: mepp(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: */
1095: mesh(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: */
1110: mefont(c12)
1111: pacmac c12;
1112: {
1113: argconcat = 1;
1114: defcomline(c12);
1115: argconcat = 0;
1116: return(0);
1117: }
1118: manfont(c12)
1119: pacmac c12;
1120: {
1121: return(mefont(c12));
1122: }
1123: manpp(c12)
1124: pacmac c12;
1125: {
1126: return(mepp(c12));
1127: }
1128:
1129: defcomline(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:
1171: comline()
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: }
1186: com:
1187: while(C==' ' || c=='\t')
1188: ;
1189: comx:
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:
1256: int macsort(p1, p2)
1257: struct mactab *p1, *p2;
1258: {
1259: return(p1->macname - p2->macname);
1260: }
1261:
1262: int 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:
1274: struct 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:
1286: buildtab(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: */
1326: struct 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: */
1344: struct 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: */
1356: struct 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:
1381: struct 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:
1389: struct 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:
1420: struct 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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.