ifdef.py 3.63 KB
Newer Older
1
#! /usr/bin/env python
Guido van Rossum's avatar
Guido van Rossum committed
2 3 4 5

# Selectively preprocess #ifdef / #ifndef statements.
# Usage:
# ifdef [-Dname] ... [-Uname] ... [file] ...
Tim Peters's avatar
Tim Peters committed
6
#
Guido van Rossum's avatar
Guido van Rossum committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
# This scans the file(s), looking for #ifdef and #ifndef preprocessor
# commands that test for one of the names mentioned in the -D and -U
# options.  On standard output it writes a copy of the input file(s)
# minus those code sections that are suppressed by the selected
# combination of defined/undefined symbols.  The #if(n)def/#else/#else
# lines themselfs (if the #if(n)def tests for one of the mentioned
# names) are removed as well.

# Features: Arbitrary nesting of recognized and unrecognized
# preprocesor statements works correctly.  Unrecognized #if* commands
# are left in place, so it will never remove too much, only too
# little.  It does accept whitespace around the '#' character.

# Restrictions: There should be no comments or other symbols on the
# #if(n)def lines.  The effect of #define/#undef commands in the input
# file or in included files is not taken into account.  Tests using
# #if and the defined() pseudo function are not recognized.  The #elif
# command is not recognized.  Improperly nesting is not detected.
# Lines that look like preprocessor commands but which are actually
# part of comments or string literals will be mistaken for
# preprocessor commands.

import sys
import getopt

defs = []
undefs = []

def main():
Tim Peters's avatar
Tim Peters committed
36 37 38 39 40 41 42 43
    opts, args = getopt.getopt(sys.argv[1:], 'D:U:')
    for o, a in opts:
        if o == '-D':
            defs.append(a)
        if o == '-U':
            undefs.append(a)
    if not args:
        args = ['-']
44 45
    for filename in args:
        if filename == '-':
Tim Peters's avatar
Tim Peters committed
46 47
            process(sys.stdin, sys.stdout)
        else:
48
            f = open(filename, 'r')
Tim Peters's avatar
Tim Peters committed
49 50
            process(f, sys.stdout)
            f.close()
Guido van Rossum's avatar
Guido van Rossum committed
51 52

def process(fpi, fpo):
Tim Peters's avatar
Tim Peters committed
53 54 55 56 57 58 59 60 61 62
    keywords = ('if', 'ifdef', 'ifndef', 'else', 'endif')
    ok = 1
    stack = []
    while 1:
        line = fpi.readline()
        if not line: break
        while line[-2:] == '\\\n':
            nextline = fpi.readline()
            if not nextline: break
            line = line + nextline
63
        tmp = line.strip()
Tim Peters's avatar
Tim Peters committed
64 65 66
        if tmp[:1] != '#':
            if ok: fpo.write(line)
            continue
67 68
        tmp = tmp[1:].strip()
        words = tmp.split()
Tim Peters's avatar
Tim Peters committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
        keyword = words[0]
        if keyword not in keywords:
            if ok: fpo.write(line)
            continue
        if keyword in ('ifdef', 'ifndef') and len(words) == 2:
            if keyword == 'ifdef':
                ko = 1
            else:
                ko = 0
            word = words[1]
            if word in defs:
                stack.append((ok, ko, word))
                if not ko: ok = 0
            elif word in undefs:
                stack.append((ok, not ko, word))
                if ko: ok = 0
            else:
                stack.append((ok, -1, word))
                if ok: fpo.write(line)
        elif keyword == 'if':
            stack.append((ok, -1, ''))
            if ok: fpo.write(line)
        elif keyword == 'else' and stack:
            s_ok, s_ko, s_word = stack[-1]
            if s_ko < 0:
                if ok: fpo.write(line)
            else:
                s_ko = not s_ko
                ok = s_ok
                if not s_ko: ok = 0
                stack[-1] = s_ok, s_ko, s_word
        elif keyword == 'endif' and stack:
            s_ok, s_ko, s_word = stack[-1]
            if s_ko < 0:
                if ok: fpo.write(line)
            del stack[-1]
            ok = s_ok
        else:
            sys.stderr.write('Unknown keyword %s\n' % keyword)
    if stack:
        sys.stderr.write('stack: %s\n' % stack)
Guido van Rossum's avatar
Guido van Rossum committed
110

111 112
if __name__ == '__main__':
    main()