|
|
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.