3 # This is the API builder, it parses the C sources and build the
4 # API formal description in XML.
6 # See Copyright for the status of this software.
15 #debugsym='ignorableWhitespaceSAXFunc'
19 # C parser analysis code
22 "trio": "too many non standard macros",
23 "trio.c": "too many non standard macros",
24 "trionan.c": "too many non standard macros",
25 "triostr.c": "too many non standard macros",
26 "acconfig.h": "generated portability layer",
27 "config.h": "generated portability layer",
28 "libxml.h": "internal only",
29 "testOOM.c": "out of memory tester",
30 "testOOMlib.h": "out of memory tester",
31 "testOOMlib.c": "out of memory tester",
32 "rngparser.c": "not yet integrated",
33 "rngparser.h": "not yet integrated",
34 "elfgcchack.h": "not a normal header",
35 "testHTML.c": "test tool",
36 "testReader.c": "test tool",
37 "testSchemas.c": "test tool",
38 "testXPath.c": "test tool",
39 "testAutomata.c": "test tool",
40 "testModule.c": "test tool",
41 "testRegexp.c": "test tool",
42 "testThreads.c": "test tool",
43 "testC14N.c": "test tool",
44 "testRelax.c": "test tool",
45 "testThreadsWin32.c": "test tool",
46 "testSAX.c": "test tool",
47 "testURI.c": "test tool",
48 "testapi.c": "generated regression tests",
49 "runtest.c": "regression tests program",
50 "runsuite.c": "regression tests program",
51 "tst.c": "not part of the library",
52 "test.c": "not part of the library",
53 "testdso.c": "test for dynamid shared libraries",
54 "testrecurse.c": "test for entities recursions",
55 "xzlib.h": "Internal API only 2.8.0",
56 "buf.h": "Internal API only 2.9.0",
57 "enc.h": "Internal API only 2.9.0",
58 "/save.h": "Internal API only 2.9.0",
59 "timsort.h": "Internal header only for xpath.c 2.9.0",
63 "WINAPI": (0, "Windows keyword"),
64 "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
65 "XMLPUBVAR": (0, "Special macro for extern vars for win32"),
66 "XSLTPUBVAR": (0, "Special macro for extern vars for win32"),
67 "EXSLTPUBVAR": (0, "Special macro for extern vars for win32"),
68 "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
69 "XSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
70 "EXSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
71 "XMLCALL": (0, "Special macro for win32 calls"),
72 "XSLTCALL": (0, "Special macro for win32 calls"),
73 "XMLCDECL": (0, "Special macro for win32 calls"),
74 "EXSLTCALL": (0, "Special macro for win32 calls"),
75 "__declspec": (3, "Windows keyword"),
76 "__stdcall": (0, "Windows keyword"),
77 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
78 "LIBEXSLT_PUBLIC": (0, "macro keyword"),
79 "X_IN_Y": (5, "macro function builder"),
80 "ATTRIBUTE_ALLOC_SIZE": (3, "macro for gcc checking extension"),
81 "ATTRIBUTE_PRINTF": (5, "macro for gcc printf args checking extension"),
82 "LIBXML_ATTR_FORMAT": (5, "macro for gcc printf args checking extension"),
83 "LIBXML_ATTR_ALLOC_SIZE": (3, "macro for gcc checking extension"),
87 raw = raw.replace('&', '&')
88 raw = raw.replace('<', '<')
89 raw = raw.replace('>', '>')
90 raw = raw.replace("'", ''')
91 raw = raw.replace('"', '"')
101 def __init__(self, name, header=None, module=None, type=None, lineno = 0,
102 info=None, extra=None, conditionals = None):
111 if conditionals == None or len(conditionals) == 0:
112 self.conditionals = None
114 self.conditionals = conditionals[:]
115 if self.name == debugsym:
116 print("=> define %s : %s" % (debugsym, (module, type, info,
117 extra, conditionals)))
120 r = "%s %s:" % (self.type, self.name)
123 if self.module != None:
124 r = r + " from %s" % (self.module)
125 if self.info != None:
126 r = r + " " + repr(self.info)
127 if self.extra != None:
128 r = r + " " + repr(self.extra)
129 if self.conditionals != None:
130 r = r + " " + repr(self.conditionals)
134 def set_header(self, header):
136 def set_module(self, module):
138 def set_type(self, type):
140 def set_info(self, info):
142 def set_extra(self, extra):
144 def set_lineno(self, lineno):
146 def set_static(self, static):
148 def set_conditionals(self, conditionals):
149 if conditionals == None or len(conditionals) == 0:
150 self.conditionals = None
152 self.conditionals = conditionals[:]
156 def get_header(self):
158 def get_module(self):
164 def get_lineno(self):
168 def get_static(self):
170 def get_conditionals(self):
171 return self.conditionals
173 def update(self, header, module, type = None, info = None, extra=None,
175 if self.name == debugsym:
176 print("=> update %s : %s" % (debugsym, (module, type, info,
177 extra, conditionals)))
178 if header != None and self.header == None:
179 self.set_header(module)
180 if module != None and (self.module == None or self.header == self.module):
181 self.set_module(module)
182 if type != None and self.type == None:
187 self.set_extra(extra)
188 if conditionals != None:
189 self.set_conditionals(conditionals)
192 def __init__(self, name = "noname"):
194 self.identifiers = {}
205 def add_ref(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
206 if name[0:2] == '__':
210 d = self.identifiers[name]
211 d.update(header, module, type, lineno, info, extra, conditionals)
213 d = identifier(name, header, module, type, lineno, info, extra, conditionals)
214 self.identifiers[name] = d
216 if d != None and static == 1:
219 if d != None and name != None and type != None:
220 self.references[name] = d
223 print("New ref: %s" % (d))
227 def add(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
228 if name[0:2] == '__':
232 d = self.identifiers[name]
233 d.update(header, module, type, lineno, info, extra, conditionals)
235 d = identifier(name, header, module, type, lineno, info, extra, conditionals)
236 self.identifiers[name] = d
238 if d != None and static == 1:
241 if d != None and name != None and type != None:
242 if type == "function":
243 self.functions[name] = d
244 elif type == "functype":
245 self.functions[name] = d
246 elif type == "variable":
247 self.variables[name] = d
248 elif type == "include":
249 self.includes[name] = d
250 elif type == "struct":
251 self.structs[name] = d
254 elif type == "typedef":
255 self.typedefs[name] = d
256 elif type == "macro":
257 self.macros[name] = d
259 print("Unable to register type ", type)
262 print("New symbol: %s" % (d))
266 def merge(self, idx):
267 for id in list(idx.functions.keys()):
269 # macro might be used to override functions or variables
272 if id in self.macros:
274 if id in self.functions:
275 print("function %s from %s redeclared in %s" % (
276 id, self.functions[id].header, idx.functions[id].header))
278 self.functions[id] = idx.functions[id]
279 self.identifiers[id] = idx.functions[id]
280 for id in list(idx.variables.keys()):
282 # macro might be used to override functions or variables
285 if id in self.macros:
287 if id in self.variables:
288 print("variable %s from %s redeclared in %s" % (
289 id, self.variables[id].header, idx.variables[id].header))
291 self.variables[id] = idx.variables[id]
292 self.identifiers[id] = idx.variables[id]
293 for id in list(idx.structs.keys()):
294 if id in self.structs:
295 print("struct %s from %s redeclared in %s" % (
296 id, self.structs[id].header, idx.structs[id].header))
298 self.structs[id] = idx.structs[id]
299 self.identifiers[id] = idx.structs[id]
300 for id in list(idx.typedefs.keys()):
301 if id in self.typedefs:
302 print("typedef %s from %s redeclared in %s" % (
303 id, self.typedefs[id].header, idx.typedefs[id].header))
305 self.typedefs[id] = idx.typedefs[id]
306 self.identifiers[id] = idx.typedefs[id]
307 for id in list(idx.macros.keys()):
309 # macro might be used to override functions or variables
312 if id in self.variables:
314 if id in self.functions:
318 if id in self.macros:
319 print("macro %s from %s redeclared in %s" % (
320 id, self.macros[id].header, idx.macros[id].header))
322 self.macros[id] = idx.macros[id]
323 self.identifiers[id] = idx.macros[id]
324 for id in list(idx.enums.keys()):
326 print("enum %s from %s redeclared in %s" % (
327 id, self.enums[id].header, idx.enums[id].header))
329 self.enums[id] = idx.enums[id]
330 self.identifiers[id] = idx.enums[id]
332 def merge_public(self, idx):
333 for id in list(idx.functions.keys()):
334 if id in self.functions:
335 # check that function condition agrees with header
336 if idx.functions[id].conditionals != \
337 self.functions[id].conditionals:
338 print("Header condition differs from Function for %s:" \
340 print(" H: %s" % self.functions[id].conditionals)
341 print(" C: %s" % idx.functions[id].conditionals)
342 up = idx.functions[id]
343 self.functions[id].update(None, up.module, up.type, up.info, up.extra)
345 # print "Function %s from %s is not declared in headers" % (
346 # id, idx.functions[id].module)
347 # TODO: do the same for variables.
349 def analyze_dict(self, type, dict):
352 for name in list(dict.keys()):
358 print(" %d %s , %d public" % (count, type, public))
360 print(" %d public %s" % (count, type))
364 self.analyze_dict("functions", self.functions)
365 self.analyze_dict("variables", self.variables)
366 self.analyze_dict("structs", self.structs)
367 self.analyze_dict("typedefs", self.typedefs)
368 self.analyze_dict("macros", self.macros)
371 """A lexer for the C language, tokenize the input by reading and
372 analyzing it line by line"""
373 def __init__(self, input):
382 line = self.input.readline()
385 self.lineno = self.lineno + 1
390 while line[-1] == '\\':
392 n = self.input.readline()
393 self.lineno = self.lineno + 1
405 def push(self, token):
406 self.tokens.insert(0, token);
409 print("Last token: ", self.last)
410 print("Token queue: ", self.tokens)
411 print("Line %d end: " % (self.lineno), self.line)
414 while self.tokens == []:
416 line = self.getline()
424 self.tokens = list(map((lambda x: ('preproc', x)),
428 if line[0] == '"' or line[0] == "'":
438 self.line = line[i+1:]
448 line = self.getline()
451 self.last = ('string', tok)
454 if l >= 2 and line[0] == '/' and line[1] == '*':
462 if line[i] == '*' and i+1 < l and line[i+1] == '/':
463 self.line = line[i+2:]
473 line = self.getline()
476 self.last = ('comment', tok)
478 if l >= 2 and line[0] == '/' and line[1] == '/':
480 self.last = ('comment', line)
484 if line[i] == '/' and i+1 < l and line[i+1] == '/':
488 if line[i] == '/' and i+1 < l and line[i+1] == '*':
492 if line[i] == '"' or line[i] == "'":
500 if line[i] == ' ' or line[i] == '\t':
504 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
505 (o >= 48 and o <= 57):
509 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
510 (o >= 48 and o <= 57) or \
511 (" \t(){}:;,+-*/%&!|[]=><".find(line[i])) == -1:
515 self.tokens.append(('name', line[s:i]))
517 if "(){}:;,[]".find(line[i]) != -1:
518 # if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
519 # line[i] == '}' or line[i] == ':' or line[i] == ';' or \
520 # line[i] == ',' or line[i] == '[' or line[i] == ']':
521 self.tokens.append(('sep', line[i]))
524 if "+-*><=/%&!|.".find(line[i]) != -1:
525 # if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
526 # line[i] == '>' or line[i] == '<' or line[i] == '=' or \
527 # line[i] == '/' or line[i] == '%' or line[i] == '&' or \
528 # line[i] == '!' or line[i] == '|' or line[i] == '.':
529 if line[i] == '.' and i + 2 < l and \
530 line[i+1] == '.' and line[i+2] == '.':
531 self.tokens.append(('name', '...'))
537 "+-*><=/%&!|".find(line[j]) != -1):
538 # line[j] == '+' or line[j] == '-' or line[j] == '*' or \
539 # line[j] == '>' or line[j] == '<' or line[j] == '=' or \
540 # line[j] == '/' or line[j] == '%' or line[j] == '&' or \
541 # line[j] == '!' or line[j] == '|'):
542 self.tokens.append(('op', line[i:j+1]))
545 self.tokens.append(('op', line[i]))
551 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
552 (o >= 48 and o <= 57) or (
553 " \t(){}:;,+-*/%&!|[]=><".find(line[i]) == -1):
554 # line[i] != ' ' and line[i] != '\t' and
555 # line[i] != '(' and line[i] != ')' and
556 # line[i] != '{' and line[i] != '}' and
557 # line[i] != ':' and line[i] != ';' and
558 # line[i] != ',' and line[i] != '+' and
559 # line[i] != '-' and line[i] != '*' and
560 # line[i] != '/' and line[i] != '%' and
561 # line[i] != '&' and line[i] != '!' and
562 # line[i] != '|' and line[i] != '[' and
563 # line[i] != ']' and line[i] != '=' and
564 # line[i] != '*' and line[i] != '>' and
569 self.tokens.append(('name', line[s:i]))
572 self.tokens = self.tokens[1:]
577 """The C module parser"""
578 def __init__(self, filename, idx = None):
579 self.filename = filename
580 if len(filename) > 2 and filename[-2:] == '.h':
584 self.input = open(filename)
585 self.lexer = CLexer(self.input)
590 self.top_comment = ""
591 self.last_comment = ""
595 self.conditionals = []
598 def collect_references(self):
601 def stop_error(self):
604 def start_error(self):
608 return self.lexer.getlineno()
610 def index_add(self, name, module, static, type, info=None, extra = None):
611 if self.is_header == 1:
612 self.index.add(name, module, module, static, type, self.lineno(),
613 info, extra, self.conditionals)
615 self.index.add(name, None, module, static, type, self.lineno(),
616 info, extra, self.conditionals)
618 def index_add_ref(self, name, module, static, type, info=None,
620 if self.is_header == 1:
621 self.index.add_ref(name, module, module, static, type,
622 self.lineno(), info, extra, self.conditionals)
624 self.index.add_ref(name, None, module, static, type, self.lineno(),
625 info, extra, self.conditionals)
627 def warning(self, msg):
632 def error(self, msg, token=-1):
636 print("Parse Error: " + msg)
638 print("Got token ", token)
642 def debug(self, msg, token=-1):
643 print("Debug: " + msg)
645 print("Got token ", token)
648 def parseTopComment(self, comment):
650 lines = comment.split("\n")
653 while line != "" and (line[0] == ' ' or line[0] == '\t'):
655 while line != "" and line[0] == '*':
657 while line != "" and (line[0] == ' ' or line[0] == '\t'):
660 (it, line) = line.split(":", 1)
662 while line != "" and (line[0] == ' ' or line[0] == '\t'):
665 res[item] = res[item] + " " + line
671 res[item] = res[item] + " " + line
674 self.index.info = res
676 def parseComment(self, token):
677 if self.top_comment == "":
678 self.top_comment = token[1]
679 if self.comment == None or token[1][0] == '*':
680 self.comment = token[1];
682 self.comment = self.comment + token[1]
683 token = self.lexer.token()
685 if self.comment.find("DOC_DISABLE") != -1:
688 if self.comment.find("DOC_ENABLE") != -1:
694 # Parse a comment block associate to a typedef
696 def parseTypeComment(self, name, quiet = 0):
697 if name[0:2] == '__':
703 if self.comment == None:
705 self.warning("Missing comment for type %s" % (name))
707 if self.comment[0] != '*':
709 self.warning("Missing * in type comment for %s" % (name))
711 lines = self.comment.split('\n')
714 if lines[0] != "* %s:" % (name):
716 self.warning("Misformatted type comment for %s" % (name))
717 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
720 while len(lines) > 0 and lines[0] == '*':
723 while len(lines) > 0:
725 while len(l) > 0 and l[0] == '*':
728 desc = desc + " " + l
735 self.warning("Type comment for %s lack description of the macro" % (name))
739 # Parse a comment block associate to a macro
741 def parseMacroComment(self, name, quiet = 0):
742 if name[0:2] == '__':
748 if self.comment == None:
750 self.warning("Missing comment for macro %s" % (name))
752 if self.comment[0] != '*':
754 self.warning("Missing * in macro comment for %s" % (name))
756 lines = self.comment.split('\n')
759 if lines[0] != "* %s:" % (name):
761 self.warning("Misformatted macro comment for %s" % (name))
762 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
765 while lines[0] == '*':
767 while len(lines) > 0 and lines[0][0:3] == '* @':
770 (arg, desc) = l.split(':', 1)
775 self.warning("Misformatted macro comment for %s" % (name))
776 self.warning(" problem with '%s'" % (lines[0]))
781 while len(l) > 2 and l[0:3] != '* @':
784 desc = desc + ' ' + l.strip()
789 args.append((arg, desc))
790 while len(lines) > 0 and lines[0] == '*':
793 while len(lines) > 0:
795 while len(l) > 0 and l[0] == '*':
798 desc = desc + " " + l
805 self.warning("Macro comment for %s lack description of the macro" % (name))
810 # Parse a comment block and merge the informations found in the
811 # parameters descriptions, finally returns a block as complete
814 def mergeFunctionComment(self, name, description, quiet = 0):
817 if name[0:2] == '__':
820 (ret, args) = description
824 if self.comment == None:
826 self.warning("Missing comment for function %s" % (name))
827 return(((ret[0], retdesc), args, desc))
828 if self.comment[0] != '*':
830 self.warning("Missing * in function comment for %s" % (name))
831 return(((ret[0], retdesc), args, desc))
832 lines = self.comment.split('\n')
835 if lines[0] != "* %s:" % (name):
837 self.warning("Misformatted function comment for %s" % (name))
838 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
839 return(((ret[0], retdesc), args, desc))
841 while lines[0] == '*':
844 while len(lines) > 0 and lines[0][0:3] == '* @':
847 (arg, desc) = l.split(':', 1)
852 self.warning("Misformatted function comment for %s" % (name))
853 self.warning(" problem with '%s'" % (lines[0]))
858 while len(l) > 2 and l[0:3] != '* @':
861 desc = desc + ' ' + l.strip()
868 if args[i][1] == arg:
869 args[i] = (args[i][0], arg, desc)
874 self.warning("Unable to find arg %s from function comment for %s" % (
876 while len(lines) > 0 and lines[0] == '*':
879 while len(lines) > 0:
881 while len(l) > 0 and l[0] == '*':
884 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
886 l = l.split(' ', 1)[1]
891 while len(lines) > 0:
893 while len(l) > 0 and l[0] == '*':
896 retdesc = retdesc + " " + l
899 desc = desc + " " + l
902 retdesc = retdesc.strip()
907 # report missing comments
911 if args[i][2] == None and args[i][0] != "void" and \
912 ((args[i][1] != None) or (args[i][1] == '')):
913 self.warning("Function comment for %s lacks description of arg %s" % (name, args[i][1]))
915 if retdesc == "" and ret[0] != "void":
916 self.warning("Function comment for %s lacks description of return value" % (name))
918 self.warning("Function comment for %s lacks description of the function" % (name))
920 return(((ret[0], retdesc), args, desc))
922 def parsePreproc(self, token):
924 print("=> preproc ", token, self.lexer.tokens)
926 if name == "#include":
927 token = self.lexer.token()
930 if token[0] == 'preproc':
931 self.index_add(token[1], self.filename, not self.is_header,
933 return self.lexer.token()
935 if name == "#define":
936 token = self.lexer.token()
939 if token[0] == 'preproc':
940 # TODO macros with arguments
943 token = self.lexer.token()
944 while token != None and token[0] == 'preproc' and \
947 token = self.lexer.token()
949 name = name.split('(') [0]
952 info = self.parseMacroComment(name, not self.is_header)
953 self.index_add(name, self.filename, not self.is_header,
958 # Processing of conditionals modified by Bill 1/1/05
960 # We process conditionals (i.e. tokens from #ifdef, #ifndef,
961 # #if, #else and #endif) for headers and mainline code,
962 # store the ones from the header in libxml2-api.xml, and later
963 # (in the routine merge_public) verify that the two (header and
964 # mainline code) agree.
966 # There is a small problem with processing the headers. Some of
967 # the variables are not concerned with enabling / disabling of
968 # library functions (e.g. '__XML_PARSER_H__'), and we don't want
969 # them to be included in libxml2-api.xml, or involved in
970 # the check between the header and the mainline code. To
971 # accomplish this, we ignore any conditional which doesn't include
972 # the string 'ENABLED'
975 apstr = self.lexer.tokens[0][1]
977 self.defines.append(apstr)
978 if apstr.find('ENABLED') != -1:
979 self.conditionals.append("defined(%s)" % apstr)
982 elif name == "#ifndef":
983 apstr = self.lexer.tokens[0][1]
985 self.defines.append(apstr)
986 if apstr.find('ENABLED') != -1:
987 self.conditionals.append("!defined(%s)" % apstr)
992 for tok in self.lexer.tokens:
995 apstr = apstr + tok[1]
997 self.defines.append(apstr)
998 if apstr.find('ENABLED') != -1:
999 self.conditionals.append(apstr)
1002 elif name == "#else":
1003 if self.conditionals != [] and \
1004 self.defines[-1].find('ENABLED') != -1:
1005 self.conditionals[-1] = "!(%s)" % self.conditionals[-1]
1006 elif name == "#endif":
1007 if self.conditionals != [] and \
1008 self.defines[-1].find('ENABLED') != -1:
1009 self.conditionals = self.conditionals[:-1]
1010 self.defines = self.defines[:-1]
1011 token = self.lexer.token()
1012 while token != None and token[0] == 'preproc' and \
1014 token = self.lexer.token()
1018 # token acquisition on top of the lexer, it handle internally
1019 # preprocessor and comments since they are logically not part of
1020 # the program structure.
1023 global ignored_words
1025 token = self.lexer.token()
1026 while token != None:
1027 if token[0] == 'comment':
1028 token = self.parseComment(token)
1030 elif token[0] == 'preproc':
1031 token = self.parsePreproc(token)
1033 elif token[0] == "name" and token[1] == "__const":
1034 token = ("name", "const")
1036 elif token[0] == "name" and token[1] == "__attribute":
1037 token = self.lexer.token()
1038 while token != None and token[1] != ";":
1039 token = self.lexer.token()
1041 elif token[0] == "name" and token[1] in ignored_words:
1042 (n, info) = ignored_words[token[1]]
1045 token = self.lexer.token()
1047 token = self.lexer.token()
1056 # Parse a typedef, it records the type and its name.
1058 def parseTypedef(self, token):
1061 token = self.parseType(token)
1063 self.error("parsing typedef")
1065 base_type = self.type
1067 #self.debug("end typedef type", token)
1068 while token != None:
1069 if token[0] == "name":
1071 signature = self.signature
1072 if signature != None:
1073 type = type.split('(')[0]
1074 d = self.mergeFunctionComment(name,
1075 ((type, None), signature), 1)
1076 self.index_add(name, self.filename, not self.is_header,
1079 if base_type == "struct":
1080 self.index_add(name, self.filename, not self.is_header,
1082 base_type = "struct " + name
1084 # TODO report missing or misformatted comments
1085 info = self.parseTypeComment(name, 1)
1086 self.index_add(name, self.filename, not self.is_header,
1087 "typedef", type, info)
1088 token = self.token()
1090 self.error("parsing typedef: expecting a name")
1092 #self.debug("end typedef", token)
1093 if token != None and token[0] == 'sep' and token[1] == ',':
1095 token = self.token()
1096 while token != None and token[0] == "op":
1097 type = type + token[1]
1098 token = self.token()
1099 elif token != None and token[0] == 'sep' and token[1] == ';':
1101 elif token != None and token[0] == 'name':
1105 self.error("parsing typedef: expecting ';'", token)
1107 token = self.token()
1111 # Parse a C code block, used for functions it parse till
1112 # the balancing } included
1114 def parseBlock(self, token):
1115 while token != None:
1116 if token[0] == "sep" and token[1] == "{":
1117 token = self.token()
1118 token = self.parseBlock(token)
1119 elif token[0] == "sep" and token[1] == "}":
1121 token = self.token()
1124 if self.collect_ref == 1:
1126 token = self.token()
1127 if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
1128 if token[0] == "sep" and token[1] == "(":
1129 self.index_add_ref(oldtok[1], self.filename,
1131 token = self.token()
1132 elif token[0] == "name":
1133 token = self.token()
1134 if token[0] == "sep" and (token[1] == ";" or
1135 token[1] == "," or token[1] == "="):
1136 self.index_add_ref(oldtok[1], self.filename,
1138 elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
1139 self.index_add_ref(oldtok[1], self.filename,
1141 elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
1142 self.index_add_ref(oldtok[1], self.filename,
1146 token = self.token()
1150 # Parse a C struct definition till the balancing }
1152 def parseStruct(self, token):
1154 #self.debug("start parseStruct", token)
1155 while token != None:
1156 if token[0] == "sep" and token[1] == "{":
1157 token = self.token()
1158 token = self.parseTypeBlock(token)
1159 elif token[0] == "sep" and token[1] == "}":
1160 self.struct_fields = fields
1161 #self.debug("end parseStruct", token)
1163 token = self.token()
1166 base_type = self.type
1167 #self.debug("before parseType", token)
1168 token = self.parseType(token)
1169 #self.debug("after parseType", token)
1170 if token != None and token[0] == "name":
1172 token = self.token()
1173 if token[0] == "sep" and token[1] == ";":
1175 token = self.token()
1176 fields.append((self.type, fname, self.comment))
1179 self.error("parseStruct: expecting ;", token)
1180 elif token != None and token[0] == "sep" and token[1] == "{":
1181 token = self.token()
1182 token = self.parseTypeBlock(token)
1183 if token != None and token[0] == "name":
1184 token = self.token()
1185 if token != None and token[0] == "sep" and token[1] == ";":
1186 token = self.token()
1188 self.error("parseStruct: expecting ;", token)
1190 self.error("parseStruct: name", token)
1191 token = self.token()
1192 self.type = base_type;
1193 self.struct_fields = fields
1194 #self.debug("end parseStruct", token)
1199 # Parse a C enum block, parse till the balancing }
1201 def parseEnumBlock(self, token):
1207 while token != None:
1208 if token[0] == "sep" and token[1] == "{":
1209 token = self.token()
1210 token = self.parseTypeBlock(token)
1211 elif token[0] == "sep" and token[1] == "}":
1213 if self.comment != None:
1214 comment = self.comment
1216 self.enums.append((name, value, comment))
1217 token = self.token()
1219 elif token[0] == "name":
1221 if self.comment != None:
1222 comment = self.comment.strip()
1224 self.enums.append((name, value, comment))
1227 token = self.token()
1228 if token[0] == "op" and token[1][0] == "=":
1230 if len(token[1]) > 1:
1231 value = token[1][1:]
1232 token = self.token()
1233 while token[0] != "sep" or (token[1] != ',' and
1235 value = value + token[1]
1236 token = self.token()
1239 value = "%d" % (int(value) + 1)
1241 self.warning("Failed to compute value of enum %s" % (name))
1243 if token[0] == "sep" and token[1] == ",":
1244 token = self.token()
1246 token = self.token()
1250 # Parse a C definition block, used for structs it parse till
1253 def parseTypeBlock(self, token):
1254 while token != None:
1255 if token[0] == "sep" and token[1] == "{":
1256 token = self.token()
1257 token = self.parseTypeBlock(token)
1258 elif token[0] == "sep" and token[1] == "}":
1259 token = self.token()
1262 token = self.token()
1266 # Parse a type: the fact that the type name can either occur after
1267 # the definition or within the definition makes it a little harder
1268 # if inside, the name token is pushed back before returning
1270 def parseType(self, token):
1272 self.struct_fields = []
1273 self.signature = None
1277 while token[0] == "name" and (
1278 token[1] == "const" or \
1279 token[1] == "unsigned" or \
1280 token[1] == "signed"):
1282 self.type = token[1]
1284 self.type = self.type + " " + token[1]
1285 token = self.token()
1287 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1289 self.type = token[1]
1291 self.type = self.type + " " + token[1]
1292 if token[0] == "name" and token[1] == "int":
1296 self.type = self.type + " " + tmp[1]
1298 elif token[0] == "name" and token[1] == "struct":
1300 self.type = token[1]
1302 self.type = self.type + " " + token[1]
1303 token = self.token()
1305 if token[0] == "name":
1307 token = self.token()
1308 if token != None and token[0] == "sep" and token[1] == "{":
1309 token = self.token()
1310 token = self.parseStruct(token)
1311 elif token != None and token[0] == "op" and token[1] == "*":
1312 self.type = self.type + " " + nametok[1] + " *"
1313 token = self.token()
1314 while token != None and token[0] == "op" and token[1] == "*":
1315 self.type = self.type + " *"
1316 token = self.token()
1317 if token[0] == "name":
1319 token = self.token()
1321 self.error("struct : expecting name", token)
1323 elif token != None and token[0] == "name" and nametok != None:
1324 self.type = self.type + " " + nametok[1]
1328 self.lexer.push(token)
1332 elif token[0] == "name" and token[1] == "enum":
1334 self.type = token[1]
1336 self.type = self.type + " " + token[1]
1338 token = self.token()
1339 if token != None and token[0] == "sep" and token[1] == "{":
1340 token = self.token()
1341 token = self.parseEnumBlock(token)
1343 self.error("parsing enum: expecting '{'", token)
1345 if token != None and token[0] != "name":
1346 self.lexer.push(token)
1347 token = ("name", "enum")
1349 enum_type = token[1]
1350 for enum in self.enums:
1351 self.index_add(enum[0], self.filename,
1352 not self.is_header, "enum",
1353 (enum[1], enum[2], enum_type))
1356 elif token[0] == "name":
1358 self.type = token[1]
1360 self.type = self.type + " " + token[1]
1362 self.error("parsing type %s: expecting a name" % (self.type),
1365 token = self.token()
1366 while token != None and (token[0] == "op" or
1367 token[0] == "name" and token[1] == "const"):
1368 self.type = self.type + " " + token[1]
1369 token = self.token()
1372 # if there is a parenthesis here, this means a function type
1374 if token != None and token[0] == "sep" and token[1] == '(':
1375 self.type = self.type + token[1]
1376 token = self.token()
1377 while token != None and token[0] == "op" and token[1] == '*':
1378 self.type = self.type + token[1]
1379 token = self.token()
1380 if token == None or token[0] != "name" :
1381 self.error("parsing function type, name expected", token);
1383 self.type = self.type + token[1]
1385 token = self.token()
1386 if token != None and token[0] == "sep" and token[1] == ')':
1387 self.type = self.type + token[1]
1388 token = self.token()
1389 if token != None and token[0] == "sep" and token[1] == '(':
1390 token = self.token()
1392 token = self.parseSignature(token);
1395 self.error("parsing function type, '(' expected", token);
1398 self.error("parsing function type, ')' expected", token);
1400 self.lexer.push(token)
1405 # do some lookahead for arrays
1407 if token != None and token[0] == "name":
1409 token = self.token()
1410 if token != None and token[0] == "sep" and token[1] == '[':
1411 self.type = self.type + nametok[1]
1412 while token != None and token[0] == "sep" and token[1] == '[':
1413 self.type = self.type + token[1]
1414 token = self.token()
1415 while token != None and token[0] != 'sep' and \
1416 token[1] != ']' and token[1] != ';':
1417 self.type = self.type + token[1]
1418 token = self.token()
1419 if token != None and token[0] == 'sep' and token[1] == ']':
1420 self.type = self.type + token[1]
1421 token = self.token()
1423 self.error("parsing array type, ']' expected", token);
1425 elif token != None and token[0] == "sep" and token[1] == ':':
1426 # remove :12 in case it's a limited int size
1427 token = self.token()
1428 token = self.token()
1429 self.lexer.push(token)
1435 # Parse a signature: '(' has been parsed and we scan the type definition
1436 # up to the ')' included
1437 def parseSignature(self, token):
1439 if token != None and token[0] == "sep" and token[1] == ')':
1441 token = self.token()
1443 while token != None:
1444 token = self.parseType(token)
1445 if token != None and token[0] == "name":
1446 signature.append((self.type, token[1], None))
1447 token = self.token()
1448 elif token != None and token[0] == "sep" and token[1] == ',':
1449 token = self.token()
1451 elif token != None and token[0] == "sep" and token[1] == ')':
1452 # only the type was provided
1453 if self.type == "...":
1454 signature.append((self.type, "...", None))
1456 signature.append((self.type, None, None))
1457 if token != None and token[0] == "sep":
1459 token = self.token()
1461 elif token[1] == ')':
1462 token = self.token()
1464 self.signature = signature
1468 # Parse a global definition, be it a type, variable or function
1469 # the extern "C" blocks are a bit nasty and require it to recurse.
1471 def parseGlobal(self, token):
1473 if token[1] == 'extern':
1474 token = self.token()
1477 if token[0] == 'string':
1479 token = self.token()
1482 if token[0] == 'sep' and token[1] == "{":
1483 token = self.token()
1484 # print 'Entering extern "C line ', self.lineno()
1485 while token != None and (token[0] != 'sep' or
1487 if token[0] == 'name':
1488 token = self.parseGlobal(token)
1491 "token %s %s unexpected at the top level" % (
1492 token[0], token[1]))
1493 token = self.parseGlobal(token)
1494 # print 'Exiting extern "C" line', self.lineno()
1495 token = self.token()
1499 elif token[1] == 'static':
1501 token = self.token()
1502 if token == None or token[0] != 'name':
1505 if token[1] == 'typedef':
1506 token = self.token()
1507 return self.parseTypedef(token)
1509 token = self.parseType(token)
1510 type_orig = self.type
1511 if token == None or token[0] != "name":
1514 self.name = token[1]
1515 token = self.token()
1516 while token != None and (token[0] == "sep" or token[0] == "op"):
1517 if token[0] == "sep":
1519 type = type + token[1]
1520 token = self.token()
1521 while token != None and (token[0] != "sep" or \
1523 type = type + token[1]
1524 token = self.token()
1526 if token != None and token[0] == "op" and token[1] == "=":
1528 # Skip the initialization of the variable
1530 token = self.token()
1531 if token[0] == 'sep' and token[1] == '{':
1532 token = self.token()
1533 token = self.parseBlock(token)
1536 while token != None and (token[0] != "sep" or \
1537 (token[1] != ';' and token[1] != ',')):
1538 token = self.token()
1540 if token == None or token[0] != "sep" or (token[1] != ';' and
1542 self.error("missing ';' or ',' after value")
1544 if token != None and token[0] == "sep":
1547 token = self.token()
1548 if type == "struct":
1549 self.index_add(self.name, self.filename,
1550 not self.is_header, "struct", self.struct_fields)
1552 self.index_add(self.name, self.filename,
1553 not self.is_header, "variable", type)
1555 elif token[1] == "(":
1556 token = self.token()
1557 token = self.parseSignature(token)
1560 if token[0] == "sep" and token[1] == ";":
1561 d = self.mergeFunctionComment(self.name,
1562 ((type, None), self.signature), 1)
1563 self.index_add(self.name, self.filename, static,
1565 token = self.token()
1566 elif token[0] == "sep" and token[1] == "{":
1567 d = self.mergeFunctionComment(self.name,
1568 ((type, None), self.signature), static)
1569 self.index_add(self.name, self.filename, static,
1571 token = self.token()
1572 token = self.parseBlock(token);
1573 elif token[1] == ',':
1575 self.index_add(self.name, self.filename, static,
1578 token = self.token()
1579 while token != None and token[0] == "sep":
1580 type = type + token[1]
1581 token = self.token()
1582 if token != None and token[0] == "name":
1583 self.name = token[1]
1584 token = self.token()
1591 self.warning("Parsing %s" % (self.filename))
1592 token = self.token()
1593 while token != None:
1594 if token[0] == 'name':
1595 token = self.parseGlobal(token)
1597 self.error("token %s %s unexpected at the top level" % (
1598 token[0], token[1]))
1599 token = self.parseGlobal(token)
1601 self.parseTopComment(self.top_comment)
1606 """A documentation builder"""
1607 def __init__(self, name, directories=['.'], excludes=[]):
1609 self.directories = directories
1610 self.excludes = excludes + list(ignored_files.keys())
1616 if name == 'libxml2':
1617 self.basename = 'libxml'
1619 self.basename = name
1621 def indexString(self, id, str):
1624 str = str.replace("'", ' ')
1625 str = str.replace('"', ' ')
1626 str = str.replace("/", ' ')
1627 str = str.replace('*', ' ')
1628 str = str.replace("[", ' ')
1629 str = str.replace("]", ' ')
1630 str = str.replace("(", ' ')
1631 str = str.replace(")", ' ')
1632 str = str.replace("<", ' ')
1633 str = str.replace('>', ' ')
1634 str = str.replace("&", ' ')
1635 str = str.replace('#', ' ')
1636 str = str.replace(",", ' ')
1637 str = str.replace('.', ' ')
1638 str = str.replace(';', ' ')
1639 tokens = str.split()
1640 for token in tokens:
1643 if string.ascii_letters.find(c) < 0:
1645 elif len(token) < 3:
1648 lower = token.lower()
1649 # TODO: generalize this a bit
1650 if lower == 'and' or lower == 'the':
1652 elif token in self.xref:
1653 self.xref[token].append(id)
1655 self.xref[token] = [id]
1660 print("Project %s : %d headers, %d modules" % (self.name, len(list(self.headers.keys())), len(list(self.modules.keys()))))
1663 def scanHeaders(self):
1664 for header in list(self.headers.keys()):
1665 parser = CParser(header)
1666 idx = parser.parse()
1667 self.headers[header] = idx;
1670 def scanModules(self):
1671 for module in list(self.modules.keys()):
1672 parser = CParser(module)
1673 idx = parser.parse()
1675 self.modules[module] = idx
1676 self.idx.merge_public(idx)
1679 for directory in self.directories:
1680 files = glob.glob(directory + "/*.c")
1683 for excl in self.excludes:
1684 if file.find(excl) != -1:
1685 print("Skipping %s" % file)
1689 self.modules[file] = None;
1690 files = glob.glob(directory + "/*.h")
1693 for excl in self.excludes:
1694 if file.find(excl) != -1:
1695 print("Skipping %s" % file)
1699 self.headers[file] = None;
1703 def modulename_file(self, file):
1704 module = os.path.basename(file)
1705 if module[-2:] == '.h':
1706 module = module[:-2]
1707 elif module[-2:] == '.c':
1708 module = module[:-2]
1711 def serialize_enum(self, output, name):
1712 id = self.idx.enums[name]
1713 output.write(" <enum name='%s' file='%s'" % (name,
1714 self.modulename_file(id.header)))
1717 if info[0] != None and info[0] != '':
1722 output.write(" value='%s'" % (val));
1723 if info[2] != None and info[2] != '':
1724 output.write(" type='%s'" % info[2]);
1725 if info[1] != None and info[1] != '':
1726 output.write(" info='%s'" % escape(info[1]));
1727 output.write("/>\n")
1729 def serialize_macro(self, output, name):
1730 id = self.idx.macros[name]
1731 output.write(" <macro name='%s' file='%s'>\n" % (name,
1732 self.modulename_file(id.header)))
1735 (args, desc) = id.info
1736 if desc != None and desc != "":
1737 output.write(" <info>%s</info>\n" % (escape(desc)))
1738 self.indexString(name, desc)
1741 if desc != None and desc != "":
1742 output.write(" <arg name='%s' info='%s'/>\n" % (
1743 name, escape(desc)))
1744 self.indexString(name, desc)
1746 output.write(" <arg name='%s'/>\n" % (name))
1749 output.write(" </macro>\n")
1751 def serialize_typedef(self, output, name):
1752 id = self.idx.typedefs[name]
1753 if id.info[0:7] == 'struct ':
1754 output.write(" <struct name='%s' file='%s' type='%s'" % (
1755 name, self.modulename_file(id.header), id.info))
1757 if name in self.idx.structs and ( \
1758 type(self.idx.structs[name].info) == type(()) or
1759 type(self.idx.structs[name].info) == type([])):
1760 output.write(">\n");
1762 for field in self.idx.structs[name].info:
1764 self.indexString(name, desc)
1769 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1771 print("Failed to serialize struct %s" % (name))
1772 output.write(" </struct>\n")
1774 output.write("/>\n");
1776 output.write(" <typedef name='%s' file='%s' type='%s'" % (
1777 name, self.modulename_file(id.header), id.info))
1780 if desc != None and desc != "":
1781 output.write(">\n <info>%s</info>\n" % (escape(desc)))
1782 output.write(" </typedef>\n")
1784 output.write("/>\n")
1786 output.write("/>\n")
1788 def serialize_variable(self, output, name):
1789 id = self.idx.variables[name]
1791 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1792 name, self.modulename_file(id.header), id.info))
1794 output.write(" <variable name='%s' file='%s'/>\n" % (
1795 name, self.modulename_file(id.header)))
1797 def serialize_function(self, output, name):
1798 id = self.idx.functions[name]
1799 if name == debugsym:
1802 output.write(" <%s name='%s' file='%s' module='%s'>\n" % (id.type,
1803 name, self.modulename_file(id.header),
1804 self.modulename_file(id.module)))
1806 # Processing of conditionals modified by Bill 1/1/05
1808 if id.conditionals != None:
1810 for cond in id.conditionals:
1812 apstr = apstr + " && "
1813 apstr = apstr + cond
1814 output.write(" <cond>%s</cond>\n"% (apstr));
1816 (ret, params, desc) = id.info
1817 if (desc == None or desc == '') and \
1818 name[0:9] != "xmlThrDef" and name != "xmlDllMain":
1819 print("%s %s from %s has no description" % (id.type, name,
1820 self.modulename_file(id.module)))
1822 output.write(" <info>%s</info>\n" % (escape(desc)))
1823 self.indexString(name, desc)
1825 if ret[0] == "void":
1826 output.write(" <return type='void'/>\n")
1828 output.write(" <return type='%s' info='%s'/>\n" % (
1829 ret[0], escape(ret[1])))
1830 self.indexString(name, ret[1])
1831 for param in params:
1832 if param[0] == 'void':
1834 if param[2] == None:
1835 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1837 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1838 self.indexString(name, param[2])
1840 print("Failed to save function %s info: " % name, repr(id.info))
1841 output.write(" </%s>\n" % (id.type))
1843 def serialize_exports(self, output, file):
1844 module = self.modulename_file(file)
1845 output.write(" <file name='%s'>\n" % (module))
1846 dict = self.headers[file]
1847 if dict.info != None:
1848 for data in ('Summary', 'Description', 'Author'):
1850 output.write(" <%s>%s</%s>\n" % (
1852 escape(dict.info[data]),
1855 print("Header %s lacks a %s description" % (module, data))
1856 if 'Description' in dict.info:
1857 desc = dict.info['Description']
1858 if desc.find("DEPRECATED") != -1:
1859 output.write(" <deprecated/>\n")
1861 ids = list(dict.macros.keys())
1863 for id in uniq(ids):
1864 # Macros are sometime used to masquerade other types.
1865 if id in dict.functions:
1867 if id in dict.variables:
1869 if id in dict.typedefs:
1871 if id in dict.structs:
1873 if id in dict.enums:
1875 output.write(" <exports symbol='%s' type='macro'/>\n" % (id))
1876 ids = list(dict.enums.keys())
1878 for id in uniq(ids):
1879 output.write(" <exports symbol='%s' type='enum'/>\n" % (id))
1880 ids = list(dict.typedefs.keys())
1882 for id in uniq(ids):
1883 output.write(" <exports symbol='%s' type='typedef'/>\n" % (id))
1884 ids = list(dict.structs.keys())
1886 for id in uniq(ids):
1887 output.write(" <exports symbol='%s' type='struct'/>\n" % (id))
1888 ids = list(dict.variables.keys())
1890 for id in uniq(ids):
1891 output.write(" <exports symbol='%s' type='variable'/>\n" % (id))
1892 ids = list(dict.functions.keys())
1894 for id in uniq(ids):
1895 output.write(" <exports symbol='%s' type='function'/>\n" % (id))
1896 output.write(" </file>\n")
1898 def serialize_xrefs_files(self, output):
1899 headers = list(self.headers.keys())
1901 for file in headers:
1902 module = self.modulename_file(file)
1903 output.write(" <file name='%s'>\n" % (module))
1904 dict = self.headers[file]
1905 ids = uniq(list(dict.functions.keys()) + list(dict.variables.keys()) + \
1906 list(dict.macros.keys()) + list(dict.typedefs.keys()) + \
1907 list(dict.structs.keys()) + list(dict.enums.keys()))
1910 output.write(" <ref name='%s'/>\n" % (id))
1911 output.write(" </file>\n")
1914 def serialize_xrefs_functions(self, output):
1916 for name in list(self.idx.functions.keys()):
1917 id = self.idx.functions[name]
1919 (ret, params, desc) = id.info
1920 for param in params:
1921 if param[0] == 'void':
1923 if param[0] in funcs:
1924 funcs[param[0]].append(name)
1926 funcs[param[0]] = [name]
1929 typ = list(funcs.keys())
1932 if type == '' or type == 'void' or type == "int" or \
1933 type == "char *" or type == "const char *" :
1935 output.write(" <type name='%s'>\n" % (type))
1938 pid = '' # not sure why we have dups, but get rid of them!
1941 output.write(" <ref name='%s'/>\n" % (id))
1943 output.write(" </type>\n")
1945 def serialize_xrefs_constructors(self, output):
1947 for name in list(self.idx.functions.keys()):
1948 id = self.idx.functions[name]
1950 (ret, params, desc) = id.info
1951 if ret[0] == "void":
1954 funcs[ret[0]].append(name)
1956 funcs[ret[0]] = [name]
1959 typ = list(funcs.keys())
1962 if type == '' or type == 'void' or type == "int" or \
1963 type == "char *" or type == "const char *" :
1965 output.write(" <type name='%s'>\n" % (type))
1969 output.write(" <ref name='%s'/>\n" % (id))
1970 output.write(" </type>\n")
1972 def serialize_xrefs_alpha(self, output):
1974 ids = list(self.idx.identifiers.keys())
1979 output.write(" </letter>\n")
1981 output.write(" <letter name='%s'>\n" % (letter))
1982 output.write(" <ref name='%s'/>\n" % (id))
1984 output.write(" </letter>\n")
1986 def serialize_xrefs_references(self, output):
1987 typ = list(self.idx.identifiers.keys())
1990 idf = self.idx.identifiers[id]
1992 output.write(" <reference name='%s' href='%s'/>\n" % (id,
1993 'html/' + self.basename + '-' +
1994 self.modulename_file(module) + '.html#' +
1997 def serialize_xrefs_index(self, output):
1999 typ = list(index.keys())
2006 if len(index[id]) > 30:
2009 if letter == None or count > 200:
2011 output.write(" </letter>\n")
2012 output.write(" </chunk>\n")
2014 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
2015 output.write(" <chunk name='chunk%s'>\n" % (chunk))
2016 first_letter = id[0]
2018 elif letter != None:
2019 output.write(" </letter>\n")
2021 output.write(" <letter name='%s'>\n" % (letter))
2022 output.write(" <word name='%s'>\n" % (id))
2026 for token in tokens:
2030 output.write(" <ref name='%s'/>\n" % (token))
2032 output.write(" </word>\n")
2034 output.write(" </letter>\n")
2035 output.write(" </chunk>\n")
2037 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
2038 output.write(" <chunks>\n")
2040 output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
2041 ch[0], ch[1], ch[2]))
2042 output.write(" </chunks>\n")
2044 def serialize_xrefs(self, output):
2045 output.write(" <references>\n")
2046 self.serialize_xrefs_references(output)
2047 output.write(" </references>\n")
2048 output.write(" <alpha>\n")
2049 self.serialize_xrefs_alpha(output)
2050 output.write(" </alpha>\n")
2051 output.write(" <constructors>\n")
2052 self.serialize_xrefs_constructors(output)
2053 output.write(" </constructors>\n")
2054 output.write(" <functions>\n")
2055 self.serialize_xrefs_functions(output)
2056 output.write(" </functions>\n")
2057 output.write(" <files>\n")
2058 self.serialize_xrefs_files(output)
2059 output.write(" </files>\n")
2060 output.write(" <index>\n")
2061 self.serialize_xrefs_index(output)
2062 output.write(" </index>\n")
2064 def serialize(self):
2065 filename = "%s-api.xml" % self.name
2066 print("Saving XML description %s" % (filename))
2067 output = open(filename, "w")
2068 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
2069 output.write("<api name='%s'>\n" % self.name)
2070 output.write(" <files>\n")
2071 headers = list(self.headers.keys())
2073 for file in headers:
2074 self.serialize_exports(output, file)
2075 output.write(" </files>\n")
2076 output.write(" <symbols>\n")
2077 macros = list(self.idx.macros.keys())
2079 for macro in macros:
2080 self.serialize_macro(output, macro)
2081 enums = list(self.idx.enums.keys())
2084 self.serialize_enum(output, enum)
2085 typedefs = list(self.idx.typedefs.keys())
2087 for typedef in typedefs:
2088 self.serialize_typedef(output, typedef)
2089 variables = list(self.idx.variables.keys())
2091 for variable in variables:
2092 self.serialize_variable(output, variable)
2093 functions = list(self.idx.functions.keys())
2095 for function in functions:
2096 self.serialize_function(output, function)
2097 output.write(" </symbols>\n")
2098 output.write("</api>\n")
2101 filename = "%s-refs.xml" % self.name
2102 print("Saving XML Cross References %s" % (filename))
2103 output = open(filename, "w")
2104 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
2105 output.write("<apirefs name='%s'>\n" % self.name)
2106 self.serialize_xrefs(output)
2107 output.write("</apirefs>\n")
2113 if glob.glob("parser.c") != [] :
2114 print("Rebuilding API description for libxml2")
2115 builder = docBuilder("libxml2", [".", "."],
2116 ["xmlwin32version.h", "tst.c"])
2117 elif glob.glob("../parser.c") != [] :
2118 print("Rebuilding API description for libxml2")
2119 builder = docBuilder("libxml2", ["..", "../include/libxml"],
2120 ["xmlwin32version.h", "tst.c"])
2121 elif glob.glob("../libxslt/transform.c") != [] :
2122 print("Rebuilding API description for libxslt")
2123 builder = docBuilder("libxslt", ["../libxslt"],
2124 ["win32config.h", "libxslt.h", "tst.c"])
2126 print("rebuild() failed, unable to guess the module")
2131 if glob.glob("../libexslt/exslt.c") != [] :
2132 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
2139 # for debugging the parser
2141 def parse(filename):
2142 parser = CParser(filename)
2143 idx = parser.parse()
2146 if __name__ == "__main__":
2147 if len(sys.argv) > 1: