1: char *xxxvers = "\nDeroff Version 1.02 24 July 1978\n";
2:
3:
4: #include <stdio.h>
5:
6: /* Deroff command -- strip troff, eqn, and Tbl sequences from
7: a file. Has one flag argument, -w, to cause output one word per line
8: rather than in the original format.
9: Deroff follows .so and .nx commands, removes contents of macro
10: definitions, equations (both .EQ ... .EN and $...$),
11: Tbl command sequences, and Troff backslash constructions.
12:
13: All input is through the C macro; the most recently read character is in c.
14: */
15:
16: #define C ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
17: #define C1 ( (c=getc(infile)) == EOF ? eof() : c)
18: #define SKIP while(C != '\n')
19:
20: #define YES 1
21: #define NO 0
22:
23: #define NOCHAR -2
24: #define SPECIAL 0
25: #define APOS 1
26: #define DIGIT 2
27: #define LETTER 3
28:
29: int wordflag = NO;
30: int inmacro = NO;
31: int intable = NO;
32:
33: char chars[128]; /* SPECIAL, APOS, DIGIT, or LETTER */
34:
35: char line[512];
36: char *lp;
37:
38: int c;
39: int ldelim = NOCHAR;
40: int rdelim = NOCHAR;
41:
42:
43: int argc;
44: char **argv;
45:
46: char fname[50];
47: FILE *files[15];
48: FILE **filesp;
49: FILE *infile;
50:
51: char *calloc();
52:
53:
54:
55: main(ac, av)
56: int ac;
57: char **av;
58: {
59: register int i;
60: register char *p;
61: static char onechar[2] = "X";
62: FILE *opn();
63:
64: argc = ac - 1;
65: argv = av + 1;
66:
67: while(argc>0 && argv[0][0]=='-' && argv[0][1]!='\0')
68: {
69: for(p=argv[0]+1; *p; ++p) switch(*p)
70: {
71: case 'w':
72: wordflag = YES;
73: break;
74: default:
75: onechar[0] = *p;
76: fatal("Invalid flag %s\n", onechar);
77: }
78: --argc;
79: ++argv;
80: }
81:
82: if(argc == 0)
83: infile = stdin;
84: else {
85: infile = opn(argv[0]);
86: --argc;
87: ++argv;
88: }
89:
90: files[0] = infile;
91: filesp = &files[0];
92:
93: for(i='a'; i<='z' ; ++i)
94: chars[i] = LETTER;
95: for(i='A'; i<='Z'; ++i)
96: chars[i] = LETTER;
97: for(i='0'; i<='9'; ++i)
98: chars[i] = DIGIT;
99: chars['\''] = APOS;
100: chars['&'] = APOS;
101:
102: work();
103: }
104:
105:
106:
107: skeqn()
108: {
109: while((c = getc(infile)) != rdelim)
110: if(c == EOF)
111: c = eof();
112: else if(c == '"')
113: while( (c = getc(infile)) != '"')
114: if(c == EOF)
115: c = eof();
116: else if(c == '\\')
117: if((c = getc(infile)) == EOF)
118: c = eof();
119: return(c = ' ');
120: }
121:
122:
123: FILE *opn(p)
124: register char *p;
125: {
126: FILE *fd;
127:
128: if(p[0]=='-' && p[1]=='\0')
129: fd = stdin;
130: else if( (fd = fopen(p, "r")) == NULL)
131: fatal("Cannot open file %s\n", p);
132:
133: return(fd);
134: }
135:
136:
137:
138: eof()
139: {
140: if(infile != stdin)
141: fclose(infile);
142: if(filesp > files)
143: infile = *--filesp;
144: else if(argc > 0)
145: {
146: infile = opn(argv[0]);
147: --argc;
148: ++argv;
149: }
150: else
151: exit(0);
152:
153: return(C);
154: }
155:
156:
157:
158: getfname()
159: {
160: register char *p;
161: struct chain { struct chain *nextp; char *datap; } *chainblock;
162: register struct chain *q;
163: static struct chain *namechain = NULL;
164: char *copys();
165:
166: while(C == ' ') ;
167:
168: for(p = fname ; (*p=c)!= '\n' && c!=' ' && c!='\t' && c!='\\' ; ++p)
169: C;
170: *p = '\0';
171: while(c != '\n')
172: C;
173:
174: /* see if this name has already been used */
175:
176: for(q = namechain ; q; q = q->nextp)
177: if( ! strcmp(fname, q->datap))
178: {
179: fname[0] = '\0';
180: return;
181: }
182:
183: q = (struct chain *) calloc(1, sizeof(*chainblock));
184: q->nextp = namechain;
185: q->datap = copys(fname);
186: namechain = q;
187: }
188:
189:
190:
191:
192: fatal(s,p)
193: char *s, *p;
194: {
195: fprintf(stderr, "Deroff: ");
196: fprintf(stderr, s, p);
197: exit(1);
198: }
199:
200: work()
201: {
202:
203: for( ;; )
204: {
205: if(C == '.' || c == '\'')
206: comline();
207: else
208: regline(NO);
209: }
210: }
211:
212:
213:
214:
215: regline(macline)
216: int macline;
217: {
218: line[0] = c;
219: lp = line;
220: for( ; ; )
221: {
222: if(c == '\\')
223: {
224: *lp = ' ';
225: backsl();
226: }
227: if(c == '\n') break;
228: if(intable && c=='T')
229: {
230: *++lp = C;
231: if(c=='{' || c=='}')
232: {
233: lp[-1] = ' ';
234: *lp = C;
235: }
236: }
237: else *++lp = C;
238: }
239:
240: *lp = '\0';
241:
242: if(line[0] != '\0')
243: if(wordflag)
244: putwords(macline);
245: else if(macline)
246: putmac(line);
247: else
248: puts(line);
249: }
250:
251:
252:
253:
254: putmac(s)
255: register char *s;
256: {
257: register char *t;
258:
259: while(*s)
260: {
261: while(*s==' ' || *s=='\t')
262: putchar(*s++);
263: for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t)
264: ;
265: if(t>s+2 && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER)
266: while(s < t)
267: putchar(*s++);
268: else
269: s = t;
270: }
271: putchar('\n');
272: }
273:
274:
275:
276: putwords(macline) /* break into words for -w option */
277: int macline;
278: {
279: register char *p, *p1;
280: int i, nlet;
281:
282:
283: for(p1 = line ; ;)
284: {
285: /* skip initial specials ampersands and apostrophes */
286: while( chars[*p1] < DIGIT)
287: if(*p1++ == '\0') return;
288: nlet = 0;
289: for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
290: if(i == LETTER) ++nlet;
291:
292: if( (!macline && nlet>1) /* MDM definition of word */
293: || (macline && nlet>2 && chars[ p1[0] ]==LETTER && chars[ p1[1] ]==LETTER) )
294: {
295: /* delete trailing ampersands and apostrophes */
296: while(p[-1]=='\'' || p[-1]=='&')
297: --p;
298: while(p1 < p) putchar(*p1++);
299: putchar('\n');
300: }
301: else
302: p1 = p;
303: }
304: }
305:
306:
307:
308: comline()
309: {
310: register int c1, c2;
311:
312: while(C==' ' || c=='\t')
313: ;
314: if( (c1=c) == '\n')
315: return;
316: c2 = C;
317: if(c1=='.' && c2!='.')
318: inmacro = NO;
319: if(c2 == '\n')
320: return;
321:
322: if(c1=='E' && c2=='Q' && filesp==files)
323: eqn();
324: else if(c1=='T' && (c2=='S' || c2=='C' || c2=='&') && filesp==files)
325: tbl();
326: else if(c1=='T' && c2=='E')
327: intable = NO;
328: else if(!inmacro && c1=='d' && c2=='e')
329: macro();
330: else if(!inmacro && c1=='i' && c2=='g')
331: macro();
332: else if(!inmacro && c1=='a' && c2 == 'm')
333: macro();
334: else if(c1=='s' && c2=='o')
335: {
336: getfname();
337: if( fname[0] )
338: infile = *++filesp = opn( fname );
339: }
340: else if(c1=='n' && c2=='x')
341: {
342: getfname();
343: if(fname[0] == '\0') exit(0);
344: if(infile != stdin)
345: fclose(infile);
346: infile = *filesp = opn(fname);
347: }
348: else if(c1=='h' && c2=='w')
349: { SKIP; }
350: else
351: {
352: if(c1=='.' && c2=='.')
353: while(C == '.')
354: ;
355: ++inmacro;
356: regline(YES);
357: --inmacro;
358: }
359: }
360:
361:
362:
363: macro()
364: {
365: /*
366: do { SKIP; }
367: while(C!='.' || C!='.' || C=='.'); /* look for .. */
368: SKIP;
369: inmacro = YES;
370: }
371:
372:
373:
374:
375: tbl()
376: {
377: while(C != '.');
378: SKIP;
379: intable = YES;
380: }
381:
382: eqn()
383: {
384: register int c1, c2;
385:
386: SKIP;
387:
388: for( ;;)
389: {
390: if(C == '.' || c == '\'')
391: {
392: while(C==' ' || c=='\t')
393: ;
394: if(c=='E' && C=='N')
395: {
396: SKIP;
397: return;
398: }
399: }
400: else if(c == 'd') /* look for delim */
401: {
402: if(C=='e' && C=='l')
403: if( C=='i' && C=='m')
404: {
405: while(C1 == ' ');
406: if((c1=c)=='\n' || (c2=C1)=='\n'
407: || (c1=='o' && c2=='f' && C1=='f') )
408: {
409: ldelim = NOCHAR;
410: rdelim = NOCHAR;
411: }
412: else {
413: ldelim = c1;
414: rdelim = c2;
415: }
416: }
417: }
418:
419: if(c != '\n') SKIP;
420: }
421: }
422:
423:
424:
425: backsl() /* skip over a complete backslash construction */
426: {
427: int bdelim;
428:
429: sw: switch(C)
430: {
431: case '"':
432: SKIP;
433: return;
434: case 's':
435: if(C == '\\') backsl();
436: else {
437: while(C>='0' && c<='9') ;
438: ungetc(c,infile);
439: c = '0';
440: }
441: --lp;
442: return;
443:
444: case 'f':
445: case 'n':
446: case '*':
447: if(C != '(')
448: return;
449:
450: case '(':
451: if(C != '\n') C;
452: return;
453:
454: case '$':
455: C; /* discard argument number */
456: return;
457:
458: case 'b':
459: case 'x':
460: case 'v':
461: case 'h':
462: case 'w':
463: case 'o':
464: case 'l':
465: case 'L':
466: if( (bdelim=C) == '\n')
467: return;
468: while(C!='\n' && c!=bdelim)
469: if(c == '\\') backsl();
470: return;
471:
472: case '\\':
473: if(inmacro)
474: goto sw;
475: default:
476: return;
477: }
478: }
479:
480:
481:
482:
483: char *copys(s)
484: register char *s;
485: {
486: register char *t, *t0;
487:
488: if( (t0 = t = calloc( strlen(s)+1, sizeof(*t) ) ) == NULL)
489: fatal("Cannot allocate memory", (char *) NULL);
490:
491: while( *t++ = *s++ )
492: ;
493: return(t0);
494: }
Defined functions
eof
defined in line
138; used 5 times
eqn
defined in line
382; used 1 times
main
defined in line
55;
never used
opn
defined in line
123; used 5 times
tbl
defined in line
375; used 1 times
work
defined in line
200; used 1 times
Defined variables
argc
defined in line
43; used 7 times
argv
defined in line
44; used 9 times
c
defined in line
38; used 41 times
- in line 16-17(5),
109-119(11),
168-171(5),
205,
218-231(6),
312-314(2),
390-394(3),
400,
406,
419,
437-439(3),
468-469(2)
chars
defined in line
33; used 11 times
fname
defined in line
46; used 8 times
line
defined in line
35; used 6 times
lp
defined in line
36; used 8 times
Defined struct's
Defined macros
APOS
defined in line
25; used 2 times
C
defined in line
16; used 29 times
- in line 18,
153,
166-172(3),
205,
230-237(3),
312-316(2),
353,
377,
390-394(3),
402-403(4),
429,
435-437(2),
447-455(4),
466-468(2)
C1
defined in line
17; used 3 times
DIGIT
defined in line
26; used 2 times
NO
defined in line
21; used 6 times
SKIP
defined in line
18; used 7 times
YES
defined in line
20; used 4 times