Update to 2.7.3
[profile/ivi/python.git] / Tools / scripts / ifdef.py
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()