#!/usr/bin/env python import string, sys, os.path, getopt escapes = {} escapes['\a'] = r'\a' escapes['\b'] = r'\b' escapes['\f'] = r'\f' escapes['\n'] = r'\n' escapes['\r'] = r'\r' #escapes['\t'] = r'\t' # Let's replace tabs with four spaces # so the text looks nicely indented in the C source escapes['\t'] = r' ' escapes['\v'] = r'\v' # escapes['\''] = r'\'' escapes['\"'] = r'\"' escapes['\\'] = r'\\' def escape(c): if c in escapes: return (escapes[c], False) elif c not in string.printable: return ("\\x%x" % ord(c), True) else: return (c, False) def stringize(line): newline = '"' was_escape = False for c in line: # Avoid an issue where characters after a hexadecimal escape are treated as part of that escape # by adding two quotes if was_escape and c in string.hexdigits: newline += '""' chars, was_escape = escape(c) newline += chars newline += '"' return newline class cfunc: def __init__(self, type, name, lines): self.type = type self.name = name self.lines = lines def cdef(self): result = "" result += "static const char * const {0} = \n\t".format(self.cfunc_name()) result += '\n\t'.join(self.lines) result += ';\n' return result def cfunc_name(self): # Translate - and . to underscore try: #Python 2 translator = string.maketrans('-.', '__') munged_name = string.translate(self.name, translator) except AttributeError: #Python 3 translator = "".maketrans('-.', '__') munged_name = self.name.translate(translator) return "{0}_{1}".format(self.type, munged_name) TYPES = ['function', 'completion'] type_to_funcs = dict((t, []) for t in TYPES) def usage(script_name): print("Usage: {0} [--output output_directory] files...".format(script_name)) print("""Command options are: --output directory\t\tThe directory to output the files -h, --help\t\t\tShow this help message """) script_name = sys.argv[0] try: opts, file_paths = getopt.gnu_getopt(sys.argv[1:], 'h', ['output=', 'help']) except getopt.GetoptError as err: print(err.msg) # will print something like "option -a not recognized" usage(script_name) sys.exit(2) output_directory = './' for opt, value in opts: if opt in ('--output',): output_directory = value elif opt in ('-h', '--help'): usage(script_name) sys.exit(0) else: assert False, "unhandled option" for file in file_paths: fd = open(file, 'r') newlines = [] for line in fd: newlines.append(stringize(line)) fd.close() dirname = os.path.dirname(file) # Try to figure out the file type (completion or function) matches = [dir in dirname for dir in TYPES] if matches.count(True) is not 1: print("Cannot determine the type of the file at path {0}".format(file)) sys.exit(-1) type = TYPES[matches.index(True)] name = os.path.basename(file) name, ext = os.path.splitext(name) newfunc = cfunc(type, name, newlines) type_to_funcs[type].append(newfunc) # Sort our functions by name for funcs in type_to_funcs.values(): funcs.sort(key=cfunc.cfunc_name) # Output our header fd = open(os.path.join(output_directory, 'builtin_scripts.h'), 'w') fd.write('/* This file is generated by internalize_scripts.py */\n\n') fd.write("""struct builtin_script_t { const wchar_t *name; const char *def; };""") fd.write('\n') for type in TYPES: funcs = type_to_funcs[type] fd.write('\n') fd.write('extern const struct builtin_script_t internal_{0}_scripts[{1}];'.format(type, len(funcs))) fd.write('\n') fd.close() # Output the function definitions fd = open(os.path.join(output_directory, 'builtin_scripts.cpp'), 'w') fd.write('/* This file is generated by internalize_scripts.py */\n\n') fd.write('#include "builtin_scripts.h"\n\n') for type in TYPES: for func in type_to_funcs[type]: fd.write(func.cdef()) fd.write('\n') # Output the refs for type in TYPES: funcs = type_to_funcs[type] func_refs = ["{0}L{1}, {2}{3}".format("{", stringize(func.name), func.cfunc_name(), "}") for func in funcs] fd.write('const struct builtin_script_t internal_{0}_scripts[{1}] =\n'.format(type, len(funcs))) fd.write('{\n\t') fd.write(',\n\t'.join(func_refs)) fd.write('\n};\n') fd.close()