1 | # Unix SMB/CIFS implementation.
|
---|
2 | # Copyright (C) 2014 Catalyst.Net Ltd
|
---|
3 | #
|
---|
4 | # Auto generate param_functions.c
|
---|
5 | #
|
---|
6 | # ** NOTE! The following LGPL license applies to the ldb
|
---|
7 | # ** library. This does NOT imply that all of Samba is released
|
---|
8 | # ** under the LGPL
|
---|
9 | #
|
---|
10 | # This library is free software; you can redistribute it and/or
|
---|
11 | # modify it under the terms of the GNU Lesser General Public
|
---|
12 | # License as published by the Free Software Foundation; either
|
---|
13 | # version 3 of the License, or (at your option) any later version.
|
---|
14 | #
|
---|
15 | # This library is distributed in the hope that it will be useful,
|
---|
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
18 | # Lesser General Public License for more details.
|
---|
19 | #
|
---|
20 | # You should have received a copy of the GNU Lesser General Public
|
---|
21 | # License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
---|
22 | #
|
---|
23 |
|
---|
24 | import errno
|
---|
25 | import os
|
---|
26 | import re
|
---|
27 | import subprocess
|
---|
28 | import xml.etree.ElementTree as ET
|
---|
29 | import sys
|
---|
30 | import optparse
|
---|
31 |
|
---|
32 | # parse command line arguments
|
---|
33 | parser = optparse.OptionParser()
|
---|
34 | parser.add_option("-f", "--file", dest="filename",
|
---|
35 | help="input file", metavar="FILE")
|
---|
36 | parser.add_option("-o", "--output", dest="output",
|
---|
37 | help='output file', metavar="FILE")
|
---|
38 | parser.add_option("--mode", type="choice", metavar="<FUNCTIONS|S3PROTO|LIBPROTO|PARAMDEFS|PARAMTABLE>",
|
---|
39 | choices=["FUNCTIONS", "S3PROTO", "LIBPROTO", "PARAMDEFS", "PARAMTABLE"], default="FUNCTIONS")
|
---|
40 | parser.add_option("--scope", metavar="<GLOBAL|LOCAL>",
|
---|
41 | choices = ["GLOBAL", "LOCAL"], default="GLOBAL")
|
---|
42 |
|
---|
43 | (options, args) = parser.parse_args()
|
---|
44 |
|
---|
45 | if options.filename is None:
|
---|
46 | parser.error("No input file specified")
|
---|
47 | if options.output is None:
|
---|
48 | parser.error("No output file specified")
|
---|
49 |
|
---|
50 | def iterate_all(path):
|
---|
51 | """Iterate and yield all the parameters.
|
---|
52 |
|
---|
53 | :param path: path to parameters xml file
|
---|
54 | """
|
---|
55 |
|
---|
56 | try:
|
---|
57 | p = open(path, 'r')
|
---|
58 | except IOError, e:
|
---|
59 | raise Exception("Error opening parameters file")
|
---|
60 | out = p.read()
|
---|
61 |
|
---|
62 | # parse the parameters xml file
|
---|
63 | root = ET.fromstring(out)
|
---|
64 | for parameter in root:
|
---|
65 | name = parameter.attrib.get("name")
|
---|
66 | param_type = parameter.attrib.get("type")
|
---|
67 | context = parameter.attrib.get("context")
|
---|
68 | func = parameter.attrib.get("function")
|
---|
69 | synonym = parameter.attrib.get("synonym")
|
---|
70 | removed = parameter.attrib.get("removed")
|
---|
71 | generated = parameter.attrib.get("generated_function")
|
---|
72 | handler = parameter.attrib.get("handler")
|
---|
73 | enumlist = parameter.attrib.get("enumlist")
|
---|
74 | deprecated = parameter.attrib.get("deprecated")
|
---|
75 | synonyms = parameter.findall('synonym')
|
---|
76 |
|
---|
77 | if removed == "1":
|
---|
78 | continue
|
---|
79 |
|
---|
80 | constant = parameter.attrib.get("constant")
|
---|
81 | parm = parameter.attrib.get("parm")
|
---|
82 | if name is None or param_type is None or context is None:
|
---|
83 | raise Exception("Error parsing parameter: " + name)
|
---|
84 | if func is None:
|
---|
85 | func = name.replace(" ", "_").lower()
|
---|
86 | if enumlist is None:
|
---|
87 | enumlist = "NULL"
|
---|
88 | if handler is None:
|
---|
89 | handler = "NULL"
|
---|
90 | yield {'name': name,
|
---|
91 | 'type': param_type,
|
---|
92 | 'context': context,
|
---|
93 | 'function': func,
|
---|
94 | 'constant': (constant == '1'),
|
---|
95 | 'parm': (parm == '1'),
|
---|
96 | 'synonym' : synonym,
|
---|
97 | 'generated' : generated,
|
---|
98 | 'enumlist' : enumlist,
|
---|
99 | 'handler' : handler,
|
---|
100 | 'deprecated' : deprecated,
|
---|
101 | 'synonyms' : synonyms }
|
---|
102 |
|
---|
103 | # map doc attributes to a section of the generated function
|
---|
104 | context_dict = {"G": "_GLOBAL", "S": "_LOCAL"}
|
---|
105 | param_type_dict = {
|
---|
106 | "boolean" : "_BOOL",
|
---|
107 | "list" : "_LIST",
|
---|
108 | "string" : "_STRING",
|
---|
109 | "integer" : "_INTEGER",
|
---|
110 | "enum" : "_INTEGER",
|
---|
111 | "char" : "_CHAR",
|
---|
112 | "boolean-auto" : "_INTEGER",
|
---|
113 | "cmdlist" : "_LIST",
|
---|
114 | "bytes" : "_INTEGER",
|
---|
115 | "octal" : "_INTEGER",
|
---|
116 | "ustring" : "_STRING",
|
---|
117 | }
|
---|
118 |
|
---|
119 | def generate_functions(path_in, path_out):
|
---|
120 | f = open(path_out, 'w')
|
---|
121 | try:
|
---|
122 | f.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n')
|
---|
123 | for parameter in iterate_all(options.filename):
|
---|
124 | # filter out parameteric options
|
---|
125 | if ':' in parameter['name']:
|
---|
126 | continue
|
---|
127 | if parameter['synonym'] == "1":
|
---|
128 | continue
|
---|
129 | if parameter['generated'] == "0":
|
---|
130 | continue
|
---|
131 |
|
---|
132 | output_string = "FN"
|
---|
133 | temp = context_dict.get(parameter['context'])
|
---|
134 | if temp is None:
|
---|
135 | raise Exception(parameter['name'] + " has an invalid context " + parameter['context'])
|
---|
136 | output_string += temp
|
---|
137 | if parameter['constant']:
|
---|
138 | output_string += "_CONST"
|
---|
139 | if parameter['parm']:
|
---|
140 | output_string += "_PARM"
|
---|
141 | temp = param_type_dict.get(parameter['type'])
|
---|
142 | if temp is None:
|
---|
143 | raise Exception(parameter['name'] + " has an invalid param type " + parameter['type'])
|
---|
144 | output_string += temp
|
---|
145 | f.write(output_string + "(" + parameter['function'] +", " + parameter['function'] + ')\n')
|
---|
146 | finally:
|
---|
147 | f.close()
|
---|
148 |
|
---|
149 | mapping = {
|
---|
150 | 'boolean' : 'bool ',
|
---|
151 | 'string' : 'char *',
|
---|
152 | 'integer' : 'int ',
|
---|
153 | 'char' : 'char ',
|
---|
154 | 'list' : 'const char **',
|
---|
155 | 'enum' : 'int ',
|
---|
156 | 'boolean-auto' : 'int ',
|
---|
157 | 'cmdlist' : 'const char **',
|
---|
158 | 'bytes' : 'int ',
|
---|
159 | 'octal' : 'int ',
|
---|
160 | 'ustring' : 'char *',
|
---|
161 | }
|
---|
162 |
|
---|
163 | def make_s3_param_proto(path_in, path_out):
|
---|
164 | file_out = open(path_out, 'w')
|
---|
165 | try:
|
---|
166 | file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n')
|
---|
167 | header = get_header(path_out)
|
---|
168 | file_out.write("#ifndef %s\n" % header)
|
---|
169 | file_out.write("#define %s\n\n" % header)
|
---|
170 | for parameter in iterate_all(path_in):
|
---|
171 | # filter out parameteric options
|
---|
172 | if ':' in parameter['name']:
|
---|
173 | continue
|
---|
174 | if parameter['synonym'] == "1":
|
---|
175 | continue
|
---|
176 | if parameter['generated'] == "0":
|
---|
177 | continue
|
---|
178 |
|
---|
179 | output_string = ""
|
---|
180 | if parameter['constant']:
|
---|
181 | output_string += 'const '
|
---|
182 | param_type = mapping.get(parameter['type'])
|
---|
183 | if param_type is None:
|
---|
184 | raise Exception(parameter['name'] + " has an invalid context " + parameter['context'])
|
---|
185 | output_string += param_type
|
---|
186 | output_string += "lp_%s" % parameter['function']
|
---|
187 |
|
---|
188 | param = None
|
---|
189 | if parameter['parm']:
|
---|
190 | param = "const struct share_params *p"
|
---|
191 | else:
|
---|
192 | param = "int"
|
---|
193 |
|
---|
194 | if parameter['type'] == 'string' and not parameter['constant']:
|
---|
195 | if parameter['context'] == 'G':
|
---|
196 | output_string += '(TALLOC_CTX *ctx);\n'
|
---|
197 | elif parameter['context'] == 'S':
|
---|
198 | output_string += '(TALLOC_CTX *ctx, %s);\n' % param
|
---|
199 | else:
|
---|
200 | raise Exception(parameter['name'] + " has an invalid param type " + parameter['type'])
|
---|
201 | else:
|
---|
202 | if parameter['context'] == 'G':
|
---|
203 | output_string += '(void);\n'
|
---|
204 | elif parameter['context'] == 'S':
|
---|
205 | output_string += '(%s);\n' % param
|
---|
206 | else:
|
---|
207 | raise Exception(parameter['name'] + " has an invalid param type " + parameter['type'])
|
---|
208 |
|
---|
209 | file_out.write(output_string)
|
---|
210 |
|
---|
211 | file_out.write("\n#endif /* %s */\n\n" % header)
|
---|
212 | finally:
|
---|
213 | file_out.close()
|
---|
214 |
|
---|
215 |
|
---|
216 | def make_lib_proto(path_in, path_out):
|
---|
217 | file_out = open(path_out, 'w')
|
---|
218 | try:
|
---|
219 | file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n')
|
---|
220 | for parameter in iterate_all(path_in):
|
---|
221 | # filter out parameteric options
|
---|
222 | if ':' in parameter['name']:
|
---|
223 | continue
|
---|
224 | if parameter['synonym'] == "1":
|
---|
225 | continue
|
---|
226 | if parameter['generated'] == "0":
|
---|
227 | continue
|
---|
228 |
|
---|
229 | output_string = ""
|
---|
230 | if parameter['constant']:
|
---|
231 | output_string += 'const '
|
---|
232 | param_type = mapping.get(parameter['type'])
|
---|
233 | if param_type is None:
|
---|
234 | raise Exception(parameter['name'] + " has an invalid context " + parameter['context'])
|
---|
235 | output_string += param_type
|
---|
236 |
|
---|
237 | output_string += "lpcfg_%s" % parameter['function']
|
---|
238 |
|
---|
239 | if parameter['type'] == 'string' and not parameter['constant']:
|
---|
240 | if parameter['context'] == 'G':
|
---|
241 | output_string += '(struct loadparm_context *, TALLOC_CTX *ctx);\n'
|
---|
242 | elif parameter['context'] == 'S':
|
---|
243 | output_string += '(struct loadparm_service *, struct loadparm_service *, TALLOC_CTX *ctx);\n'
|
---|
244 | else:
|
---|
245 | raise Exception(parameter['name'] + " has an invalid param type " + parameter['type'])
|
---|
246 | else:
|
---|
247 | if parameter['context'] == 'G':
|
---|
248 | output_string += '(struct loadparm_context *);\n'
|
---|
249 | elif parameter['context'] == 'S':
|
---|
250 | output_string += '(struct loadparm_service *, struct loadparm_service *);\n'
|
---|
251 | else:
|
---|
252 | raise Exception(parameter['name'] + " has an invalid param type " + parameter['type'])
|
---|
253 |
|
---|
254 |
|
---|
255 | file_out.write(output_string)
|
---|
256 | finally:
|
---|
257 | file_out.close()
|
---|
258 |
|
---|
259 | def get_header(path):
|
---|
260 | header = os.path.basename(path).upper()
|
---|
261 | header = header.replace(".", "_").replace("\\", "_").replace("-", "_")
|
---|
262 | return "__%s__" % header
|
---|
263 |
|
---|
264 | def make_param_defs(path_in, path_out, scope):
|
---|
265 | file_out = open(path_out, 'w')
|
---|
266 | try:
|
---|
267 | file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n')
|
---|
268 | header = get_header(path_out)
|
---|
269 | file_out.write("#ifndef %s\n" % header)
|
---|
270 | file_out.write("#define %s\n\n" % header)
|
---|
271 | if scope == "GLOBAL":
|
---|
272 | file_out.write("/**\n")
|
---|
273 | file_out.write(" * This structure describes global (ie., server-wide) parameters.\n")
|
---|
274 | file_out.write(" */\n")
|
---|
275 | file_out.write("struct loadparm_global \n")
|
---|
276 | file_out.write("{\n")
|
---|
277 | file_out.write("\tTALLOC_CTX *ctx; /* Context for talloced members */\n")
|
---|
278 | elif scope == "LOCAL":
|
---|
279 | file_out.write("/**\n")
|
---|
280 | file_out.write(" * This structure describes a single service.\n")
|
---|
281 | file_out.write(" */\n")
|
---|
282 | file_out.write("struct loadparm_service \n")
|
---|
283 | file_out.write("{\n")
|
---|
284 | file_out.write("\tbool autoloaded;\n")
|
---|
285 |
|
---|
286 | for parameter in iterate_all(path_in):
|
---|
287 | # filter out parameteric options
|
---|
288 | if ':' in parameter['name']:
|
---|
289 | continue
|
---|
290 | if parameter['synonym'] == "1":
|
---|
291 | continue
|
---|
292 |
|
---|
293 | if (scope == "GLOBAL" and parameter['context'] != "G" or
|
---|
294 | scope == "LOCAL" and parameter['context'] != "S"):
|
---|
295 | continue
|
---|
296 |
|
---|
297 | output_string = "\t"
|
---|
298 | param_type = mapping.get(parameter['type'])
|
---|
299 | if param_type is None:
|
---|
300 | raise Exception(parameter['name'] + " has an invalid context " + parameter['context'])
|
---|
301 | output_string += param_type
|
---|
302 |
|
---|
303 | output_string += " %s;\n" % parameter['function']
|
---|
304 | file_out.write(output_string)
|
---|
305 |
|
---|
306 | file_out.write("LOADPARM_EXTRA_%sS\n" % scope)
|
---|
307 | file_out.write("};\n")
|
---|
308 | file_out.write("\n#endif /* %s */\n\n" % header)
|
---|
309 | finally:
|
---|
310 | file_out.close()
|
---|
311 |
|
---|
312 | type_dict = {
|
---|
313 | "boolean" : "P_BOOL",
|
---|
314 | "boolean-rev" : "P_BOOLREV",
|
---|
315 | "boolean-auto" : "P_ENUM",
|
---|
316 | "list" : "P_LIST",
|
---|
317 | "string" : "P_STRING",
|
---|
318 | "integer" : "P_INTEGER",
|
---|
319 | "enum" : "P_ENUM",
|
---|
320 | "char" : "P_CHAR",
|
---|
321 | "cmdlist" : "P_CMDLIST",
|
---|
322 | "bytes" : "P_BYTES",
|
---|
323 | "octal" : "P_OCTAL",
|
---|
324 | "ustring" : "P_USTRING",
|
---|
325 | }
|
---|
326 |
|
---|
327 | def make_param_table(path_in, path_out):
|
---|
328 | file_out = open(path_out, 'w')
|
---|
329 | try:
|
---|
330 | file_out.write('/* This file was automatically generated by generate_param.py. DO NOT EDIT */\n\n')
|
---|
331 | header = get_header(path_out)
|
---|
332 | file_out.write("#ifndef %s\n" % header)
|
---|
333 | file_out.write("#define %s\n\n" % header)
|
---|
334 |
|
---|
335 | file_out.write("struct parm_struct parm_table[] = {\n")
|
---|
336 |
|
---|
337 | for parameter in iterate_all(path_in):
|
---|
338 | # filter out parameteric options
|
---|
339 | if ':' in parameter['name']:
|
---|
340 | continue
|
---|
341 | if parameter['context'] == 'G':
|
---|
342 | p_class = "P_GLOBAL"
|
---|
343 | else:
|
---|
344 | p_class = "P_LOCAL"
|
---|
345 |
|
---|
346 | p_type = type_dict.get(parameter['type'])
|
---|
347 |
|
---|
348 | if parameter['context'] == 'G':
|
---|
349 | temp = "GLOBAL"
|
---|
350 | else:
|
---|
351 | temp = "LOCAL"
|
---|
352 | offset = "%s_VAR(%s)" % (temp, parameter['function'])
|
---|
353 |
|
---|
354 | enumlist = parameter['enumlist']
|
---|
355 | handler = parameter['handler']
|
---|
356 | synonym = parameter['synonym']
|
---|
357 | deprecated = parameter['deprecated']
|
---|
358 | flags_list = []
|
---|
359 | if synonym == "1":
|
---|
360 | flags_list.append("FLAG_SYNONYM")
|
---|
361 | if deprecated == "1":
|
---|
362 | flags_list.append("FLAG_DEPRECATED")
|
---|
363 | flags = "|".join(flags_list)
|
---|
364 | synonyms = parameter['synonyms']
|
---|
365 |
|
---|
366 | file_out.write("\t{\n")
|
---|
367 | file_out.write("\t\t.label\t\t= \"%s\",\n" % parameter['name'])
|
---|
368 | file_out.write("\t\t.type\t\t= %s,\n" % p_type)
|
---|
369 | file_out.write("\t\t.p_class\t= %s,\n" % p_class)
|
---|
370 | file_out.write("\t\t.offset\t\t= %s,\n" % offset)
|
---|
371 | file_out.write("\t\t.special\t= %s,\n" % handler)
|
---|
372 | file_out.write("\t\t.enum_list\t= %s,\n" % enumlist)
|
---|
373 | if flags != "":
|
---|
374 | file_out.write("\t\t.flags\t\t= %s,\n" % flags)
|
---|
375 | file_out.write("\t},\n")
|
---|
376 |
|
---|
377 | if synonyms is not None:
|
---|
378 | # for synonyms, we only list the synonym flag:
|
---|
379 | flags = "FLAG_SYNONYM"
|
---|
380 | for syn in synonyms:
|
---|
381 | file_out.write("\t{\n")
|
---|
382 | file_out.write("\t\t.label\t\t= \"%s\",\n" % syn.text)
|
---|
383 | file_out.write("\t\t.type\t\t= %s,\n" % p_type)
|
---|
384 | file_out.write("\t\t.p_class\t= %s,\n" % p_class)
|
---|
385 | file_out.write("\t\t.offset\t\t= %s,\n" % offset)
|
---|
386 | file_out.write("\t\t.special\t= %s,\n" % handler)
|
---|
387 | file_out.write("\t\t.enum_list\t= %s,\n" % enumlist)
|
---|
388 | if flags != "":
|
---|
389 | file_out.write("\t\t.flags\t\t= %s,\n" % flags)
|
---|
390 | file_out.write("\t},\n")
|
---|
391 |
|
---|
392 | file_out.write("\n\t{NULL, P_BOOL, P_NONE, 0, NULL, NULL, 0}\n");
|
---|
393 | file_out.write("};\n")
|
---|
394 | file_out.write("\n#endif /* %s */\n\n" % header)
|
---|
395 | finally:
|
---|
396 | file_out.close()
|
---|
397 |
|
---|
398 | if options.mode == 'FUNCTIONS':
|
---|
399 | generate_functions(options.filename, options.output)
|
---|
400 | elif options.mode == 'S3PROTO':
|
---|
401 | make_s3_param_proto(options.filename, options.output)
|
---|
402 | elif options.mode == 'LIBPROTO':
|
---|
403 | make_lib_proto(options.filename, options.output)
|
---|
404 | elif options.mode == 'PARAMDEFS':
|
---|
405 | make_param_defs(options.filename, options.output, options.scope)
|
---|
406 | elif options.mode == 'PARAMTABLE':
|
---|
407 | make_param_table(options.filename, options.output)
|
---|