home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / unifdef / unifdef.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-16  |  14.6 KB  |  639 lines

  1. /*
  2.  * Copyright (c) 1985 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Dave Yost.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1985 The Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)unifdef.c    4.7 (Berkeley) 6/1/90";
  45. #endif /* not lint */
  46.  
  47. /*
  48.  * unifdef - remove ifdef'ed lines
  49.  *
  50.  *  Warning: will not work correctly if input contains null characters.
  51.  *
  52.  *  Wishlist:
  53.  *      provide an option which will append the name of the
  54.  *        appropriate symbol after #else's and #endif's
  55.  *      provide an option which will check symbols after
  56.  *        #else's and #endif's to see that they match their
  57.  *        corresponding #ifdef or #ifndef
  58.  */
  59.  
  60. #include <stdio.h>
  61. #include <ctype.h>
  62.  
  63. #define BSS
  64. FILE *input;
  65. #ifndef YES
  66. #define YES 1
  67. #define NO  0
  68. #endif/*YES */
  69. typedef int Bool;
  70.  
  71. char *progname BSS;
  72. char *filename BSS;
  73. char text BSS;          /* -t option in effect: this is a text file */
  74. char lnblank BSS;       /* -l option in effect: blank deleted lines */
  75. char complement BSS;    /* -c option in effect: complement the operation */
  76.  
  77. #define MAXSYMS 100
  78. char *symname[MAXSYMS] BSS; /* symbol name */
  79. char true[MAXSYMS] BSS;     /* -Dsym */
  80. char ignore[MAXSYMS] BSS;   /* -iDsym or -iUsym */
  81. char insym[MAXSYMS] BSS;    /* state: false, inactive, true */
  82. #define SYM_INACTIVE 0      /* symbol is currently inactive */
  83. #define SYM_FALSE    1      /* symbol is currently false */
  84. #define SYM_TRUE     2      /* symbol is currently true  */
  85.  
  86. char nsyms BSS;
  87. char incomment BSS;         /* inside C comment */
  88.  
  89. #define QUOTE_NONE   0
  90. #define QUOTE_SINGLE 1
  91. #define QUOTE_DOUBLE 2
  92. char inquote BSS;           /* inside single or double quotes */
  93.  
  94. int exitstat BSS;
  95. char *skipcomment ();
  96. char *skipquote ();
  97.  
  98. main (argc, argv)
  99. int argc;
  100. char **argv;
  101. {
  102.     char **curarg;
  103.     register char *cp;
  104.     register char *cp1;
  105.     char ignorethis;
  106.  
  107.     progname = argv[0][0] ? argv[0] : "unifdef";
  108.  
  109.     for (curarg = &argv[1]; --argc > 0; curarg++) {
  110.     if (*(cp1 = cp = *curarg) != '-')
  111.         break;
  112.     if (*++cp1 == 'i') {
  113.         ignorethis = YES;
  114.         cp1++;
  115.     } else
  116.         ignorethis = NO;
  117.     if (   (   *cp1 == 'D'
  118.         || *cp1 == 'U'
  119.            )
  120.         && cp1[1] != '\0'
  121.        ) {
  122.         register int symind;
  123.  
  124.         if ((symind = findsym (&cp1[1])) < 0) {
  125.         if (nsyms >= MAXSYMS) {
  126.             prname ();
  127.             fprintf (stderr, "too many symbols.\n");
  128.             exit (2);
  129.         }
  130.         symind = nsyms++;
  131.         symname[symind] = &cp1[1];
  132.         insym[symind] = SYM_INACTIVE;
  133.         }
  134.         ignore[symind] = ignorethis;
  135.         true[symind] = *cp1 == 'D' ? YES : NO;
  136.     } else if (ignorethis)
  137.         goto unrec;
  138.     else if (strcmp (&cp[1], "t") == 0)
  139.         text = YES;
  140.     else if (strcmp (&cp[1], "l") == 0)
  141.         lnblank = YES;
  142.     else if (strcmp (&cp[1], "c") == 0)
  143.         complement = YES;
  144.     else {
  145.  unrec:
  146.         prname ();
  147.         fprintf (stderr, "unrecognized option: %s\n", cp);
  148.         goto usage;
  149.     }
  150.     }
  151.     if (nsyms == 0) {
  152.  usage:
  153.     fprintf (stderr, "\
  154. Usage: %s [-l] [-t] [-c] [[-Dsym] [-Usym] [-iDsym] [-iUsym]]... [file]\n\
  155.     At least one arg from [-D -U -iD -iU] is required\n", progname);
  156.     exit (2);
  157.     }
  158.  
  159.     if (argc > 1) {
  160.     prname ();
  161.     fprintf (stderr, "can only do one file.\n");
  162.     } else if (argc == 1) {
  163.     filename = *curarg;
  164.     if ((input = fopen (filename, "r")) != NULL) {
  165.         pfile();
  166.         (void) fclose (input);
  167.     } else {
  168.         prname ();
  169.         fprintf (stderr, "can't open ");
  170.         perror(*curarg);
  171.     }
  172.     } else {
  173.     filename = "[stdin]";
  174.     input = stdin;
  175.     pfile();
  176.     }
  177.  
  178.     (void) fflush (stdout);
  179.     exit (exitstat);
  180. }
  181.  
  182. /* types of input lines: */
  183. typedef int Linetype;
  184. #define LT_PLAIN       0   /* ordinary line */
  185. #define LT_TRUE        1   /* a true  #ifdef of a symbol known to us */
  186. #define LT_FALSE       2   /* a false #ifdef of a symbol known to us */
  187. #define LT_OTHER       3   /* an #ifdef of a symbol not known to us */
  188. #define LT_IF          4   /* an #ifdef of a symbol not known to us */
  189. #define LT_ELSE        5   /* #else */
  190. #define LT_ENDIF       6   /* #endif */
  191. #define LT_LEOF        7   /* end of file */
  192. extern Linetype checkline ();
  193.  
  194. typedef int Reject_level;
  195. Reject_level reject BSS;    /* 0 or 1: pass thru; 1 or 2: ignore comments */
  196. #define REJ_NO          0
  197. #define REJ_IGNORE      1
  198. #define REJ_YES         2
  199.  
  200. int linenum BSS;    /* current line number */
  201. int stqcline BSS;   /* start of current coment or quote */
  202. char *errs[] = {
  203. #define NO_ERR      0
  204.             "",
  205. #define END_ERR     1
  206.             "",
  207. #define ELSE_ERR    2
  208.             "Inappropriate else",
  209. #define ENDIF_ERR   3
  210.             "Inappropriate endif",
  211. #define IEOF_ERR    4
  212.             "Premature EOF in ifdef",
  213. #define CEOF_ERR    5
  214.             "Premature EOF in comment",
  215. #define Q1EOF_ERR   6
  216.             "Premature EOF in quoted character",
  217. #define Q2EOF_ERR   7
  218.             "Premature EOF in quoted string"
  219. };
  220.  
  221. /* States for inif arg to doif */
  222. #define IN_NONE 0
  223. #define IN_IF   1
  224. #define IN_ELSE 2
  225.  
  226. pfile ()
  227. {
  228.     reject = REJ_NO;
  229.     (void) doif (-1, IN_NONE, reject, 0);
  230.     return;
  231. }
  232.  
  233. int
  234. doif (thissym, inif, prevreject, depth)
  235. register int thissym;   /* index of the symbol who was last ifdef'ed */
  236. int inif;               /* YES or NO we are inside an ifdef */
  237. Reject_level prevreject;/* previous value of reject */
  238. int depth;              /* depth of ifdef's */
  239. {
  240.     register Linetype lineval;
  241.     register Reject_level thisreject;
  242.     int doret;          /* tmp return value of doif */
  243.     int cursym;         /* index of the symbol returned by checkline */
  244.     int stline;         /* line number when called this time */
  245.  
  246.     stline = linenum;
  247.     for (;;) {
  248.     switch (lineval = checkline (&cursym)) {
  249.     case LT_PLAIN:
  250.         flushline (YES);
  251.         break;
  252.  
  253.     case LT_TRUE:
  254.     case LT_FALSE:
  255.         thisreject = reject;
  256.         if (lineval == LT_TRUE)
  257.         insym[cursym] = SYM_TRUE;
  258.         else {
  259.         if (reject != REJ_YES)
  260.             reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
  261.         insym[cursym] = SYM_FALSE;
  262.         }
  263.         if (ignore[cursym])
  264.         flushline (YES);
  265.         else {
  266.         exitstat = 1;
  267.         flushline (NO);
  268.         }
  269.         if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
  270.         return error (doret, stline, depth);
  271.         break;
  272.  
  273.     case LT_IF:
  274.     case LT_OTHER:
  275.         flushline (YES);
  276.         if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
  277.         return error (doret, stline, depth);
  278.         break;
  279.  
  280.     case LT_ELSE:
  281.         if (inif != IN_IF)
  282.         return error (ELSE_ERR, linenum, depth);
  283.         inif = IN_ELSE;
  284.         if (thissym >= 0) {
  285.         if (insym[thissym] == SYM_TRUE) {
  286.             reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
  287.             insym[thissym] = SYM_FALSE;
  288.         } else { /* (insym[thissym] == SYM_FALSE) */
  289.             reject = prevreject;
  290.             insym[thissym] = SYM_TRUE;
  291.         }
  292.         if (!ignore[thissym]) {
  293.             flushline (NO);
  294.             break;
  295.         }
  296.         }
  297.         flushline (YES);
  298.         break;
  299.  
  300.     case LT_ENDIF:
  301.         if (inif == IN_NONE)
  302.         return error (ENDIF_ERR, linenum, depth);
  303.         if (thissym >= 0) {
  304.         insym[thissym] = SYM_INACTIVE;
  305.         reject = prevreject;
  306.         if (!ignore[thissym]) {
  307.             flushline (NO);
  308.             return NO_ERR;
  309.         }
  310.         }
  311.         flushline (YES);
  312.         return NO_ERR;
  313.  
  314.     case LT_LEOF: {
  315.         int err;
  316.         err =   incomment
  317.           ? CEOF_ERR
  318.           : inquote == QUOTE_SINGLE
  319.           ? Q1EOF_ERR
  320.           : inquote == QUOTE_DOUBLE
  321.           ? Q2EOF_ERR
  322.           : NO_ERR;
  323.         if (inif != IN_NONE) {
  324.         if (err != NO_ERR)
  325.             (void) error (err, stqcline, depth);
  326.         return error (IEOF_ERR, stline, depth);
  327.         } else if (err != NO_ERR)
  328.         return error (err, stqcline, depth);
  329.         else
  330.         return NO_ERR;
  331.         }
  332.     }
  333.     }
  334. }
  335.  
  336. #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
  337.  
  338. #define MAXLINE 256
  339. char tline[MAXLINE] BSS;
  340.  
  341. Linetype
  342. checkline (cursym)
  343. int *cursym;    /* if LT_TRUE or LT_FALSE returned, set this to sym index */
  344. {
  345.     register char *cp;
  346.     register char *symp;
  347.     char *scp;
  348.     Linetype retval;
  349. #   define KWSIZE 8
  350.     char keyword[KWSIZE];
  351.  
  352.     linenum++;
  353.     if (getlin (tline, sizeof tline, input, NO) == EOF)
  354.     return LT_LEOF;
  355.  
  356.     retval = LT_PLAIN;
  357.     if (   *(cp = tline) != '#'
  358.     || incomment
  359.     || inquote == QUOTE_SINGLE
  360.     || inquote == QUOTE_DOUBLE
  361.        )
  362.     goto eol;
  363.  
  364.     cp = skipcomment (++cp);
  365.     symp = keyword;
  366.     while (!endsym (*cp)) {
  367.     *symp = *cp++;
  368.     if (++symp >= &keyword[KWSIZE])
  369.         goto eol;
  370.     }
  371.     *symp = '\0';
  372.  
  373.     if (strcmp (keyword, "ifdef") == 0) {
  374.     retval = YES;
  375.     goto ifdef;
  376.     } else if (strcmp (keyword, "ifndef") == 0) {
  377.     retval = NO;
  378.  ifdef:
  379.     scp = cp = skipcomment (++cp);
  380.     if (incomment) {
  381.         retval = LT_PLAIN;
  382.         goto eol;
  383.     }
  384.     {
  385.         int symind;
  386.  
  387.         if ((symind = findsym (scp)) >= 0)
  388.         retval = (retval ^ true[*cursym = symind])
  389.              ? LT_FALSE : LT_TRUE;
  390.         else
  391.         retval = LT_OTHER;
  392.     }
  393.     } else if (strcmp (keyword, "if") == 0)
  394.     retval = LT_IF;
  395.     else if (strcmp (keyword, "else") == 0)
  396.     retval = LT_ELSE;
  397.     else if (strcmp (keyword, "endif") == 0)
  398.     retval = LT_ENDIF;
  399.  
  400.  eol:
  401.     if (!text && reject != REJ_IGNORE)
  402.     for (; *cp; ) {
  403.         if (incomment)
  404.         cp = skipcomment (cp);
  405.         else if (inquote == QUOTE_SINGLE)
  406.         cp = skipquote (cp, QUOTE_SINGLE);
  407.         else if (inquote == QUOTE_DOUBLE)
  408.         cp = skipquote (cp, QUOTE_DOUBLE);
  409.         else if (*cp == '/' && cp[1] == '*')
  410.         cp = skipcomment (cp);
  411.         else if (*cp == '\'')
  412.         cp = skipquote (cp, QUOTE_SINGLE);
  413.         else if (*cp == '"')
  414.         cp = skipquote (cp, QUOTE_DOUBLE);
  415.         else
  416.         cp++;
  417.     }
  418.     return retval;
  419. }
  420.  
  421. /*
  422.  *  Skip over comments and stop at the next charaacter
  423.  *  position that is not whitespace.
  424.  */
  425. char *
  426. skipcomment (cp)
  427. register char *cp;
  428. {
  429.     if (incomment)
  430.     goto inside;
  431.     for (;; cp++) {
  432.     while (*cp == ' ' || *cp == '\t')
  433.         cp++;
  434.     if (text)
  435.         return cp;
  436.     if (   cp[0] != '/'
  437.         || cp[1] != '*'
  438.        )
  439.         return cp;
  440.     cp += 2;
  441.     if (!incomment) {
  442.         incomment = YES;
  443.         stqcline = linenum;
  444.     }
  445.  inside:
  446.     for (;;) {
  447.         for (; *cp != '*'; cp++)
  448.         if (*cp == '\0')
  449.             return cp;
  450.         if (*++cp == '/') {
  451.         incomment = NO;
  452.         break;
  453.         }
  454.     }
  455.     }
  456. }
  457.  
  458. /*
  459.  *  Skip over a quoted string or character and stop at the next charaacter
  460.  *  position that is not whitespace.
  461.  */
  462. char *
  463. skipquote (cp, type)
  464. register char *cp;
  465. register int type;
  466. {
  467.     register char qchar;
  468.  
  469.     qchar = type == QUOTE_SINGLE ? '\'' : '"';
  470.  
  471.     if (inquote == type)
  472.     goto inside;
  473.     for (;; cp++) {
  474.     if (*cp != qchar)
  475.         return cp;
  476.     cp++;
  477.     inquote = type;
  478.     stqcline = linenum;
  479.  inside:
  480.     for (; ; cp++) {
  481.         if (*cp == qchar)
  482.         break;
  483.         if (   *cp == '\0'
  484.         || *cp == '\\' && *++cp == '\0'
  485.            )
  486.         return cp;
  487.     }
  488.     inquote = QUOTE_NONE;
  489.     }
  490. }
  491.  
  492. /*
  493.  *  findsym - look for the symbol in the symbol table.
  494.  *            if found, return symbol table index,
  495.  *            else return -1.
  496.  */
  497. int
  498. findsym (str)
  499. char *str;
  500. {
  501.     register char *cp;
  502.     register char *symp;
  503.     register int symind;
  504.     register char chr;
  505.  
  506.     for (symind = 0; symind < nsyms; ++symind) {
  507.     if (insym[symind] == SYM_INACTIVE) {
  508.         for ( symp = symname[symind], cp = str
  509.         ; *symp && *cp == *symp
  510.         ; cp++, symp++
  511.         )
  512.         continue;
  513.         chr = *cp;
  514.         if (*symp == '\0' && endsym (chr))
  515.         return symind;
  516.     }
  517.     }
  518.     return -1;
  519. }
  520.  
  521. /*
  522.  *   getlin - expands tabs if asked for
  523.  *            and (if compiled in) treats form-feed as an end-of-line
  524.  */
  525. int
  526. getlin (line, maxline, inp, expandtabs)
  527. register char *line;
  528. int maxline;
  529. FILE *inp;
  530. int expandtabs;
  531. {
  532.     int tmp;
  533.     register int num;
  534.     register int chr;
  535. #ifdef  FFSPECIAL
  536.     static char havechar = NO;  /* have leftover char from last time */
  537.     static char svchar BSS;
  538. #endif/*FFSPECIAL */
  539.  
  540.     num = 0;
  541. #ifdef  FFSPECIAL
  542.     if (havechar) {
  543.     havechar = NO;
  544.     chr = svchar;
  545.     goto ent;
  546.     }
  547. #endif/*FFSPECIAL */
  548.     while (num + 8 < maxline) {   /* leave room for tab */
  549.     chr = getc (inp);
  550.     if (isprint (chr)) {
  551. #ifdef  FFSPECIAL
  552.  ent:
  553. #endif/*FFSPECIAL */
  554.         *line++ = chr;
  555.         num++;
  556.     } else
  557.         switch (chr) {
  558.         case EOF:
  559.         return EOF;
  560.  
  561.         case '\t':
  562.         if (expandtabs) {
  563.             num += tmp = 8 - (num & 7);
  564.             do
  565.             *line++ = ' ';
  566.             while (--tmp);
  567.             break;
  568.         }
  569.         default:
  570.         *line++ = chr;
  571.         num++;
  572.         break;
  573.  
  574.         case '\n':
  575.         *line = '\n';
  576.         num++;
  577.         goto end;
  578.  
  579. #ifdef  FFSPECIAL
  580.         case '\f':
  581.         if (++num == 1)
  582.             *line = '\f';
  583.         else {
  584.             *line = '\n';
  585.             havechar = YES;
  586.             svchar = chr;
  587.         }
  588.         goto end;
  589. #endif/*FFSPECIAL */
  590.         }
  591.     }
  592.  end:
  593.     *++line = '\0';
  594.     return num;
  595. }
  596.  
  597. flushline (keep)
  598. Bool keep;
  599. {
  600.     if ((keep && reject != REJ_YES) ^ complement) {
  601.     register char *line = tline;
  602.     register FILE *out = stdout;
  603.     register char chr;
  604.  
  605.     while (chr = *line++)
  606.         putc (chr, out);
  607.     } else if (lnblank)
  608.     putc ('\n', stdout);
  609.     return;
  610. }
  611.  
  612. prname ()
  613. {
  614.     fprintf (stderr, "%s: ", progname);
  615.     return;
  616. }
  617.  
  618. int
  619. error (err, line, depth)
  620. int err;        /* type of error & index into error string array */
  621. int line;       /* line number */
  622. int depth;      /* how many ifdefs we are inside */
  623. {
  624.     if (err == END_ERR)
  625.     return err;
  626.  
  627.     prname ();
  628.  
  629. #ifndef TESTING
  630.     fprintf (stderr, "Error in %s line %d: %s.\n", filename, line, errs[err]);
  631. #else/* TESTING */
  632.     fprintf (stderr, "Error in %s line %d: %s. ", filename, line, errs[err]);
  633.     fprintf (stderr, "ifdef depth: %d\n", depth);
  634. #endif/*TESTING */
  635.  
  636.     exitstat = 2;
  637.     return depth > 1 ? IEOF_ERR : END_ERR;
  638. }
  639.