home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_progs / prog_c / unifdef.lzh / UNIFDEF / UNIFDEF.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-01  |  12.1 KB  |  592 lines

  1. /*
  2.  *
  3.  *    unifdef - remove ifdef'ed lines
  4.  *
  5.  *    Wishlist:
  6.  *        provide an option which will append the name of the
  7.  *        appropriate symbol after #else's and #endif's
  8.  *
  9.  *        provide an option which will check symbols after
  10.  *        #else's and #endif's to see that they match their
  11.  *        corresponding #ifdef or #ifndef
  12.  *
  13.  */
  14.  
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #ifdef ORIGINALCODE    /* And that's how it was folks...  (fnf) */
  18. #include <c_env.h>
  19. #endif
  20.  
  21. #define BSS
  22. FILE *input;
  23. #ifndef YES
  24. #define YES 1
  25. #define NO  0
  26. #endif
  27. typedef int Bool;
  28.  
  29. char *progname BSS;
  30. char *filename BSS;
  31. char text BSS;          /* -t option in effect: this is a text file */
  32. char lnblank BSS;       /* -l option in effect: blank deleted lines */
  33. char complement BSS;    /* -c option in effect: complement the operation */
  34.  
  35. #define MAXSYMS 100
  36. char *sym[MAXSYMS] BSS;     /* symbol name */
  37. char true[MAXSYMS] BSS;     /* -dsym */
  38. char ignore[MAXSYMS] BSS;   /* -idsym or -iusym */
  39. char insym[MAXSYMS] BSS;    /* state: false, inactive, true */
  40. #define SYM_INACTIVE 0      /* symbol is currently inactive */
  41. #define SYM_FALSE    1      /* symbol is currently false */
  42. #define SYM_TRUE     2      /* symbol is currently true  */
  43.  
  44. char nsyms BSS;
  45. char incomment BSS;         /* inside C comment */
  46.  
  47. #define QUOTE_NONE   0
  48. #define QUOTE_SINGLE 1
  49. #define QUOTE_DOUBLE 2
  50. char inquote BSS;           /* inside single or double quotes */
  51.  
  52. int exitstat BSS;
  53. char *skipcomment ();
  54. char *skipquote ();
  55.  
  56. main (argc, argv)
  57. int argc;
  58. char **argv;
  59. {
  60.     char **curarg;
  61.     register char *cp;
  62.     register char *cp1;
  63.     char ignorethis;
  64.  
  65.     progname = argv[0][0] ? argv[0] : "unifdef";
  66.  
  67.     for (curarg = &argv[1]; --argc > 0; curarg++) {
  68.     if (*(cp1 = cp = *curarg) != '-')
  69.         break;
  70.     if (*++cp1 == 'i') {
  71.         ignorethis = YES;
  72.         cp1++;
  73.     }
  74.     else
  75.         ignorethis = NO;
  76.     if (   (   *cp1 == 'd'
  77.         || *cp1 == 'u'
  78.            )
  79.         && cp1[1] != '\0'
  80.        ) {
  81.         if (nsyms >= MAXSYMS) {
  82.         prname ();
  83.         fprintf (stderr, "too many symbols.\n");
  84.         exit (2);
  85.         }
  86.         insym[nsyms] = SYM_INACTIVE;
  87.         ignore[nsyms] = ignorethis;
  88.         true[nsyms] = *cp1 == 'd' ? YES : NO;
  89.         sym[nsyms++] = &cp1[1];
  90.     }
  91.     else if (ignorethis)
  92.         goto unrec;
  93.     else if (strcmp (&cp[1], "t") == 0)
  94.         text = YES;
  95.     else if (strcmp (&cp[1], "l") == 0)
  96.         lnblank = YES;
  97.     else if (strcmp (&cp[1], "c") == 0)
  98.         complement = YES;
  99.     else {
  100.  unrec:
  101.         prname ();
  102.         fprintf (stderr, "unrecognized option: %s\n", cp);
  103.         goto usage;
  104.     }
  105.     }
  106.     if (nsyms == 0) {
  107.  usage:
  108.     fprintf (stderr, "\
  109. Usage: %s [-l] [-t] [-c] [[-dsym] [-usym] [-idsym] [-iusym]]... [file]\n\
  110.     At least one arg from [-d -u -id -iu] is required\n", progname);
  111.     exit (2);
  112.     }
  113.  
  114.     if (argc > 1) {
  115.     prname ();
  116.     fprintf (stderr, "can only do one file.\n");
  117.     }
  118.     else if (argc == 1) {
  119.     filename = *curarg;
  120.     if ((input = fopen (filename, "r")) != NULL) {
  121.         pfile();
  122.         (void) fclose (input);
  123.     }
  124.     else {
  125.         prname ();
  126.         fprintf (stderr, "can't open %s\n", *curarg);
  127.     }
  128.     }
  129.     else {
  130.     filename = "[stdin]";
  131.     input = stdin;
  132.     pfile();
  133.     }
  134.  
  135.     (void) fflush (stdout);
  136.     exit (exitstat);
  137. }
  138.  
  139. /* types of input lines: */
  140. typedef int Linetype;
  141. #define LT_PLAIN       0   /* ordinary line */
  142. #define LT_TRUE        1   /* a true  #ifdef of a symbol known to us */
  143. #define LT_FALSE       2   /* a false #ifdef of a symbol known to us */
  144. #define LT_OTHER       3   /* an #ifdef of a symbol not known to us */
  145. #define LT_IF          4   /* an #ifdef of a symbol not known to us */
  146. #define LT_ELSE        5   /* #else */
  147. #define LT_ENDIF       6   /* #endif */
  148. #define LT_LEOF        7   /* end of file */
  149. extern Linetype checkline ();
  150.  
  151. typedef int Reject_level;
  152. Reject_level reject BSS;    /* 0 or 1: pass thru; 1 or 2: ignore comments */
  153. #define REJ_NO          0
  154. #define REJ_IGNORE      1
  155. #define REJ_YES         2
  156.  
  157. int linenum BSS;    /* current line number */
  158. int stqcline BSS;   /* start of current coment or quote */
  159. char *errs[] = {
  160. #define NO_ERR      0
  161.             "",
  162. #define END_ERR     1
  163.             "",
  164. #define ELSE_ERR    2
  165.             "Inappropriate else",
  166. #define ENDIF_ERR   3
  167.             "Inappropriate endif",
  168. #define IEOF_ERR    4
  169.             "Premature EOF in ifdef",
  170. #define CEOF_ERR    5
  171.             "Premature EOF in comment",
  172. #define Q1EOF_ERR   6
  173.             "Premature EOF in quoted character",
  174. #define Q2EOF_ERR   7
  175.             "Premature EOF in quoted string"
  176. };
  177.  
  178. /* States for inif arg to doif */
  179. #define IN_NONE 0
  180. #define IN_IF   1
  181. #define IN_ELSE 2
  182.  
  183. pfile ()
  184. {
  185.     reject = REJ_NO;
  186.     (void) doif (-1, IN_NONE, reject, 0);
  187.     return;
  188. }
  189.  
  190. doif (thissym, inif, prevreject, depth)
  191. register int thissym;   /* index of the symbol who was last ifdef'ed */
  192. int inif;               /* YES or NO we are inside an ifdef */
  193. Reject_level prevreject;/* previous value of reject */
  194. int depth;              /* depth of ifdef's */
  195. {
  196.     register Linetype lineval;
  197.     register Reject_level thisreject;
  198.     int doret;          /* tmp return value of doif */
  199.     int cursym;         /* index of the symbol returned by checkline */
  200.     int stline;         /* line number when called this time */
  201.  
  202.     stline = linenum;
  203.     for (;;) {
  204.     switch (lineval = checkline (&cursym)) {
  205.     case LT_PLAIN:
  206.         flushline (YES);
  207.         break;
  208.  
  209.     case LT_TRUE:
  210.     case LT_FALSE:
  211.         thisreject = reject;
  212.         if (lineval == LT_TRUE)
  213.         insym[cursym] = SYM_TRUE;
  214.         else {
  215.         if (reject != REJ_YES)
  216.             reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
  217.         insym[cursym] = SYM_FALSE;
  218.         }
  219.         if (ignore[cursym])
  220.         flushline (YES);
  221.         else {
  222.         exitstat = 1;
  223.         flushline (NO);
  224.         }
  225.         if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
  226.         return error (doret, stline, depth);
  227.             break;
  228.  
  229.     case LT_IF:
  230.     case LT_OTHER:
  231.         flushline (YES);
  232.         if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
  233.         return error (doret, stline, depth);
  234.         break;
  235.  
  236.     case LT_ELSE:
  237.         if (inif != IN_IF)
  238.         return error (ELSE_ERR, linenum, depth);
  239.         inif = IN_ELSE;
  240.         if (thissym >= 0) {
  241.         if (insym[thissym] == SYM_TRUE) {
  242.             reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
  243.             insym[thissym] = SYM_FALSE;
  244.         }
  245.         else { /* (insym[thissym] == SYM_FALSE) */
  246.             reject = prevreject;
  247.             insym[thissym] = SYM_TRUE;
  248.         }
  249.         if (!ignore[thissym]) {
  250.             flushline (NO);
  251.             break;
  252.         }
  253.         }
  254.         flushline (YES);
  255.         break;
  256.  
  257.     case LT_ENDIF:
  258.         if (inif == IN_NONE)
  259.         return error (ENDIF_ERR, linenum, depth);
  260.         if (thissym >= 0) {
  261.         insym[thissym] = SYM_INACTIVE;
  262.         reject = prevreject;
  263.         if (!ignore[thissym]) {
  264.             flushline (NO);
  265.             return NO_ERR;
  266.         }
  267.         }
  268.         flushline (YES);
  269.         return NO_ERR;
  270.  
  271.     case LT_LEOF: {
  272.         int err;
  273.         err =   incomment
  274.           ? CEOF_ERR
  275.           : inquote == QUOTE_SINGLE
  276.           ? Q1EOF_ERR
  277.           : inquote == QUOTE_DOUBLE
  278.           ? Q2EOF_ERR
  279.           : NO_ERR;
  280.         if (inif != IN_NONE) {
  281.         if (err != NO_ERR)
  282.             (void) error (err, stqcline, depth);
  283.         return error (IEOF_ERR, stline, depth);
  284.         }
  285.         else if (err != NO_ERR)
  286.         return error (err, stqcline, depth);
  287.         else
  288.         return NO_ERR;
  289.         }
  290.     }
  291.     }
  292. }
  293.  
  294. #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
  295.  
  296. #define MAXLINE 256
  297. char tline[MAXLINE] BSS;
  298.  
  299. Linetype
  300. checkline (cursym)
  301. int *cursym;
  302. {
  303.     register char *cp;
  304.     register char *symp;
  305.     register char chr;
  306.     char *scp;
  307.     Linetype retval;
  308.     int symind;
  309. #   define KWSIZE 8
  310.     char keyword[KWSIZE];
  311.  
  312.     linenum++;
  313.     if (getlin (tline, sizeof tline, input, NO) == EOF)
  314.     return LT_LEOF;
  315.  
  316.     retval = LT_PLAIN;
  317.     if (   *(cp = tline) != '#'
  318.     || incomment
  319.     || inquote == QUOTE_SINGLE
  320.     || inquote == QUOTE_DOUBLE
  321.        )
  322.     goto eol;
  323.  
  324.     cp = skipcomment (++cp);
  325.     symp = keyword;
  326.     while (!endsym (*cp)) {
  327.     *symp = *cp++;
  328.     if (++symp >= &keyword[KWSIZE])
  329.         goto eol;
  330.     }
  331.     *symp = '\0';
  332.  
  333.     if (strcmp (keyword, "ifdef") == 0) {
  334.     retval = YES;
  335.     goto ifdef;
  336.     }
  337.     else if (strcmp (keyword, "ifndef") == 0) {
  338.     retval = NO;
  339.  ifdef:
  340.     scp = cp = skipcomment (++cp);
  341.     if (incomment) {
  342.         retval = LT_PLAIN;
  343.         goto eol;
  344.     }
  345.     for (symind = 0; ; ) {
  346.         if (insym[symind] == SYM_INACTIVE) {
  347.         for ( symp = sym[symind], cp = scp
  348.             ; *symp && *cp == *symp
  349.             ; cp++, symp++
  350.             )
  351.             continue;
  352.         chr = *cp;
  353.         if (*symp == '\0' && endsym (chr)) {
  354.             *cursym = symind;
  355.             retval = (retval ^ true[symind]) ? LT_FALSE : LT_TRUE;
  356.             break;
  357.         }
  358.         }
  359.         if (++symind >= nsyms) {
  360.         retval = LT_OTHER;
  361.         break;
  362.         }
  363.     }
  364.     }
  365.     else if (strcmp (keyword, "if") == 0)
  366.     retval = LT_IF;
  367.     else if (strcmp (keyword, "else") == 0)
  368.     retval = LT_ELSE;
  369.     else if (strcmp (keyword, "endif") == 0)
  370.     retval = LT_ENDIF;
  371.  
  372.  eol:
  373.     if (!text && reject == REJ_NO)
  374.     for (; *cp; ) {
  375.         if (incomment)
  376.         cp = skipcomment (cp);
  377.         else if (inquote == QUOTE_SINGLE)
  378.         cp = skipquote (cp, QUOTE_SINGLE);
  379.         else if (inquote == QUOTE_DOUBLE)
  380.         cp = skipquote (cp, QUOTE_DOUBLE);
  381.         else if (*cp == '/' && cp[1] == '*')
  382.         cp = skipcomment (cp);
  383.         else if (*cp == '\'')
  384.         cp = skipquote (cp, QUOTE_SINGLE);
  385.         else if (*cp == '"')
  386.         cp = skipquote (cp, QUOTE_DOUBLE);
  387.         else
  388.         cp++;
  389.     }
  390.     return retval;
  391. }
  392.  
  393. /*  Skip over comments and stop at the next charaacter
  394. /*  position that is not whitespace.
  395. /**/
  396. char *
  397. skipcomment (cp)
  398. register char *cp;
  399. {
  400.     if (incomment)
  401.     goto inside;
  402.     for (;; cp++) {
  403.         while (*cp == ' ' || *cp == '\t')
  404.             cp++;
  405.     if (text)
  406.             return cp;
  407.     if (   cp[0] != '/'
  408.         || cp[1] != '*'
  409.        )
  410.             return cp;
  411.     cp += 2;
  412.     if (!incomment) {
  413.         incomment = YES;
  414.         stqcline = linenum;
  415.     }
  416.  inside:
  417.     for (;;) {
  418.         for (; *cp != '*'; cp++)
  419.         if (*cp == '\0')
  420.             return cp;
  421.         if (*++cp == '/')
  422.         break;
  423.     }
  424.     incomment = NO;
  425.     }
  426. }
  427.  
  428. /*  Skip over a quoted string or character and stop at the next charaacter
  429. /*  position that is not whitespace.
  430. /**/
  431. char *
  432. skipquote (cp, type)
  433. register char *cp;
  434. register int type;
  435. {
  436.     register char qchar;
  437.  
  438.     qchar = type == QUOTE_SINGLE ? '\'' : '"';
  439.  
  440.     if (inquote == type)
  441.     goto inside;
  442.     for (;; cp++) {
  443.     if (*cp != qchar)
  444.         return cp;
  445.     cp++;
  446.     inquote = type;
  447.     stqcline = linenum;
  448.  inside:
  449.     for (; ; cp++) {
  450.         if (*cp == qchar)
  451.         break;
  452.         if (   *cp == '\0'
  453.         || *cp == '\\'
  454.         && *++cp == '\0'
  455.            )
  456.         return cp;
  457.     }
  458.     inquote = QUOTE_NONE;
  459.     }
  460. }
  461.  
  462. /*
  463. /*   special getlin - treats form-feed as an end-of-line
  464. /*                    and expands tabs if asked for
  465. /*
  466. /**/
  467. getlin (line, maxline, inp, expandtabs)
  468. register char *line;
  469. int maxline;
  470. FILE *inp;
  471. int expandtabs;
  472. {
  473.     int tmp;
  474.     register int num;
  475.     register int chr;
  476. #ifdef FFSPECIAL
  477.     static char havechar = NO;  /* have leftover char from last time */
  478.     static char svchar BSS;
  479. #endif
  480.  
  481.     num = 0;
  482. #ifdef FFSPECIAL
  483.     if (havechar) {
  484.     havechar = NO;
  485.     chr = svchar;
  486.     goto ent;
  487.     }
  488. #endif
  489.     while (num + 8 < maxline) {   /* leave room for tab */
  490.         chr = getc (inp);
  491.     if (isprint (chr)) {
  492. #ifdef FFSPECIAL
  493.  ent:
  494. #endif
  495.         *line++ = chr;
  496.         num++;
  497.     }
  498.     else
  499.         switch (chr) {
  500.         case EOF:
  501.         return EOF;
  502.  
  503.         case '\t':
  504.         if (expandtabs) {
  505.             num += tmp = 8 - (num & 7);
  506.             do
  507.             *line++ = ' ';
  508.             while (--tmp);
  509.             break;
  510.         } 
  511.             default:
  512.                 *line++ = chr;
  513.                 num++;
  514.         break;
  515.  
  516.         case '\n':
  517.                 *line = '\n';
  518.                 num++;
  519.                 goto end;
  520.     
  521. #ifdef FFSPECIAL
  522.         case '\f':
  523.         if (++num == 1)
  524.             *line = '\f';
  525.         else {
  526.             *line = '\n';
  527.             havechar = YES;
  528.                     svchar = chr;
  529.                 }
  530.                 goto end;
  531. #endif
  532.         }
  533.     }
  534.  end:
  535.     *++line = '\0';
  536.     return num;
  537. }
  538.  
  539. flushline (keep)
  540. Bool keep;
  541. {
  542.     if ((keep && reject != REJ_YES) ^ complement)
  543.     putlin (tline, stdout);
  544.     else if (lnblank)
  545.     putlin ("\n", stdout);
  546.     return;
  547. }
  548.  
  549. /*
  550. /*  putlin - for tools
  551. /*
  552. /**/
  553. putlin (line, fio)
  554. register char *line;
  555. register FILE *fio;
  556. {
  557.     register char chr;
  558.  
  559.     while (chr = *line++)
  560.     putc (chr, fio);
  561.     return;
  562. }
  563.  
  564. prname ()
  565. {
  566.     fprintf (stderr, "%s: ", progname);
  567.     return;
  568. }
  569.  
  570. int
  571. error (err, line, depth)
  572. {
  573.     if (err == END_ERR)
  574.     return err;
  575.  
  576.     prname ();
  577.  
  578. #ifndef TESTING
  579.     fprintf (stderr, "Error in %s line %d: %s.\n",
  580.          filename, line, errs[err]);
  581. #endif
  582.  
  583. #ifdef TESTING
  584.     fprintf (stderr, "Error in %s line %d: %s. ",
  585.          filename, line, errs[err]);
  586.     fprintf (stderr, "ifdef depth: %d\n", depth);
  587. #endif
  588.  
  589.     exitstat = 2;
  590.     return depth > 1 ? IEOF_ERR : END_ERR;
  591. }
  592.