|
|
1.1 root 1: char *xxxvers = "@(#)deroff.c 1.7";
2:
3:
4: #include <stdio.h>
5:
6: /* Deroff command -- strip troff, eqn, and Tbl sequences from
7: a file. Has three flags argument, -w, to cause output one word per line
8: rather than in the original format.
9: -mm (or -ms) causes the corresponding macro's to be interpreted
10: so that just sentences are output
11: -ml also gets rid of lists.
12: -i causes deroff to ignore .so and .nx commands.
13: Deroff follows .so and .nx commands, removes contents of macro
14: definitions, equations (both .EQ ... .EN and $...$),
15: Tbl command sequences, and Troff backslash constructions.
16:
17: All input is through the C macro; the most recently read character is in c.
18: */
19:
20: #define C ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() :( c == '\n'?(linect++,c):c) ))
21: #define C1 ( (c=getc(infile)) == EOF ? eof() : (c == '\n' ? (linect++,c): c))
22: #define SKIP while(C != '\n')
23: #define SKIP_TO_COM SKIP; SKIP; pc=c; while(C != '.' || pc != '\n' || C > 'Z')pc=c
24:
25: #define YES 1
26: #define NO 0
27: #define MS 0
28: #define MM 1
29: #define ONE 1
30: #define TWO 2
31:
32: #define NOCHAR -2
33: #define SPECIAL 0
34: #define APOS 1
35: #define PUNCT 2
36: #define DIGIT 3
37: #define LETTER 4
38:
39: int linect = 0;
40: int numflag = 0;
41: int wordflag = NO;
42: int msflag = NO;
43: int iflag = NO;
44: int mac = MM;
45: int disp = 0;
46: int parag = 0;
47: int inmacro = NO;
48: int intable = NO;
49: int eqnflag = 0;
50:
51: char chars[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */
52:
53: char line[512];
54: char *lp;
55:
56: int c;
57: int pc;
58: int ldelim = NOCHAR;
59: int rdelim = NOCHAR;
60:
61:
62: int argc;
63: char **argv;
64:
65: extern int optind;
66: extern char*optarg;
67: char fname[50];
68: FILE *files[15];
69: FILE **filesp;
70: FILE *infile;
71:
72: main(ac, av)
73: int ac;
74: char **av;
75: {
76: register int i;
77: int errflg = 0;
78: register optchar;
79: FILE *opn();
80:
81: argc = ac;
82: argv = av;
83: while ((optchar = getopt(argc, argv, "winpm:")) != EOF) switch(optchar) {
84: case 'n':
85: numflag = 1;
86: break;
87: case 'w':
88: wordflag = YES;
89: break;
90: case 'm':
91: msflag = YES;
92: if (*optarg == 'm')
93: mac = MM;
94: else if (*optarg == 's')
95: mac = MS;
96: else if (*optarg == 'l')
97: disp = 1;
98: else errflg++;
99: break;
100: case 'p':
101: parag=YES;
102: break;
103: case 'i':
104: iflag = YES;
105: break;
106: case '?':
107: errflg++;
108: }
109: if (errflg)
110: fatal("usage: deroff [ -w ] [ -m (m s l) ] [ -i ] [ file ] ... \n", (char *) NULL);
111: if ( optind == argc )
112: infile = stdin;
113: else
114: infile = opn(argv[optind++]);
115: files[0] = infile;
116: filesp = &files[0];
117:
118: for(i='a'; i<='z' ; ++i)
119: chars[i] = LETTER;
120: for(i='A'; i<='Z'; ++i)
121: chars[i] = LETTER;
122: for(i='0'; i<='9'; ++i)
123: chars[i] = DIGIT;
124: chars['\''] = APOS;
125: chars['&'] = APOS;
126: chars['.'] = PUNCT;
127: chars[','] = PUNCT;
128: chars[';'] = PUNCT;
129: chars['?'] = PUNCT;
130: chars[':'] = PUNCT;
131: work();
132: }
133: char *calloc();
134:
135:
136:
137:
138:
139:
140: skeqn()
141: {
142: while((c = getc(infile)) != rdelim)
143: if(c == '\n')linect++;
144: else if(c == '\\')
145: c = getc(infile);
146: else if(c == EOF)
147: c = eof();
148: else if(c == '"')
149: while( (c = getc(infile)) != '"')
150: if(c == '\n')linect++;
151: else if(c == EOF)
152: c = eof();
153: else if(c == '\\'){
154: if((c = getc(infile)) == EOF)
155: c = eof();
156: else if(c == '\n')linect++;
157: }
158: if(msflag)
159: eqnflag = 1;
160: return(c = ' ');
161: }
162:
163:
164: char *devnull = "/dev/null";
165: FILE *opn(p)
166: register char *p;
167: {
168: FILE *fd;
169:
170: again:
171: if( (fd = fopen(p, "r")) == NULL){
172: if(msflag || p==devnull)
173: fatal("Cannot open file %s - quitting\n", p);
174: else {
175: fprintf(stderr,"Deroff: Cannot open file %s - continuing\n",
176: p);
177: p = devnull;
178: goto again;
179: }
180: }
181: linect = 0;
182: if(numflag)printf(".F %s\n",p);
183:
184: return(fd);
185: }
186:
187:
188:
189: eof()
190: {
191: if(infile != stdin)
192: fclose(infile);
193: if(filesp > files)
194: infile = *--filesp;
195: else if(optind < argc)
196: {
197: infile = opn(argv[optind++]);
198: }
199: else
200: exit(0);
201:
202: return(C);
203: }
204:
205:
206:
207: getfname()
208: {
209: register char *p;
210: struct chain {
211: struct chain *nextp;
212: char *datap;
213: } *chainblock;
214: register struct chain *q;
215: static struct chain *namechain = NULL;
216: char *copys();
217:
218: while(C == ' ') ;
219:
220: for(p = fname ; (*p=c)!= '\n' && c!=' ' && c!='\t' && c!='\\' ; ++p)
221: C;
222: *p = '\0';
223: while(c != '\n')
224: C;
225:
226: /* see if this name has already been used */
227:
228: for(q = namechain ; q; q = q->nextp)
229: if( ! strcmp(fname, q->datap))
230: {
231: fname[0] = '\0';
232: return;
233: }
234:
235: q = (struct chain *) calloc(1, sizeof(*chainblock));
236: q->nextp = namechain;
237: q->datap = copys(fname);
238: namechain = q;
239: }
240:
241:
242:
243:
244: fatal(s,p)
245: char *s, *p;
246: {
247: fprintf(stderr, "Deroff: ");
248: fprintf(stderr, s, p);
249: exit(1);
250: }
251:
252: work()
253: {
254:
255: for( ;; )
256: {
257: eqnflag = 0;
258: if(C == '.' || c == '\'')
259: comline();
260: else
261: regline(NO,TWO);
262: }
263: }
264:
265:
266:
267:
268: regline(macline,const)
269: int macline;
270: int const;
271: {
272: line[0] = c;
273: lp = line;
274: for( ; ; )
275: {
276: if(c == '\\')
277: {
278: *lp = ' ';
279: backsl();
280: if ( c == '%') /* no blank for hyphenation char */
281: lp--;
282: }
283: if(c == '\n') break;
284: if(intable && c=='T')
285: {
286: *++lp = C;
287: if(c=='{' || c=='}')
288: {
289: lp[-1] = ' ';
290: *lp = C;
291: }
292: }
293: else {
294: if((msflag == 1) && (eqnflag == 1)){
295: eqnflag = 0;
296: *++lp = 'x';
297: }
298: *++lp = C;
299: }
300: }
301:
302: *lp = '\0';
303:
304: if(line[0] != '\0'){
305: if(wordflag)
306: putwords(macline);
307: else if(macline)
308: putmac(line,const);
309: else
310: puts(line);
311: if(numflag &&(linect%10 == 0))printf(".%d\n",linect);
312: }
313: }
314:
315:
316:
317:
318: putmac(s,const)
319: register char *s;
320: int const;
321: {
322: register char *t;
323: register found;
324: int last;
325: found = 0;
326:
327: while(*s)
328: {
329: while(*s==' ' || *s=='\t')
330: putchar(*s++);
331: for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t)
332: ;
333: if(*s == '\"')s++;
334: if(t>s+const && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER){
335: while(s < t)
336: if(*s == '\"')s++;
337: else
338: putchar(*s++);
339: last = *(t-1);
340: found++;
341: }
342: else if(found && chars[ s[0] ] == PUNCT && s[1] == '\0')
343: putchar(*s++);
344: else{
345: last = *(t-1);
346: s = t;
347: }
348: }
349: putchar('\n');
350: if(msflag && chars[last] == PUNCT){
351: printf(" %c\n",last);
352: }
353: }
354:
355:
356:
357: putwords(macline) /* break into words for -w option */
358: int macline;
359: {
360: register char *p, *p1;
361: int i, nlet;
362:
363:
364: for(p1 = line ; ;)
365: {
366: /* skip initial specials ampersands and apostrophes */
367: while( chars[*p1] < DIGIT)
368: if(*p1++ == '\0') return;
369: nlet = 0;
370: for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
371: if(i == LETTER) ++nlet;
372:
373: if( (!macline && nlet>1) /* MDM definition of word */
374: || (macline && nlet>2 && chars[ p1[0] ]==LETTER && chars[ p1[1] ]==LETTER) )
375: {
376: /* delete trailing ampersands and apostrophes */
377: while(p[-1]=='\'' || p[-1]=='&'|| chars[ p[-1] ] == PUNCT)
378: --p;
379: while(p1 < p) putchar(*p1++);
380: putchar('\n');
381: }
382: else
383: p1 = p;
384: }
385: }
386:
387:
388: comline()
389: {
390: register int c1, c2;
391:
392: com:
393: while(C==' ' || c=='\t')
394: ;
395: comx:
396: if( (c1=c) == '\n')
397: return;
398: c2 = C;
399: if(c1=='.' && c2!='.')
400: inmacro = NO;
401: if(msflag && c1 == '['){
402: refer(c2);
403: return;
404: }
405: if(parag && mac==MM && c1 == 'P' && c2 == '\n'){
406: printf(".P\n");
407: return;
408: }
409: if(c2 == '\n')
410: return;
411:
412: if(c1 == '\\' && c2 == '\"')
413: SKIP;
414: else if(c1=='E' && c2=='Q' && filesp==files)
415: eqn();
416: else if(c1=='T' && (c2=='S' || c2=='C' || c2=='&') && filesp==files){
417: if(msflag){
418: stbl();
419: }
420: else tbl();
421: }
422: else if(c1=='T' && c2=='E')
423: intable = NO;
424: else if(!inmacro && c1=='d' && c2=='e')
425: macro();
426: else if(!inmacro && c1=='i' && c2=='g')
427: macro();
428: else if(!inmacro && c1=='a' && c2 == 'm')
429: macro();
430: else if(c1=='s' && c2=='o')
431: {
432: if(iflag)
433: SKIP;
434: else
435: {
436: getfname();
437: if( fname[0] ){
438: infile = *++filesp = opn( fname );
439: if(!infile)
440: infile = *--filesp;
441: }
442: }
443: }
444: else if(c1=='n' && c2=='x')
445: if(iflag)
446: SKIP;
447: else
448: {
449: getfname();
450: if(fname[0] == '\0') exit(0);
451: if(infile != stdin)
452: fclose(infile);
453: infile = *filesp = opn(fname);
454: }
455: else if(c1 == 't' && c2 == 'm')
456: SKIP;
457: else if(c1=='h' && c2=='w')
458: SKIP;
459: else if(msflag && c1 == 'T' && c2 == 'L'){
460: SKIP_TO_COM;
461: goto comx;
462: }
463: else if(msflag && c1=='N' && c2 == 'R')SKIP;
464: else if(parag && msflag && (c1 == 'P' || c1 == 'I' || c1 == 'L') && c2 == 'P'){
465: printf(".%c%c",c1,c2);
466: while(C != '\n')putchar(c);
467: putchar('\n');
468: }
469: else if(parag && mac==MM && c1 == 'P' && c2 == ' '){
470: printf(".%c%c",c1,c2);
471: while(C != '\n')putchar(c);
472: putchar('\n');
473: }
474: else if(msflag && c1 == 'A' && (c2 == 'U' || c2 == 'I')){
475: if(mac==MM)SKIP;
476: else {
477: SKIP_TO_COM;
478: goto comx;
479: }
480: }
481: else if(msflag && c1 == 'F' && c2 == 'S'){
482: SKIP_TO_COM;
483: goto comx;
484: }
485: else if(msflag && (c1 == 'S' || c1 == 'N') && c2 == 'H'){
486: if(parag){
487: printf(".%c%c",c1,c2);
488: while(C != '\n')putchar(c);
489: putchar(c);
490: putchar('!');
491: while(1){
492: while(C != '\n')putchar(c);
493: putchar('\n');
494: if(C == '.')goto com;
495: putchar('!');
496: putchar(c);
497: }
498: }
499: else {
500: SKIP_TO_COM;
501: goto comx;
502: }
503: }
504: else if(c1 == 'U' && c2 == 'X'){
505: if(wordflag)printf("UNIX\n");
506: else printf("UNIX ");
507: }
508: else if(msflag && c1 == 'O' && c2 == 'K'){
509: SKIP_TO_COM;
510: goto comx;
511: }
512: else if(msflag && c1 == 'N' && c2 == 'D')
513: SKIP;
514: else if(msflag && mac==MM && c1=='H' && (c2==' '||c2=='U')){
515: if(parag){
516: printf(".%c%c",c1,c2);
517: while(C != '\n')putchar(c);
518: putchar('\n');
519: }
520: else {
521: SKIP;
522: }
523: }
524: else if(msflag && mac==MM && c2=='L'){
525: if(disp || c1 == 'R')sdis('L','E');
526: else{
527: SKIP;
528: printf(" .");
529: }
530: }
531: else if(!msflag &&c1 == 'P' && c2 == 'S'){
532: inpic();
533: }
534: else if(msflag && (c1 == 'D' || c1 == 'N' || c1 == 'K'|| c1=='P') && c2 == 'S')
535: {
536: sdis(c1,'E');
537: } /* removed RS-RE */
538: else if(msflag && (c1 == 'K' && c2 == 'F'))
539: {
540: sdis(c1,'E');
541: }
542: else if(msflag && c1 == 'n' && c2 == 'f')
543: sdis('f','i');
544: else if(msflag && c1 == 'c' && c2 == 'e')
545: sce();
546: else
547: {
548: if(c1=='.' && c2=='.'){
549: if(msflag){
550: SKIP;
551: return;
552: }
553: while(C == '.')
554: ;
555: }
556: ++inmacro;
557: if(c1 <= 'Z' && msflag)regline(YES,ONE);
558: else regline(YES,TWO);
559: --inmacro;
560: }
561: }
562:
563:
564:
565: macro()
566: {
567: if(msflag){
568: do {
569: SKIP;
570: } while(C!='.' || C!='.' || C=='.'); /* look for .. */
571: if(c != '\n')SKIP;
572: return;
573: }
574: SKIP;
575: inmacro = YES;
576: }
577:
578:
579:
580:
581: sdis(a1,a2)
582: char a1,a2;
583: {
584: register int c1,c2;
585: register int eqnf;
586: int lct;
587: if(a1 == 'P'){
588: if(C == ' ')
589: while(C == ' ');
590: if(c == '<'){
591: SKIP;
592: return;
593: }
594: }
595: lct = 0;
596: eqnf=1;
597: if(c != '\n')
598: SKIP;
599: while(1){
600: while(C != '.')
601: if(c == '\n')continue;
602: else SKIP;
603: if((c1=C) == '\n')continue;
604: if((c2=C) == '\n')continue;
605: if(c1==a1 && c2 == a2){
606: SKIP;
607: if(lct != 0){
608: lct--;
609: continue;
610: }
611: if(eqnf)printf(" .");
612: putchar('\n');
613: return;
614: }
615: else if(a1 == 'L' && c2 == 'L'){
616: lct++;
617: SKIP;
618: }
619: else if(a1 == 'D' && c1 == 'E' && c2 == 'Q'){
620: eqn();
621: eqnf=0;
622: }
623: else if(a1 == 'f' && (c1 == 'P' || c2 == 'P')){
624: SKIP;
625: return;
626: }
627: else SKIP;
628: }
629: }
630: tbl()
631: {
632: while(C != '.');
633: SKIP;
634: intable = YES;
635: }
636: stbl()
637: {
638: while(C != '.');
639: SKIP_TO_COM;
640: if(c != 'T' || C != 'E'){
641: SKIP;
642: pc=c;
643: while(C != '.' || pc != '\n' || C != 'T' || C != 'E')pc=c;
644: }
645: }
646:
647: eqn()
648: {
649: register int c1, c2;
650: register int dflg;
651: char last;
652:
653: last=0;
654: dflg = 1;
655: SKIP;
656:
657: for( ;;)
658: {
659: if(C1 == '.' || c == '\'')
660: {
661: while(C1==' ' || c=='\t')
662: ;
663: if(c=='E' && C1=='N')
664: {
665: SKIP;
666: if(msflag && dflg){
667: putchar('x');
668: putchar(' ');
669: if(last){
670: putchar(last);
671: putchar('\n');
672: }
673: }
674: return;
675: }
676: }
677: else if(c == 'd') /* look for delim */
678: {
679: if(C1=='e' && C1=='l')
680: if( C1=='i' && C1=='m')
681: {
682: while(C1 == ' ');
683: if((c1=c)=='\n' || (c2=C1)=='\n'
684: || (c1=='o' && c2=='f' && C1=='f') )
685: {
686: ldelim = NOCHAR;
687: rdelim = NOCHAR;
688: }
689: else {
690: ldelim = c1;
691: rdelim = c2;
692: }
693: }
694: dflg = 0;
695: }
696:
697: if(c != '\n') while(C1 != '\n'){
698: if(chars[c] == PUNCT)last = c;
699: else if(c != ' ')last = 0;
700: }
701: }
702: }
703:
704:
705: backsl() /* skip over a complete backslash construction */
706: {
707: int bdelim;
708:
709: sw:
710: switch(C)
711: {
712: case '"':
713: SKIP;
714: return;
715: case 's':
716: if(C == '\\') backsl();
717: else {
718: while(C>='0' && c<='9') ;
719: ungetc(c,infile);
720: c = '0';
721: }
722: --lp;
723: return;
724:
725: case 'f':
726: case 'n':
727: case '*':
728: if(C != '(')
729: return;
730:
731: case '(':
732: if(msflag){
733: if(C == 'e'){
734: if(C == 'm'){
735: *lp = '-';
736: return;
737: }
738: }
739: else if(c != '\n')C;
740: return;
741: }
742: if(C != '\n') C;
743: return;
744:
745: case '$':
746: C; /* discard argument number */
747: return;
748:
749: case 'b':
750: case 'x':
751: case 'v':
752: case 'h':
753: case 'w':
754: case 'o':
755: case 'l':
756: case 'L':
757: if( (bdelim=C) == '\n')
758: return;
759: while(C!='\n' && c!=bdelim)
760: if(c == '\\') backsl();
761: return;
762:
763: case '\\':
764: if(inmacro)
765: goto sw;
766: default:
767: return;
768: }
769: }
770:
771:
772:
773:
774: char *copys(s)
775: register char *s;
776: {
777: register char *t, *t0;
778:
779: if( (t0 = t = calloc( (unsigned)(strlen(s)+1), sizeof(*t) ) ) == NULL)
780: fatal("Cannot allocate memory", (char *) NULL);
781:
782: while( *t++ = *s++ )
783: ;
784: return(t0);
785: }
786: sce(){
787: register char *ap;
788: register int n, i;
789: char a[10];
790: for(ap=a;C != '\n';ap++){
791: *ap = c;
792: if(ap == &a[9]){
793: SKIP;
794: ap=a;
795: break;
796: }
797: }
798: if(ap != a)n = atoi(a);
799: else n = 1;
800: for(i=0;i<n;){
801: if(C == '.'){
802: if(C == 'c'){
803: if(C == 'e'){
804: while(C == ' ');
805: if(c == '0'){
806: SKIP;
807: break;
808: }
809: else SKIP;
810: }
811: else SKIP;
812: }
813: else if(c == 'P' || C == 'P'){
814: if(c != '\n')SKIP;
815: break;
816: }
817: else if(c != '\n')SKIP;
818: }
819: else {
820: SKIP;
821: i++;
822: }
823: }
824: }
825: refer(c1)
826: {
827: register int c2;
828: if(c1 != '\n')
829: SKIP;
830: while(1){
831: if(C != '.')
832: SKIP;
833: else {
834: if(C != ']')
835: SKIP;
836: else {
837: while(C != '\n')
838: c2=c;
839: if(chars[c2] == PUNCT)printf(" %c",c2);
840: return;
841: }
842: }
843: }
844: }
845: inpic(){
846: register int c1;
847: register char *p1;
848: SKIP;
849: p1 = line;
850: c = '\n';
851: while(1){
852: c1 = c;
853: if(C1 == '.' && c1 == '\n'){
854: if(C1 != 'P'){
855: if(c == '\n')continue;
856: else { SKIP; c='\n'; continue;}
857: }
858: if(C1 != 'E'){
859: if(c == '\n')continue;
860: else { SKIP; c='\n';continue; }
861: }
862: SKIP;
863: return;
864: }
865: else if(c == '\"'){
866: while(C1 != '\"'){
867: if(c == '\\'){
868: if(C1 == '\"')continue;
869: ungetc(c,infile);
870: backsl();
871: }
872: else *p1++ = c;
873: }
874: *p1++ = ' ';
875: }
876: else if(c == '\n' && p1 != line){
877: *p1 = '\0';
878: if(wordflag)putwords(NO);
879: else {
880: puts(line);
881: putchar('\n');
882: }
883: p1 = line;
884: }
885: }
886: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.