diff options
Diffstat (limited to 'script/generate_param.py')
-rw-r--r-- | script/generate_param.py | 431 |
1 files changed, 431 insertions, 0 deletions
diff --git a/script/generate_param.py b/script/generate_param.py new file mode 100644 index 0000000..4a4f7fe --- /dev/null +++ b/script/generate_param.py @@ -0,0 +1,431 @@ +# Unix SMB/CIFS implementation. +# Copyright (C) 2014 Catalyst.Net Ltd +# +# Auto generate param_functions.c +# +# ** NOTE! The following LGPL license applies to the ldb +# ** library. This does NOT imply that all of Samba is released +# ** under the LGPL +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see <http://www.gnu.org/licenses/>. +# + +import os +import xml.etree.ElementTree as ET +import optparse + +# parse command line arguments +parser = optparse.OptionParser() +parser.add_option("-f", "--file", dest="filename", + help="input file", metavar="FILE") +parser.add_option("-o", "--output", dest="output", + help='output file', metavar="FILE") +parser.add_option("--mode", type="choice", metavar="<FUNCTIONS|S3PROTO|LIBPROTO|PARAMDEFS|PARAMTABLE>", + choices=["FUNCTIONS", "S3PROTO", "LIBPROTO", "PARAMDEFS", "PARAMTABLE"], default="FUNCTIONS") +parser.add_option("--scope", metavar="<GLOBAL|LOCAL>", + choices=["GLOBAL", "LOCAL"], default="GLOBAL") + +(options, args) = parser.parse_args() + +if options.filename is None: + parser.error("No input file specified") +if options.output is None: + parser.error("No output file specified") + + +def iterate_all(path): + """Iterate and yield all the parameters. + + :param path: path to parameters xml file + """ + + try: + p = open(path, 'r') + except IOError as e: + raise Exception("Error opening parameters file") + out = p.read() + + # parse the parameters xml file + root = ET.fromstring(out) + for parameter in root: + name = parameter.attrib.get("name") + param_type = parameter.attrib.get("type") + context = parameter.attrib.get("context") + func = parameter.attrib.get("function") + synonym = parameter.attrib.get("synonym") + removed = parameter.attrib.get("removed") + generated = parameter.attrib.get("generated_function") + handler = parameter.attrib.get("handler") + enumlist = parameter.attrib.get("enumlist") + deprecated = parameter.attrib.get("deprecated") + synonyms = parameter.findall('synonym') + + if removed == "1": + continue + + constant = parameter.attrib.get("constant") + substitution = parameter.attrib.get("substitution") + parm = parameter.attrib.get("parm") + if name is None or param_type is None or context is None: + raise Exception("Error parsing parameter: " + name) + if func is None: + func = name.replace(" ", "_").lower() + if enumlist is None: + enumlist = "NULL" + if handler is None: + handler = "NULL" + yield {'name': name, + 'type': param_type, + 'context': context, + 'function': func, + 'constant': (constant == '1'), + 'substitution': (substitution == '1'), + 'parm': (parm == '1'), + 'synonym' : synonym, + 'generated' : generated, + 'enumlist' : enumlist, + 'handler' : handler, + 'deprecated' : deprecated, + 'synonyms' : synonyms } + + +# map doc attributes to a section of the generated function +context_dict = {"G": "_GLOBAL", "S": "_LOCAL"} +param_type_dict = { + "boolean" : "_BOOL", + "list" : "_LIST", + "string" : "_STRING", + "integer" : "_INTEGER", + "enum" : "_INTEGER", + "char" : "_CHAR", + "boolean-auto" : "_INTEGER", + "cmdlist" : "_LIST", + "bytes" : "_INTEGER", + "octal" : "_INTEGER", + "ustring" : "_STRING", + } + + +def generate_functions(path_in, path_out): + f = open(path_out, 'w') + try: + f.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n') + for parameter in iterate_all(options.filename): + # filter out parameteric options + if ':' in parameter['name']: + continue + if parameter['synonym'] == "1": + continue + if parameter['generated'] == "0": + continue + + output_string = "FN" + temp = context_dict.get(parameter['context']) + if temp is None: + raise Exception(parameter['name'] + " has an invalid context " + parameter['context']) + output_string += temp + if parameter['type'] == "string" or parameter['type'] == "ustring": + if parameter['substitution']: + output_string += "_SUBSTITUTED" + else: + output_string += "_CONST" + if parameter['parm']: + output_string += "_PARM" + temp = param_type_dict.get(parameter['type']) + if temp is None: + raise Exception(parameter['name'] + " has an invalid param type " + parameter['type']) + output_string += temp + f.write(output_string + "(" + parameter['function'] + ", " + parameter['function'] + ')\n') + finally: + f.close() + + +mapping = { + 'boolean' : 'bool ', + 'string' : 'char *', + 'integer' : 'int ', + 'char' : 'char ', + 'list' : 'const char **', + 'enum' : 'int ', + 'boolean-auto' : 'int ', + 'cmdlist' : 'const char **', + 'bytes' : 'int ', + 'octal' : 'int ', + 'ustring' : 'char *', + } + + +def make_s3_param_proto(path_in, path_out): + file_out = open(path_out, 'w') + try: + file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n') + header = get_header(path_out) + file_out.write("#ifndef %s\n" % header) + file_out.write("#define %s\n\n" % header) + file_out.write("struct share_params;\n") + file_out.write("struct loadparm_substitution;\n") + for parameter in iterate_all(path_in): + # filter out parameteric options + if ':' in parameter['name']: + continue + if parameter['synonym'] == "1": + continue + if parameter['generated'] == "0": + continue + + output_string = "" + param_type = mapping.get(parameter['type']) + if param_type is None: + raise Exception(parameter['name'] + " has an invalid context " + parameter['context']) + output_string += param_type + output_string += "lp_%s" % parameter['function'] + + param = None + if parameter['parm']: + param = "const struct share_params *p" + else: + param = "int" + + if parameter['type'] == 'string' or parameter['type'] == 'ustring': + if parameter['substitution']: + if parameter['context'] == 'G': + output_string += '(TALLOC_CTX *ctx, const struct loadparm_substitution *lp_sub);\n' + elif parameter['context'] == 'S': + output_string += '(TALLOC_CTX *ctx, const struct loadparm_substitution *lp_sub, %s);\n' % param + else: + raise Exception(parameter['name'] + " has an invalid param type " + parameter['type']) + else: + if parameter['context'] == 'G': + output_string = 'const ' + output_string + '(void);\n' + elif parameter['context'] == 'S': + output_string = 'const ' + output_string + '(%s);\n' % param + else: + raise Exception(parameter['name'] + " has an invalid param type " + parameter['type']) + else: + if parameter['context'] == 'G': + output_string += '(void);\n' + elif parameter['context'] == 'S': + output_string += '(%s);\n' % param + else: + raise Exception(parameter['name'] + " has an invalid param type " + parameter['type']) + + file_out.write(output_string) + + file_out.write("\n#endif /* %s */\n\n" % header) + finally: + file_out.close() + + +def make_lib_proto(path_in, path_out): + file_out = open(path_out, 'w') + try: + file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n') + for parameter in iterate_all(path_in): + # filter out parameteric options + if ':' in parameter['name']: + continue + if parameter['synonym'] == "1": + continue + if parameter['generated'] == "0": + continue + + output_string = "" + param_type = mapping.get(parameter['type']) + if param_type is None: + raise Exception(parameter['name'] + " has an invalid context " + parameter['context']) + output_string += param_type + + output_string += "lpcfg_%s" % parameter['function'] + + if parameter['type'] == 'string' or parameter['type'] == 'ustring': + if parameter['substitution']: + if parameter['context'] == 'G': + output_string += '(struct loadparm_context *, const struct loadparm_substitution *lp_sub, TALLOC_CTX *ctx);\n' + elif parameter['context'] == 'S': + output_string += '(struct loadparm_service *, struct loadparm_service *, TALLOC_CTX *ctx);\n' + else: + raise Exception(parameter['name'] + " has an invalid context " + parameter['context']) + else: + if parameter['context'] == 'G': + output_string = 'const ' + output_string + '(struct loadparm_context *);\n' + elif parameter['context'] == 'S': + output_string = 'const ' + output_string + '(struct loadparm_service *, struct loadparm_service *);\n' + else: + raise Exception(parameter['name'] + " has an invalid param type " + parameter['type']) + else: + if parameter['context'] == 'G': + output_string += '(struct loadparm_context *);\n' + elif parameter['context'] == 'S': + output_string += '(struct loadparm_service *, struct loadparm_service *);\n' + else: + raise Exception(parameter['name'] + " has an invalid param type " + parameter['type']) + + file_out.write(output_string) + finally: + file_out.close() + + +def get_header(path): + header = os.path.basename(path).upper() + header = header.replace(".", "_").replace("\\", "_").replace("-", "_") + return "__%s__" % header + + +def make_param_defs(path_in, path_out, scope): + file_out = open(path_out, 'w') + try: + file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n') + header = get_header(path_out) + file_out.write("#ifndef %s\n" % header) + file_out.write("#define %s\n\n" % header) + if scope == "GLOBAL": + file_out.write("/**\n") + file_out.write(" * This structure describes global (ie., server-wide) parameters.\n") + file_out.write(" */\n") + file_out.write("struct loadparm_global \n") + file_out.write("{\n") + file_out.write("\tTALLOC_CTX *ctx; /* Context for talloced members */\n") + elif scope == "LOCAL": + file_out.write("/**\n") + file_out.write(" * This structure describes a single service.\n") + file_out.write(" */\n") + file_out.write("struct loadparm_service \n") + file_out.write("{\n") + file_out.write("\tbool autoloaded;\n") + + for parameter in iterate_all(path_in): + # filter out parameteric options + if ':' in parameter['name']: + continue + if parameter['synonym'] == "1": + continue + + if (scope == "GLOBAL" and parameter['context'] != "G" or + scope == "LOCAL" and parameter['context'] != "S"): + continue + + output_string = "\t" + param_type = mapping.get(parameter['type']) + if param_type is None: + raise Exception(parameter['name'] + " has an invalid context " + parameter['context']) + output_string += param_type + + output_string += " %s;\n" % parameter['function'] + file_out.write(output_string) + + file_out.write("LOADPARM_EXTRA_%sS\n" % scope) + file_out.write("};\n") + file_out.write("\n#endif /* %s */\n\n" % header) + finally: + file_out.close() + + +type_dict = { + "boolean" : "P_BOOL", + "boolean-rev" : "P_BOOLREV", + "boolean-auto" : "P_ENUM", + "list" : "P_LIST", + "string" : "P_STRING", + "integer" : "P_INTEGER", + "enum" : "P_ENUM", + "char" : "P_CHAR", + "cmdlist" : "P_CMDLIST", + "bytes" : "P_BYTES", + "octal" : "P_OCTAL", + "ustring" : "P_USTRING", + } + + +def make_param_table(path_in, path_out): + file_out = open(path_out, 'w') + try: + file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n') + header = get_header(path_out) + file_out.write("#ifndef %s\n" % header) + file_out.write("#define %s\n\n" % header) + + file_out.write("struct parm_struct parm_table[] = {\n") + + for parameter in iterate_all(path_in): + # filter out parameteric options + if ':' in parameter['name']: + continue + if parameter['context'] == 'G': + p_class = "P_GLOBAL" + else: + p_class = "P_LOCAL" + + p_type = type_dict.get(parameter['type']) + + if parameter['context'] == 'G': + temp = "GLOBAL" + else: + temp = "LOCAL" + offset = "%s_VAR(%s)" % (temp, parameter['function']) + + enumlist = parameter['enumlist'] + handler = parameter['handler'] + synonym = parameter['synonym'] + deprecated = parameter['deprecated'] + flags_list = [] + if synonym == "1": + flags_list.append("FLAG_SYNONYM") + if deprecated == "1": + flags_list.append("FLAG_DEPRECATED") + flags = "|".join(flags_list) + synonyms = parameter['synonyms'] + + file_out.write("\t{\n") + file_out.write("\t\t.label\t\t= \"%s\",\n" % parameter['name']) + file_out.write("\t\t.type\t\t= %s,\n" % p_type) + file_out.write("\t\t.p_class\t= %s,\n" % p_class) + file_out.write("\t\t.offset\t\t= %s,\n" % offset) + file_out.write("\t\t.special\t= %s,\n" % handler) + file_out.write("\t\t.enum_list\t= %s,\n" % enumlist) + if flags != "": + file_out.write("\t\t.flags\t\t= %s,\n" % flags) + file_out.write("\t},\n") + + if synonyms is not None: + # for synonyms, we only list the synonym flag: + flags = "FLAG_SYNONYM" + for syn in synonyms: + file_out.write("\t{\n") + file_out.write("\t\t.label\t\t= \"%s\",\n" % syn.text) + file_out.write("\t\t.type\t\t= %s,\n" % p_type) + file_out.write("\t\t.p_class\t= %s,\n" % p_class) + file_out.write("\t\t.offset\t\t= %s,\n" % offset) + file_out.write("\t\t.special\t= %s,\n" % handler) + file_out.write("\t\t.enum_list\t= %s,\n" % enumlist) + if flags != "": + file_out.write("\t\t.flags\t\t= %s,\n" % flags) + file_out.write("\t},\n") + + file_out.write("\n\t{ .label = NULL }\n") + file_out.write("};\n") + file_out.write("\n#endif /* %s */\n\n" % header) + finally: + file_out.close() + + +if options.mode == 'FUNCTIONS': + generate_functions(options.filename, options.output) +elif options.mode == 'S3PROTO': + make_s3_param_proto(options.filename, options.output) +elif options.mode == 'LIBPROTO': + make_lib_proto(options.filename, options.output) +elif options.mode == 'PARAMDEFS': + make_param_defs(options.filename, options.output, options.scope) +elif options.mode == 'PARAMTABLE': + make_param_table(options.filename, options.output) |