home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / deroff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-05-05  |  6.7 KB  |  495 lines

  1. char *xxxvers = "\nDeroff Version 1.02    24 July 1978\n";
  2.  
  3.  
  4. #include <stdio.h>
  5.  
  6. /* Deroff command -- strip troff, eqn, and Tbl sequences from
  7. a file.  Has one flag argument, -w, to cause output one word per line
  8. rather than in the original format.
  9. Deroff follows .so and .nx commands, removes contents of macro
  10. definitions, equations (both .EQ ... .EN and $...$),
  11. Tbl command sequences, and Troff backslash constructions.
  12.  
  13. All input is through the C macro; the most recently read character is in c.
  14. */
  15.  
  16. #define C ( (c=getc(infile)) == EOF ? eof() : ((c==ldelim)&&(filesp==files) ? skeqn() : c) )
  17. #define C1 ( (c=getc(infile)) == EOF ? eof() :  c)
  18. #define SKIP while(C != '\n') 
  19.  
  20. #define YES 1
  21. #define NO 0
  22.  
  23. #define NOCHAR -2
  24. #define SPECIAL 0
  25. #define APOS 1
  26. #define DIGIT 2
  27. #define LETTER 3
  28.  
  29. int wordflag = NO;
  30. int inmacro = NO;
  31. int intable = NO;
  32.  
  33. char chars[128];  /* SPECIAL, APOS, DIGIT, or LETTER */
  34.  
  35. char line[512];
  36. char *lp;
  37.  
  38. int c;
  39. int ldelim    = NOCHAR;
  40. int rdelim    = NOCHAR;
  41.  
  42.  
  43. int argc;
  44. char **argv;
  45.  
  46. char fname[50];
  47. FILE *files[15];
  48. FILE **filesp;
  49. FILE *infile;
  50.  
  51. char *calloc();
  52.  
  53.  
  54.  
  55. main(ac, av)
  56. int ac;
  57. char **av;
  58. {
  59. register int i;
  60. register char *p;
  61. static char onechar[2] = "X";
  62. FILE *opn();
  63.  
  64. argc = ac - 1;
  65. argv = av + 1;
  66.  
  67. while(argc>0 && argv[0][0]=='-' && argv[0][1]!='\0') 
  68.     {
  69.     for(p=argv[0]+1; *p; ++p) switch(*p)
  70.         {
  71.         case 'w':
  72.             wordflag = YES;
  73.             break;
  74.         default:
  75.             onechar[0] = *p;
  76.             fatal("Invalid flag %s\n", onechar);
  77.         }
  78.     --argc;
  79.     ++argv;
  80.     }
  81.  
  82. if(argc == 0)
  83.     infile = stdin;
  84. else    {
  85.     infile = opn(argv[0]);
  86.     --argc;
  87.     ++argv;
  88.     }
  89.  
  90. files[0] = infile;
  91. filesp = &files[0];
  92.  
  93. for(i='a'; i<='z' ; ++i)
  94.     chars[i] = LETTER;
  95. for(i='A'; i<='Z'; ++i)
  96.     chars[i] = LETTER;
  97. for(i='0'; i<='9'; ++i)
  98.     chars[i] = DIGIT;
  99. chars['\''] = APOS;
  100. chars['&'] = APOS;
  101.  
  102. work();
  103. }
  104.  
  105.  
  106.  
  107. skeqn()
  108. {
  109. while((c = getc(infile)) != rdelim)
  110.     if(c == EOF)
  111.         c = eof();
  112.     else if(c == '"')
  113.         while( (c = getc(infile)) != '"')
  114.             if(c == EOF)
  115.                 c = eof();
  116.             else if(c == '\\')
  117.                 if((c = getc(infile)) == EOF)
  118.                     c = eof();
  119. return(c = ' ');
  120. }
  121.  
  122.  
  123. FILE *opn(p)
  124. register char *p;
  125. {
  126. FILE *fd;
  127.  
  128. if(p[0]=='-' && p[1]=='\0')
  129.     fd = stdin;
  130. else if( (fd = fopen(p, "r")) == NULL)
  131.     fatal("Cannot open file %s\n", p);
  132.  
  133. return(fd);
  134. }
  135.  
  136.  
  137.  
  138. eof()
  139. {
  140. if(infile != stdin)
  141.     fclose(infile);
  142. if(filesp > files)
  143.     infile = *--filesp;
  144. else if(argc > 0)
  145.     {
  146.     infile = opn(argv[0]);
  147.     --argc;
  148.     ++argv;
  149.     }
  150. else
  151.     exit(0);
  152.  
  153. return(C);
  154. }
  155.  
  156.  
  157.  
  158. getfname()
  159. {
  160. register char *p;
  161. struct chain { struct chain *nextp; char *datap; } *chainblock;
  162. register struct chain *q;
  163. static struct chain *namechain    = NULL;
  164. char *copys();
  165.  
  166. while(C == ' ') ;
  167.  
  168. for(p = fname ; (*p=c)!= '\n' && c!=' ' && c!='\t' && c!='\\' ; ++p)
  169.     C;
  170. *p = '\0';
  171. while(c != '\n')
  172.     C;
  173.  
  174. /* see if this name has already been used */
  175.  
  176. for(q = namechain ; q; q = q->nextp)
  177.     if( ! strcmp(fname, q->datap))
  178.         {
  179.         fname[0] = '\0';
  180.         return;
  181.         }
  182.  
  183. q = (struct chain *) calloc(1, sizeof(*chainblock));
  184. q->nextp = namechain;
  185. q->datap = copys(fname);
  186. namechain = q;
  187. }
  188.  
  189.  
  190.  
  191.  
  192. fatal(s,p)
  193. char *s, *p;
  194. {
  195. fprintf(stderr, "Deroff: ");
  196. fprintf(stderr, s, p);
  197. exit(1);
  198. }
  199.  
  200. work()
  201. {
  202.  
  203. for( ;; )
  204.     {
  205.     if(C == '.'  ||  c == '\'')
  206.         comline();
  207.     else
  208.         regline(NO);
  209.     }
  210. }
  211.  
  212.  
  213.  
  214.  
  215. regline(macline)
  216. int macline;
  217. {
  218. line[0] = c;
  219. lp = line;
  220. for( ; ; )
  221.     {
  222.     if(c == '\\')
  223.         {
  224.         *lp = ' ';
  225.         backsl();
  226.         }
  227.     if(c == '\n') break;
  228.     if(intable && c=='T')
  229.         {
  230.         *++lp = C;
  231.         if(c=='{' || c=='}')
  232.             {
  233.             lp[-1] = ' ';
  234.             *lp = C;
  235.             }
  236.         }
  237.     else    *++lp = C;
  238.     }
  239.  
  240. *lp = '\0';
  241.  
  242. if(line[0] != '\0')
  243.     if(wordflag)
  244.         putwords(macline);
  245.     else if(macline)
  246.         putmac(line);
  247.     else
  248.         puts(line);
  249. }
  250.  
  251.  
  252.  
  253.  
  254. putmac(s)
  255. register char *s;
  256. {
  257. register char *t;
  258.  
  259. while(*s)
  260.     {
  261.     while(*s==' ' || *s=='\t')
  262.         putchar(*s++);
  263.     for(t = s ; *t!=' ' && *t!='\t' && *t!='\0' ; ++t)
  264.         ;
  265.     if(t>s+2 && chars[ s[0] ]==LETTER && chars[ s[1] ]==LETTER)
  266.         while(s < t)
  267.             putchar(*s++);
  268.     else
  269.         s = t;
  270.     }
  271. putchar('\n');
  272. }
  273.  
  274.  
  275.  
  276. putwords(macline)    /* break into words for -w option */
  277. int macline;
  278. {
  279. register char *p, *p1;
  280. int i, nlet;
  281.  
  282.  
  283. for(p1 = line ; ;)
  284.     {
  285.     /* skip initial specials ampersands and apostrophes */
  286.     while( chars[*p1] < DIGIT)
  287.         if(*p1++ == '\0') return;
  288.     nlet = 0;
  289.     for(p = p1 ; (i=chars[*p]) != SPECIAL ; ++p)
  290.         if(i == LETTER) ++nlet;
  291.  
  292.     if( (!macline && nlet>1)   /* MDM definition of word */
  293.        || (macline && nlet>2 && chars[ p1[0] ]==LETTER && chars[ p1[1] ]==LETTER) )
  294.         {
  295.         /* delete trailing ampersands and apostrophes */
  296.         while(p[-1]=='\'' || p[-1]=='&')
  297.              --p;
  298.         while(p1 < p) putchar(*p1++);
  299.         putchar('\n');
  300.         }
  301.     else
  302.         p1 = p;
  303.     }
  304. }
  305.  
  306.  
  307.  
  308. comline()
  309. {
  310. register int c1, c2;
  311.  
  312. while(C==' ' || c=='\t')
  313.     ;
  314. if( (c1=c) == '\n')
  315.     return;
  316. c2 = C;
  317. if(c1=='.' && c2!='.')
  318.     inmacro = NO;
  319. if(c2 == '\n')
  320.     return;
  321.  
  322. if(c1=='E' && c2=='Q' && filesp==files)
  323.     eqn();
  324. else if(c1=='T' && (c2=='S' || c2=='C' || c2=='&') && filesp==files)
  325.     tbl();
  326. else if(c1=='T' && c2=='E')
  327.     intable = NO;
  328. else if(!inmacro && c1=='d' && c2=='e')
  329.     macro();
  330. else if(!inmacro && c1=='i' && c2=='g')
  331.     macro();
  332. else if(!inmacro && c1=='a' && c2 == 'm')
  333.     macro();
  334. else if(c1=='s' && c2=='o')
  335.     {
  336.     getfname();
  337.     if( fname[0] )
  338.         infile = *++filesp = opn( fname );
  339.     }
  340. else if(c1=='n' && c2=='x')
  341.     {
  342.     getfname();
  343.     if(fname[0] == '\0') exit(0);
  344.     if(infile != stdin)
  345.         fclose(infile);
  346.     infile = *filesp = opn(fname);
  347.     }
  348. else if(c1=='h' && c2=='w')
  349.     { SKIP; }
  350. else
  351.     {
  352.     if(c1=='.' && c2=='.')
  353.         while(C == '.')
  354.             ;
  355.     ++inmacro;
  356.     regline(YES);
  357.     --inmacro;
  358.     }
  359. }
  360.  
  361.  
  362.  
  363. macro()
  364. {
  365. /*
  366. do { SKIP; }
  367.     while(C!='.' || C!='.' || C=='.');    /* look for  .. */
  368. SKIP;
  369. inmacro = YES;
  370. }
  371.  
  372.  
  373.  
  374.  
  375. tbl()
  376. {
  377. while(C != '.');
  378. SKIP;
  379. intable = YES;
  380. }
  381.  
  382. eqn()
  383. {
  384. register int c1, c2;
  385.  
  386. SKIP;
  387.  
  388. for( ;;)
  389.     {
  390.     if(C == '.'  || c == '\'')
  391.         {
  392.         while(C==' ' || c=='\t')
  393.             ;
  394.         if(c=='E' && C=='N')
  395.             {
  396.             SKIP;
  397.             return;
  398.             }
  399.         }
  400.     else if(c == 'd')    /* look for delim */
  401.         {
  402.         if(C=='e' && C=='l')
  403.             if( C=='i' && C=='m')
  404.             {
  405.             while(C1 == ' ');
  406.             if((c1=c)=='\n' || (c2=C1)=='\n'
  407.                 || (c1=='o' && c2=='f' && C1=='f') )
  408.                 {
  409.                 ldelim = NOCHAR;
  410.                 rdelim = NOCHAR;
  411.                 }
  412.             else    {
  413.                 ldelim = c1;
  414.                 rdelim = c2;
  415.                 }
  416.             }
  417.         }
  418.  
  419.     if(c != '\n')  SKIP;
  420.     }
  421. }
  422.  
  423.  
  424.  
  425. backsl()    /* skip over a complete backslash construction */
  426. {
  427. int bdelim;
  428.  
  429. sw:  switch(C)
  430.     {
  431.     case '"':
  432.         SKIP;
  433.         return;
  434.     case 's':
  435.         if(C == '\\') backsl();
  436.         else    {
  437.             while(C>='0' && c<='9') ;
  438.             ungetc(c,infile);
  439.             c = '0';
  440.             }
  441.         --lp;
  442.         return;
  443.  
  444.     case 'f':
  445.     case 'n':
  446.     case '*':
  447.         if(C != '(')
  448.             return;
  449.  
  450.     case '(':
  451.         if(C != '\n') C;
  452.         return;
  453.  
  454.     case '$':
  455.         C;    /* discard argument number */
  456.         return;
  457.  
  458.     case 'b':
  459.     case 'x':
  460.     case 'v':
  461.     case 'h':
  462.     case 'w':
  463.     case 'o':
  464.     case 'l':
  465.     case 'L':
  466.         if( (bdelim=C) == '\n')
  467.             return;
  468.         while(C!='\n' && c!=bdelim)
  469.             if(c == '\\') backsl();
  470.         return;
  471.  
  472.     case '\\':
  473.         if(inmacro)
  474.             goto sw;
  475.     default:
  476.         return;
  477.     }
  478. }
  479.  
  480.  
  481.  
  482.  
  483. char *copys(s)
  484. register char *s;
  485. {
  486. register char *t, *t0;
  487.  
  488. if( (t0 = t = calloc( strlen(s)+1, sizeof(*t) ) ) == NULL)
  489.     fatal("Cannot allocate memory", (char *) NULL);
  490.  
  491. while( *t++ = *s++ )
  492.     ;
  493. return(t0);
  494. }
  495.