summaryrefslogtreecommitdiff
path: root/man/simplecpp
diff options
context:
space:
mode:
Diffstat (limited to 'man/simplecpp')
-rwxr-xr-xman/simplecpp211
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)
+