Home | History | Annotate | Download | only in scripts
      1 #! /usr/bin/env python

      2 
      3 # Selectively preprocess #ifdef / #ifndef statements.

      4 # Usage:

      5 # ifdef [-Dname] ... [-Uname] ... [file] ...

      6 #

      7 # This scans the file(s), looking for #ifdef and #ifndef preprocessor

      8 # commands that test for one of the names mentioned in the -D and -U

      9 # options.  On standard output it writes a copy of the input file(s)

     10 # minus those code sections that are suppressed by the selected

     11 # combination of defined/undefined symbols.  The #if(n)def/#else/#else

     12 # lines themselfs (if the #if(n)def tests for one of the mentioned

     13 # names) are removed as well.

     14 
     15 # Features: Arbitrary nesting of recognized and unrecognized

     16 # preprocesor statements works correctly.  Unrecognized #if* commands

     17 # are left in place, so it will never remove too much, only too

     18 # little.  It does accept whitespace around the '#' character.

     19 
     20 # Restrictions: There should be no comments or other symbols on the

     21 # #if(n)def lines.  The effect of #define/#undef commands in the input

     22 # file or in included files is not taken into account.  Tests using

     23 # #if and the defined() pseudo function are not recognized.  The #elif

     24 # command is not recognized.  Improperly nesting is not detected.

     25 # Lines that look like preprocessor commands but which are actually

     26 # part of comments or string literals will be mistaken for

     27 # preprocessor commands.

     28 
     29 import sys
     30 import getopt
     31 
     32 defs = []
     33 undefs = []
     34 
     35 def main():
     36     opts, args = getopt.getopt(sys.argv[1:], 'D:U:')
     37     for o, a in opts:
     38         if o == '-D':
     39             defs.append(a)
     40         if o == '-U':
     41             undefs.append(a)
     42     if not args:
     43         args = ['-']
     44     for filename in args:
     45         if filename == '-':
     46             process(sys.stdin, sys.stdout)
     47         else:
     48             f = open(filename, 'r')
     49             process(f, sys.stdout)
     50             f.close()
     51 
     52 def process(fpi, fpo):
     53     keywords = ('if', 'ifdef', 'ifndef', 'else', 'endif')
     54     ok = 1
     55     stack = []
     56     while 1:
     57         line = fpi.readline()
     58         if not line: break
     59         while line[-2:] == '\\\n':
     60             nextline = fpi.readline()
     61             if not nextline: break
     62             line = line + nextline
     63         tmp = line.strip()
     64         if tmp[:1] != '#':
     65             if ok: fpo.write(line)
     66             continue
     67         tmp = tmp[1:].strip()
     68         words = tmp.split()
     69         keyword = words[0]
     70         if keyword not in keywords:
     71             if ok: fpo.write(line)
     72             continue
     73         if keyword in ('ifdef', 'ifndef') and len(words) == 2:
     74             if keyword == 'ifdef':
     75                 ko = 1
     76             else:
     77                 ko = 0
     78             word = words[1]
     79             if word in defs:
     80                 stack.append((ok, ko, word))
     81                 if not ko: ok = 0
     82             elif word in undefs:
     83                 stack.append((ok, not ko, word))
     84                 if ko: ok = 0
     85             else:
     86                 stack.append((ok, -1, word))
     87                 if ok: fpo.write(line)
     88         elif keyword == 'if':
     89             stack.append((ok, -1, ''))
     90             if ok: fpo.write(line)
     91         elif keyword == 'else' and stack:
     92             s_ok, s_ko, s_word = stack[-1]
     93             if s_ko < 0:
     94                 if ok: fpo.write(line)
     95             else:
     96                 s_ko = not s_ko
     97                 ok = s_ok
     98                 if not s_ko: ok = 0
     99                 stack[-1] = s_ok, s_ko, s_word
    100         elif keyword == 'endif' and stack:
    101             s_ok, s_ko, s_word = stack[-1]
    102             if s_ko < 0:
    103                 if ok: fpo.write(line)
    104             del stack[-1]
    105             ok = s_ok
    106         else:
    107             sys.stderr.write('Unknown keyword %s\n' % keyword)
    108     if stack:
    109         sys.stderr.write('stack: %s\n' % stack)
    110 
    111 if __name__ == '__main__':
    112     main()
    113