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

Defined functions

AU defined in line 979; used 2 times
EQ defined in line 913; used 1 times
MMHU defined in line 1025; used 2 times
PP defined in line 968; used 5 times
PS defined in line 923; used 1 times
SH defined in line 989; used 2 times
UX defined in line 1016; used 1 times
_C defined in line 625; used 1 times
  • in line 28
_C1 defined in line 621; used 1 times
  • in line 29
backsl defined in line 435; used 4 times
buildtab defined in line 1286; used 1 times
ce defined in line 1065; used 1 times
comline defined in line 1171; used 1 times
copys defined in line 501; used 2 times
defcomline defined in line 1129; used 3 times
domacro defined in line 918; used 3 times
eof defined in line 233; used 5 times
eqn defined in line 378; used 2 times
fatal defined in line 282; used 2 times
getfname defined in line 248; used 2 times
inpic defined in line 576; used 1 times
intbl defined in line 939; used 3 times
macfill defined in line 1274; used 4 times
macro defined in line 348; used 1 times
macsort defined in line 1256; used 1 times
main defined in line 106; never used
manfont defined in line 1118; used 6 times
manpp defined in line 1123; used 3 times
mefont defined in line 1110; used 9 times
meip defined in line 1071; used 1 times
mepp defined in line 1086; used 6 times
meputmac defined in line 742; used 2 times
meputwords defined in line 829; used 1 times
mesh defined in line 1095; used 2 times
mesnblock defined in line 1041; used 8 times
msputmac defined in line 662; used 2 times
msputwords defined in line 706; used 4 times
mssnblock defined in line 1050; used 4 times
nf defined in line 1059; used 1 times
noblock defined in line 854; used 5 times
nx defined in line 957; used 1 times
opn defined in line 219; used 6 times
outtbl defined in line 948; used 1 times
refer defined in line 555; used 1 times
regline defined in line 317; used 5 times
sce defined in line 514; used 1 times
sizetab defined in line 1262; used 4 times
skeqn defined in line 203; used 1 times
  • in line 24
skip defined in line 933; used 5 times
skiptocom defined in line 966; used 3 times
so defined in line 950; used 1 times
stbl defined in line 367; used 1 times
tbl defined in line 361; used 1 times
textline defined in line 291; used 1 times
work defined in line 302; used 1 times

Defined variables

argc defined in line 79; used 7 times
argconcat defined in line 638; used 4 times
argv defined in line 80; used 9 times
c defined in line 73; used 78 times
chars defined in line 68; used 23 times
disp defined in line 62; used 4 times
fname defined in line 82; used 8 times
inmacro defined in line 64; used 8 times
intable defined in line 65; used 4 times
keepblock defined in line 66; used 5 times
ldelim defined in line 75; used 4 times
line defined in line 70; used 9 times
lp defined in line 71; used 9 times
mac defined in line 61; used 16 times
mactab defined in line 46; used 5 times
manmactab defined in line 1420; used 1 times
memactab defined in line 1389; used 1 times
mmmactab defined in line 1381; used 1 times
msflag defined in line 60; used 16 times
msmactab defined in line 1356; used 2 times
parag defined in line 63; used 8 times
pc defined in line 74; used 6 times
ppmactab defined in line 1344; used 2 times
rdelim defined in line 76; used 4 times
sccsid defined in line 2; never used
troffmactab defined in line 1326; used 2 times
wordflag defined in line 59; used 9 times

Defined struct's

chain defined in line 251; used 8 times
mactab defined in line 643; used 54 times

Defined typedef's

pacmac defined in line 637; used 14 times

Defined macros

APOS defined in line 54; used 3 times
C defined in line 31; used 57 times
C1 defined in line 32; used 11 times
C1get defined in line 25; used 2 times
COM defined in line 104; used 1 times
COMX defined in line 103; used 3 times
Cget defined in line 24; used 2 times
DIGIT defined in line 56; used 2 times
FNEST defined in line 92; used 4 times
LETTER defined in line 57; used 7 times
M defined in line 657; used 73 times
MA defined in line 43; used 1 times
MAC defined in line 94; never used
ME defined in line 42; used 7 times
MM defined in line 41; used 4 times
MS defined in line 40; used 1 times
MSF defined in line 96; never used
NBLK defined in line 97; used 14 times
NO defined in line 39; used 11 times
NOCHAR defined in line 52; used 4 times
NOMAC defined in line 93; used 3 times
NONE defined in line 91; used 36 times
ONE defined in line 49; used 3 times
PARAG defined in line 95; used 16 times
PUNCT defined in line 55; used 12 times
SKIP defined in line 35; used 36 times
SKIPBLANK defined in line 739; used 1 times
SKIPNONBLANK defined in line 740; never used
SKIP_TO_COM defined in line 36; used 4 times
SPECIAL defined in line 53; used 1 times
TWO defined in line 50; used 2 times
YES defined in line 38; used 13 times
frommac defined in line 641; used 6 times
reg defined in line 636; used 10 times
tomac defined in line 640; used 2 times
Last modified: 1987-02-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 9360
Valid CSS Valid XHTML 1.0 Strict