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