aboutsummaryrefslogtreecommitdiff
path: root/build-aux
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2011-01-12 13:42:50 -0800
committerBen Pfaff <blp@nicira.com>2011-01-12 13:51:43 -0800
commitdc4762edd02693770d392b8f6495deb7e52635bf (patch)
tree92ed4ec143b5d99170a479ab4d95f9cb627eb389 /build-aux
parenta44d74d75294e358e501cc83fd35e6a5e50ebf0b (diff)
Automatically extract error types and codes for formatting.
Diffstat (limited to 'build-aux')
-rwxr-xr-xbuild-aux/extract-ofp-errors225
1 files changed, 225 insertions, 0 deletions
diff --git a/build-aux/extract-ofp-errors b/build-aux/extract-ofp-errors
new file mode 100755
index 00000000..c34888fc
--- /dev/null
+++ b/build-aux/extract-ofp-errors
@@ -0,0 +1,225 @@
+#! /usr/bin/python
+
+import sys
+import os.path
+import re
+
+macros = {}
+
+token = None
+line = ""
+idRe = "[a-zA-Z_][a-zA-Z_0-9]*"
+tokenRe = "#?" + idRe + "|[0-9]+|."
+inComment = False
+inDirective = False
+def getToken():
+ global token
+ global line
+ global inComment
+ global inDirective
+ while True:
+ line = line.lstrip()
+ if line != "":
+ if line.startswith("/*"):
+ inComment = True
+ line = line[2:]
+ elif inComment:
+ commentEnd = line.find("*/")
+ if commentEnd < 0:
+ line = ""
+ else:
+ inComment = False
+ line = line[commentEnd + 2:]
+ else:
+ match = re.match(tokenRe, line)
+ token = match.group(0)
+ line = line[len(token):]
+ if token.startswith('#'):
+ inDirective = True
+ elif token in macros and not inDirective:
+ line = macros[token] + line
+ continue
+ return True
+ elif inDirective:
+ token = "$"
+ inDirective = False
+ return True
+ else:
+ global lineNumber
+ line = inputFile.readline()
+ lineNumber += 1
+ while line.endswith("\\\n"):
+ line = line[:-2] + inputFile.readline()
+ lineNumber += 1
+ if line == "":
+ if token == None:
+ fatal("unexpected end of input")
+ token = None
+ return False
+
+def fatal(msg):
+ sys.stderr.write("%s:%d: error at \"%s\": %s\n" % (fileName, lineNumber, token, msg))
+ sys.exit(1)
+
+def skipDirective():
+ getToken()
+ while token != '$':
+ getToken()
+
+def isId(s):
+ return re.match(idRe + "$", s) != None
+
+def forceId():
+ if not isId(token):
+ fatal("identifier expected")
+
+def forceInteger():
+ if not re.match('[0-9]+$', token):
+ fatal("integer expected")
+
+def match(t):
+ if token == t:
+ getToken()
+ return True
+ else:
+ return False
+
+def forceMatch(t):
+ if not match(t):
+ fatal("%s expected" % t)
+
+def parseTaggedName():
+ assert token in ('struct', 'union')
+ name = token
+ getToken()
+ forceId()
+ name = "%s %s" % (name, token)
+ getToken()
+ return name
+
+def print_enum(tag, constants, storage_class):
+ print """
+%(storage_class)sconst char *
+%(tag)s_to_string(uint16_t value)
+{
+ switch (value) {\
+""" % {"tag": tag,
+ "bufferlen": len(tag) + 32,
+ "storage_class": storage_class}
+ for constant in constants:
+ print " case %s: return \"%s\";" % (constant, constant)
+ print """\
+ }
+ return NULL;
+}\
+""" % {"tag": tag}
+
+def usage():
+ argv0 = os.path.basename(sys.argv[0])
+ print '''\
+%(argv0)s, for extracting OpenFlow error codes from header files
+usage: %(argv0)s FILE [FILE...]
+
+This program reads the header files specified on the command line and
+outputs a C source file for translating OpenFlow error codes into
+strings, for use as lib/ofp-errors.c in the Open vSwitch source tree.
+
+This program is specialized for reading include/openflow/openflow.h
+and include/openflow/nicira-ext.h. It will not work on arbitrary
+header files without extensions.''' % {"argv0": argv0}
+ sys.exit(0)
+
+def extract_ofp_errors(filenames):
+ error_types = {}
+
+ global fileName
+ for fileName in filenames:
+ global inputFile
+ global lineNumber
+ inputFile = open(fileName)
+ lineNumber = 0
+ while getToken():
+ if token in ("#ifdef", "#ifndef", "#include",
+ "#endif", "#elif", "#else", '#define'):
+ skipDirective()
+ elif match('enum'):
+ forceId()
+ enum_tag = token
+ getToken()
+
+ forceMatch("{")
+
+ constants = []
+ while isId(token):
+ constants.append(token)
+ getToken()
+ if match('='):
+ while token != ',' and token != '}':
+ getToken()
+ match(',')
+
+ forceMatch('}')
+
+ if enum_tag == "ofp_error_type":
+ error_types = {}
+ for error_type in constants:
+ error_types[error_type] = []
+ elif enum_tag == 'nx_vendor_code':
+ pass
+ elif enum_tag.endswith('_code'):
+ error_type = 'OFPET_%s' % '_'.join(enum_tag.split('_')[1:-1]).upper()
+ if error_type not in error_types:
+ fatal("enum %s looks like an error code enumeration but %s is unknown" % (enum_tag, error_type))
+ error_types[error_type] += constants
+ elif token in ('struct', 'union'):
+ getToken()
+ forceId()
+ getToken()
+ forceMatch('{')
+ while not match('}'):
+ getToken()
+ elif match('OFP_ASSERT') or match('BOOST_STATIC_ASSERT'):
+ while token != ';':
+ getToken()
+ else:
+ fatal("parse error")
+ inputFile.close()
+
+ print "/* -*- buffer-read-only: t -*- */"
+ print "#include <config.h>"
+ print '#include "ofp-errors.h"'
+ print "#include <inttypes.h>"
+ print "#include <stdio.h>"
+ for fileName in sys.argv[1:]:
+ print '#include "%s"' % fileName
+ print '#include "type-props.h"'
+
+ for error_type, constants in sorted(error_types.items()):
+ tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower()
+ print_enum(tag, constants, "static ")
+ print_enum("ofp_error_type", error_types.keys(), "")
+ print """
+const char *
+ofp_error_code_to_string(uint16_t type, uint16_t code)
+{
+ switch (type) {\
+"""
+ for error_type in error_types:
+ tag = 'ofp_%s_code' % re.sub('^OFPET_', '', error_type).lower()
+ print " case %s:" % error_type
+ print " return %s_to_string(code);" % tag
+ print """\
+ }
+ return NULL;
+}\
+"""
+
+if __name__ == '__main__':
+ if '--help' in sys.argv:
+ usage()
+ elif len(sys.argv) < 2:
+ sys.stderr.write("at least one non-option argument required; "
+ "use --help for help\n")
+ sys.exit(1)
+ else:
+ extract_ofp_errors(sys.argv[1:])