diff options
Diffstat (limited to 'makewrappers')
-rwxr-xr-x | makewrappers | 221 |
1 files changed, 134 insertions, 87 deletions
diff --git a/makewrappers b/makewrappers index 8fb1484..073f35b 100755 --- a/makewrappers +++ b/makewrappers @@ -15,19 +15,17 @@ # version 2.1 along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -'convert wrapfuncs.in to wrapper function stubs and tables' +"""convert wrapfuncs.in to wrapper function stubs and tables""" import glob import sys import re import os -import string import datetime -import time from string import Template class SourceFile(object): - "A template for creating a source file" + """A template for creating a source file""" def __init__(self, path): # default values... @@ -46,16 +44,14 @@ class SourceFile(object): self.sections['body'] = [] current = self.sections['body'] - self.f = file(path, 'r') - if not self.f: - return None - for line in self.f: + self.template = open(path) + for line in self.template: line = line.rstrip() if line.startswith('@'): if ' ' in line: - leading, trailing = line.split(' ', 1) + leading, trailing = line.split(' ', 1) else: - leading, trailing = line, None + leading, trailing = line, None if leading == '@name': if not trailing: @@ -65,23 +61,24 @@ class SourceFile(object): self.file_per_func = True else: section = leading[1:] - if not section in self.sections: + if section not in self.sections: self.sections[section] = [] current = self.sections[section] else: current.append(line) + self.template.close() for section, data in self.sections.items(): self.sections[section] = Template("\n".join(data)) # You need a file if this isn't a file-per-func if not self.file_per_func: - self.file = file(self.path, 'w') - if not self.file: - raise IOError("Couldn't open %s to read a template." % self.path) + self.file = open(self.path, 'w') - def __del__(self): + def close(self): + """Close the associated file.""" if self.file: self.file.close() + self.file = None def __repr__(self): strings = [] @@ -94,18 +91,20 @@ class SourceFile(object): strings.append(data.safe_substitute({})) return "\n".join(strings) - def emit(self, template, func = None): + def emit(self, template, func=None): + """Emit a template, with optional interpolation of a function.""" if self.file_per_func: if not func: - # print "Must have a function to emit any part of a file-per-func template." return path = Template(self.path).safe_substitute(func) if os.path.exists(path): # print "We don't overwrite existing files." return - self.file = file(path, 'w') + self.file = open(path, 'w') if not self.file: - print "Couldn't open '%s' (expanded from %s), not emitting '%s'." % (path, self.path, template) + print "Couldn't open '%s' (expanded from %s), " \ + "not emitting '%s'." % \ + (path, self.path, template) return if template == "copyright": @@ -123,16 +122,17 @@ class SourceFile(object): self.file = None class ArgumentList: - "A (possibly empty) list of arguments" + """A (possibly empty) list of arguments""" def __init__(self, text): - "parse a comma-separated argument list (may contain function prototypes)" + "parse a comma-separated argument list (including function prototypes)" self.args = [] self.variadic = False self.variadic_decl = "" self.variadic_start = "" self.variadic_end = "" - self.prologue_call_real = "/* pass the call on to the underlying syscall */" + self.prologue_call_real = \ + "/* pass the call on to the underlying syscall */" # (void) is an empty list, not a list of a single argument which is void if text == "void": return @@ -148,7 +148,7 @@ class ArgumentList: if (depth > 0): accum += arg + ', ' else: - self.args.append(C_Argument(accum + arg)) + self.args.append(Argument(accum + arg)) accum = '' if depth != 0: raise Exception("mismatched ()s while parsing '%s'" % text) @@ -159,36 +159,59 @@ class ArgumentList: self.variadic_decl = "va_list ap;\n" self.variadic_start = "va_start(ap, %s);\n" % self.last_fixed_arg if self.variadic_arg.vararg_wraps: - self.variadic_decl += "\t%s;\n" % self.variadic_arg.vararg_wraps.decl() - self.variadic_start += "\t%s = va_arg(ap, %s);\n\tva_end(ap);\n" % (self.variadic_arg.name, self.variadic_arg.type) + self.variadic_decl += "\t%s;\n" % \ + self.variadic_arg.vararg_wraps.decl() + self.variadic_start += ("\t%s = va_arg(ap, %s);" + "\n\tva_end(ap);\n") % \ + (self.variadic_arg.name, + self.variadic_arg.type) else: self.variadic_end = "va_end(ap);\n" - self.prologue_call_real = '/* no way to pass a ... */\n\t\t\t\tassert(!"cannot chain to real versions of variadic functions");' + self.prologue_call_real = ('/* no way to pass a ... */' + '\n\t\t\t\tassert(!"cannot chain ' + 'to real versions of variadic' + 'functions");') + + # for a wrap function, the outer foo() wrapper will convert to a va_list, + # but the inner wrap_foo() just passes the va_list through. + def maybe_variadic_start(self): + """Use va_arg() to grab an optional argument if needed.""" + if self.variadic and self.variadic_arg.vararg_wraps: + return self.variadic_start + else: + return "" + + def maybe_variadic_decl(self): + """Declare va_list ap and optional argument, if needed.""" + if self.variadic and self.variadic_arg.vararg_wraps: + return self.variadic_decl + else: + return "" - def decl(self, **kw): + def decl(self, comment=False, wrap=False): + """Produce the declaration form of this argument list.""" if not self.args: return "void" - list = map(lambda x: x.decl(**kw), self.args) - return ', '.join(list) + return ', '.join(x.decl(comment=comment, wrap=wrap) for x in self.args) def call(self): + """Produce the calling form of this argument list.""" if not self.args: return "" - list = map(lambda x: x.call(), self.args) - return ', '.join(list) + return ', '.join([x.call() for x in self.args]) def __repr__(self): if not self.args: return "no arguments" else: - return '::'.join(map(lambda x:x.decl(), self.args)) + return '::'.join([x.decl() for x in self.args]) -class C_Argument: - "A function argument such as 'char *path' or 'char (*foo)(void)'" +class Argument: + """A function argument such as 'char *path' or 'char (*foo)(void)'""" def __init__(self, text): - "get the type and name of a trivial C declaration" + """get the type and name of a trivial C declaration""" self.vararg = False self.function_pointer = False self.spacer = '' @@ -202,9 +225,9 @@ class C_Argument: # we're a wrapper for something else, declared as # ...{real_decl}, as in the third argument to open(2) text = text[4:-1] - # stash a copy of these values without the vararg flag, so we can - # declare them prettily later - self.vararg_wraps = C_Argument(text) + # stash a copy of these values without the vararg flag, so + # we can declare them prettily later + self.vararg_wraps = Argument(text) else: # nothing to do. self.vararg_wraps = None @@ -218,17 +241,15 @@ class C_Argument: if match: self.function_pointer = True self.args = match.group(3) - ret_type = match.group(1) - args = match.group(3) - self.fulltype = "$ret_type(*)($args)" - self.name = match.group(2).rstrip(' ') - self.type = ret_type + self.type = match.group(1) + self.name = match.group(2).rstrip() else: # plain declaration match = re.match('(.*[ *])\(?\*?([a-zA-Z0-9_]*)\)?', text) - # there may not be a match, say in the special case where an arg is '...' + # there may not be a match, say in the special case + # where an arg is '...' if match: - self.type, self.name = match.group(1).rstrip(' '), match.group(2) + self.type, self.name = match.group(1).rstrip(), match.group(2) else: self.type, self.name = None, None @@ -237,10 +258,11 @@ class C_Argument: if re.match('[_a-zA-Z0-9]', self.type[-1]): self.spacer = ' ' - def decl(self, **kw): - comment = kw.get('comment', False) + def decl(self, comment=False, wrap=False): + """Produce the declaration form of this argument.""" if self.function_pointer: - decl = "%s%s(*%s)(%s)" % (self.type, self.spacer, self.name, self.args) + decl = "%s%s(*%s)(%s)" % \ + (self.type, self.spacer, self.name, self.args) else: decl = "%s%s%s" % (self.type, self.spacer, self.name) @@ -251,10 +273,14 @@ class C_Argument: else: decl = "... /* %s */" % decl else: - decl = "..." + if wrap: + decl = "va_list ap" + else: + decl = "..." return decl def call(self): + """Produce the call form of this argument (usually its name).""" if self.type == 'void': return '' @@ -263,17 +289,23 @@ class C_Argument: return self.name - def str(self): + def __str__(self): return self.decl() def __repr__(self): return self.decl() -class C_Function: - "A function signature and additional data about how the function works" +class Function: + """A function signature and additional data about how the function works""" def __init__(self, line): # table of known default values: - default_values = { 'gid_t': '0', 'uid_t': '0', 'int': '-1', 'long': '-1', 'ssize_t': '-1' } + default_values = { + 'gid_t': '0', + 'uid_t': '0', + 'int': '-1', + 'long': '-1', + 'ssize_t': '-1' + } self.dirfd = 'AT_FDCWD' self.flags = '0' @@ -289,11 +321,11 @@ class C_Function: self.comments = None bits = re.match('([^(]*)\((.*)\)', function) - x = C_Argument(bits.group(1)) - self.type, self.name = x.type, x.name - # it's convenient to have this declared here so we can use its .decl later + type_and_name = Argument(bits.group(1)) + self.type, self.name = type_and_name.type, type_and_name.name + # convenient to have this declared here so we can use its .decl later if self.type != 'void': - self.rc = C_Argument("%s rc" % x.type) + self.return_code = Argument("%s rc" % self.type) # Some args get special treatment: # * If the arg has a name ending in 'path', we will canonicalize it. @@ -322,81 +354,97 @@ class C_Function: try: self.default_value = default_values[self.type] except KeyError: - raise Exception("Function %s has return type %s, for which there is no default value." % (self.name, self.type)) + raise KeyError("Function %s has return type %s," + "for which there is no default value." % + (self.name, self.type)) # handle special comments, such as flags=AT_SYMLINK_NOFOLLOW if self.comments: modifiers = self.comments.split(', ') for mod in modifiers: key, value = mod.split('=') - value = value.rstrip(' ') + value = value.rstrip() setattr(self, key, value) def comment(self): + """declare self (in a comment)""" return self.decl(comment = True) - def decl(self, **kw): + def decl(self, comment=False, wrap=True): + """declare self""" if self.type[-1:] == '*': spacer = '' else: spacer = ' ' - return "%s%s%s(%s)" % (self.type, spacer, self.name, self.args.decl(**kw)) + return "%s%s%s(%s)" % \ + (self.type, spacer, self.name, self.args.decl(comment, wrap)) def decl_args(self): + """declare argument list""" return self.args.decl() def wrap_args(self): + """declare argument list for wrap_foo() variant""" return self.args.decl(wrap = True) def call_args(self): + """present argument list for a function call""" return self.args.call() def alloc_paths(self): + """create/allocate canonical paths""" alloc_paths = [] - for p in self.paths_to_munge: - alloc_paths.append("%s = pseudo_root_path(__func__, __LINE__, %s, %s, %s);" % (p, self.dirfd, p, self.flags)) - return "\n\t\t\t".join(alloc_paths); + for path in self.paths_to_munge: + alloc_paths.append( + "%s = pseudo_root_path(__func__, __LINE__, %s, %s, %s);" % + (path, self.dirfd, path, self.flags)) + return "\n\t\t\t".join(alloc_paths) def free_paths(self): + """free any allocated paths""" free_paths = [] # the cast is here because free's argument isn't const qualified, but - # the original path may have been -- but we only GET here if the path has - # been overwritten. - for p in self.paths_to_munge: - free_paths.append("free((void *) %s);" % p) - return "\n\t\t\t".join(free_paths); + # the original path may have been -- but we only GET here if the path + # has been overwritten. + for path in self.paths_to_munge: + free_paths.append("free((void *) %s);" % path) + return "\n\t\t\t".join(free_paths) def rc_return(self): + """return rc (or just return)""" if self.type == 'void': return "return;" else: return "return rc;" def rc_decl(self): + """declare rc (if needed)""" if self.type == 'void': return "" else: - return "%s = %s;" % (self.rc.decl(), self.default_value) + return "%s = %s;" % (self.return_code.decl(), self.default_value) def rc_assign(self): + """assign something to rc (or discard it)""" if self.type == 'void': return "(void)" else: return "rc =" def def_return(self): + """return default value (or just return)""" if self.type == 'void': return "return;" else: return "return %s;" % self.default_value def __getitem__(self, key): - "Make this object look like a dict for Templates to use" + """Make this object look like a dict for Templates to use""" try: attr = getattr(self, key) except AttributeError: - # There's a few attributes that are handled inside the args object, so check there - # too... + # There's a few attributes that are handled inside the args + # object, so check there too... attr = getattr(self.args, key) if callable(attr): @@ -411,14 +459,13 @@ class C_Function: pretty += ' (%s)' % self.comments return pretty -files = {} - def main(): + """Read in function defintions, write out files based on templates.""" funcs = [] sources = [] # error checking helpfully provided by the exception handler - copyright_file = file('guts/COPYRIGHT', 'r') + copyright_file = open('guts/COPYRIGHT') SourceFile.copyright = copyright_file.read() copyright_file.close() @@ -433,35 +480,35 @@ def main(): exit(1) for filename in sys.argv[1:]: - "parse the list of functions" + # parse the list of functions sys.stdout.write("%s: " % filename) - f = file(filename, 'r') - for line in f: - line = line.rstrip(" \r\n") - if line.startswith('#') or line == "": + funclist = open(filename) + for line in funclist: + line = line.rstrip() + if line.startswith('#') or not line: continue try: - func = C_Function(line) + func = Function(line) funcs.append(func) sys.stdout.write(".") - except Exception as e: + except Exception, e: print "Parsing failed:", e exit(1) - f.close() + funclist.close() print "" # the per-function stuff print "Writing functions...", for func in funcs: - "populate various tables and files with each function" + # populate various tables and files with each function for source in sources: source.emit('body', func) print "done. Cleaning up." for source in sources: - "clean up files" + # clean up files source.emit('footer') - del source + source.close() if __name__ == '__main__': main() |