1 #ifndef lint 2 static char sccsid[] = "@(#)deroff.c 4.6 (Berkeley) 87/09/28"; 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 for (C; c == ' ' || c == '\t'; C); 926 if (c == '<') { /* ".PS < file" -- don't expect a .PE */ 927 SKIP; 928 return(0); 929 } 930 if (!msflag) { 931 inpic(); 932 } else { 933 noblock('P', 'E'); 934 } 935 return(0); 936 } 937 938 skip() 939 { 940 SKIP; 941 return(0); 942 } 943 944 intbl() 945 { 946 if(msflag){ 947 stbl(); 948 } 949 else tbl(); 950 return(0); 951 } 952 953 outtbl(){ intable = NO; } 954 955 so() 956 { 957 getfname(); 958 if( fname[0] ) 959 infile = *++filesp = opn( fname ); 960 return(0); 961 } 962 nx() 963 { 964 getfname(); 965 if(fname[0] == '\0') exit(0); 966 if(infile != stdin) 967 fclose(infile); 968 infile = *filesp = opn(fname); 969 return(0); 970 } 971 skiptocom(){ SKIP_TO_COM; return(COMX); } 972 973 PP(c12) 974 pacmac c12; 975 { 976 int c1, c2; 977 978 frommac(c12, c1, c2); 979 printf(".%c%c",c1,c2); 980 while(C != '\n')putchar(c); 981 putchar('\n'); 982 return(0); 983 } 984 AU() 985 { 986 if(mac==MM) { 987 return(0); 988 } else { 989 SKIP_TO_COM; 990 return(COMX); 991 } 992 } 993 994 SH(c12) 995 pacmac c12; 996 { 997 int c1, c2; 998 999 frommac(c12, c1, c2); 1000 1001 if(parag){ 1002 printf(".%c%c",c1,c2); 1003 while(C != '\n')putchar(c); 1004 putchar(c); 1005 putchar('!'); 1006 while(1){ 1007 while(C != '\n')putchar(c); 1008 putchar('\n'); 1009 if(C == '.') 1010 return(COM); 1011 putchar('!'); 1012 putchar(c); 1013 } 1014 /*NOTREACHED*/ 1015 } else { 1016 SKIP_TO_COM; 1017 return(COMX); 1018 } 1019 } 1020 1021 UX() 1022 { 1023 if(wordflag) 1024 printf("UNIX\n"); 1025 else 1026 printf("UNIX "); 1027 return(0); 1028 } 1029 1030 MMHU(c12) 1031 pacmac c12; 1032 { 1033 int c1, c2; 1034 1035 frommac(c12, c1, c2); 1036 if(parag){ 1037 printf(".%c%c",c1,c2); 1038 while(C != '\n')putchar(c); 1039 putchar('\n'); 1040 } else { 1041 SKIP; 1042 } 1043 return(0); 1044 } 1045 1046 mesnblock(c12) 1047 pacmac c12; 1048 { 1049 int c1, c2; 1050 1051 frommac(c12, c1, c2); 1052 noblock(')',c2); 1053 return(0); 1054 } 1055 mssnblock(c12) 1056 pacmac c12; 1057 { 1058 int c1, c2; 1059 1060 frommac(c12, c1, c2); 1061 noblock(c1,'E'); 1062 return(0); 1063 } 1064 nf() 1065 { 1066 noblock('f','i'); 1067 return(0); 1068 } 1069 1070 ce() 1071 { 1072 sce(); 1073 return(0); 1074 } 1075 1076 meip(c12) 1077 pacmac c12; 1078 { 1079 if(parag) 1080 mepp(c12); 1081 else if (wordflag) /* save the tag */ 1082 regline(meputmac, ONE); 1083 else { 1084 SKIP; 1085 } 1086 return(0); 1087 } 1088 /* 1089 * only called for -me .pp or .sh, when parag is on 1090 */ 1091 mepp(c12) 1092 pacmac c12; 1093 { 1094 PP(c12); /* eats the line */ 1095 return(0); 1096 } 1097 /* 1098 * Start of a section heading; output the section name if doing words 1099 */ 1100 mesh(c12) 1101 pacmac c12; 1102 { 1103 if (parag) 1104 mepp(c12); 1105 else if (wordflag) 1106 defcomline(c12); 1107 else { 1108 SKIP; 1109 } 1110 return(0); 1111 } 1112 /* 1113 * process a font setting 1114 */ 1115 mefont(c12) 1116 pacmac c12; 1117 { 1118 argconcat = 1; 1119 defcomline(c12); 1120 argconcat = 0; 1121 return(0); 1122 } 1123 manfont(c12) 1124 pacmac c12; 1125 { 1126 return(mefont(c12)); 1127 } 1128 manpp(c12) 1129 pacmac c12; 1130 { 1131 return(mepp(c12)); 1132 } 1133 1134 defcomline(c12) 1135 pacmac c12; 1136 { 1137 int c1, c2; 1138 1139 frommac(c12, c1, c2); 1140 if(msflag && mac==MM && c2=='L'){ 1141 if(disp || c1 == 'R') { 1142 noblock('L','E'); 1143 } else { 1144 SKIP; 1145 putchar('.'); 1146 } 1147 } 1148 else if(c1=='.' && c2=='.'){ 1149 if(msflag){ 1150 SKIP; 1151 return; 1152 } 1153 while(C == '.') 1154 /*VOID*/; 1155 } 1156 ++inmacro; 1157 /* 1158 * Process the arguments to the macro 1159 */ 1160 switch(mac){ 1161 default: 1162 case MM: 1163 case MS: 1164 if(c1 <= 'Z' && msflag) 1165 regline(msputmac, ONE); 1166 else 1167 regline(msputmac, TWO); 1168 break; 1169 case ME: 1170 regline(meputmac, ONE); 1171 break; 1172 } 1173 --inmacro; 1174 } 1175 1176 comline() 1177 { 1178 reg int c1; 1179 reg int c2; 1180 pacmac c12; 1181 reg int mid; 1182 int lb, ub; 1183 int hit; 1184 static int tabsize = 0; 1185 static struct mactab *mactab = (struct mactab *)0; 1186 reg struct mactab *mp; 1187 1188 if (mactab == 0){ 1189 buildtab(&mactab, &tabsize); 1190 } 1191 com: 1192 while(C==' ' || c=='\t') 1193 ; 1194 comx: 1195 if( (c1=c) == '\n') 1196 return; 1197 c2 = C; 1198 if(c1=='.' && c2 !='.') 1199 inmacro = NO; 1200 if(msflag && c1 == '['){ 1201 refer(c2); 1202 return; 1203 } 1204 if(parag && mac==MM && c1 == 'P' && c2 == '\n'){ 1205 printf(".P\n"); 1206 return; 1207 } 1208 if(c2 == '\n') 1209 return; 1210 /* 1211 * Single letter macro 1212 */ 1213 if (mac == ME && (c2 == ' ' || c2 == '\t') ) 1214 c2 = ' '; 1215 c12 = tomac(c1, c2); 1216 /* 1217 * binary search through the table of macros 1218 */ 1219 lb = 0; 1220 ub = tabsize - 1; 1221 while(lb <= ub){ 1222 mid = (ub + lb) / 2; 1223 mp = &mactab[mid]; 1224 if (mp->macname < c12) 1225 lb = mid + 1; 1226 else if (mp->macname > c12) 1227 ub = mid - 1; 1228 else { 1229 hit = 1; 1230 #ifdef FULLDEBUG 1231 printf("preliminary hit macro %c%c ", c1, c2); 1232 #endif FULLDEBUG 1233 switch(mp->condition){ 1234 case NONE: hit = YES; break; 1235 case FNEST: hit = (filesp == files); break; 1236 case NOMAC: hit = !inmacro; break; 1237 case MAC: hit = inmacro; break; 1238 case PARAG: hit = parag; break; 1239 case NBLK: hit = !keepblock; break; 1240 default: hit = 0; 1241 } 1242 if (hit) { 1243 #ifdef FULLDEBUG 1244 printf("MATCH\n"); 1245 #endif FULLDEBUG 1246 switch( (*(mp->func))(c12) ) { 1247 default: return; 1248 case COMX: goto comx; 1249 case COM: goto com; 1250 } 1251 } 1252 #ifdef FULLDEBUG 1253 printf("FAIL\n"); 1254 #endif FULLDEBUG 1255 break; 1256 } 1257 } 1258 defcomline(c12); 1259 } 1260 1261 int macsort(p1, p2) 1262 struct mactab *p1, *p2; 1263 { 1264 return(p1->macname - p2->macname); 1265 } 1266 1267 int sizetab(mp) 1268 reg struct mactab *mp; 1269 { 1270 reg int i; 1271 i = 0; 1272 if (mp){ 1273 for (; mp->macname; mp++, i++) 1274 /*VOID*/ ; 1275 } 1276 return(i); 1277 } 1278 1279 struct mactab *macfill(dst, src) 1280 reg struct mactab *dst; 1281 reg struct mactab *src; 1282 { 1283 if (src) { 1284 while(src->macname){ 1285 *dst++ = *src++; 1286 } 1287 } 1288 return(dst); 1289 } 1290 1291 buildtab(r_back, r_size) 1292 struct mactab **r_back; 1293 int *r_size; 1294 { 1295 int size; 1296 1297 struct mactab *p, *p1, *p2; 1298 struct mactab *back; 1299 1300 size = sizetab(troffmactab); 1301 size += sizetab(ppmactab); 1302 p1 = p2 = (struct mactab *)0; 1303 if (msflag){ 1304 switch(mac){ 1305 case ME: p1 = memactab; break; 1306 case MM: p1 = msmactab; 1307 p2 = mmmactab; break; 1308 1309 case MS: p1 = msmactab; break; 1310 case MA: p1 = manmactab; break; 1311 default: break; 1312 } 1313 } 1314 size += sizetab(p1); 1315 size += sizetab(p2); 1316 back = (struct mactab *)calloc(size+2, sizeof(struct mactab)); 1317 1318 p = macfill(back, troffmactab); 1319 p = macfill(p, ppmactab); 1320 p = macfill(p, p1); 1321 p = macfill(p, p2); 1322 1323 qsort(back, size, sizeof(struct mactab), macsort); 1324 *r_size = size; 1325 *r_back = back; 1326 } 1327 1328 /* 1329 * troff commands 1330 */ 1331 struct mactab troffmactab[] = { 1332 M(NONE, '\\','"', skip), /* comment */ 1333 M(NOMAC, 'd','e', domacro), /* define */ 1334 M(NOMAC, 'i','g', domacro), /* ignore till .. */ 1335 M(NOMAC, 'a','m', domacro), /* append macro */ 1336 M(NBLK, 'n','f', nf), /* filled */ 1337 M(NBLK, 'c','e', ce), /* centered */ 1338 1339 M(NONE, 's','o', so), /* source a file */ 1340 M(NONE, 'n','x', nx), /* go to next file */ 1341 1342 M(NONE, 't','m', skip), /* print string on tty */ 1343 M(NONE, 'h','w', skip), /* exception hyphen words */ 1344 M(NONE, 0,0, 0) 1345 }; 1346 /* 1347 * Preprocessor output 1348 */ 1349 struct mactab ppmactab[] = { 1350 M(FNEST, 'E','Q', EQ), /* equation starting */ 1351 M(FNEST, 'T','S', intbl), /* table starting */ 1352 M(FNEST, 'T','C', intbl), /* alternative table? */ 1353 M(FNEST, 'T','&', intbl), /* table reformatting */ 1354 M(NONE, 'T','E', outtbl),/* table ending */ 1355 M(NONE, 'P','S', PS), /* picture starting */ 1356 M(NONE, 0,0, 0) 1357 }; 1358 /* 1359 * Particular to ms and mm 1360 */ 1361 struct mactab msmactab[] = { 1362 M(NONE, 'T','L', skiptocom), /* title follows */ 1363 M(NONE, 'F','S', skiptocom), /* start footnote */ 1364 M(NONE, 'O','K', skiptocom), /* Other kws */ 1365 1366 M(NONE, 'N','R', skip), /* undocumented */ 1367 M(NONE, 'N','D', skip), /* use supplied date */ 1368 1369 M(PARAG, 'P','P', PP), /* begin parag */ 1370 M(PARAG, 'I','P', PP), /* begin indent parag, tag x */ 1371 M(PARAG, 'L','P', PP), /* left blocked parag */ 1372 1373 M(NONE, 'A','U', AU), /* author */ 1374 M(NONE, 'A','I', AU), /* authors institution */ 1375 1376 M(NONE, 'S','H', SH), /* section heading */ 1377 M(NONE, 'S','N', SH), /* undocumented */ 1378 M(NONE, 'U','X', UX), /* unix */ 1379 1380 M(NBLK, 'D','S', mssnblock), /* start display text */ 1381 M(NBLK, 'K','S', mssnblock), /* start keep */ 1382 M(NBLK, 'K','F', mssnblock), /* start float keep */ 1383 M(NONE, 0,0, 0) 1384 }; 1385 1386 struct mactab mmmactab[] = { 1387 M(NONE, 'H',' ', MMHU), /* -mm ? */ 1388 M(NONE, 'H','U', MMHU), /* -mm ? */ 1389 M(PARAG, 'P',' ', PP), /* paragraph for -mm */ 1390 M(NBLK, 'N','S', mssnblock), /* undocumented */ 1391 M(NONE, 0,0, 0) 1392 }; 1393 1394 struct mactab memactab[] = { 1395 M(PARAG, 'p','p', mepp), 1396 M(PARAG, 'l','p', mepp), 1397 M(PARAG, 'n','p', mepp), 1398 M(NONE, 'i','p', meip), 1399 1400 M(NONE, 's','h', mesh), 1401 M(NONE, 'u','h', mesh), 1402 1403 M(NBLK, '(','l', mesnblock), 1404 M(NBLK, '(','q', mesnblock), 1405 M(NBLK, '(','b', mesnblock), 1406 M(NBLK, '(','z', mesnblock), 1407 M(NBLK, '(','c', mesnblock), 1408 1409 M(NBLK, '(','d', mesnblock), 1410 M(NBLK, '(','f', mesnblock), 1411 M(NBLK, '(','x', mesnblock), 1412 1413 M(NONE, 'r',' ', mefont), 1414 M(NONE, 'i',' ', mefont), 1415 M(NONE, 'b',' ', mefont), 1416 M(NONE, 'u',' ', mefont), 1417 M(NONE, 'q',' ', mefont), 1418 M(NONE, 'r','b', mefont), 1419 M(NONE, 'b','i', mefont), 1420 M(NONE, 'b','x', mefont), 1421 M(NONE, 0,0, 0) 1422 }; 1423 1424 1425 struct mactab manmactab[] = { 1426 M(PARAG, 'B','I', manfont), 1427 M(PARAG, 'B','R', manfont), 1428 M(PARAG, 'I','B', manfont), 1429 M(PARAG, 'I','R', manfont), 1430 M(PARAG, 'R','B', manfont), 1431 M(PARAG, 'R','I', manfont), 1432 1433 M(PARAG, 'P','P', manpp), 1434 M(PARAG, 'L','P', manpp), 1435 M(PARAG, 'H','P', manpp), 1436 M(NONE, 0,0, 0) 1437 }; 1438