# 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 . # 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="", choices=["FUNCTIONS", "S3PROTO", "LIBPROTO", "PARAMDEFS", "PARAMTABLE"], default="FUNCTIONS") parser.add_option("--scope", metavar="", 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") 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'), '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['constant']: 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) 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 = "" if parameter['constant']: output_string += 'const ' 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' and not parameter['constant']: if parameter['context'] == 'G': output_string += '(TALLOC_CTX *ctx);\n' elif parameter['context'] == 'S': output_string += '(TALLOC_CTX *ctx, %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 = "" if parameter['constant']: output_string += 'const ' 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' and not parameter['constant']: if parameter['context'] == 'G': output_string += '(struct loadparm_context *, 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 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)