diff options
Diffstat (limited to 'man/simplecpp')
-rwxr-xr-x | man/simplecpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/man/simplecpp b/man/simplecpp new file mode 100755 index 00000000..d277f278 --- /dev/null +++ b/man/simplecpp @@ -0,0 +1,211 @@ +#!/usr/bin/env python +# +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Contributors to the Freedoom project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the freedoom project nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# simple cpp-style preprocessor +# +# Understands: +# +# #define NAME +# +# Set an option +# You can use -D on the command line too +# +# #undef NAME +# +# Unset an option if it is set +# +# #if .. #endif / #ifdef .. #endif +# +# Specify a list of options set, eg #ifdef DOOM2 || ULTDOOM || SHAREWARE +# The block is only displayed if one of the options is set +# +# #ifn .. #endif / #ifndef .. #endif +# +# Similarly specify a list of options +# The block is displayed if none of the options are set +# +# #include "filename" +# +# include the contents of a file + +import sys +import re + +debug = False +defines = {} + +command_re = re.compile("\#(\w+)(\s+(.*))?") +include_re = re.compile("\s*\"(.*)\"\s*") + +def debug_msg(message): + if debug: + sys.stderr.write(message) + +# Parse command line options + +def parse_cmdline(): + for arg in sys.argv[1:]: + if arg.startswith("-D"): + name = arg[2:] + defines[name] = True + +def parse_stream(stream): + result = read_block(stream, False) + + if result is not None: + raise Exception("Mismatched #if in '%s'" % stream.name) + +def parse_file(filename): + f = open(filename) + + try: + parse_stream(f) + finally: + f.close() + +# #include + +def cmd_include(arg): + # Extract the filename + + match = include_re.match(arg) + + if not match: + raise Exception("Invalid 'include' command") + + filename = match.group(1) + + # Open the file and process it + + parse_file(filename) + +# #define + +def cmd_define(arg): + defines[arg] = True + +# #undef + +def cmd_undef(arg): + if arg in defines: + del defines[arg] + +# #ifdef/#ifndef + +def cmd_ifdef(arg, command, stream, ignore): + + # Get the define name + name = arg.strip() + + debug_msg("%s %s >\n" % (command, arg)) + + # Should we ignore the contents of this block? + + sub_ignore = (name not in defines) + + if "n" in command: + sub_ignore = not sub_ignore + + # Parse the block + + result = read_block(stream, ignore or sub_ignore) + + debug_msg("%s %s < (%s)\n" % (command, arg, result)) + + # There may be a second "else" block to parse: + + if result == "else": + debug_msg("%s %s else >\n" % (command, arg)) + result = read_block(stream, ignore or (not sub_ignore)) + debug_msg("%s %s else < (%s)\n" % (command, arg, result)) + + # Should end in an endif: + + if result != "endif": + raise Exception("'if' block did not end in an 'endif'") + +commands = { + "include" : cmd_include, + "define" : cmd_define, + "undef" : cmd_undef, + "if" : cmd_ifdef, + "ifdef" : cmd_ifdef, + "ifn" : cmd_ifdef, + "ifndef" : cmd_ifdef, +} + +# Recursive block reading function +# if 'ignore' argument is 1, contents are ignored + +def read_block(stream, ignore): + + for line in stream: + + # Remove newline + + line = line[0:-1] + + # Check if this line has a command + + match = command_re.match(line) + + if match: + command = match.group(1) + arg = match.group(3) + + if command == "else" or command == "endif": + return command + elif command not in commands: + raise Exception("Unknown command: '%s'" % \ + command) + + # Get the callback function. + + func = commands[command] + + # Invoke the callback function. #ifdef commands + # are a special case and need extra arguments. + # Other commands are only executed if we are not + # ignoring this block. + + if func == cmd_ifdef: + cmd_ifdef(arg, command=command, + stream=stream, + ignore=ignore) + elif not ignore: + func(arg) + else: + if not ignore: + print(line) + +parse_cmdline() +parse_stream(sys.stdin) + |