2 * Copyright (c) 1985, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
38 static const char copyright[] =
39 "@(#) Copyright (c) 1985, 1993\n\
40 The Regents of the University of California. All rights reserved.\n";
45 static char sccsid[] = "@(#)unifdef.c 8.1 (Berkeley) 6/6/93";
47 static const char rcsid[] =
52 * unifdef - remove ifdef'ed lines
54 * Warning: will not work correctly if input contains null characters.
57 * provide an option which will append the name of the
58 * appropriate symbol after #else's and #endif's
59 * provide an option which will check symbols after
60 * #else's and #endif's to see that they match their
61 * corresponding #ifdef or #ifndef
68 typedef int Reject_level;
79 char text BSS; /* -t option in effect: this is a text file */
80 char lnblank BSS; /* -l option in effect: blank deleted lines */
81 char complement BSS; /* -c option in effect: complement the operation */
84 char *symname[MAXSYMS] BSS; /* symbol name */
85 char true[MAXSYMS] BSS; /* -Dsym */
86 char ignore[MAXSYMS] BSS; /* -iDsym or -iUsym */
87 char insym[MAXSYMS] BSS; /* state: false, inactive, true */
88 #define SYM_INACTIVE 0 /* symbol is currently inactive */
89 #define SYM_FALSE 1 /* symbol is currently false */
90 #define SYM_TRUE 2 /* symbol is currently true */
93 char incomment BSS; /* inside C comment */
96 #define QUOTE_SINGLE 1
97 #define QUOTE_DOUBLE 2
98 char inquote BSS; /* inside single or double quotes */
101 char *skipcomment ();
103 static void usage __P((void));
104 void flushline __P((Bool));
105 int getlin __P((char *, int, FILE *, int));
106 int error __P((int, int, int));
107 void pfile __P((void));
108 int doif __P((int, int, Reject_level, int));
109 int findsym __P((char *));
121 for (curarg = &argv[1]; --argc > 0; curarg++) {
122 if (*(cp1 = cp = *curarg) != '-')
136 if ((symind = findsym (&cp1[1])) < 0) {
137 if (nsyms >= MAXSYMS)
138 errx(2, "too many symbols");
140 symname[symind] = &cp1[1];
141 insym[symind] = SYM_INACTIVE;
143 ignore[symind] = ignorethis;
144 true[symind] = *cp1 == 'D' ? YES : NO;
145 } else if (ignorethis)
147 else if (strcmp (&cp[1], "t") == 0)
149 else if (strcmp (&cp[1], "l") == 0)
151 else if (strcmp (&cp[1], "c") == 0)
155 warnx("unrecognized option: %s", cp);
163 warnx("can only do one file");
164 } else if (argc == 1) {
166 if ((input = fopen (filename, "r")) != NULL) {
168 (void) fclose (input);
170 warn("can't open %s", *curarg);
173 filename = "[stdin]";
178 (void) fflush (stdout);
185 fprintf (stderr, "usage: %s",
186 "unifdef [-l] [-t] [-c] [[-Dsym] [-Usym] [-iDsym] [-iUsym]] ... [file]\n");
190 /* types of input lines: */
191 typedef int Linetype;
192 #define LT_PLAIN 0 /* ordinary line */
193 #define LT_TRUE 1 /* a true #ifdef of a symbol known to us */
194 #define LT_FALSE 2 /* a false #ifdef of a symbol known to us */
195 #define LT_OTHER 3 /* an #ifdef of a symbol not known to us */
196 #define LT_IF 4 /* an #ifdef of a symbol not known to us */
197 #define LT_ELSE 5 /* #else */
198 #define LT_ENDIF 6 /* #endif */
199 #define LT_LEOF 7 /* end of file */
200 extern Linetype checkline ();
202 Reject_level reject BSS; /* 0 or 1: pass thru; 1 or 2: ignore comments */
207 int linenum BSS; /* current line number */
208 int stqcline BSS; /* start of current coment or quote */
215 "Inappropriate else",
217 "Inappropriate endif",
219 "Premature EOF in ifdef",
221 "Premature EOF in comment",
223 "Premature EOF in quoted character",
225 "Premature EOF in quoted string"
228 /* States for inif arg to doif */
237 (void) doif (-1, IN_NONE, reject, 0);
241 doif (thissym, inif, prevreject, depth)
242 register int thissym; /* index of the symbol who was last ifdef'ed */
243 int inif; /* YES or NO we are inside an ifdef */
244 Reject_level prevreject;/* previous value of reject */
245 int depth; /* depth of ifdef's */
247 register Linetype lineval;
248 register Reject_level thisreject;
249 int doret; /* tmp return value of doif */
250 int cursym; /* index of the symbol returned by checkline */
251 int stline; /* line number when called this time */
255 switch (lineval = checkline (&cursym)) {
263 if (lineval == LT_TRUE)
264 insym[cursym] = SYM_TRUE;
266 if (reject != REJ_YES)
267 reject = ignore[cursym] ? REJ_IGNORE : REJ_YES;
268 insym[cursym] = SYM_FALSE;
276 if ((doret = doif (cursym, IN_IF, thisreject, depth + 1)) != NO_ERR)
277 return error (doret, stline, depth);
283 if ((doret = doif (-1, IN_IF, reject, depth + 1)) != NO_ERR)
284 return error (doret, stline, depth);
289 return error (ELSE_ERR, linenum, depth);
292 if (insym[thissym] == SYM_TRUE) {
293 reject = ignore[thissym] ? REJ_IGNORE : REJ_YES;
294 insym[thissym] = SYM_FALSE;
295 } else { /* (insym[thissym] == SYM_FALSE) */
297 insym[thissym] = SYM_TRUE;
299 if (!ignore[thissym]) {
309 return error (ENDIF_ERR, linenum, depth);
311 insym[thissym] = SYM_INACTIVE;
313 if (!ignore[thissym]) {
325 : inquote == QUOTE_SINGLE
327 : inquote == QUOTE_DOUBLE
330 if (inif != IN_NONE) {
332 (void) error (err, stqcline, depth);
333 return error (IEOF_ERR, stline, depth);
334 } else if (err != NO_ERR)
335 return error (err, stqcline, depth);
343 #define endsym(c) (!isalpha (c) && !isdigit (c) && c != '_')
346 char tline[MAXLINE] BSS;
350 int *cursym; /* if LT_TRUE or LT_FALSE returned, set this to sym index */
357 char keyword[KWSIZE];
360 if (getlin (tline, sizeof tline, input, NO) == EOF)
364 if ( *(cp = tline) != '#'
366 || inquote == QUOTE_SINGLE
367 || inquote == QUOTE_DOUBLE
371 cp = skipcomment (++cp);
373 while (!endsym (*cp)) {
375 if (++symp >= &keyword[KWSIZE])
380 if (strcmp (keyword, "ifdef") == 0) {
383 } else if (strcmp (keyword, "ifndef") == 0) {
386 scp = cp = skipcomment (++cp);
394 if ((symind = findsym (scp)) >= 0)
395 retval = (retval ^ true[*cursym = symind])
396 ? LT_FALSE : LT_TRUE;
400 } else if (strcmp (keyword, "if") == 0)
402 else if (strcmp (keyword, "else") == 0)
404 else if (strcmp (keyword, "endif") == 0)
408 if (!text && reject != REJ_IGNORE)
411 cp = skipcomment (cp);
412 else if (inquote == QUOTE_SINGLE)
413 cp = skipquote (cp, QUOTE_SINGLE);
414 else if (inquote == QUOTE_DOUBLE)
415 cp = skipquote (cp, QUOTE_DOUBLE);
416 else if (*cp == '/' && cp[1] == '*')
417 cp = skipcomment (cp);
418 else if (*cp == '\'')
419 cp = skipquote (cp, QUOTE_SINGLE);
421 cp = skipquote (cp, QUOTE_DOUBLE);
429 * Skip over comments and stop at the next charaacter
430 * position that is not whitespace.
439 while (*cp == ' ' || *cp == '\t')
454 for (; *cp != '*'; cp++)
466 * Skip over a quoted string or character and stop at the next charaacter
467 * position that is not whitespace.
476 qchar = type == QUOTE_SINGLE ? '\'' : '"';
491 || (*cp == '\\' && *++cp == '\0')
495 inquote = QUOTE_NONE;
500 * findsym - look for the symbol in the symbol table.
501 * if found, return symbol table index,
513 for (symind = 0; symind < nsyms; ++symind) {
514 if (insym[symind] == SYM_INACTIVE) {
515 for ( symp = symname[symind], cp = str
516 ; *symp && *cp == *symp
521 if (*symp == '\0' && endsym (chr))
529 * getlin - expands tabs if asked for
530 * and (if compiled in) treats form-feed as an end-of-line
533 getlin (line, maxline, inp, expandtabs)
543 static char havechar = NO; /* have leftover char from last time */
544 static char svchar BSS;
555 while (num + 8 < maxline) { /* leave room for tab */
570 num += tmp = 8 - (num & 7);
608 if ((keep && reject != REJ_YES) ^ complement) {
609 register char *line = tline;
610 register FILE *out = stdout;
613 while ((chr = *line++))
620 error (err, line, depth)
621 int err; /* type of error & index into error string array */
622 int line; /* line number */
623 int depth; /* how many ifdefs we are inside */
629 warnx("error in %s line %d: %s", filename, line, errs[err]);
631 warnx("error in %s line %d: %s. ifdef depth: %d",
632 filename, line, errs[err], depth);
636 return depth > 1 ? IEOF_ERR : END_ERR;