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: };