1 /*- 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)deroff.c 4.8 (Berkeley) 04/17/91"; 16 #endif /* not lint */ 17 18 #include <stdio.h> 19 20 /* 21 * Deroff command -- strip troff, eqn, and Tbl sequences from 22 * a file. Has two flags argument, -w, to cause output one word per line 23 * rather than in the original format. 24 * -mm (or -ms) causes the corresponding macro's to be interpreted 25 * so that just sentences are output 26 * -ml also gets rid of lists. 27 * Deroff follows .so and .nx commands, removes contents of macro 28 * definitions, equations (both .EQ ... .EN and $...$), 29 * Tbl command sequences, and Troff backslash constructions. 30 * 31 * All input is through the Cget macro; 32 * the most recently read character is in c. 33 * 34 * Modified by Robert Henry to process -me and -man macros. 35 */ 36 37 #define Cget ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) ) 38 #define C1get ( (c=getc(infile)) == EOF ? eof() : c) 39 40 #ifdef DEBUG 41 # define C _C() 42 # define C1 _C1() 43 #else not DEBUG 44 # define C Cget 45 # define C1 C1get 46 #endif not DEBUG 47 48 #define SKIP while(C != '\n') 49 #define SKIP_TO_COM SKIP; SKIP; pc=c; while(C != '.' || pc != '\n' || C > 'Z')pc=c 50 51 #define YES 1 52 #define NO 0 53 #define MS 0 /* -ms */ 54 #define MM 1 /* -mm */ 55 #define ME 2 /* -me */ 56 #define MA 3 /* -man */ 57 58 #ifdef DEBUG 59 char *mactab[] = {"-ms", "-mm", "-me", "-ma"}; 60 #endif DEBUG 61 62 #define ONE 1 63 #define TWO 2 64 65 #define NOCHAR -2 66 #define SPECIAL 0 67 #define APOS 1 68 #define PUNCT 2 69 #define DIGIT 3 70 #define LETTER 4 71 72 int wordflag; 73 int msflag; /* processing a source written using a mac package */ 74 int mac; /* which package */ 75 int disp; 76 int parag; 77 int inmacro; 78 int intable; 79 int keepblock; /* keep blocks of text; normally false when msflag */ 80 81 char chars[128]; /* SPECIAL, PUNCT, APOS, DIGIT, or LETTER */ 82 83 char line[512]; 84 char *lp; 85 86 int c; 87 int pc; 88 int ldelim; 89 int rdelim; 90 91 92 int argc; 93 char **argv; 94 95 char fname[50]; 96 FILE *files[15]; 97 FILE **filesp; 98 FILE *infile; 99 FILE *opn(); 100 /* 101 * Flags for matching conditions other than 102 * the macro name 103 */ 104 #define NONE 0 105 #define FNEST 1 /* no nested files */ 106 #define NOMAC 2 /* no macro */ 107 #define MAC 3 /* macro */ 108 #define PARAG 4 /* in a paragraph */ 109 #define MSF 5 /* msflag is on */ 110 #define NBLK 6 /* set if no blocks to be kept */ 111 112 /* 113 * Return codes from macro minions, determine where to jump, 114 * how to repeat/reprocess text 115 */ 116 #define COMX 1 /* goto comx */ 117 #define COM 2 /* goto com */ 118 119 main(ac, av) 120 int ac; 121 char **av; 122 { 123 register int i; 124 int errflg = 0; 125 register optchar; 126 FILE *opn(); 127 int kflag = NO; 128 char *p; 129 130 wordflag = NO; 131 msflag = NO; 132 mac = ME; 133 disp = NO; 134 parag = NO; 135 inmacro = NO; 136 intable = NO; 137 ldelim = NOCHAR; 138 rdelim = NOCHAR; 139 keepblock = YES; 140 141 for(argc = ac - 1, argv = av + 1; 142 ( (argc > 0) 143 && (argv[0][0] == '-') 144 && (argv[0][1] != '\0') ); 145 --argc, ++argv 146 ){ 147 for(p = argv[0]+1; *p; ++p) { 148 switch(*p) { 149 case 'p': 150 parag=YES; 151 break; 152 case 'k': 153 kflag = YES; 154 break; 155 case 'w': 156 wordflag = YES; 157 kflag = YES; 158 break; 159 case 'm': 160 msflag = YES; 161 keepblock = NO; 162 switch(p[1]){ 163 case 'm': mac = MM; p++; break; 164 case 's': mac = MS; p++; break; 165 case 'e': mac = ME; p++; break; 166 case 'a': mac = MA; p++; break; 167 case 'l': disp = YES; p++; break; 168 default: errflg++; break; 169 } 170 break; 171 default: 172 errflg++; 173 } 174 } 175 } 176 177 if (kflag) 178 keepblock = YES; 179 if (errflg) 180 fatal("usage: deroff [ -w ] [ -k] [ -m (a e m s l) ] [ file ] ... \n", 181 (char *) NULL); 182 183 #ifdef DEBUG 184 printf("msflag = %d, mac = %s, keepblock = %d, disp = %d\n", 185 msflag, mactab[mac], keepblock, disp); 186 #endif DEBUG 187 if (argc == 0){ 188 infile = stdin; 189 } else { 190 infile = opn(argv[0]); 191 --argc; 192 ++argv; 193 } 194 195 196 files[0] = infile; 197 filesp = &files[0]; 198 199 for(i='a'; i<='z' ; ++i) 200 chars[i] = LETTER; 201 for(i='A'; i<='Z'; ++i) 202 chars[i] = LETTER; 203 for(i='0'; i<='9'; ++i) 204 chars[i] = DIGIT; 205 chars['\''] = APOS; 206 chars['&'] = APOS; 207 chars['.'] = PUNCT; 208 chars[','] = PUNCT; 209 chars[';'] = PUNCT; 210 chars['?'] = PUNCT; 211 chars[':'] = PUNCT; 212 work(); 213 } 214 char *calloc(); 215 216 skeqn() 217 { 218 while((c = getc(infile)) != rdelim) 219 if(c == EOF) 220 c = eof(); 221 else if(c == '"') 222 while( (c = getc(infile)) != '"') 223 if(c == EOF) 224 c = eof(); 225 else if(c == '\\') 226 if((c = getc(infile)) == EOF) 227 c = eof(); 228 if(msflag)return(c='x'); 229 return(c = ' '); 230 } 231 232 FILE *opn(p) 233 register char *p; 234 { 235 FILE *fd; 236 237 if( (fd = fopen(p, "r")) == NULL) { 238 fprintf(stderr, "Deroff: "); 239 perror(p); 240 exit(1); 241 } 242 243 return(fd); 244 } 245 246 eof() 247 { 248 if(infile != stdin) 249 fclose(infile); 250 if(filesp > files) 251 infile = *--filesp; 252 else if (argc > 0) { 253 infile = opn(argv[0]); 254 --argc; 255 ++argv; 256 } else 257 exit(0); 258 return(C); 259 } 260 261 getfname() 262 { 263 register char *p; 264 struct chain { 265 struct chain *nextp; 266 char *datap; 267 } *chainblock; 268 register struct chain *q; 269 static struct chain *namechain = NULL; 270 char *copys(); 271 272 while(C == ' ') ; 273 274 for(p = fname ; (*p=c)!= '\n' && c!=' ' && c!='\t' && c!='\\' ; ++p) 275 C; 276 *p = '\0'; 277 while(c != '\n') 278 C; 279 280 /* see if this name has already been used */ 281 282 for(q = namechain ; q; q = q->nextp) 283 if( ! strcmp(fname, q->datap)) 284 { 285 fname[0] = '\0'; 286 return; 287 } 288 289 q = (struct chain *) calloc(1, sizeof(*chainblock)); 290 q->nextp = namechain; 291 q->datap = copys(fname); 292 namechain = q; 293 } 294 295 fatal(s,p) 296 char *s, *p; 297 { 298 fprintf(stderr, "Deroff: "); 299 fprintf(stderr, s, p); 300 exit(1); 301 } 302 303 /*ARGSUSED*/ 304 textline(str, constant) 305 char *str; 306 int constant; 307 { 308 if (wordflag) { 309 msputwords(0); 310 return; 311 } 312 puts(str); 313 } 314 315 work() 316 { 317 for( ;; ) 318 { 319 C; 320 #ifdef FULLDEBUG 321 printf("Starting work with `%c'\n", c); 322 #endif FULLDEBUG 323 if(c == '.' || c == '\'') 324 comline(); 325 else 326 regline(textline, TWO); 327 } 328 } 329 330 regline(pfunc, constant) 331 int (*pfunc)(); 332 int constant; 333 { 334 line[0] = c; 335 lp = line; 336 for( ; ; ) 337 { 338 if(c == '\\') { 339 *lp = ' '; 340 backsl(); 341 } 342 if(c == '\n') 343 break; 344 if(intable && c=='T') { 345 *++lp = C; 346 if(c=='{' || c=='}') { 347 lp[-1] = ' '; 348 *lp = C; 349 } 350 } else { 351 *++lp = C; 352 } 353 } 354 355 *lp = '\0'; 356 357 if(line[0] != '\0') 358 (*pfunc)(line, constant); 359 } 360 361 macro() 362 { 363 if(msflag){ 364 do { 365 SKIP; 366 } while(C!='.' || C!='.' || C=='.'); /* look for .. */ 367 if(c != '\n')SKIP; 368 return; 369 } 370 SKIP; 371 inmacro = YES; 372 } 373 374 tbl() 375 { 376 while(C != '.'); 377 SKIP; 378 intable = YES; 379 } 380 stbl() 381 { 382 while(C != '.'); 383 SKIP_TO_COM; 384 if(c != 'T' || C != 'E'){ 385 SKIP; 386 pc=c; 387 while(C != '.' || pc != '\n' || C != 'T' || C != 'E')pc=c; 388 } 389 } 390 391 eqn() 392 { 393 register int c1, c2; 394 register int dflg; 395 char last; 396 397 last=0; 398 dflg = 1; 399 SKIP; 400 401 for( ;;) 402 { 403 if(C1 == '.' || c == '\'') 404 { 405 while(C1==' ' || c=='\t') 406 ; 407 if(c=='E' && C1=='N') 408 { 409 SKIP; 410 if(msflag && dflg){ 411 putchar('x'); 412 putchar(' '); 413 if(last){ 414 putchar(last); 415 putchar('\n'); 416 } 417 } 418 return; 419 } 420 } 421 else if(c == 'd') /* look for delim */ 422 { 423 if(C1=='e' && C1=='l') 424 if( C1=='i' && C1=='m') 425 { 426 while(C1 == ' '); 427 if((c1=c)=='\n' || (c2=C1)=='\n' 428 || (c1=='o' && c2=='f' && C1=='f') ) 429 { 430 ldelim = NOCHAR; 431 rdelim = NOCHAR; 432 } 433 else { 434 ldelim = c1; 435 rdelim = c2; 436 } 437 } 438 dflg = 0; 439 } 440 441 if(c != '\n') while(C1 != '\n'){ 442 if(chars[c] == PUNCT)last = c; 443 else if(c != ' ')last = 0; 444 } 445 } 446 } 447 448 backsl() /* skip over a complete backslash construction */ 449 { 450 int bdelim; 451 452 sw: 453 switch(C) 454 { 455 case '"': 456 SKIP; 457 return; 458 case 's': 459 if(C == '\\') backsl(); 460 else { 461 while(C>='0' && c<='9') ; 462 ungetc(c,infile); 463 c = '0'; 464 } 465 --lp; 466 return; 467 468 case 'f': 469 case 'n': 470 case '*': 471 if(C != '(') 472 return; 473 474 case '(': 475 if(msflag){ 476 if(C == 'e'){ 477 if(C == 'm'){ 478 *lp = '-'; 479 return; 480 } 481 } 482 else if(c != '\n')C; 483 return; 484 } 485 if(C != '\n') C; 486 return; 487 488 case '$': 489 C; /* discard argument number */ 490 return; 491 492 case 'b': 493 case 'x': 494 case 'v': 495 case 'h': 496 case 'w': 497 case 'o': 498 case 'l': 499 case 'L': 500 if( (bdelim=C) == '\n') 501 return; 502 while(C!='\n' && c!=bdelim) 503 if(c == '\\') backsl(); 504 return; 505 506 case '\\': 507 if(inmacro) 508 goto sw; 509 default: 510 return; 511 } 512 } 513 514 char *copys(s) 515 register char *s; 516 { 517 register char *t, *t0; 518 519 if( (t0 = t = calloc( (unsigned)(strlen(s)+1), sizeof(*t) ) ) == NULL) 520 fatal("Cannot allocate memory", (char *) NULL); 521 522 while( *t++ = *s++ ) 523 ; 524 return(t0); 525 } 526 527 sce() 528 { 529 register char *ap; 530 register int n, i; 531 char a[10]; 532 for(ap=a;C != '\n';ap++){ 533 *ap = c; 534 if(ap == &a[9]){ 535 SKIP; 536 ap=a; 537 break; 538 } 539 } 540 if(ap != a)n = atoi(a); 541 else n = 1; 542 for(i=0;i<n;){ 543 if(C == '.'){ 544 if(C == 'c'){ 545 if(C == 'e'){ 546 while(C == ' '); 547 if(c == '0'){ 548 SKIP; 549 break; 550 } 551 else SKIP; 552 } 553 else SKIP; 554 } 555 else if(c == 'P' || C == 'P'){ 556 if(c != '\n')SKIP; 557 break; 558 } 559 else if(c != '\n')SKIP; 560 } 561 else { 562 SKIP; 563 i++; 564 } 565 } 566 } 567 568 refer(c1) 569 { 570 register int c2; 571 if(c1 != '\n') 572 SKIP; 573 while(1){ 574 if(C != '.') 575 SKIP; 576 else { 577 if(C != ']') 578 SKIP; 579 else { 580 while(C != '\n') 581 c2=c; 582 if(chars[c2] == PUNCT)putchar(c2); 583 return; 584 } 585 } 586 } 587 } 588 589 inpic() 590 { 591 register int c1; 592 register char *p1; 593 SKIP; 594 p1 = line; 595 c = '\n'; 596 while(1){ 597 c1 = c; 598 if(C == '.' && c1 == '\n'){ 599 if(C != 'P'){ 600 if(c == '\n')continue; 601 else { SKIP; c='\n'; continue;} 602 } 603 if(C != 'E'){ 604 if(c == '\n')continue; 605 else { SKIP; c='\n';continue; } 606 } 607 SKIP; 608 return; 609 } 610 else if(c == '\"'){ 611 while(C != '\"'){ 612 if(c == '\\'){ 613 if(C == '\"')continue; 614 ungetc(c,infile); 615 backsl(); 616 } 617 else *p1++ = c; 618 } 619 *p1++ = ' '; 620 } 621 else if(c == '\n' && p1 != line){ 622 *p1 = '\0'; 623 if(wordflag)msputwords(NO); 624 else { 625 puts(line); 626 putchar('\n'); 627 } 628 p1 = line; 629 } 630 } 631 } 632 633 #ifdef DEBUG 634 _C1() 635 { 636 return(C1get); 637 } 638 _C() 639 { 640 return(Cget); 641 } 642 #endif DEBUG 643 644 /* 645 * Macro processing 646 * 647 * Macro table definitions 648 */ 649 #define reg register 650 typedef int pacmac; /* compressed macro name */ 651 int argconcat = 0; /* concat arguments together (-me only) */ 652 653 #define tomac(c1, c2) ((((c1) & 0xFF) << 8) | ((c2) & 0xFF)) 654 #define frommac(src, c1, c2) (((c1)=((src)>>8)&0xFF),((c2) =(src)&0xFF)) 655 656 struct mactab{ 657 int condition; 658 pacmac macname; 659 int (*func)(); 660 }; 661 struct mactab troffmactab[]; 662 struct mactab ppmactab[]; 663 struct mactab msmactab[]; 664 struct mactab mmmactab[]; 665 struct mactab memactab[]; 666 struct mactab manmactab[]; 667 /* 668 * macro table initialization 669 */ 670 #define M(cond, c1, c2, func) {cond, tomac(c1, c2), func} 671 672 /* 673 * Put out a macro line, using ms and mm conventions. 674 */ 675 msputmac(s, constant) 676 register char *s; 677 int constant; 678 { 679 register char *t; 680 register found; 681 int last; 682 found = 0; 683 684 if (wordflag) { 685 msputwords(YES); 686 return; 687 } 688 while(*s) 689 { 690 while(*s==' ' || *s=='\t') 691 putchar(*s++); 692 for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t) 693 ; 694 if(*s == '\"')s++; 695 if(t>s+constant && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER){ 696 while(s < t) 697 if(*s == '\"')s++; 698 else 699 putchar(*s++); 700 last = *(t-1); 701 found++; 702 } 703 else if(found && chars[ s[0] ] == PUNCT && s[1] == '\0') 704 putchar(*s++); 705 else{ 706 last = *(t-1); 707 s = t; 708 } 709 } 710 putchar('\n'); 711 if(msflag && chars[last] == PUNCT){ 712 putchar(last); 713 putchar('\n'); 714 } 715 } 716 /* 717 * put out words (for the -w option) with ms and mm conventions 718 */ 719 msputwords(macline) 720 int macline; /* is this is a macro line */ 721 { 722 register char *p, *p1; 723 int i, nlet; 724 725 for(p1 = line ; ;) { 726 /* 727 * skip initial specials ampersands and apostrophes 728 */ 729 while( chars[*p1] < DIGIT) 730 if(*p1++ == '\0') return; 731 nlet = 0; 732 for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p) 733 if(i == LETTER) ++nlet; 734 735 if (nlet > 1 && chars[p1[0]] == LETTER) { 736 /* 737 * delete trailing ampersands and apostrophes 738 */ 739 while( (i=chars[p[-1]]) == PUNCT || i == APOS ) 740 --p; 741 while(p1 < p) 742 putchar(*p1++); 743 putchar('\n'); 744 } else { 745 p1 = p; 746 } 747 } 748 } 749 /* 750 * put out a macro using the me conventions 751 */ 752 #define SKIPBLANK(cp) while(*cp == ' ' || *cp == '\t') { cp++; } 753 #define SKIPNONBLANK(cp) while(*cp !=' ' && *cp !='\cp' && *cp !='\0') { cp++; } 754 755 meputmac(cp, constant) 756 reg char *cp; 757 int constant; 758 { 759 reg char *np; 760 int found; 761 int argno; 762 int last; 763 int inquote; 764 765 if (wordflag) { 766 meputwords(YES); 767 return; 768 } 769 for (argno = 0; *cp; argno++){ 770 SKIPBLANK(cp); 771 inquote = (*cp == '"'); 772 if (inquote) 773 cp++; 774 for (np = cp; *np; np++){ 775 switch(*np){ 776 case '\n': 777 case '\0': break; 778 case '\t': 779 case ' ': if (inquote) { 780 continue; 781 } else { 782 goto endarg; 783 } 784 case '"': if(inquote && np[1] == '"'){ 785 strcpy(np, np + 1); 786 np++; 787 continue; 788 } else { 789 *np = ' '; /* bye bye " */ 790 goto endarg; 791 } 792 default: continue; 793 } 794 } 795 endarg: ; 796 /* 797 * cp points at the first char in the arg 798 * np points one beyond the last char in the arg 799 */ 800 if ((argconcat == 0) || (argconcat != argno)) { 801 putchar(' '); 802 } 803 #ifdef FULLDEBUG 804 { 805 char *p; 806 printf("[%d,%d: ", argno, np - cp); 807 for (p = cp; p < np; p++) { 808 putchar(*p); 809 } 810 printf("]"); 811 } 812 #endif FULLDEBUG 813 /* 814 * Determine if the argument merits being printed 815 * 816 * constant is the cut off point below which something 817 * is not a word. 818 */ 819 if ( ( (np - cp) > constant) 820 && ( inquote 821 || (chars[cp[0]] == LETTER)) ){ 822 for (cp = cp; cp < np; cp++){ 823 putchar(*cp); 824 } 825 last = np[-1]; 826 found++; 827 } else 828 if(found && (np - cp == 1) && chars[*cp] == PUNCT){ 829 putchar(*cp); 830 } else { 831 last = np[-1]; 832 } 833 cp = np; 834 } 835 if(msflag && chars[last] == PUNCT) 836 putchar(last); 837 putchar('\n'); 838 } 839 /* 840 * put out words (for the -w option) with ms and mm conventions 841 */ 842 meputwords(macline) 843 int macline; 844 { 845 msputwords(macline); 846 } 847 /* 848 * 849 * Skip over a nested set of macros 850 * 851 * Possible arguments to noblock are: 852 * 853 * fi end of unfilled text 854 * PE pic ending 855 * DE display ending 856 * 857 * for ms and mm only: 858 * KE keep ending 859 * 860 * NE undocumented match to NS (for mm?) 861 * LE mm only: matches RL or *L (for lists) 862 * 863 * for me: 864 * ([lqbzcdf] 865 */ 866 867 noblock(a1, a2) 868 char a1, a2; 869 { 870 register int c1,c2; 871 register int eqnf; 872 int lct; 873 lct = 0; 874 eqnf = 1; 875 SKIP; 876 while(1){ 877 while(C != '.') 878 if(c == '\n') 879 continue; 880 else 881 SKIP; 882 if((c1=C) == '\n') 883 continue; 884 if((c2=C) == '\n') 885 continue; 886 if(c1==a1 && c2 == a2){ 887 SKIP; 888 if(lct != 0){ 889 lct--; 890 continue; 891 } 892 if(eqnf) 893 putchar('.'); 894 putchar('\n'); 895 return; 896 } else if(a1 == 'L' && c2 == 'L'){ 897 lct++; 898 SKIP; 899 } 900 /* 901 * equations (EQ) nested within a display 902 */ 903 else if(c1 == 'E' && c2 == 'Q'){ 904 if ( (mac == ME && a1 == ')') 905 || (mac != ME && a1 == 'D') ) { 906 eqn(); 907 eqnf=0; 908 } 909 } 910 /* 911 * turning on filling is done by the paragraphing 912 * macros 913 */ 914 else if(a1 == 'f') { /* .fi */ 915 if ( (mac == ME && (c2 == 'h' || c2 == 'p')) 916 ||(mac != ME && (c1 == 'P' || c2 == 'P')) ) { 917 SKIP; 918 return; 919 } 920 } else { 921 SKIP; 922 } 923 } 924 } 925 926 EQ() 927 { 928 eqn(); 929 return(0); 930 } 931 domacro() 932 { 933 macro(); 934 return(0); 935 } 936 PS() 937 { 938 for (C; c == ' ' || c == '\t'; C); 939 if (c == '<') { /* ".PS < file" -- don't expect a .PE */ 940 SKIP; 941 return(0); 942 } 943 if (!msflag) { 944 inpic(); 945 } else { 946 noblock('P', 'E'); 947 } 948 return(0); 949 } 950 951 skip() 952 { 953 SKIP; 954 return(0); 955 } 956 957 intbl() 958 { 959 if(msflag){ 960 stbl(); 961 } 962 else tbl(); 963 return(0); 964 } 965 966 outtbl(){ intable = NO; } 967 968 so() 969 { 970 getfname(); 971 if( fname[0] ) 972 infile = *++filesp = opn( fname ); 973 return(0); 974 } 975 nx() 976 { 977 getfname(); 978 if(fname[0] == '\0') exit(0); 979 if(infile != stdin) 980 fclose(infile); 981 infile = *filesp = opn(fname); 982 return(0); 983 } 984 skiptocom(){ SKIP_TO_COM; return(COMX); } 985 986 PP(c12) 987 pacmac c12; 988 { 989 int c1, c2; 990 991 frommac(c12, c1, c2); 992 printf(".%c%c",c1,c2); 993 while(C != '\n')putchar(c); 994 putchar('\n'); 995 return(0); 996 } 997 AU() 998 { 999 if(mac==MM) { 1000 return(0); 1001 } else { 1002 SKIP_TO_COM; 1003 return(COMX); 1004 } 1005 } 1006 1007 SH(c12) 1008 pacmac c12; 1009 { 1010 int c1, c2; 1011 1012 frommac(c12, c1, c2); 1013 1014 if(parag){ 1015 printf(".%c%c",c1,c2); 1016 while(C != '\n')putchar(c); 1017 putchar(c); 1018 putchar('!'); 1019 while(1){ 1020 while(C != '\n')putchar(c); 1021 putchar('\n'); 1022 if(C == '.') 1023 return(COM); 1024 putchar('!'); 1025 putchar(c); 1026 } 1027 /*NOTREACHED*/ 1028 } else { 1029 SKIP_TO_COM; 1030 return(COMX); 1031 } 1032 } 1033 1034 UX() 1035 { 1036 if(wordflag) 1037 printf("UNIX\n"); 1038 else 1039 printf("UNIX "); 1040 return(0); 1041 } 1042 1043 MMHU(c12) 1044 pacmac c12; 1045 { 1046 int c1, c2; 1047 1048 frommac(c12, c1, c2); 1049 if(parag){ 1050 printf(".%c%c",c1,c2); 1051 while(C != '\n')putchar(c); 1052 putchar('\n'); 1053 } else { 1054 SKIP; 1055 } 1056 return(0); 1057 } 1058 1059 mesnblock(c12) 1060 pacmac c12; 1061 { 1062 int c1, c2; 1063 1064 frommac(c12, c1, c2); 1065 noblock(')',c2); 1066 return(0); 1067 } 1068 mssnblock(c12) 1069 pacmac c12; 1070 { 1071 int c1, c2; 1072 1073 frommac(c12, c1, c2); 1074 noblock(c1,'E'); 1075 return(0); 1076 } 1077 nf() 1078 { 1079 noblock('f','i'); 1080 return(0); 1081 } 1082 1083 ce() 1084 { 1085 sce(); 1086 return(0); 1087 } 1088 1089 meip(c12) 1090 pacmac c12; 1091 { 1092 if(parag) 1093 mepp(c12); 1094 else if (wordflag) /* save the tag */ 1095 regline(meputmac, ONE); 1096 else { 1097 SKIP; 1098 } 1099 return(0); 1100 } 1101 /* 1102 * only called for -me .pp or .sh, when parag is on 1103 */ 1104 mepp(c12) 1105 pacmac c12; 1106 { 1107 PP(c12); /* eats the line */ 1108 return(0); 1109 } 1110 /* 1111 * Start of a section heading; output the section name if doing words 1112 */ 1113 mesh(c12) 1114 pacmac c12; 1115 { 1116 if (parag) 1117 mepp(c12); 1118 else if (wordflag) 1119 defcomline(c12); 1120 else { 1121 SKIP; 1122 } 1123 return(0); 1124 } 1125 /* 1126 * process a font setting 1127 */ 1128 mefont(c12) 1129 pacmac c12; 1130 { 1131 argconcat = 1; 1132 defcomline(c12); 1133 argconcat = 0; 1134 return(0); 1135 } 1136 manfont(c12) 1137 pacmac c12; 1138 { 1139 return(mefont(c12)); 1140 } 1141 manpp(c12) 1142 pacmac c12; 1143 { 1144 return(mepp(c12)); 1145 } 1146 1147 defcomline(c12) 1148 pacmac c12; 1149 { 1150 int c1, c2; 1151 1152 frommac(c12, c1, c2); 1153 if(msflag && mac==MM && c2=='L'){ 1154 if(disp || c1 == 'R') { 1155 noblock('L','E'); 1156 } else { 1157 SKIP; 1158 putchar('.'); 1159 } 1160 } 1161 else if(c1=='.' && c2=='.'){ 1162 if(msflag){ 1163 SKIP; 1164 return; 1165 } 1166 while(C == '.') 1167 /*VOID*/; 1168 } 1169 ++inmacro; 1170 /* 1171 * Process the arguments to the macro 1172 */ 1173 switch(mac){ 1174 default: 1175 case MM: 1176 case MS: 1177 if(c1 <= 'Z' && msflag) 1178 regline(msputmac, ONE); 1179 else 1180 regline(msputmac, TWO); 1181 break; 1182 case ME: 1183 regline(meputmac, ONE); 1184 break; 1185 } 1186 --inmacro; 1187 } 1188 1189 comline() 1190 { 1191 reg int c1; 1192 reg int c2; 1193 pacmac c12; 1194 reg int mid; 1195 int lb, ub; 1196 int hit; 1197 static int tabsize = 0; 1198 static struct mactab *mactab = (struct mactab *)0; 1199 reg struct mactab *mp; 1200 1201 if (mactab == 0){ 1202 buildtab(&mactab, &tabsize); 1203 } 1204 com: 1205 while(C==' ' || c=='\t') 1206 ; 1207 comx: 1208 if( (c1=c) == '\n') 1209 return; 1210 c2 = C; 1211 if(c1=='.' && c2 !='.') 1212 inmacro = NO; 1213 if(msflag && c1 == '['){ 1214 refer(c2); 1215 return; 1216 } 1217 if(parag && mac==MM && c1 == 'P' && c2 == '\n'){ 1218 printf(".P\n"); 1219 return; 1220 } 1221 if(c2 == '\n') 1222 return; 1223 /* 1224 * Single letter macro 1225 */ 1226 if (mac == ME && (c2 == ' ' || c2 == '\t') ) 1227 c2 = ' '; 1228 c12 = tomac(c1, c2); 1229 /* 1230 * binary search through the table of macros 1231 */ 1232 lb = 0; 1233 ub = tabsize - 1; 1234 while(lb <= ub){ 1235 mid = (ub + lb) / 2; 1236 mp = &mactab[mid]; 1237 if (mp->macname < c12) 1238 lb = mid + 1; 1239 else if (mp->macname > c12) 1240 ub = mid - 1; 1241 else { 1242 hit = 1; 1243 #ifdef FULLDEBUG 1244 printf("preliminary hit macro %c%c ", c1, c2); 1245 #endif FULLDEBUG 1246 switch(mp->condition){ 1247 case NONE: hit = YES; break; 1248 case FNEST: hit = (filesp == files); break; 1249 case NOMAC: hit = !inmacro; break; 1250 case MAC: hit = inmacro; break; 1251 case PARAG: hit = parag; break; 1252 case NBLK: hit = !keepblock; break; 1253 default: hit = 0; 1254 } 1255 if (hit) { 1256 #ifdef FULLDEBUG 1257 printf("MATCH\n"); 1258 #endif FULLDEBUG 1259 switch( (*(mp->func))(c12) ) { 1260 default: return; 1261 case COMX: goto comx; 1262 case COM: goto com; 1263 } 1264 } 1265 #ifdef FULLDEBUG 1266 printf("FAIL\n"); 1267 #endif FULLDEBUG 1268 break; 1269 } 1270 } 1271 defcomline(c12); 1272 } 1273 1274 int macsort(p1, p2) 1275 struct mactab *p1, *p2; 1276 { 1277 return(p1->macname - p2->macname); 1278 } 1279 1280 int sizetab(mp) 1281 reg struct mactab *mp; 1282 { 1283 reg int i; 1284 i = 0; 1285 if (mp){ 1286 for (; mp->macname; mp++, i++) 1287 /*VOID*/ ; 1288 } 1289 return(i); 1290 } 1291 1292 struct mactab *macfill(dst, src) 1293 reg struct mactab *dst; 1294 reg struct mactab *src; 1295 { 1296 if (src) { 1297 while(src->macname){ 1298 *dst++ = *src++; 1299 } 1300 } 1301 return(dst); 1302 } 1303 1304 buildtab(r_back, r_size) 1305 struct mactab **r_back; 1306 int *r_size; 1307 { 1308 int size; 1309 1310 struct mactab *p, *p1, *p2; 1311 struct mactab *back; 1312 1313 size = sizetab(troffmactab); 1314 size += sizetab(ppmactab); 1315 p1 = p2 = (struct mactab *)0; 1316 if (msflag){ 1317 switch(mac){ 1318 case ME: p1 = memactab; break; 1319 case MM: p1 = msmactab; 1320 p2 = mmmactab; break; 1321 1322 case MS: p1 = msmactab; break; 1323 case MA: p1 = manmactab; break; 1324 default: break; 1325 } 1326 } 1327 size += sizetab(p1); 1328 size += sizetab(p2); 1329 back = (struct mactab *)calloc(size+2, sizeof(struct mactab)); 1330 1331 p = macfill(back, troffmactab); 1332 p = macfill(p, ppmactab); 1333 p = macfill(p, p1); 1334 p = macfill(p, p2); 1335 1336 qsort(back, size, sizeof(struct mactab), macsort); 1337 *r_size = size; 1338 *r_back = back; 1339 } 1340 1341 /* 1342 * troff commands 1343 */ 1344 struct mactab troffmactab[] = { 1345 M(NONE, '\\','"', skip), /* comment */ 1346 M(NOMAC, 'd','e', domacro), /* define */ 1347 M(NOMAC, 'i','g', domacro), /* ignore till .. */ 1348 M(NOMAC, 'a','m', domacro), /* append macro */ 1349 M(NBLK, 'n','f', nf), /* filled */ 1350 M(NBLK, 'c','e', ce), /* centered */ 1351 1352 M(NONE, 's','o', so), /* source a file */ 1353 M(NONE, 'n','x', nx), /* go to next file */ 1354 1355 M(NONE, 't','m', skip), /* print string on tty */ 1356 M(NONE, 'h','w', skip), /* exception hyphen words */ 1357 M(NONE, 0,0, 0) 1358 }; 1359 /* 1360 * Preprocessor output 1361 */ 1362 struct mactab ppmactab[] = { 1363 M(FNEST, 'E','Q', EQ), /* equation starting */ 1364 M(FNEST, 'T','S', intbl), /* table starting */ 1365 M(FNEST, 'T','C', intbl), /* alternative table? */ 1366 M(FNEST, 'T','&', intbl), /* table reformatting */ 1367 M(NONE, 'T','E', outtbl),/* table ending */ 1368 M(NONE, 'P','S', PS), /* picture starting */ 1369 M(NONE, 0,0, 0) 1370 }; 1371 /* 1372 * Particular to ms and mm 1373 */ 1374 struct mactab msmactab[] = { 1375 M(NONE, 'T','L', skiptocom), /* title follows */ 1376 M(NONE, 'F','S', skiptocom), /* start footnote */ 1377 M(NONE, 'O','K', skiptocom), /* Other kws */ 1378 1379 M(NONE, 'N','R', skip), /* undocumented */ 1380 M(NONE, 'N','D', skip), /* use supplied date */ 1381 1382 M(PARAG, 'P','P', PP), /* begin parag */ 1383 M(PARAG, 'I','P', PP), /* begin indent parag, tag x */ 1384 M(PARAG, 'L','P', PP), /* left blocked parag */ 1385 1386 M(NONE, 'A','U', AU), /* author */ 1387 M(NONE, 'A','I', AU), /* authors institution */ 1388 1389 M(NONE, 'S','H', SH), /* section heading */ 1390 M(NONE, 'S','N', SH), /* undocumented */ 1391 M(NONE, 'U','X', UX), /* unix */ 1392 1393 M(NBLK, 'D','S', mssnblock), /* start display text */ 1394 M(NBLK, 'K','S', mssnblock), /* start keep */ 1395 M(NBLK, 'K','F', mssnblock), /* start float keep */ 1396 M(NONE, 0,0, 0) 1397 }; 1398 1399 struct mactab mmmactab[] = { 1400 M(NONE, 'H',' ', MMHU), /* -mm ? */ 1401 M(NONE, 'H','U', MMHU), /* -mm ? */ 1402 M(PARAG, 'P',' ', PP), /* paragraph for -mm */ 1403 M(NBLK, 'N','S', mssnblock), /* undocumented */ 1404 M(NONE, 0,0, 0) 1405 }; 1406 1407 struct mactab memactab[] = { 1408 M(PARAG, 'p','p', mepp), 1409 M(PARAG, 'l','p', mepp), 1410 M(PARAG, 'n','p', mepp), 1411 M(NONE, 'i','p', meip), 1412 1413 M(NONE, 's','h', mesh), 1414 M(NONE, 'u','h', mesh), 1415 1416 M(NBLK, '(','l', mesnblock), 1417 M(NBLK, '(','q', mesnblock), 1418 M(NBLK, '(','b', mesnblock), 1419 M(NBLK, '(','z', mesnblock), 1420 M(NBLK, '(','c', mesnblock), 1421 1422 M(NBLK, '(','d', mesnblock), 1423 M(NBLK, '(','f', mesnblock), 1424 M(NBLK, '(','x', mesnblock), 1425 1426 M(NONE, 'r',' ', mefont), 1427 M(NONE, 'i',' ', mefont), 1428 M(NONE, 'b',' ', mefont), 1429 M(NONE, 'u',' ', mefont), 1430 M(NONE, 'q',' ', mefont), 1431 M(NONE, 'r','b', mefont), 1432 M(NONE, 'b','i', mefont), 1433 M(NONE, 'b','x', mefont), 1434 M(NONE, 0,0, 0) 1435 }; 1436 1437 1438 struct mactab manmactab[] = { 1439 M(PARAG, 'B','I', manfont), 1440 M(PARAG, 'B','R', manfont), 1441 M(PARAG, 'I','B', manfont), 1442 M(PARAG, 'I','R', manfont), 1443 M(PARAG, 'R','B', manfont), 1444 M(PARAG, 'R','I', manfont), 1445 1446 M(PARAG, 'P','P', manpp), 1447 M(PARAG, 'L','P', manpp), 1448 M(PARAG, 'H','P', manpp), 1449 M(NONE, 0,0, 0) 1450 }; 1451