~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/unifdef.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /scripts/unifdef.c (Version linux-6.12-rc7) and /scripts/unifdef.c (Version linux-6.9.12)


  1 /*                                                  1 /*
  2  * Copyright (c) 2002 - 2011 Tony Finch <dot@d      2  * Copyright (c) 2002 - 2011 Tony Finch <dot@dotat.at>
  3  *                                                  3  *
  4  * Redistribution and use in source and binary      4  * Redistribution and use in source and binary forms, with or without
  5  * modification, are permitted provided that t      5  * modification, are permitted provided that the following conditions
  6  * are met:                                         6  * are met:
  7  * 1. Redistributions of source code must reta      7  * 1. Redistributions of source code must retain the above copyright
  8  *    notice, this list of conditions and the       8  *    notice, this list of conditions and the following disclaimer.
  9  * 2. Redistributions in binary form must repr      9  * 2. Redistributions in binary form must reproduce the above copyright
 10  *    notice, this list of conditions and the      10  *    notice, this list of conditions and the following disclaimer in the
 11  *    documentation and/or other materials pro     11  *    documentation and/or other materials provided with the distribution.
 12  *                                                 12  *
 13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND     13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDIN     14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND F     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTH     16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECI     17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PRO     18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS;     19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILI     20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR     21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF AD     22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 23  * SUCH DAMAGE.                                    23  * SUCH DAMAGE.
 24  */                                                24  */
 25                                                    25 
 26 /*                                                 26 /*
 27  * unifdef - remove ifdef'ed lines                 27  * unifdef - remove ifdef'ed lines
 28  *                                                 28  *
 29  * This code was derived from software contrib     29  * This code was derived from software contributed to Berkeley by Dave Yost.
 30  * It was rewritten to support ANSI C by Tony      30  * It was rewritten to support ANSI C by Tony Finch. The original version
 31  * of unifdef carried the 4-clause BSD copyrig     31  * of unifdef carried the 4-clause BSD copyright licence. None of its code
 32  * remains in this version (though some of the     32  * remains in this version (though some of the names remain) so it now
 33  * carries a more liberal licence.                 33  * carries a more liberal licence.
 34  *                                                 34  *
 35  *  Wishlist:                                      35  *  Wishlist:
 36  *      provide an option which will append th     36  *      provide an option which will append the name of the
 37  *        appropriate symbol after #else's and     37  *        appropriate symbol after #else's and #endif's
 38  *      provide an option which will check sym     38  *      provide an option which will check symbols after
 39  *        #else's and #endif's to see that the     39  *        #else's and #endif's to see that they match their
 40  *        corresponding #ifdef or #ifndef          40  *        corresponding #ifdef or #ifndef
 41  *                                                 41  *
 42  *   These require better buffer handling, whi     42  *   These require better buffer handling, which would also make
 43  *   it possible to handle all "dodgy" directi     43  *   it possible to handle all "dodgy" directives correctly.
 44  */                                                44  */
 45                                                    45 
 46 #include <sys/types.h>                             46 #include <sys/types.h>
 47 #include <sys/stat.h>                              47 #include <sys/stat.h>
 48                                                    48 
 49 #include <ctype.h>                                 49 #include <ctype.h>
 50 #include <err.h>                                   50 #include <err.h>
 51 #include <errno.h>                                 51 #include <errno.h>
 52 #include <stdarg.h>                                52 #include <stdarg.h>
 53 #include <stdbool.h>                               53 #include <stdbool.h>
 54 #include <stdio.h>                                 54 #include <stdio.h>
 55 #include <stdlib.h>                                55 #include <stdlib.h>
 56 #include <string.h>                                56 #include <string.h>
 57 #include <unistd.h>                                57 #include <unistd.h>
 58                                                    58 
 59 const char copyright[] =                           59 const char copyright[] =
 60     "@(#) $Version: unifdef-2.5 $\n"               60     "@(#) $Version: unifdef-2.5 $\n"
 61     "@(#) $Author: Tony Finch (dot@dotat.at) $     61     "@(#) $Author: Tony Finch (dot@dotat.at) $\n"
 62     "@(#) $URL: http://dotat.at/prog/unifdef $     62     "@(#) $URL: http://dotat.at/prog/unifdef $\n"
 63 ;                                                  63 ;
 64                                                    64 
 65 /* types of input lines: */                        65 /* types of input lines: */
 66 typedef enum {                                     66 typedef enum {
 67         LT_TRUEI,               /* a true #if      67         LT_TRUEI,               /* a true #if with ignore flag */
 68         LT_FALSEI,              /* a false #if     68         LT_FALSEI,              /* a false #if with ignore flag */
 69         LT_IF,                  /* an unknown      69         LT_IF,                  /* an unknown #if */
 70         LT_TRUE,                /* a true #if      70         LT_TRUE,                /* a true #if */
 71         LT_FALSE,               /* a false #if     71         LT_FALSE,               /* a false #if */
 72         LT_ELIF,                /* an unknown      72         LT_ELIF,                /* an unknown #elif */
 73         LT_ELTRUE,              /* a true #eli     73         LT_ELTRUE,              /* a true #elif */
 74         LT_ELFALSE,             /* a false #el     74         LT_ELFALSE,             /* a false #elif */
 75         LT_ELSE,                /* #else */        75         LT_ELSE,                /* #else */
 76         LT_ENDIF,               /* #endif */       76         LT_ENDIF,               /* #endif */
 77         LT_DODGY,               /* flag: direc     77         LT_DODGY,               /* flag: directive is not on one line */
 78         LT_DODGY_LAST = LT_DODGY + LT_ENDIF,       78         LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
 79         LT_PLAIN,               /* ordinary li     79         LT_PLAIN,               /* ordinary line */
 80         LT_EOF,                 /* end of file     80         LT_EOF,                 /* end of file */
 81         LT_ERROR,               /* unevaluable     81         LT_ERROR,               /* unevaluable #if */
 82         LT_COUNT                                   82         LT_COUNT
 83 } Linetype;                                        83 } Linetype;
 84                                                    84 
 85 static char const * const linetype_name[] = {      85 static char const * const linetype_name[] = {
 86         "TRUEI", "FALSEI", "IF", "TRUE", "FALS     86         "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
 87         "ELIF", "ELTRUE", "ELFALSE", "ELSE", "     87         "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF",
 88         "DODGY TRUEI", "DODGY FALSEI",             88         "DODGY TRUEI", "DODGY FALSEI",
 89         "DODGY IF", "DODGY TRUE", "DODGY FALSE     89         "DODGY IF", "DODGY TRUE", "DODGY FALSE",
 90         "DODGY ELIF", "DODGY ELTRUE", "DODGY E     90         "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
 91         "DODGY ELSE", "DODGY ENDIF",               91         "DODGY ELSE", "DODGY ENDIF",
 92         "PLAIN", "EOF", "ERROR"                    92         "PLAIN", "EOF", "ERROR"
 93 };                                                 93 };
 94                                                    94 
 95 /* state of #if processing */                      95 /* state of #if processing */
 96 typedef enum {                                     96 typedef enum {
 97         IS_OUTSIDE,                                97         IS_OUTSIDE,
 98         IS_FALSE_PREFIX,        /* false #if f     98         IS_FALSE_PREFIX,        /* false #if followed by false #elifs */
 99         IS_TRUE_PREFIX,         /* first non-f     99         IS_TRUE_PREFIX,         /* first non-false #(el)if is true */
100         IS_PASS_MIDDLE,         /* first non-f    100         IS_PASS_MIDDLE,         /* first non-false #(el)if is unknown */
101         IS_FALSE_MIDDLE,        /* a false #el    101         IS_FALSE_MIDDLE,        /* a false #elif after a pass state */
102         IS_TRUE_MIDDLE,         /* a true #eli    102         IS_TRUE_MIDDLE,         /* a true #elif after a pass state */
103         IS_PASS_ELSE,           /* an else aft    103         IS_PASS_ELSE,           /* an else after a pass state */
104         IS_FALSE_ELSE,          /* an else aft    104         IS_FALSE_ELSE,          /* an else after a true state */
105         IS_TRUE_ELSE,           /* an else aft    105         IS_TRUE_ELSE,           /* an else after only false states */
106         IS_FALSE_TRAILER,       /* #elifs afte    106         IS_FALSE_TRAILER,       /* #elifs after a true are false */
107         IS_COUNT                                  107         IS_COUNT
108 } Ifstate;                                        108 } Ifstate;
109                                                   109 
110 static char const * const ifstate_name[] = {      110 static char const * const ifstate_name[] = {
111         "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFI    111         "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX",
112         "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_M    112         "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
113         "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE"    113         "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
114         "FALSE_TRAILER"                           114         "FALSE_TRAILER"
115 };                                                115 };
116                                                   116 
117 /* state of comment parser */                     117 /* state of comment parser */
118 typedef enum {                                    118 typedef enum {
119         NO_COMMENT = false,     /* outside a c    119         NO_COMMENT = false,     /* outside a comment */
120         C_COMMENT,              /* in a commen    120         C_COMMENT,              /* in a comment like this one */
121         CXX_COMMENT,            /* between //     121         CXX_COMMENT,            /* between // and end of line */
122         STARTING_COMMENT,       /* just after     122         STARTING_COMMENT,       /* just after slash-backslash-newline */
123         FINISHING_COMMENT,      /* star-backsl    123         FINISHING_COMMENT,      /* star-backslash-newline in a C comment */
124         CHAR_LITERAL,           /* inside '' *    124         CHAR_LITERAL,           /* inside '' */
125         STRING_LITERAL          /* inside "" *    125         STRING_LITERAL          /* inside "" */
126 } Comment_state;                                  126 } Comment_state;
127                                                   127 
128 static char const * const comment_name[] = {      128 static char const * const comment_name[] = {
129         "NO", "C", "CXX", "STARTING", "FINISHI    129         "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING"
130 };                                                130 };
131                                                   131 
132 /* state of preprocessor line parser */           132 /* state of preprocessor line parser */
133 typedef enum {                                    133 typedef enum {
134         LS_START,               /* only space     134         LS_START,               /* only space and comments on this line */
135         LS_HASH,                /* only space,    135         LS_HASH,                /* only space, comments, and a hash */
136         LS_DIRTY                /* this line c    136         LS_DIRTY                /* this line can't be a preprocessor line */
137 } Line_state;                                     137 } Line_state;
138                                                   138 
139 static char const * const linestate_name[] = {    139 static char const * const linestate_name[] = {
140         "START", "HASH", "DIRTY"                  140         "START", "HASH", "DIRTY"
141 };                                                141 };
142                                                   142 
143 /*                                                143 /*
144  * Minimum translation limits from ISO/IEC 989    144  * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1
145  */                                               145  */
146 #define MAXDEPTH        64                        146 #define MAXDEPTH        64                      /* maximum #if nesting */
147 #define MAXLINE         4096                      147 #define MAXLINE         4096                    /* maximum length of line */
148 #define MAXSYMS         4096                      148 #define MAXSYMS         4096                    /* maximum number of symbols */
149                                                   149 
150 /*                                                150 /*
151  * Sometimes when editing a keyword the replac    151  * Sometimes when editing a keyword the replacement text is longer, so
152  * we leave some space at the end of the tline    152  * we leave some space at the end of the tline buffer to accommodate this.
153  */                                               153  */
154 #define EDITSLOP        10                        154 #define EDITSLOP        10
155                                                   155 
156 /*                                                156 /*
157  * For temporary filenames                        157  * For temporary filenames
158  */                                               158  */
159 #define TEMPLATE        "unifdef.XXXXXX"          159 #define TEMPLATE        "unifdef.XXXXXX"
160                                                   160 
161 /*                                                161 /*
162  * Globals.                                       162  * Globals.
163  */                                               163  */
164                                                   164 
165 static bool             compblank;                165 static bool             compblank;              /* -B: compress blank lines */
166 static bool             lnblank;                  166 static bool             lnblank;                /* -b: blank deleted lines */
167 static bool             complement;               167 static bool             complement;             /* -c: do the complement */
168 static bool             debugging;                168 static bool             debugging;              /* -d: debugging reports */
169 static bool             iocccok;                  169 static bool             iocccok;                /* -e: fewer IOCCC errors */
170 static bool             strictlogic;              170 static bool             strictlogic;            /* -K: keep ambiguous #ifs */
171 static bool             killconsts;               171 static bool             killconsts;             /* -k: eval constant #ifs */
172 static bool             lnnum;                    172 static bool             lnnum;                  /* -n: add #line directives */
173 static bool             symlist;                  173 static bool             symlist;                /* -s: output symbol list */
174 static bool             symdepth;                 174 static bool             symdepth;               /* -S: output symbol depth */
175 static bool             text;                     175 static bool             text;                   /* -t: this is a text file */
176                                                   176 
177 static const char      *symname[MAXSYMS];         177 static const char      *symname[MAXSYMS];       /* symbol name */
178 static const char      *value[MAXSYMS];           178 static const char      *value[MAXSYMS];         /* -Dsym=value */
179 static bool             ignore[MAXSYMS];          179 static bool             ignore[MAXSYMS];        /* -iDsym or -iUsym */
180 static int              nsyms;                    180 static int              nsyms;                  /* number of symbols */
181                                                   181 
182 static FILE            *input;                    182 static FILE            *input;                  /* input file pointer */
183 static const char      *filename;                 183 static const char      *filename;               /* input file name */
184 static int              linenum;                  184 static int              linenum;                /* current line number */
185 static FILE            *output;                   185 static FILE            *output;                 /* output file pointer */
186 static const char      *ofilename;                186 static const char      *ofilename;              /* output file name */
187 static bool             overwriting;              187 static bool             overwriting;            /* output overwrites input */
188 static char             tempname[FILENAME_MAX]    188 static char             tempname[FILENAME_MAX]; /* used when overwriting */
189                                                   189 
190 static char             tline[MAXLINE+EDITSLOP    190 static char             tline[MAXLINE+EDITSLOP];/* input buffer plus space */
191 static char            *keyword;                  191 static char            *keyword;                /* used for editing #elif's */
192                                                   192 
193 static const char      *newline;                  193 static const char      *newline;                /* input file format */
194 static const char       newline_unix[] = "\n";    194 static const char       newline_unix[] = "\n";
195 static const char       newline_crlf[] = "\r\n    195 static const char       newline_crlf[] = "\r\n";
196                                                   196 
197 static Comment_state    incomment;                197 static Comment_state    incomment;              /* comment parser state */
198 static Line_state       linestate;                198 static Line_state       linestate;              /* #if line parser state */
199 static Ifstate          ifstate[MAXDEPTH];        199 static Ifstate          ifstate[MAXDEPTH];      /* #if processor state */
200 static bool             ignoring[MAXDEPTH];       200 static bool             ignoring[MAXDEPTH];     /* ignore comments state */
201 static int              stifline[MAXDEPTH];       201 static int              stifline[MAXDEPTH];     /* start of current #if */
202 static int              depth;                    202 static int              depth;                  /* current #if nesting */
203 static int              delcount;                 203 static int              delcount;               /* count of deleted lines */
204 static unsigned         blankcount;               204 static unsigned         blankcount;             /* count of blank lines */
205 static unsigned         blankmax;                 205 static unsigned         blankmax;               /* maximum recent blankcount */
206 static bool             constexpression;       !! 206 static bool             constexpr;              /* constant #if expression */
207 static bool             zerosyms = true;          207 static bool             zerosyms = true;        /* to format symdepth output */
208 static bool             firstsym;                 208 static bool             firstsym;               /* ditto */
209                                                   209 
210 static int              exitstat;                 210 static int              exitstat;               /* program exit status */
211                                                   211 
212 static void             addsym(bool, bool, cha    212 static void             addsym(bool, bool, char *);
213 static void             closeout(void);           213 static void             closeout(void);
214 static void             debug(const char *, ..    214 static void             debug(const char *, ...);
215 static void             done(void);               215 static void             done(void);
216 static void             error(const char *);      216 static void             error(const char *);
217 static int              findsym(const char *);    217 static int              findsym(const char *);
218 static void             flushline(bool);          218 static void             flushline(bool);
219 static Linetype         parseline(void);          219 static Linetype         parseline(void);
220 static Linetype         ifeval(const char **);    220 static Linetype         ifeval(const char **);
221 static void             ignoreoff(void);          221 static void             ignoreoff(void);
222 static void             ignoreon(void);           222 static void             ignoreon(void);
223 static void             keywordedit(const char    223 static void             keywordedit(const char *);
224 static void             nest(void);               224 static void             nest(void);
225 static void             process(void);            225 static void             process(void);
226 static const char      *skipargs(const char *)    226 static const char      *skipargs(const char *);
227 static const char      *skipcomment(const char    227 static const char      *skipcomment(const char *);
228 static const char      *skipsym(const char *);    228 static const char      *skipsym(const char *);
229 static void             state(Ifstate);           229 static void             state(Ifstate);
230 static int              strlcmp(const char *,     230 static int              strlcmp(const char *, const char *, size_t);
231 static void             unnest(void);             231 static void             unnest(void);
232 static void             usage(void);              232 static void             usage(void);
233 static void             version(void);            233 static void             version(void);
234                                                   234 
235 #define endsym(c) (!isalnum((unsigned char)c)     235 #define endsym(c) (!isalnum((unsigned char)c) && c != '_')
236                                                   236 
237 /*                                                237 /*
238  * The main program.                              238  * The main program.
239  */                                               239  */
240 int                                               240 int
241 main(int argc, char *argv[])                      241 main(int argc, char *argv[])
242 {                                                 242 {
243         int opt;                                  243         int opt;
244                                                   244 
245         while ((opt = getopt(argc, argv, "i:D:    245         while ((opt = getopt(argc, argv, "i:D:U:I:o:bBcdeKklnsStV")) != -1)
246                 switch (opt) {                    246                 switch (opt) {
247                 case 'i': /* treat stuff contr    247                 case 'i': /* treat stuff controlled by these symbols as text */
248                         /*                        248                         /*
249                          * For strict backward    249                          * For strict backwards-compatibility the U or D
250                          * should be immediate    250                          * should be immediately after the -i but it doesn't
251                          * matter much if we r    251                          * matter much if we relax that requirement.
252                          */                       252                          */
253                         opt = *optarg++;          253                         opt = *optarg++;
254                         if (opt == 'D')           254                         if (opt == 'D')
255                                 addsym(true, t    255                                 addsym(true, true, optarg);
256                         else if (opt == 'U')      256                         else if (opt == 'U')
257                                 addsym(true, f    257                                 addsym(true, false, optarg);
258                         else                      258                         else
259                                 usage();          259                                 usage();
260                         break;                    260                         break;
261                 case 'D': /* define a symbol *    261                 case 'D': /* define a symbol */
262                         addsym(false, true, op    262                         addsym(false, true, optarg);
263                         break;                    263                         break;
264                 case 'U': /* undef a symbol */    264                 case 'U': /* undef a symbol */
265                         addsym(false, false, o    265                         addsym(false, false, optarg);
266                         break;                    266                         break;
267                 case 'I': /* no-op for compati    267                 case 'I': /* no-op for compatibility with cpp */
268                         break;                    268                         break;
269                 case 'b': /* blank deleted lin    269                 case 'b': /* blank deleted lines instead of omitting them */
270                 case 'l': /* backwards compati    270                 case 'l': /* backwards compatibility */
271                         lnblank = true;           271                         lnblank = true;
272                         break;                    272                         break;
273                 case 'B': /* compress blank li    273                 case 'B': /* compress blank lines around removed section */
274                         compblank = true;         274                         compblank = true;
275                         break;                    275                         break;
276                 case 'c': /* treat -D as -U an    276                 case 'c': /* treat -D as -U and vice versa */
277                         complement = true;        277                         complement = true;
278                         break;                    278                         break;
279                 case 'd':                         279                 case 'd':
280                         debugging = true;         280                         debugging = true;
281                         break;                    281                         break;
282                 case 'e': /* fewer errors from    282                 case 'e': /* fewer errors from dodgy lines */
283                         iocccok = true;           283                         iocccok = true;
284                         break;                    284                         break;
285                 case 'K': /* keep ambiguous #i    285                 case 'K': /* keep ambiguous #ifs */
286                         strictlogic = true;       286                         strictlogic = true;
287                         break;                    287                         break;
288                 case 'k': /* process constant     288                 case 'k': /* process constant #ifs */
289                         killconsts = true;        289                         killconsts = true;
290                         break;                    290                         break;
291                 case 'n': /* add #line directi    291                 case 'n': /* add #line directive after deleted lines */
292                         lnnum = true;             292                         lnnum = true;
293                         break;                    293                         break;
294                 case 'o': /* output to a file     294                 case 'o': /* output to a file */
295                         ofilename = optarg;       295                         ofilename = optarg;
296                         break;                    296                         break;
297                 case 's': /* only output list     297                 case 's': /* only output list of symbols that control #ifs */
298                         symlist = true;           298                         symlist = true;
299                         break;                    299                         break;
300                 case 'S': /* list symbols with    300                 case 'S': /* list symbols with their nesting depth */
301                         symlist = symdepth = t    301                         symlist = symdepth = true;
302                         break;                    302                         break;
303                 case 't': /* don't parse C com    303                 case 't': /* don't parse C comments */
304                         text = true;              304                         text = true;
305                         break;                    305                         break;
306                 case 'V': /* print version */     306                 case 'V': /* print version */
307                         version();                307                         version();
308                 default:                          308                 default:
309                         usage();                  309                         usage();
310                 }                                 310                 }
311         argc -= optind;                           311         argc -= optind;
312         argv += optind;                           312         argv += optind;
313         if (compblank && lnblank)                 313         if (compblank && lnblank)
314                 errx(2, "-B and -b are mutuall    314                 errx(2, "-B and -b are mutually exclusive");
315         if (argc > 1) {                           315         if (argc > 1) {
316                 errx(2, "can only do one file"    316                 errx(2, "can only do one file");
317         } else if (argc == 1 && strcmp(*argv,     317         } else if (argc == 1 && strcmp(*argv, "-") != 0) {
318                 filename = *argv;                 318                 filename = *argv;
319                 input = fopen(filename, "rb");    319                 input = fopen(filename, "rb");
320                 if (input == NULL)                320                 if (input == NULL)
321                         err(2, "can't open %s"    321                         err(2, "can't open %s", filename);
322         } else {                                  322         } else {
323                 filename = "[stdin]";             323                 filename = "[stdin]";
324                 input = stdin;                    324                 input = stdin;
325         }                                         325         }
326         if (ofilename == NULL) {                  326         if (ofilename == NULL) {
327                 ofilename = "[stdout]";           327                 ofilename = "[stdout]";
328                 output = stdout;                  328                 output = stdout;
329         } else {                                  329         } else {
330                 struct stat ist, ost;             330                 struct stat ist, ost;
331                 if (stat(ofilename, &ost) == 0    331                 if (stat(ofilename, &ost) == 0 &&
332                     fstat(fileno(input), &ist)    332                     fstat(fileno(input), &ist) == 0)
333                         overwriting = (ist.st_    333                         overwriting = (ist.st_dev == ost.st_dev
334                                     && ist.st_    334                                     && ist.st_ino == ost.st_ino);
335                 if (overwriting) {                335                 if (overwriting) {
336                         const char *dirsep;       336                         const char *dirsep;
337                         int ofd;                  337                         int ofd;
338                                                   338 
339                         dirsep = strrchr(ofile    339                         dirsep = strrchr(ofilename, '/');
340                         if (dirsep != NULL)       340                         if (dirsep != NULL)
341                                 snprintf(tempn    341                                 snprintf(tempname, sizeof(tempname),
342                                     "%.*s/" TE    342                                     "%.*s/" TEMPLATE,
343                                     (int)(dirs    343                                     (int)(dirsep - ofilename), ofilename);
344                         else                      344                         else
345                                 snprintf(tempn    345                                 snprintf(tempname, sizeof(tempname),
346                                     TEMPLATE);    346                                     TEMPLATE);
347                         ofd = mkstemp(tempname    347                         ofd = mkstemp(tempname);
348                         if (ofd != -1)            348                         if (ofd != -1)
349                                 output = fdope    349                                 output = fdopen(ofd, "wb+");
350                         if (output == NULL)       350                         if (output == NULL)
351                                 err(2, "can't     351                                 err(2, "can't create temporary file");
352                         fchmod(ofd, ist.st_mod    352                         fchmod(ofd, ist.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
353                 } else {                          353                 } else {
354                         output = fopen(ofilena    354                         output = fopen(ofilename, "wb");
355                         if (output == NULL)       355                         if (output == NULL)
356                                 err(2, "can't     356                                 err(2, "can't open %s", ofilename);
357                 }                                 357                 }
358         }                                         358         }
359         process();                                359         process();
360         abort(); /* bug */                        360         abort(); /* bug */
361 }                                                 361 }
362                                                   362 
363 static void                                       363 static void
364 version(void)                                     364 version(void)
365 {                                                 365 {
366         const char *c = copyright;                366         const char *c = copyright;
367         for (;;) {                                367         for (;;) {
368                 while (*++c != '$')               368                 while (*++c != '$')
369                         if (*c == '\0')           369                         if (*c == '\0')
370                                 exit(0);          370                                 exit(0);
371                 while (*++c != '$')               371                 while (*++c != '$')
372                         putc(*c, stderr);         372                         putc(*c, stderr);
373                 putc('\n', stderr);               373                 putc('\n', stderr);
374         }                                         374         }
375 }                                                 375 }
376                                                   376 
377 static void                                       377 static void
378 usage(void)                                       378 usage(void)
379 {                                                 379 {
380         fprintf(stderr, "usage: unifdef [-bBcd    380         fprintf(stderr, "usage: unifdef [-bBcdeKknsStV] [-Ipath]"
381             " [-Dsym[=val]] [-Usym] [-iDsym[=v    381             " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
382         exit(2);                                  382         exit(2);
383 }                                                 383 }
384                                                   384 
385 /*                                                385 /*
386  * A state transition function alters the glob    386  * A state transition function alters the global #if processing state
387  * in a particular way. The table below is ind    387  * in a particular way. The table below is indexed by the current
388  * processing state and the type of the curren    388  * processing state and the type of the current line.
389  *                                                389  *
390  * Nesting is handled by keeping a stack of st    390  * Nesting is handled by keeping a stack of states; some transition
391  * functions increase or decrease the depth. T    391  * functions increase or decrease the depth. They also maintain the
392  * ignore state on a stack. In some complicate    392  * ignore state on a stack. In some complicated cases they have to
393  * alter the preprocessor directive, as follow    393  * alter the preprocessor directive, as follows.
394  *                                                394  *
395  * When we have processed a group that starts     395  * When we have processed a group that starts off with a known-false
396  * #if/#elif sequence (which has therefore bee    396  * #if/#elif sequence (which has therefore been deleted) followed by a
397  * #elif that we don't understand and therefor    397  * #elif that we don't understand and therefore must keep, we edit the
398  * latter into a #if to keep the nesting corre    398  * latter into a #if to keep the nesting correct. We use memcpy() to
399  * overwrite the 4 byte token "elif" with "if     399  * overwrite the 4 byte token "elif" with "if  " without a '\0' byte.
400  *                                                400  *
401  * When we find a true #elif in a group, the f    401  * When we find a true #elif in a group, the following block will
402  * always be kept and the rest of the sequence    402  * always be kept and the rest of the sequence after the next #elif or
403  * #else will be discarded. We edit the #elif     403  * #else will be discarded. We edit the #elif into a #else and the
404  * following directive to #endif since this ha    404  * following directive to #endif since this has the desired behaviour.
405  *                                                405  *
406  * "Dodgy" directives are split across multipl    406  * "Dodgy" directives are split across multiple lines, the most common
407  * example being a multi-line comment hanging     407  * example being a multi-line comment hanging off the right of the
408  * directive. We can handle them correctly onl    408  * directive. We can handle them correctly only if there is no change
409  * from printing to dropping (or vice versa) c    409  * from printing to dropping (or vice versa) caused by that directive.
410  * If the directive is the first of a group we    410  * If the directive is the first of a group we have a choice between
411  * failing with an error, or passing it throug    411  * failing with an error, or passing it through unchanged instead of
412  * evaluating it. The latter is not the defaul    412  * evaluating it. The latter is not the default to avoid questions from
413  * users about unifdef unexpectedly leaving be    413  * users about unifdef unexpectedly leaving behind preprocessor directives.
414  */                                               414  */
415 typedef void state_fn(void);                      415 typedef void state_fn(void);
416                                                   416 
417 /* report an error */                             417 /* report an error */
418 static void Eelif (void) { error("Inappropriat    418 static void Eelif (void) { error("Inappropriate #elif"); }
419 static void Eelse (void) { error("Inappropriat    419 static void Eelse (void) { error("Inappropriate #else"); }
420 static void Eendif(void) { error("Inappropriat    420 static void Eendif(void) { error("Inappropriate #endif"); }
421 static void Eeof  (void) { error("Premature EO    421 static void Eeof  (void) { error("Premature EOF"); }
422 static void Eioccc(void) { error("Obfuscated p    422 static void Eioccc(void) { error("Obfuscated preprocessor control line"); }
423 /* plain line handling */                         423 /* plain line handling */
424 static void print (void) { flushline(true); }     424 static void print (void) { flushline(true); }
425 static void drop  (void) { flushline(false); }    425 static void drop  (void) { flushline(false); }
426 /* output lacks group's start line */             426 /* output lacks group's start line */
427 static void Strue (void) { drop();  ignoreoff(    427 static void Strue (void) { drop();  ignoreoff(); state(IS_TRUE_PREFIX); }
428 static void Sfalse(void) { drop();  ignoreoff(    428 static void Sfalse(void) { drop();  ignoreoff(); state(IS_FALSE_PREFIX); }
429 static void Selse (void) { drop();                429 static void Selse (void) { drop();               state(IS_TRUE_ELSE); }
430 /* print/pass this block */                       430 /* print/pass this block */
431 static void Pelif (void) { print(); ignoreoff(    431 static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); }
432 static void Pelse (void) { print();               432 static void Pelse (void) { print();              state(IS_PASS_ELSE); }
433 static void Pendif(void) { print(); unnest();     433 static void Pendif(void) { print(); unnest(); }
434 /* discard this block */                          434 /* discard this block */
435 static void Dfalse(void) { drop();  ignoreoff(    435 static void Dfalse(void) { drop();  ignoreoff(); state(IS_FALSE_TRAILER); }
436 static void Delif (void) { drop();  ignoreoff(    436 static void Delif (void) { drop();  ignoreoff(); state(IS_FALSE_MIDDLE); }
437 static void Delse (void) { drop();                437 static void Delse (void) { drop();               state(IS_FALSE_ELSE); }
438 static void Dendif(void) { drop();  unnest();     438 static void Dendif(void) { drop();  unnest(); }
439 /* first line of group */                         439 /* first line of group */
440 static void Fdrop (void) { nest();  Dfalse();     440 static void Fdrop (void) { nest();  Dfalse(); }
441 static void Fpass (void) { nest();  Pelif(); }    441 static void Fpass (void) { nest();  Pelif(); }
442 static void Ftrue (void) { nest();  Strue(); }    442 static void Ftrue (void) { nest();  Strue(); }
443 static void Ffalse(void) { nest();  Sfalse();     443 static void Ffalse(void) { nest();  Sfalse(); }
444 /* variable pedantry for obfuscated lines */      444 /* variable pedantry for obfuscated lines */
445 static void Oiffy (void) { if (!iocccok) Eiocc    445 static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); }
446 static void Oif   (void) { if (!iocccok) Eiocc    446 static void Oif   (void) { if (!iocccok) Eioccc(); Fpass(); }
447 static void Oelif (void) { if (!iocccok) Eiocc    447 static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
448 /* ignore comments in this block */               448 /* ignore comments in this block */
449 static void Idrop (void) { Fdrop();  ignoreon(    449 static void Idrop (void) { Fdrop();  ignoreon(); }
450 static void Itrue (void) { Ftrue();  ignoreon(    450 static void Itrue (void) { Ftrue();  ignoreon(); }
451 static void Ifalse(void) { Ffalse(); ignoreon(    451 static void Ifalse(void) { Ffalse(); ignoreon(); }
452 /* modify this line */                            452 /* modify this line */
453 static void Mpass (void) { memcpy(keyword, "if    453 static void Mpass (void) { memcpy(keyword, "if  ", 4); Pelif(); }
454 static void Mtrue (void) { keywordedit("else")    454 static void Mtrue (void) { keywordedit("else");  state(IS_TRUE_MIDDLE); }
455 static void Melif (void) { keywordedit("endif"    455 static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); }
456 static void Melse (void) { keywordedit("endif"    456 static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); }
457                                                   457 
458 static state_fn * const trans_table[IS_COUNT][    458 static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
459 /* IS_OUTSIDE */                                  459 /* IS_OUTSIDE */
460 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Ee    460 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
461   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Ee    461   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Eelif, Eelif, Eelse, Eendif,
462   print, done,  abort },                          462   print, done,  abort },
463 /* IS_FALSE_PREFIX */                             463 /* IS_FALSE_PREFIX */
464 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, St    464 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
465   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Ei    465   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
466   drop,  Eeof,  abort },                          466   drop,  Eeof,  abort },
467 /* IS_TRUE_PREFIX */                              467 /* IS_TRUE_PREFIX */
468 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Df    468 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
469   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eioccc,Ei    469   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
470   print, Eeof,  abort },                          470   print, Eeof,  abort },
471 /* IS_PASS_MIDDLE */                              471 /* IS_PASS_MIDDLE */
472 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mt    472 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
473   Oiffy, Oiffy, Fpass, Oif,   Oif,   Pelif, Oe    473   Oiffy, Oiffy, Fpass, Oif,   Oif,   Pelif, Oelif, Oelif, Pelse, Pendif,
474   print, Eeof,  abort },                          474   print, Eeof,  abort },
475 /* IS_FALSE_MIDDLE */                             475 /* IS_FALSE_MIDDLE */
476 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mt    476 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
477   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Ei    477   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
478   drop,  Eeof,  abort },                          478   drop,  Eeof,  abort },
479 /* IS_TRUE_MIDDLE */                              479 /* IS_TRUE_MIDDLE */
480 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Me    480 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
481   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eioccc,Ei    481   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
482   print, Eeof,  abort },                          482   print, Eeof,  abort },
483 /* IS_PASS_ELSE */                                483 /* IS_PASS_ELSE */
484 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Ee    484 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
485   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Ee    485   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Eelif, Eelif, Eelse, Pendif,
486   print, Eeof,  abort },                          486   print, Eeof,  abort },
487 /* IS_FALSE_ELSE */                               487 /* IS_FALSE_ELSE */
488 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Ee    488 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
489   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Ee    489   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
490   drop,  Eeof,  abort },                          490   drop,  Eeof,  abort },
491 /* IS_TRUE_ELSE */                                491 /* IS_TRUE_ELSE */
492 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Ee    492 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
493   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Ee    493   Oiffy, Oiffy, Fpass, Oif,   Oif,   Eelif, Eelif, Eelif, Eelse, Eioccc,
494   print, Eeof,  abort },                          494   print, Eeof,  abort },
495 /* IS_FALSE_TRAILER */                            495 /* IS_FALSE_TRAILER */
496 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Df    496 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
497   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Df    497   Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
498   drop,  Eeof,  abort }                           498   drop,  Eeof,  abort }
499 /*TRUEI  FALSEI IF     TRUE   FALSE  ELIF   EL    499 /*TRUEI  FALSEI IF     TRUE   FALSE  ELIF   ELTRUE ELFALSE ELSE  ENDIF
500   TRUEI  FALSEI IF     TRUE   FALSE  ELIF   EL    500   TRUEI  FALSEI IF     TRUE   FALSE  ELIF   ELTRUE ELFALSE ELSE  ENDIF (DODGY)
501   PLAIN  EOF    ERROR */                          501   PLAIN  EOF    ERROR */
502 };                                                502 };
503                                                   503 
504 /*                                                504 /*
505  * State machine utility functions                505  * State machine utility functions
506  */                                               506  */
507 static void                                       507 static void
508 ignoreoff(void)                                   508 ignoreoff(void)
509 {                                                 509 {
510         if (depth == 0)                           510         if (depth == 0)
511                 abort(); /* bug */                511                 abort(); /* bug */
512         ignoring[depth] = ignoring[depth-1];      512         ignoring[depth] = ignoring[depth-1];
513 }                                                 513 }
514 static void                                       514 static void
515 ignoreon(void)                                    515 ignoreon(void)
516 {                                                 516 {
517         ignoring[depth] = true;                   517         ignoring[depth] = true;
518 }                                                 518 }
519 static void                                       519 static void
520 keywordedit(const char *replacement)              520 keywordedit(const char *replacement)
521 {                                                 521 {
522         snprintf(keyword, tline + sizeof(tline    522         snprintf(keyword, tline + sizeof(tline) - keyword,
523             "%s%s", replacement, newline);        523             "%s%s", replacement, newline);
524         print();                                  524         print();
525 }                                                 525 }
526 static void                                       526 static void
527 nest(void)                                        527 nest(void)
528 {                                                 528 {
529         if (depth > MAXDEPTH-1)                   529         if (depth > MAXDEPTH-1)
530                 abort(); /* bug */                530                 abort(); /* bug */
531         if (depth == MAXDEPTH-1)                  531         if (depth == MAXDEPTH-1)
532                 error("Too many levels of nest    532                 error("Too many levels of nesting");
533         depth += 1;                               533         depth += 1;
534         stifline[depth] = linenum;                534         stifline[depth] = linenum;
535 }                                                 535 }
536 static void                                       536 static void
537 unnest(void)                                      537 unnest(void)
538 {                                                 538 {
539         if (depth == 0)                           539         if (depth == 0)
540                 abort(); /* bug */                540                 abort(); /* bug */
541         depth -= 1;                               541         depth -= 1;
542 }                                                 542 }
543 static void                                       543 static void
544 state(Ifstate is)                                 544 state(Ifstate is)
545 {                                                 545 {
546         ifstate[depth] = is;                      546         ifstate[depth] = is;
547 }                                                 547 }
548                                                   548 
549 /*                                                549 /*
550  * Write a line to the output or not, accordin    550  * Write a line to the output or not, according to command line options.
551  */                                               551  */
552 static void                                       552 static void
553 flushline(bool keep)                              553 flushline(bool keep)
554 {                                                 554 {
555         if (symlist)                              555         if (symlist)
556                 return;                           556                 return;
557         if (keep ^ complement) {                  557         if (keep ^ complement) {
558                 bool blankline = tline[strspn(    558                 bool blankline = tline[strspn(tline, " \t\r\n")] == '\0';
559                 if (blankline && compblank &&     559                 if (blankline && compblank && blankcount != blankmax) {
560                         delcount += 1;            560                         delcount += 1;
561                         blankcount += 1;          561                         blankcount += 1;
562                 } else {                          562                 } else {
563                         if (lnnum && delcount     563                         if (lnnum && delcount > 0)
564                                 printf("#line     564                                 printf("#line %d%s", linenum, newline);
565                         fputs(tline, output);     565                         fputs(tline, output);
566                         delcount = 0;             566                         delcount = 0;
567                         blankmax = blankcount     567                         blankmax = blankcount = blankline ? blankcount + 1 : 0;
568                 }                                 568                 }
569         } else {                                  569         } else {
570                 if (lnblank)                      570                 if (lnblank)
571                         fputs(newline, output)    571                         fputs(newline, output);
572                 exitstat = 1;                     572                 exitstat = 1;
573                 delcount += 1;                    573                 delcount += 1;
574                 blankcount = 0;                   574                 blankcount = 0;
575         }                                         575         }
576         if (debugging)                            576         if (debugging)
577                 fflush(output);                   577                 fflush(output);
578 }                                                 578 }
579                                                   579 
580 /*                                                580 /*
581  * The driver for the state machine.              581  * The driver for the state machine.
582  */                                               582  */
583 static void                                       583 static void
584 process(void)                                     584 process(void)
585 {                                                 585 {
586         /* When compressing blank lines, act a    586         /* When compressing blank lines, act as if the file
587            is preceded by a large number of bl    587            is preceded by a large number of blank lines. */
588         blankmax = blankcount = 1000;             588         blankmax = blankcount = 1000;
589         for (;;) {                                589         for (;;) {
590                 Linetype lineval = parseline()    590                 Linetype lineval = parseline();
591                 trans_table[ifstate[depth]][li    591                 trans_table[ifstate[depth]][lineval]();
592                 debug("process line %d %s -> %    592                 debug("process line %d %s -> %s depth %d",
593                     linenum, linetype_name[lin    593                     linenum, linetype_name[lineval],
594                     ifstate_name[ifstate[depth    594                     ifstate_name[ifstate[depth]], depth);
595         }                                         595         }
596 }                                                 596 }
597                                                   597 
598 /*                                                598 /*
599  * Flush the output and handle errors.            599  * Flush the output and handle errors.
600  */                                               600  */
601 static void                                       601 static void
602 closeout(void)                                    602 closeout(void)
603 {                                                 603 {
604         if (symdepth && !zerosyms)                604         if (symdepth && !zerosyms)
605                 printf("\n");                     605                 printf("\n");
606         if (fclose(output) == EOF) {              606         if (fclose(output) == EOF) {
607                 warn("couldn't write to %s", o    607                 warn("couldn't write to %s", ofilename);
608                 if (overwriting) {                608                 if (overwriting) {
609                         unlink(tempname);         609                         unlink(tempname);
610                         errx(2, "%s unchanged"    610                         errx(2, "%s unchanged", filename);
611                 } else {                          611                 } else {
612                         exit(2);                  612                         exit(2);
613                 }                                 613                 }
614         }                                         614         }
615 }                                                 615 }
616                                                   616 
617 /*                                                617 /*
618  * Clean up and exit.                             618  * Clean up and exit.
619  */                                               619  */
620 static void                                       620 static void
621 done(void)                                        621 done(void)
622 {                                                 622 {
623         if (incomment)                            623         if (incomment)
624                 error("EOF in comment");          624                 error("EOF in comment");
625         closeout();                               625         closeout();
626         if (overwriting && rename(tempname, of    626         if (overwriting && rename(tempname, ofilename) == -1) {
627                 warn("couldn't rename temporar    627                 warn("couldn't rename temporary file");
628                 unlink(tempname);                 628                 unlink(tempname);
629                 errx(2, "%s unchanged", ofilen    629                 errx(2, "%s unchanged", ofilename);
630         }                                         630         }
631         exit(exitstat);                           631         exit(exitstat);
632 }                                                 632 }
633                                                   633 
634 /*                                                634 /*
635  * Parse a line and determine its type. We kee    635  * Parse a line and determine its type. We keep the preprocessor line
636  * parser state between calls in the global va    636  * parser state between calls in the global variable linestate, with
637  * help from skipcomment().                       637  * help from skipcomment().
638  */                                               638  */
639 static Linetype                                   639 static Linetype
640 parseline(void)                                   640 parseline(void)
641 {                                                 641 {
642         const char *cp;                           642         const char *cp;
643         int cursym;                               643         int cursym;
644         int kwlen;                                644         int kwlen;
645         Linetype retval;                          645         Linetype retval;
646         Comment_state wascomment;                 646         Comment_state wascomment;
647                                                   647 
648         linenum++;                                648         linenum++;
649         if (fgets(tline, MAXLINE, input) == NU    649         if (fgets(tline, MAXLINE, input) == NULL)
650                 return (LT_EOF);                  650                 return (LT_EOF);
651         if (newline == NULL) {                    651         if (newline == NULL) {
652                 if (strrchr(tline, '\n') == st    652                 if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1)
653                         newline = newline_crlf    653                         newline = newline_crlf;
654                 else                              654                 else
655                         newline = newline_unix    655                         newline = newline_unix;
656         }                                         656         }
657         retval = LT_PLAIN;                        657         retval = LT_PLAIN;
658         wascomment = incomment;                   658         wascomment = incomment;
659         cp = skipcomment(tline);                  659         cp = skipcomment(tline);
660         if (linestate == LS_START) {              660         if (linestate == LS_START) {
661                 if (*cp == '#') {                 661                 if (*cp == '#') {
662                         linestate = LS_HASH;      662                         linestate = LS_HASH;
663                         firstsym = true;          663                         firstsym = true;
664                         cp = skipcomment(cp +     664                         cp = skipcomment(cp + 1);
665                 } else if (*cp != '\0')           665                 } else if (*cp != '\0')
666                         linestate = LS_DIRTY;     666                         linestate = LS_DIRTY;
667         }                                         667         }
668         if (!incomment && linestate == LS_HASH    668         if (!incomment && linestate == LS_HASH) {
669                 keyword = tline + (cp - tline)    669                 keyword = tline + (cp - tline);
670                 cp = skipsym(cp);                 670                 cp = skipsym(cp);
671                 kwlen = cp - keyword;             671                 kwlen = cp - keyword;
672                 /* no way can we deal with a c    672                 /* no way can we deal with a continuation inside a keyword */
673                 if (strncmp(cp, "\\\r\n", 3) =    673                 if (strncmp(cp, "\\\r\n", 3) == 0 ||
674                     strncmp(cp, "\\\n", 2) ==     674                     strncmp(cp, "\\\n", 2) == 0)
675                         Eioccc();                 675                         Eioccc();
676                 if (strlcmp("ifdef", keyword,     676                 if (strlcmp("ifdef", keyword, kwlen) == 0 ||
677                     strlcmp("ifndef", keyword,    677                     strlcmp("ifndef", keyword, kwlen) == 0) {
678                         cp = skipcomment(cp);     678                         cp = skipcomment(cp);
679                         if ((cursym = findsym(    679                         if ((cursym = findsym(cp)) < 0)
680                                 retval = LT_IF    680                                 retval = LT_IF;
681                         else {                    681                         else {
682                                 retval = (keyw    682                                 retval = (keyword[2] == 'n')
683                                     ? LT_FALSE    683                                     ? LT_FALSE : LT_TRUE;
684                                 if (value[curs    684                                 if (value[cursym] == NULL)
685                                         retval    685                                         retval = (retval == LT_TRUE)
686                                             ?     686                                             ? LT_FALSE : LT_TRUE;
687                                 if (ignore[cur    687                                 if (ignore[cursym])
688                                         retval    688                                         retval = (retval == LT_TRUE)
689                                             ?     689                                             ? LT_TRUEI : LT_FALSEI;
690                         }                         690                         }
691                         cp = skipsym(cp);         691                         cp = skipsym(cp);
692                 } else if (strlcmp("if", keywo    692                 } else if (strlcmp("if", keyword, kwlen) == 0)
693                         retval = ifeval(&cp);     693                         retval = ifeval(&cp);
694                 else if (strlcmp("elif", keywo    694                 else if (strlcmp("elif", keyword, kwlen) == 0)
695                         retval = ifeval(&cp) -    695                         retval = ifeval(&cp) - LT_IF + LT_ELIF;
696                 else if (strlcmp("else", keywo    696                 else if (strlcmp("else", keyword, kwlen) == 0)
697                         retval = LT_ELSE;         697                         retval = LT_ELSE;
698                 else if (strlcmp("endif", keyw    698                 else if (strlcmp("endif", keyword, kwlen) == 0)
699                         retval = LT_ENDIF;        699                         retval = LT_ENDIF;
700                 else {                            700                 else {
701                         linestate = LS_DIRTY;     701                         linestate = LS_DIRTY;
702                         retval = LT_PLAIN;        702                         retval = LT_PLAIN;
703                 }                                 703                 }
704                 cp = skipcomment(cp);             704                 cp = skipcomment(cp);
705                 if (*cp != '\0') {                705                 if (*cp != '\0') {
706                         linestate = LS_DIRTY;     706                         linestate = LS_DIRTY;
707                         if (retval == LT_TRUE     707                         if (retval == LT_TRUE || retval == LT_FALSE ||
708                             retval == LT_TRUEI    708                             retval == LT_TRUEI || retval == LT_FALSEI)
709                                 retval = LT_IF    709                                 retval = LT_IF;
710                         if (retval == LT_ELTRU    710                         if (retval == LT_ELTRUE || retval == LT_ELFALSE)
711                                 retval = LT_EL    711                                 retval = LT_ELIF;
712                 }                                 712                 }
713                 if (retval != LT_PLAIN && (was    713                 if (retval != LT_PLAIN && (wascomment || incomment)) {
714                         retval += LT_DODGY;       714                         retval += LT_DODGY;
715                         if (incomment)            715                         if (incomment)
716                                 linestate = LS    716                                 linestate = LS_DIRTY;
717                 }                                 717                 }
718                 /* skipcomment normally change    718                 /* skipcomment normally changes the state, except
719                    if the last line of the fil    719                    if the last line of the file lacks a newline, or
720                    if there is too much whites    720                    if there is too much whitespace in a directive */
721                 if (linestate == LS_HASH) {       721                 if (linestate == LS_HASH) {
722                         size_t len = cp - tlin    722                         size_t len = cp - tline;
723                         if (fgets(tline + len,    723                         if (fgets(tline + len, MAXLINE - len, input) == NULL) {
724                                 /* append the     724                                 /* append the missing newline */
725                                 strcpy(tline +    725                                 strcpy(tline + len, newline);
726                                 cp += strlen(n    726                                 cp += strlen(newline);
727                                 linestate = LS    727                                 linestate = LS_START;
728                         } else {                  728                         } else {
729                                 linestate = LS    729                                 linestate = LS_DIRTY;
730                         }                         730                         }
731                 }                                 731                 }
732         }                                         732         }
733         if (linestate == LS_DIRTY) {              733         if (linestate == LS_DIRTY) {
734                 while (*cp != '\0')               734                 while (*cp != '\0')
735                         cp = skipcomment(cp +     735                         cp = skipcomment(cp + 1);
736         }                                         736         }
737         debug("parser line %d state %s comment    737         debug("parser line %d state %s comment %s line", linenum,
738             comment_name[incomment], linestate    738             comment_name[incomment], linestate_name[linestate]);
739         return (retval);                          739         return (retval);
740 }                                                 740 }
741                                                   741 
742 /*                                                742 /*
743  * These are the binary operators that are sup    743  * These are the binary operators that are supported by the expression
744  * evaluator.                                     744  * evaluator.
745  */                                               745  */
746 static Linetype op_strict(int *p, int v, Linet    746 static Linetype op_strict(int *p, int v, Linetype at, Linetype bt) {
747         if(at == LT_IF || bt == LT_IF) return     747         if(at == LT_IF || bt == LT_IF) return (LT_IF);
748         return (*p = v, v ? LT_TRUE : LT_FALSE    748         return (*p = v, v ? LT_TRUE : LT_FALSE);
749 }                                                 749 }
750 static Linetype op_lt(int *p, Linetype at, int    750 static Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) {
751         return op_strict(p, a < b, at, bt);       751         return op_strict(p, a < b, at, bt);
752 }                                                 752 }
753 static Linetype op_gt(int *p, Linetype at, int    753 static Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) {
754         return op_strict(p, a > b, at, bt);       754         return op_strict(p, a > b, at, bt);
755 }                                                 755 }
756 static Linetype op_le(int *p, Linetype at, int    756 static Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) {
757         return op_strict(p, a <= b, at, bt);      757         return op_strict(p, a <= b, at, bt);
758 }                                                 758 }
759 static Linetype op_ge(int *p, Linetype at, int    759 static Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) {
760         return op_strict(p, a >= b, at, bt);      760         return op_strict(p, a >= b, at, bt);
761 }                                                 761 }
762 static Linetype op_eq(int *p, Linetype at, int    762 static Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) {
763         return op_strict(p, a == b, at, bt);      763         return op_strict(p, a == b, at, bt);
764 }                                                 764 }
765 static Linetype op_ne(int *p, Linetype at, int    765 static Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) {
766         return op_strict(p, a != b, at, bt);      766         return op_strict(p, a != b, at, bt);
767 }                                                 767 }
768 static Linetype op_or(int *p, Linetype at, int    768 static Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) {
769         if (!strictlogic && (at == LT_TRUE ||     769         if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE))
770                 return (*p = 1, LT_TRUE);         770                 return (*p = 1, LT_TRUE);
771         return op_strict(p, a || b, at, bt);      771         return op_strict(p, a || b, at, bt);
772 }                                                 772 }
773 static Linetype op_and(int *p, Linetype at, in    773 static Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) {
774         if (!strictlogic && (at == LT_FALSE ||    774         if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE))
775                 return (*p = 0, LT_FALSE);        775                 return (*p = 0, LT_FALSE);
776         return op_strict(p, a && b, at, bt);      776         return op_strict(p, a && b, at, bt);
777 }                                                 777 }
778                                                   778 
779 /*                                                779 /*
780  * An evaluation function takes three argument    780  * An evaluation function takes three arguments, as follows: (1) a pointer to
781  * an element of the precedence table which li    781  * an element of the precedence table which lists the operators at the current
782  * level of precedence; (2) a pointer to an in    782  * level of precedence; (2) a pointer to an integer which will receive the
783  * value of the expression; and (3) a pointer     783  * value of the expression; and (3) a pointer to a char* that points to the
784  * expression to be evaluated and that is upda    784  * expression to be evaluated and that is updated to the end of the expression
785  * when evaluation is complete. The function r    785  * when evaluation is complete. The function returns LT_FALSE if the value of
786  * the expression is zero, LT_TRUE if it is no    786  * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression
787  * depends on an unknown symbol, or LT_ERROR i    787  * depends on an unknown symbol, or LT_ERROR if there is a parse failure.
788  */                                               788  */
789 struct ops;                                       789 struct ops;
790                                                   790 
791 typedef Linetype eval_fn(const struct ops *, i    791 typedef Linetype eval_fn(const struct ops *, int *, const char **);
792                                                   792 
793 static eval_fn eval_table, eval_unary;            793 static eval_fn eval_table, eval_unary;
794                                                   794 
795 /*                                                795 /*
796  * The precedence table. Expressions involving    796  * The precedence table. Expressions involving binary operators are evaluated
797  * in a table-driven way by eval_table. When i    797  * in a table-driven way by eval_table. When it evaluates a subexpression it
798  * calls the inner function with its first arg    798  * calls the inner function with its first argument pointing to the next
799  * element of the table. Innermost expressions    799  * element of the table. Innermost expressions have special non-table-driven
800  * handling.                                      800  * handling.
801  */                                               801  */
802 static const struct ops {                         802 static const struct ops {
803         eval_fn *inner;                           803         eval_fn *inner;
804         struct op {                               804         struct op {
805                 const char *str;                  805                 const char *str;
806                 Linetype (*fn)(int *, Linetype    806                 Linetype (*fn)(int *, Linetype, int, Linetype, int);
807         } op[5];                                  807         } op[5];
808 } eval_ops[] = {                                  808 } eval_ops[] = {
809         { eval_table, { { "||", op_or } } },      809         { eval_table, { { "||", op_or } } },
810         { eval_table, { { "&&", op_and } } },     810         { eval_table, { { "&&", op_and } } },
811         { eval_table, { { "==", op_eq },          811         { eval_table, { { "==", op_eq },
812                         { "!=", op_ne } } },      812                         { "!=", op_ne } } },
813         { eval_unary, { { "<=", op_le },          813         { eval_unary, { { "<=", op_le },
814                         { ">=", op_ge },          814                         { ">=", op_ge },
815                         { "<", op_lt },           815                         { "<", op_lt },
816                         { ">", op_gt } } }        816                         { ">", op_gt } } }
817 };                                                817 };
818                                                   818 
819 /*                                                819 /*
820  * Function for evaluating the innermost parts    820  * Function for evaluating the innermost parts of expressions,
821  * viz. !expr (expr) number defined(symbol) sy    821  * viz. !expr (expr) number defined(symbol) symbol
822  * We reset the constexpression flag in the la !! 822  * We reset the constexpr flag in the last two cases.
823  */                                               823  */
824 static Linetype                                   824 static Linetype
825 eval_unary(const struct ops *ops, int *valp, c    825 eval_unary(const struct ops *ops, int *valp, const char **cpp)
826 {                                                 826 {
827         const char *cp;                           827         const char *cp;
828         char *ep;                                 828         char *ep;
829         int sym;                                  829         int sym;
830         bool defparen;                            830         bool defparen;
831         Linetype lt;                              831         Linetype lt;
832                                                   832 
833         cp = skipcomment(*cpp);                   833         cp = skipcomment(*cpp);
834         if (*cp == '!') {                         834         if (*cp == '!') {
835                 debug("eval%d !", ops - eval_o    835                 debug("eval%d !", ops - eval_ops);
836                 cp++;                             836                 cp++;
837                 lt = eval_unary(ops, valp, &cp    837                 lt = eval_unary(ops, valp, &cp);
838                 if (lt == LT_ERROR)               838                 if (lt == LT_ERROR)
839                         return (LT_ERROR);        839                         return (LT_ERROR);
840                 if (lt != LT_IF) {                840                 if (lt != LT_IF) {
841                         *valp = !*valp;           841                         *valp = !*valp;
842                         lt = *valp ? LT_TRUE :    842                         lt = *valp ? LT_TRUE : LT_FALSE;
843                 }                                 843                 }
844         } else if (*cp == '(') {                  844         } else if (*cp == '(') {
845                 cp++;                             845                 cp++;
846                 debug("eval%d (", ops - eval_o    846                 debug("eval%d (", ops - eval_ops);
847                 lt = eval_table(eval_ops, valp    847                 lt = eval_table(eval_ops, valp, &cp);
848                 if (lt == LT_ERROR)               848                 if (lt == LT_ERROR)
849                         return (LT_ERROR);        849                         return (LT_ERROR);
850                 cp = skipcomment(cp);             850                 cp = skipcomment(cp);
851                 if (*cp++ != ')')                 851                 if (*cp++ != ')')
852                         return (LT_ERROR);        852                         return (LT_ERROR);
853         } else if (isdigit((unsigned char)*cp)    853         } else if (isdigit((unsigned char)*cp)) {
854                 debug("eval%d number", ops - e    854                 debug("eval%d number", ops - eval_ops);
855                 *valp = strtol(cp, &ep, 0);       855                 *valp = strtol(cp, &ep, 0);
856                 if (ep == cp)                     856                 if (ep == cp)
857                         return (LT_ERROR);        857                         return (LT_ERROR);
858                 lt = *valp ? LT_TRUE : LT_FALS    858                 lt = *valp ? LT_TRUE : LT_FALSE;
859                 cp = skipsym(cp);                 859                 cp = skipsym(cp);
860         } else if (strncmp(cp, "defined", 7) =    860         } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
861                 cp = skipcomment(cp+7);           861                 cp = skipcomment(cp+7);
862                 debug("eval%d defined", ops -     862                 debug("eval%d defined", ops - eval_ops);
863                 if (*cp == '(') {                 863                 if (*cp == '(') {
864                         cp = skipcomment(cp+1)    864                         cp = skipcomment(cp+1);
865                         defparen = true;          865                         defparen = true;
866                 } else {                          866                 } else {
867                         defparen = false;         867                         defparen = false;
868                 }                                 868                 }
869                 sym = findsym(cp);                869                 sym = findsym(cp);
870                 if (sym < 0) {                    870                 if (sym < 0) {
871                         lt = LT_IF;               871                         lt = LT_IF;
872                 } else {                          872                 } else {
873                         *valp = (value[sym] !=    873                         *valp = (value[sym] != NULL);
874                         lt = *valp ? LT_TRUE :    874                         lt = *valp ? LT_TRUE : LT_FALSE;
875                 }                                 875                 }
876                 cp = skipsym(cp);                 876                 cp = skipsym(cp);
877                 cp = skipcomment(cp);             877                 cp = skipcomment(cp);
878                 if (defparen && *cp++ != ')')     878                 if (defparen && *cp++ != ')')
879                         return (LT_ERROR);        879                         return (LT_ERROR);
880                 constexpression = false;       !! 880                 constexpr = false;
881         } else if (!endsym(*cp)) {                881         } else if (!endsym(*cp)) {
882                 debug("eval%d symbol", ops - e    882                 debug("eval%d symbol", ops - eval_ops);
883                 sym = findsym(cp);                883                 sym = findsym(cp);
884                 cp = skipsym(cp);                 884                 cp = skipsym(cp);
885                 if (sym < 0) {                    885                 if (sym < 0) {
886                         lt = LT_IF;               886                         lt = LT_IF;
887                         cp = skipargs(cp);        887                         cp = skipargs(cp);
888                 } else if (value[sym] == NULL)    888                 } else if (value[sym] == NULL) {
889                         *valp = 0;                889                         *valp = 0;
890                         lt = LT_FALSE;            890                         lt = LT_FALSE;
891                 } else {                          891                 } else {
892                         *valp = strtol(value[s    892                         *valp = strtol(value[sym], &ep, 0);
893                         if (*ep != '\0' || ep     893                         if (*ep != '\0' || ep == value[sym])
894                                 return (LT_ERR    894                                 return (LT_ERROR);
895                         lt = *valp ? LT_TRUE :    895                         lt = *valp ? LT_TRUE : LT_FALSE;
896                         cp = skipargs(cp);        896                         cp = skipargs(cp);
897                 }                                 897                 }
898                 constexpression = false;       !! 898                 constexpr = false;
899         } else {                                  899         } else {
900                 debug("eval%d bad expr", ops -    900                 debug("eval%d bad expr", ops - eval_ops);
901                 return (LT_ERROR);                901                 return (LT_ERROR);
902         }                                         902         }
903                                                   903 
904         *cpp = cp;                                904         *cpp = cp;
905         debug("eval%d = %d", ops - eval_ops, *    905         debug("eval%d = %d", ops - eval_ops, *valp);
906         return (lt);                              906         return (lt);
907 }                                                 907 }
908                                                   908 
909 /*                                                909 /*
910  * Table-driven evaluation of binary operators    910  * Table-driven evaluation of binary operators.
911  */                                               911  */
912 static Linetype                                   912 static Linetype
913 eval_table(const struct ops *ops, int *valp, c    913 eval_table(const struct ops *ops, int *valp, const char **cpp)
914 {                                                 914 {
915         const struct op *op;                      915         const struct op *op;
916         const char *cp;                           916         const char *cp;
917         int val;                                  917         int val;
918         Linetype lt, rt;                          918         Linetype lt, rt;
919                                                   919 
920         debug("eval%d", ops - eval_ops);          920         debug("eval%d", ops - eval_ops);
921         cp = *cpp;                                921         cp = *cpp;
922         lt = ops->inner(ops+1, valp, &cp);        922         lt = ops->inner(ops+1, valp, &cp);
923         if (lt == LT_ERROR)                       923         if (lt == LT_ERROR)
924                 return (LT_ERROR);                924                 return (LT_ERROR);
925         for (;;) {                                925         for (;;) {
926                 cp = skipcomment(cp);             926                 cp = skipcomment(cp);
927                 for (op = ops->op; op->str !=     927                 for (op = ops->op; op->str != NULL; op++)
928                         if (strncmp(cp, op->st    928                         if (strncmp(cp, op->str, strlen(op->str)) == 0)
929                                 break;            929                                 break;
930                 if (op->str == NULL)              930                 if (op->str == NULL)
931                         break;                    931                         break;
932                 cp += strlen(op->str);            932                 cp += strlen(op->str);
933                 debug("eval%d %s", ops - eval_    933                 debug("eval%d %s", ops - eval_ops, op->str);
934                 rt = ops->inner(ops+1, &val, &    934                 rt = ops->inner(ops+1, &val, &cp);
935                 if (rt == LT_ERROR)               935                 if (rt == LT_ERROR)
936                         return (LT_ERROR);        936                         return (LT_ERROR);
937                 lt = op->fn(valp, lt, *valp, r    937                 lt = op->fn(valp, lt, *valp, rt, val);
938         }                                         938         }
939                                                   939 
940         *cpp = cp;                                940         *cpp = cp;
941         debug("eval%d = %d", ops - eval_ops, *    941         debug("eval%d = %d", ops - eval_ops, *valp);
942         debug("eval%d lt = %s", ops - eval_ops    942         debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]);
943         return (lt);                              943         return (lt);
944 }                                                 944 }
945                                                   945 
946 /*                                                946 /*
947  * Evaluate the expression on a #if or #elif l    947  * Evaluate the expression on a #if or #elif line. If we can work out
948  * the result we return LT_TRUE or LT_FALSE ac    948  * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we
949  * return just a generic LT_IF.                   949  * return just a generic LT_IF.
950  */                                               950  */
951 static Linetype                                   951 static Linetype
952 ifeval(const char **cpp)                          952 ifeval(const char **cpp)
953 {                                                 953 {
954         int ret;                                  954         int ret;
955         int val = 0;                              955         int val = 0;
956                                                   956 
957         debug("eval %s", *cpp);                   957         debug("eval %s", *cpp);
958         constexpression = killconsts ? false : !! 958         constexpr = killconsts ? false : true;
959         ret = eval_table(eval_ops, &val, cpp);    959         ret = eval_table(eval_ops, &val, cpp);
960         debug("eval = %d", val);                  960         debug("eval = %d", val);
961         return (constexpression ? LT_IF : ret  !! 961         return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret);
962 }                                                 962 }
963                                                   963 
964 /*                                                964 /*
965  * Skip over comments, strings, and character     965  * Skip over comments, strings, and character literals and stop at the
966  * next character position that is not whitesp    966  * next character position that is not whitespace. Between calls we keep
967  * the comment state in the global variable in    967  * the comment state in the global variable incomment, and we also adjust
968  * the global variable linestate when we see a    968  * the global variable linestate when we see a newline.
969  * XXX: doesn't cope with the buffer splitting    969  * XXX: doesn't cope with the buffer splitting inside a state transition.
970  */                                               970  */
971 static const char *                               971 static const char *
972 skipcomment(const char *cp)                       972 skipcomment(const char *cp)
973 {                                                 973 {
974         if (text || ignoring[depth]) {            974         if (text || ignoring[depth]) {
975                 for (; isspace((unsigned char)    975                 for (; isspace((unsigned char)*cp); cp++)
976                         if (*cp == '\n')          976                         if (*cp == '\n')
977                                 linestate = LS    977                                 linestate = LS_START;
978                 return (cp);                      978                 return (cp);
979         }                                         979         }
980         while (*cp != '\0')                       980         while (*cp != '\0')
981                 /* don't reset to LS_START aft    981                 /* don't reset to LS_START after a line continuation */
982                 if (strncmp(cp, "\\\r\n", 3) =    982                 if (strncmp(cp, "\\\r\n", 3) == 0)
983                         cp += 3;                  983                         cp += 3;
984                 else if (strncmp(cp, "\\\n", 2    984                 else if (strncmp(cp, "\\\n", 2) == 0)
985                         cp += 2;                  985                         cp += 2;
986                 else switch (incomment) {         986                 else switch (incomment) {
987                 case NO_COMMENT:                  987                 case NO_COMMENT:
988                         if (strncmp(cp, "/\\\r    988                         if (strncmp(cp, "/\\\r\n", 4) == 0) {
989                                 incomment = ST    989                                 incomment = STARTING_COMMENT;
990                                 cp += 4;          990                                 cp += 4;
991                         } else if (strncmp(cp,    991                         } else if (strncmp(cp, "/\\\n", 3) == 0) {
992                                 incomment = ST    992                                 incomment = STARTING_COMMENT;
993                                 cp += 3;          993                                 cp += 3;
994                         } else if (strncmp(cp,    994                         } else if (strncmp(cp, "/*", 2) == 0) {
995                                 incomment = C_    995                                 incomment = C_COMMENT;
996                                 cp += 2;          996                                 cp += 2;
997                         } else if (strncmp(cp,    997                         } else if (strncmp(cp, "//", 2) == 0) {
998                                 incomment = CX    998                                 incomment = CXX_COMMENT;
999                                 cp += 2;          999                                 cp += 2;
1000                         } else if (strncmp(cp    1000                         } else if (strncmp(cp, "\'", 1) == 0) {
1001                                 incomment = C    1001                                 incomment = CHAR_LITERAL;
1002                                 linestate = L    1002                                 linestate = LS_DIRTY;
1003                                 cp += 1;         1003                                 cp += 1;
1004                         } else if (strncmp(cp    1004                         } else if (strncmp(cp, "\"", 1) == 0) {
1005                                 incomment = S    1005                                 incomment = STRING_LITERAL;
1006                                 linestate = L    1006                                 linestate = LS_DIRTY;
1007                                 cp += 1;         1007                                 cp += 1;
1008                         } else if (strncmp(cp    1008                         } else if (strncmp(cp, "\n", 1) == 0) {
1009                                 linestate = L    1009                                 linestate = LS_START;
1010                                 cp += 1;         1010                                 cp += 1;
1011                         } else if (strchr(" \    1011                         } else if (strchr(" \r\t", *cp) != NULL) {
1012                                 cp += 1;         1012                                 cp += 1;
1013                         } else                   1013                         } else
1014                                 return (cp);     1014                                 return (cp);
1015                         continue;                1015                         continue;
1016                 case CXX_COMMENT:                1016                 case CXX_COMMENT:
1017                         if (strncmp(cp, "\n",    1017                         if (strncmp(cp, "\n", 1) == 0) {
1018                                 incomment = N    1018                                 incomment = NO_COMMENT;
1019                                 linestate = L    1019                                 linestate = LS_START;
1020                         }                        1020                         }
1021                         cp += 1;                 1021                         cp += 1;
1022                         continue;                1022                         continue;
1023                 case CHAR_LITERAL:               1023                 case CHAR_LITERAL:
1024                 case STRING_LITERAL:             1024                 case STRING_LITERAL:
1025                         if ((incomment == CHA    1025                         if ((incomment == CHAR_LITERAL && cp[0] == '\'') ||
1026                             (incomment == STR    1026                             (incomment == STRING_LITERAL && cp[0] == '\"')) {
1027                                 incomment = N    1027                                 incomment = NO_COMMENT;
1028                                 cp += 1;         1028                                 cp += 1;
1029                         } else if (cp[0] == '    1029                         } else if (cp[0] == '\\') {
1030                                 if (cp[1] ==     1030                                 if (cp[1] == '\0')
1031                                         cp +=    1031                                         cp += 1;
1032                                 else             1032                                 else
1033                                         cp +=    1033                                         cp += 2;
1034                         } else if (strncmp(cp    1034                         } else if (strncmp(cp, "\n", 1) == 0) {
1035                                 if (incomment    1035                                 if (incomment == CHAR_LITERAL)
1036                                         error    1036                                         error("unterminated char literal");
1037                                 else             1037                                 else
1038                                         error    1038                                         error("unterminated string literal");
1039                         } else                   1039                         } else
1040                                 cp += 1;         1040                                 cp += 1;
1041                         continue;                1041                         continue;
1042                 case C_COMMENT:                  1042                 case C_COMMENT:
1043                         if (strncmp(cp, "*\\\    1043                         if (strncmp(cp, "*\\\r\n", 4) == 0) {
1044                                 incomment = F    1044                                 incomment = FINISHING_COMMENT;
1045                                 cp += 4;         1045                                 cp += 4;
1046                         } else if (strncmp(cp    1046                         } else if (strncmp(cp, "*\\\n", 3) == 0) {
1047                                 incomment = F    1047                                 incomment = FINISHING_COMMENT;
1048                                 cp += 3;         1048                                 cp += 3;
1049                         } else if (strncmp(cp    1049                         } else if (strncmp(cp, "*/", 2) == 0) {
1050                                 incomment = N    1050                                 incomment = NO_COMMENT;
1051                                 cp += 2;         1051                                 cp += 2;
1052                         } else                   1052                         } else
1053                                 cp += 1;         1053                                 cp += 1;
1054                         continue;                1054                         continue;
1055                 case STARTING_COMMENT:           1055                 case STARTING_COMMENT:
1056                         if (*cp == '*') {        1056                         if (*cp == '*') {
1057                                 incomment = C    1057                                 incomment = C_COMMENT;
1058                                 cp += 1;         1058                                 cp += 1;
1059                         } else if (*cp == '/'    1059                         } else if (*cp == '/') {
1060                                 incomment = C    1060                                 incomment = CXX_COMMENT;
1061                                 cp += 1;         1061                                 cp += 1;
1062                         } else {                 1062                         } else {
1063                                 incomment = N    1063                                 incomment = NO_COMMENT;
1064                                 linestate = L    1064                                 linestate = LS_DIRTY;
1065                         }                        1065                         }
1066                         continue;                1066                         continue;
1067                 case FINISHING_COMMENT:          1067                 case FINISHING_COMMENT:
1068                         if (*cp == '/') {        1068                         if (*cp == '/') {
1069                                 incomment = N    1069                                 incomment = NO_COMMENT;
1070                                 cp += 1;         1070                                 cp += 1;
1071                         } else                   1071                         } else
1072                                 incomment = C    1072                                 incomment = C_COMMENT;
1073                         continue;                1073                         continue;
1074                 default:                         1074                 default:
1075                         abort(); /* bug */       1075                         abort(); /* bug */
1076                 }                                1076                 }
1077         return (cp);                             1077         return (cp);
1078 }                                                1078 }
1079                                                  1079 
1080 /*                                               1080 /*
1081  * Skip macro arguments.                         1081  * Skip macro arguments.
1082  */                                              1082  */
1083 static const char *                              1083 static const char *
1084 skipargs(const char *cp)                         1084 skipargs(const char *cp)
1085 {                                                1085 {
1086         const char *ocp = cp;                    1086         const char *ocp = cp;
1087         int level = 0;                           1087         int level = 0;
1088         cp = skipcomment(cp);                    1088         cp = skipcomment(cp);
1089         if (*cp != '(')                          1089         if (*cp != '(')
1090                 return (cp);                     1090                 return (cp);
1091         do {                                     1091         do {
1092                 if (*cp == '(')                  1092                 if (*cp == '(')
1093                         level++;                 1093                         level++;
1094                 if (*cp == ')')                  1094                 if (*cp == ')')
1095                         level--;                 1095                         level--;
1096                 cp = skipcomment(cp+1);          1096                 cp = skipcomment(cp+1);
1097         } while (level != 0 && *cp != '\0');     1097         } while (level != 0 && *cp != '\0');
1098         if (level == 0)                          1098         if (level == 0)
1099                 return (cp);                     1099                 return (cp);
1100         else                                     1100         else
1101         /* Rewind and re-detect the syntax er    1101         /* Rewind and re-detect the syntax error later. */
1102                 return (ocp);                    1102                 return (ocp);
1103 }                                                1103 }
1104                                                  1104 
1105 /*                                               1105 /*
1106  * Skip over an identifier.                      1106  * Skip over an identifier.
1107  */                                              1107  */
1108 static const char *                              1108 static const char *
1109 skipsym(const char *cp)                          1109 skipsym(const char *cp)
1110 {                                                1110 {
1111         while (!endsym(*cp))                     1111         while (!endsym(*cp))
1112                 ++cp;                            1112                 ++cp;
1113         return (cp);                             1113         return (cp);
1114 }                                                1114 }
1115                                                  1115 
1116 /*                                               1116 /*
1117  * Look for the symbol in the symbol table. I    1117  * Look for the symbol in the symbol table. If it is found, we return
1118  * the symbol table index, else we return -1.    1118  * the symbol table index, else we return -1.
1119  */                                              1119  */
1120 static int                                       1120 static int
1121 findsym(const char *str)                         1121 findsym(const char *str)
1122 {                                                1122 {
1123         const char *cp;                          1123         const char *cp;
1124         int symind;                              1124         int symind;
1125                                                  1125 
1126         cp = skipsym(str);                       1126         cp = skipsym(str);
1127         if (cp == str)                           1127         if (cp == str)
1128                 return (-1);                     1128                 return (-1);
1129         if (symlist) {                           1129         if (symlist) {
1130                 if (symdepth && firstsym)        1130                 if (symdepth && firstsym)
1131                         printf("%s%3d", zeros    1131                         printf("%s%3d", zerosyms ? "" : "\n", depth);
1132                 firstsym = zerosyms = false;     1132                 firstsym = zerosyms = false;
1133                 printf("%s%.*s%s",               1133                 printf("%s%.*s%s",
1134                     symdepth ? " " : "",         1134                     symdepth ? " " : "",
1135                     (int)(cp-str), str,          1135                     (int)(cp-str), str,
1136                     symdepth ? "" : "\n");       1136                     symdepth ? "" : "\n");
1137                 /* we don't care about the va    1137                 /* we don't care about the value of the symbol */
1138                 return (0);                      1138                 return (0);
1139         }                                        1139         }
1140         for (symind = 0; symind < nsyms; ++sy    1140         for (symind = 0; symind < nsyms; ++symind) {
1141                 if (strlcmp(symname[symind],     1141                 if (strlcmp(symname[symind], str, cp-str) == 0) {
1142                         debug("findsym %s %s"    1142                         debug("findsym %s %s", symname[symind],
1143                             value[symind] ? v    1143                             value[symind] ? value[symind] : "");
1144                         return (symind);         1144                         return (symind);
1145                 }                                1145                 }
1146         }                                        1146         }
1147         return (-1);                             1147         return (-1);
1148 }                                                1148 }
1149                                                  1149 
1150 /*                                               1150 /*
1151  * Add a symbol to the symbol table.             1151  * Add a symbol to the symbol table.
1152  */                                              1152  */
1153 static void                                      1153 static void
1154 addsym(bool ignorethis, bool definethis, char    1154 addsym(bool ignorethis, bool definethis, char *sym)
1155 {                                                1155 {
1156         int symind;                              1156         int symind;
1157         char *val;                               1157         char *val;
1158                                                  1158 
1159         symind = findsym(sym);                   1159         symind = findsym(sym);
1160         if (symind < 0) {                        1160         if (symind < 0) {
1161                 if (nsyms >= MAXSYMS)            1161                 if (nsyms >= MAXSYMS)
1162                         errx(2, "too many sym    1162                         errx(2, "too many symbols");
1163                 symind = nsyms++;                1163                 symind = nsyms++;
1164         }                                        1164         }
1165         symname[symind] = sym;                   1165         symname[symind] = sym;
1166         ignore[symind] = ignorethis;             1166         ignore[symind] = ignorethis;
1167         val = sym + (skipsym(sym) - sym);        1167         val = sym + (skipsym(sym) - sym);
1168         if (definethis) {                        1168         if (definethis) {
1169                 if (*val == '=') {               1169                 if (*val == '=') {
1170                         value[symind] = val+1    1170                         value[symind] = val+1;
1171                         *val = '\0';             1171                         *val = '\0';
1172                 } else if (*val == '\0')         1172                 } else if (*val == '\0')
1173                         value[symind] = "1";     1173                         value[symind] = "1";
1174                 else                             1174                 else
1175                         usage();                 1175                         usage();
1176         } else {                                 1176         } else {
1177                 if (*val != '\0')                1177                 if (*val != '\0')
1178                         usage();                 1178                         usage();
1179                 value[symind] = NULL;            1179                 value[symind] = NULL;
1180         }                                        1180         }
1181         debug("addsym %s=%s", symname[symind]    1181         debug("addsym %s=%s", symname[symind],
1182             value[symind] ? value[symind] : "    1182             value[symind] ? value[symind] : "undef");
1183 }                                                1183 }
1184                                                  1184 
1185 /*                                               1185 /*
1186  * Compare s with n characters of t.             1186  * Compare s with n characters of t.
1187  * The same as strncmp() except that it check    1187  * The same as strncmp() except that it checks that s[n] == '\0'.
1188  */                                              1188  */
1189 static int                                       1189 static int
1190 strlcmp(const char *s, const char *t, size_t     1190 strlcmp(const char *s, const char *t, size_t n)
1191 {                                                1191 {
1192         while (n-- && *t != '\0')                1192         while (n-- && *t != '\0')
1193                 if (*s != *t)                    1193                 if (*s != *t)
1194                         return ((unsigned cha    1194                         return ((unsigned char)*s - (unsigned char)*t);
1195                 else                             1195                 else
1196                         ++s, ++t;                1196                         ++s, ++t;
1197         return ((unsigned char)*s);              1197         return ((unsigned char)*s);
1198 }                                                1198 }
1199                                                  1199 
1200 /*                                               1200 /*
1201  * Diagnostics.                                  1201  * Diagnostics.
1202  */                                              1202  */
1203 static void                                      1203 static void
1204 debug(const char *msg, ...)                      1204 debug(const char *msg, ...)
1205 {                                                1205 {
1206         va_list ap;                              1206         va_list ap;
1207                                                  1207 
1208         if (debugging) {                         1208         if (debugging) {
1209                 va_start(ap, msg);               1209                 va_start(ap, msg);
1210                 vwarnx(msg, ap);                 1210                 vwarnx(msg, ap);
1211                 va_end(ap);                      1211                 va_end(ap);
1212         }                                        1212         }
1213 }                                                1213 }
1214                                                  1214 
1215 static void                                      1215 static void
1216 error(const char *msg)                           1216 error(const char *msg)
1217 {                                                1217 {
1218         if (depth == 0)                          1218         if (depth == 0)
1219                 warnx("%s: %d: %s", filename,    1219                 warnx("%s: %d: %s", filename, linenum, msg);
1220         else                                     1220         else
1221                 warnx("%s: %d: %s (#if line %    1221                 warnx("%s: %d: %s (#if line %d depth %d)",
1222                     filename, linenum, msg, s    1222                     filename, linenum, msg, stifline[depth], depth);
1223         closeout();                              1223         closeout();
1224         errx(2, "output may be truncated");      1224         errx(2, "output may be truncated");
1225 }                                                1225 }
1226                                                  1226 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php