Annotation of embedaddon/libxml2/doc/apibuild.py, revision 1.1.1.3
1.1 misho 1: #!/usr/bin/python -u
2: #
3: # This is the API builder, it parses the C sources and build the
4: # API formal description in XML.
5: #
6: # See Copyright for the status of this software.
7: #
8: # daniel@veillard.com
9: #
10: import os, sys
11: import string
12: import glob
13:
14: debug=0
15: #debugsym='ignorableWhitespaceSAXFunc'
16: debugsym=None
17:
18: #
19: # C parser analysis code
20: #
21: ignored_files = {
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",
1.1.1.3 ! misho 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",
1.1 misho 60: }
61:
62: ignored_words = {
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"),
84: }
85:
86: def escape(raw):
1.1.1.3 ! misho 87: raw = raw.replace('&', '&')
! 88: raw = raw.replace('<', '<')
! 89: raw = raw.replace('>', '>')
! 90: raw = raw.replace("'", ''')
! 91: raw = raw.replace('"', '"')
1.1 misho 92: return raw
93:
94: def uniq(items):
95: d = {}
96: for item in items:
97: d[item]=1
1.1.1.3 ! misho 98: return list(d.keys())
1.1 misho 99:
100: class identifier:
101: def __init__(self, name, header=None, module=None, type=None, lineno = 0,
102: info=None, extra=None, conditionals = None):
103: self.name = name
1.1.1.3 ! misho 104: self.header = header
! 105: self.module = module
! 106: self.type = type
! 107: self.info = info
! 108: self.extra = extra
! 109: self.lineno = lineno
! 110: self.static = 0
! 111: if conditionals == None or len(conditionals) == 0:
! 112: self.conditionals = None
! 113: else:
! 114: self.conditionals = conditionals[:]
! 115: if self.name == debugsym:
! 116: print("=> define %s : %s" % (debugsym, (module, type, info,
! 117: extra, conditionals)))
1.1 misho 118:
119: def __repr__(self):
120: r = "%s %s:" % (self.type, self.name)
1.1.1.3 ! misho 121: if self.static:
! 122: r = r + " static"
! 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)
! 131: return r
1.1 misho 132:
133:
134: def set_header(self, header):
135: self.header = header
136: def set_module(self, module):
137: self.module = module
138: def set_type(self, type):
139: self.type = type
140: def set_info(self, info):
141: self.info = info
142: def set_extra(self, extra):
143: self.extra = extra
144: def set_lineno(self, lineno):
145: self.lineno = lineno
146: def set_static(self, static):
147: self.static = static
148: def set_conditionals(self, conditionals):
1.1.1.3 ! misho 149: if conditionals == None or len(conditionals) == 0:
! 150: self.conditionals = None
! 151: else:
! 152: self.conditionals = conditionals[:]
1.1 misho 153:
154: def get_name(self):
155: return self.name
156: def get_header(self):
157: return self.module
158: def get_module(self):
159: return self.module
160: def get_type(self):
161: return self.type
162: def get_info(self):
163: return self.info
164: def get_lineno(self):
165: return self.lineno
166: def get_extra(self):
167: return self.extra
168: def get_static(self):
169: return self.static
170: def get_conditionals(self):
171: return self.conditionals
172:
173: def update(self, header, module, type = None, info = None, extra=None,
174: conditionals=None):
1.1.1.3 ! misho 175: if self.name == debugsym:
! 176: print("=> update %s : %s" % (debugsym, (module, type, info,
! 177: extra, conditionals)))
1.1 misho 178: if header != None and self.header == None:
1.1.1.3 ! misho 179: self.set_header(module)
1.1 misho 180: if module != None and (self.module == None or self.header == self.module):
1.1.1.3 ! misho 181: self.set_module(module)
1.1 misho 182: if type != None and self.type == None:
1.1.1.3 ! misho 183: self.set_type(type)
1.1 misho 184: if info != None:
1.1.1.3 ! misho 185: self.set_info(info)
1.1 misho 186: if extra != None:
1.1.1.3 ! misho 187: self.set_extra(extra)
1.1 misho 188: if conditionals != None:
1.1.1.3 ! misho 189: self.set_conditionals(conditionals)
1.1 misho 190:
191: class index:
192: def __init__(self, name = "noname"):
193: self.name = name
194: self.identifiers = {}
195: self.functions = {}
1.1.1.3 ! misho 196: self.variables = {}
! 197: self.includes = {}
! 198: self.structs = {}
! 199: self.enums = {}
! 200: self.typedefs = {}
! 201: self.macros = {}
! 202: self.references = {}
! 203: self.info = {}
1.1 misho 204:
205: def add_ref(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
206: if name[0:2] == '__':
1.1.1.3 ! misho 207: return None
1.1 misho 208: d = None
209: try:
1.1.1.3 ! misho 210: d = self.identifiers[name]
! 211: d.update(header, module, type, lineno, info, extra, conditionals)
! 212: except:
! 213: d = identifier(name, header, module, type, lineno, info, extra, conditionals)
! 214: self.identifiers[name] = d
! 215:
! 216: if d != None and static == 1:
! 217: d.set_static(1)
1.1 misho 218:
1.1.1.3 ! misho 219: if d != None and name != None and type != None:
! 220: self.references[name] = d
1.1 misho 221:
1.1.1.3 ! misho 222: if name == debugsym:
! 223: print("New ref: %s" % (d))
1.1 misho 224:
1.1.1.3 ! misho 225: return d
1.1 misho 226:
227: def add(self, name, header, module, static, type, lineno, info=None, extra=None, conditionals = None):
228: if name[0:2] == '__':
1.1.1.3 ! misho 229: return None
1.1 misho 230: d = None
231: try:
1.1.1.3 ! misho 232: d = self.identifiers[name]
! 233: d.update(header, module, type, lineno, info, extra, conditionals)
! 234: except:
! 235: d = identifier(name, header, module, type, lineno, info, extra, conditionals)
! 236: self.identifiers[name] = d
! 237:
! 238: if d != None and static == 1:
! 239: d.set_static(1)
! 240:
! 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
! 252: elif type == "enum":
! 253: self.enums[name] = d
! 254: elif type == "typedef":
! 255: self.typedefs[name] = d
! 256: elif type == "macro":
! 257: self.macros[name] = d
! 258: else:
! 259: print("Unable to register type ", type)
1.1 misho 260:
1.1.1.3 ! misho 261: if name == debugsym:
! 262: print("New symbol: %s" % (d))
1.1 misho 263:
1.1.1.3 ! misho 264: return d
1.1 misho 265:
266: def merge(self, idx):
1.1.1.3 ! misho 267: for id in list(idx.functions.keys()):
1.1 misho 268: #
269: # macro might be used to override functions or variables
270: # definitions
271: #
1.1.1.3 ! misho 272: if id in self.macros:
! 273: del self.macros[id]
! 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))
! 277: else:
! 278: self.functions[id] = idx.functions[id]
! 279: self.identifiers[id] = idx.functions[id]
! 280: for id in list(idx.variables.keys()):
1.1 misho 281: #
282: # macro might be used to override functions or variables
283: # definitions
284: #
1.1.1.3 ! misho 285: if id in self.macros:
! 286: del self.macros[id]
! 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))
! 290: else:
! 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))
! 297: else:
! 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))
! 304: else:
! 305: self.typedefs[id] = idx.typedefs[id]
! 306: self.identifiers[id] = idx.typedefs[id]
! 307: for id in list(idx.macros.keys()):
1.1 misho 308: #
309: # macro might be used to override functions or variables
310: # definitions
311: #
1.1.1.3 ! misho 312: if id in self.variables:
1.1 misho 313: continue
1.1.1.3 ! misho 314: if id in self.functions:
1.1 misho 315: continue
1.1.1.3 ! misho 316: if id in self.enums:
1.1 misho 317: continue
1.1.1.3 ! misho 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))
! 321: else:
! 322: self.macros[id] = idx.macros[id]
! 323: self.identifiers[id] = idx.macros[id]
! 324: for id in list(idx.enums.keys()):
! 325: if id in self.enums:
! 326: print("enum %s from %s redeclared in %s" % (
! 327: id, self.enums[id].header, idx.enums[id].header))
! 328: else:
! 329: self.enums[id] = idx.enums[id]
! 330: self.identifiers[id] = idx.enums[id]
1.1 misho 331:
332: def merge_public(self, idx):
1.1.1.3 ! misho 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:" \
! 339: % id)
! 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)
! 344: # else:
! 345: # print "Function %s from %s is not declared in headers" % (
! 346: # id, idx.functions[id].module)
! 347: # TODO: do the same for variables.
1.1 misho 348:
349: def analyze_dict(self, type, dict):
350: count = 0
1.1.1.3 ! misho 351: public = 0
! 352: for name in list(dict.keys()):
! 353: id = dict[name]
! 354: count = count + 1
! 355: if id.static == 0:
! 356: public = public + 1
1.1 misho 357: if count != public:
1.1.1.3 ! misho 358: print(" %d %s , %d public" % (count, type, public))
! 359: elif count != 0:
! 360: print(" %d public %s" % (count, type))
1.1 misho 361:
362:
363: def analyze(self):
1.1.1.3 ! misho 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)
1.1 misho 369:
370: class CLexer:
371: """A lexer for the C language, tokenize the input by reading and
372: analyzing it line by line"""
373: def __init__(self, input):
374: self.input = input
1.1.1.3 ! misho 375: self.tokens = []
! 376: self.line = ""
! 377: self.lineno = 0
1.1 misho 378:
379: def getline(self):
380: line = ''
1.1.1.3 ! misho 381: while line == '':
! 382: line = self.input.readline()
! 383: if not line:
! 384: return None
! 385: self.lineno = self.lineno + 1
! 386: line = line.lstrip()
! 387: line = line.rstrip()
! 388: if line == '':
! 389: continue
! 390: while line[-1] == '\\':
! 391: line = line[:-1]
! 392: n = self.input.readline()
! 393: self.lineno = self.lineno + 1
! 394: n = n.lstrip()
! 395: n = n.rstrip()
! 396: if not n:
! 397: break
! 398: else:
! 399: line = line + n
1.1 misho 400: return line
401:
402: def getlineno(self):
403: return self.lineno
404:
405: def push(self, token):
406: self.tokens.insert(0, token);
407:
408: def debug(self):
1.1.1.3 ! misho 409: print("Last token: ", self.last)
! 410: print("Token queue: ", self.tokens)
! 411: print("Line %d end: " % (self.lineno), self.line)
1.1 misho 412:
413: def token(self):
414: while self.tokens == []:
1.1.1.3 ! misho 415: if self.line == "":
! 416: line = self.getline()
! 417: else:
! 418: line = self.line
! 419: self.line = ""
! 420: if line == None:
! 421: return None
! 422:
! 423: if line[0] == '#':
! 424: self.tokens = list(map((lambda x: ('preproc', x)),
! 425: line.split()))
! 426: break;
! 427: l = len(line)
! 428: if line[0] == '"' or line[0] == "'":
! 429: end = line[0]
! 430: line = line[1:]
! 431: found = 0
! 432: tok = ""
! 433: while found == 0:
! 434: i = 0
! 435: l = len(line)
! 436: while i < l:
! 437: if line[i] == end:
! 438: self.line = line[i+1:]
! 439: line = line[:i]
! 440: l = i
! 441: found = 1
! 442: break
! 443: if line[i] == '\\':
! 444: i = i + 1
! 445: i = i + 1
! 446: tok = tok + line
! 447: if found == 0:
! 448: line = self.getline()
! 449: if line == None:
! 450: return None
! 451: self.last = ('string', tok)
! 452: return self.last
! 453:
! 454: if l >= 2 and line[0] == '/' and line[1] == '*':
! 455: line = line[2:]
! 456: found = 0
! 457: tok = ""
! 458: while found == 0:
! 459: i = 0
! 460: l = len(line)
! 461: while i < l:
! 462: if line[i] == '*' and i+1 < l and line[i+1] == '/':
! 463: self.line = line[i+2:]
! 464: line = line[:i-1]
! 465: l = i
! 466: found = 1
! 467: break
! 468: i = i + 1
! 469: if tok != "":
! 470: tok = tok + "\n"
! 471: tok = tok + line
! 472: if found == 0:
! 473: line = self.getline()
! 474: if line == None:
! 475: return None
! 476: self.last = ('comment', tok)
! 477: return self.last
! 478: if l >= 2 and line[0] == '/' and line[1] == '/':
! 479: line = line[2:]
! 480: self.last = ('comment', line)
! 481: return self.last
! 482: i = 0
! 483: while i < l:
! 484: if line[i] == '/' and i+1 < l and line[i+1] == '/':
! 485: self.line = line[i:]
! 486: line = line[:i]
! 487: break
! 488: if line[i] == '/' and i+1 < l and line[i+1] == '*':
! 489: self.line = line[i:]
! 490: line = line[:i]
! 491: break
! 492: if line[i] == '"' or line[i] == "'":
! 493: self.line = line[i:]
! 494: line = line[:i]
! 495: break
! 496: i = i + 1
! 497: l = len(line)
! 498: i = 0
! 499: while i < l:
! 500: if line[i] == ' ' or line[i] == '\t':
! 501: i = i + 1
! 502: continue
! 503: o = ord(line[i])
! 504: if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
! 505: (o >= 48 and o <= 57):
! 506: s = i
! 507: while i < l:
! 508: o = ord(line[i])
! 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:
! 512: i = i + 1
! 513: else:
! 514: break
! 515: self.tokens.append(('name', line[s:i]))
! 516: continue
! 517: if "(){}:;,[]".find(line[i]) != -1:
1.1 misho 518: # if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
1.1.1.3 ! misho 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]))
! 522: i = i + 1
! 523: continue
! 524: if "+-*><=/%&!|.".find(line[i]) != -1:
1.1 misho 525: # if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
1.1.1.3 ! misho 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', '...'))
! 532: i = i + 3
! 533: continue
! 534:
! 535: j = i + 1
! 536: if j < l and (
! 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]))
! 543: i = j + 1
! 544: else:
! 545: self.tokens.append(('op', line[i]))
! 546: i = i + 1
! 547: continue
! 548: s = i
! 549: while i < l:
! 550: o = ord(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
! 565: # line[i] != '<'):
! 566: i = i + 1
! 567: else:
! 568: break
! 569: self.tokens.append(('name', line[s:i]))
! 570:
! 571: tok = self.tokens[0]
! 572: self.tokens = self.tokens[1:]
! 573: self.last = tok
! 574: return tok
1.1 misho 575:
576: class CParser:
577: """The C module parser"""
578: def __init__(self, filename, idx = None):
579: self.filename = filename
1.1.1.3 ! misho 580: if len(filename) > 2 and filename[-2:] == '.h':
! 581: self.is_header = 1
! 582: else:
! 583: self.is_header = 0
1.1 misho 584: self.input = open(filename)
1.1.1.3 ! misho 585: self.lexer = CLexer(self.input)
! 586: if idx == None:
! 587: self.index = index()
! 588: else:
! 589: self.index = idx
! 590: self.top_comment = ""
! 591: self.last_comment = ""
! 592: self.comment = None
! 593: self.collect_ref = 0
! 594: self.no_error = 0
! 595: self.conditionals = []
! 596: self.defines = []
1.1 misho 597:
598: def collect_references(self):
599: self.collect_ref = 1
600:
601: def stop_error(self):
602: self.no_error = 1
603:
604: def start_error(self):
605: self.no_error = 0
606:
607: def lineno(self):
608: return self.lexer.getlineno()
609:
610: def index_add(self, name, module, static, type, info=None, extra = None):
1.1.1.3 ! misho 611: if self.is_header == 1:
! 612: self.index.add(name, module, module, static, type, self.lineno(),
! 613: info, extra, self.conditionals)
! 614: else:
! 615: self.index.add(name, None, module, static, type, self.lineno(),
! 616: info, extra, self.conditionals)
1.1 misho 617:
618: def index_add_ref(self, name, module, static, type, info=None,
619: extra = None):
1.1.1.3 ! misho 620: if self.is_header == 1:
! 621: self.index.add_ref(name, module, module, static, type,
! 622: self.lineno(), info, extra, self.conditionals)
! 623: else:
! 624: self.index.add_ref(name, None, module, static, type, self.lineno(),
! 625: info, extra, self.conditionals)
1.1 misho 626:
627: def warning(self, msg):
628: if self.no_error:
1.1.1.3 ! misho 629: return
! 630: print(msg)
1.1 misho 631:
632: def error(self, msg, token=-1):
633: if self.no_error:
1.1.1.3 ! misho 634: return
1.1 misho 635:
1.1.1.3 ! misho 636: print("Parse Error: " + msg)
! 637: if token != -1:
! 638: print("Got token ", token)
! 639: self.lexer.debug()
! 640: sys.exit(1)
1.1 misho 641:
642: def debug(self, msg, token=-1):
1.1.1.3 ! misho 643: print("Debug: " + msg)
! 644: if token != -1:
! 645: print("Got token ", token)
! 646: self.lexer.debug()
1.1 misho 647:
648: def parseTopComment(self, comment):
1.1.1.3 ! misho 649: res = {}
! 650: lines = comment.split("\n")
! 651: item = None
! 652: for line in lines:
! 653: while line != "" and (line[0] == ' ' or line[0] == '\t'):
! 654: line = line[1:]
! 655: while line != "" and line[0] == '*':
! 656: line = line[1:]
! 657: while line != "" and (line[0] == ' ' or line[0] == '\t'):
! 658: line = line[1:]
! 659: try:
! 660: (it, line) = line.split(":", 1)
! 661: item = it
! 662: while line != "" and (line[0] == ' ' or line[0] == '\t'):
! 663: line = line[1:]
! 664: if item in res:
! 665: res[item] = res[item] + " " + line
! 666: else:
! 667: res[item] = line
! 668: except:
! 669: if item != None:
! 670: if item in res:
! 671: res[item] = res[item] + " " + line
! 672: else:
! 673: res[item] = line
! 674: self.index.info = res
1.1 misho 675:
676: def parseComment(self, token):
677: if self.top_comment == "":
1.1.1.3 ! misho 678: self.top_comment = token[1]
! 679: if self.comment == None or token[1][0] == '*':
! 680: self.comment = token[1];
! 681: else:
! 682: self.comment = self.comment + token[1]
! 683: token = self.lexer.token()
1.1 misho 684:
1.1.1.3 ! misho 685: if self.comment.find("DOC_DISABLE") != -1:
! 686: self.stop_error()
1.1 misho 687:
1.1.1.3 ! misho 688: if self.comment.find("DOC_ENABLE") != -1:
! 689: self.start_error()
1.1 misho 690:
1.1.1.3 ! misho 691: return token
1.1 misho 692:
693: #
694: # Parse a comment block associate to a typedef
695: #
696: def parseTypeComment(self, name, quiet = 0):
697: if name[0:2] == '__':
1.1.1.3 ! misho 698: quiet = 1
1.1 misho 699:
700: args = []
1.1.1.3 ! misho 701: desc = ""
1.1 misho 702:
703: if self.comment == None:
1.1.1.3 ! misho 704: if not quiet:
! 705: self.warning("Missing comment for type %s" % (name))
! 706: return((args, desc))
1.1 misho 707: if self.comment[0] != '*':
1.1.1.3 ! misho 708: if not quiet:
! 709: self.warning("Missing * in type comment for %s" % (name))
! 710: return((args, desc))
! 711: lines = self.comment.split('\n')
! 712: if lines[0] == '*':
! 713: del lines[0]
! 714: if lines[0] != "* %s:" % (name):
! 715: if not quiet:
! 716: self.warning("Misformatted type comment for %s" % (name))
! 717: self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
! 718: return((args, desc))
! 719: del lines[0]
! 720: while len(lines) > 0 and lines[0] == '*':
! 721: del lines[0]
! 722: desc = ""
! 723: while len(lines) > 0:
! 724: l = lines[0]
! 725: while len(l) > 0 and l[0] == '*':
! 726: l = l[1:]
! 727: l = l.strip()
! 728: desc = desc + " " + l
! 729: del lines[0]
! 730:
! 731: desc = desc.strip()
! 732:
! 733: if quiet == 0:
! 734: if desc == "":
! 735: self.warning("Type comment for %s lack description of the macro" % (name))
1.1 misho 736:
1.1.1.3 ! misho 737: return(desc)
1.1 misho 738: #
739: # Parse a comment block associate to a macro
740: #
741: def parseMacroComment(self, name, quiet = 0):
742: if name[0:2] == '__':
1.1.1.3 ! misho 743: quiet = 1
1.1 misho 744:
745: args = []
1.1.1.3 ! misho 746: desc = ""
1.1 misho 747:
748: if self.comment == None:
1.1.1.3 ! misho 749: if not quiet:
! 750: self.warning("Missing comment for macro %s" % (name))
! 751: return((args, desc))
1.1 misho 752: if self.comment[0] != '*':
1.1.1.3 ! misho 753: if not quiet:
! 754: self.warning("Missing * in macro comment for %s" % (name))
! 755: return((args, desc))
! 756: lines = self.comment.split('\n')
! 757: if lines[0] == '*':
! 758: del lines[0]
! 759: if lines[0] != "* %s:" % (name):
! 760: if not quiet:
! 761: self.warning("Misformatted macro comment for %s" % (name))
! 762: self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
! 763: return((args, desc))
! 764: del lines[0]
! 765: while lines[0] == '*':
! 766: del lines[0]
! 767: while len(lines) > 0 and lines[0][0:3] == '* @':
! 768: l = lines[0][3:]
! 769: try:
! 770: (arg, desc) = l.split(':', 1)
! 771: desc=desc.strip()
! 772: arg=arg.strip()
1.1 misho 773: except:
1.1.1.3 ! misho 774: if not quiet:
! 775: self.warning("Misformatted macro comment for %s" % (name))
! 776: self.warning(" problem with '%s'" % (lines[0]))
! 777: del lines[0]
! 778: continue
! 779: del lines[0]
! 780: l = lines[0].strip()
! 781: while len(l) > 2 and l[0:3] != '* @':
! 782: while l[0] == '*':
! 783: l = l[1:]
! 784: desc = desc + ' ' + l.strip()
! 785: del lines[0]
! 786: if len(lines) == 0:
! 787: break
! 788: l = lines[0]
1.1 misho 789: args.append((arg, desc))
1.1.1.3 ! misho 790: while len(lines) > 0 and lines[0] == '*':
! 791: del lines[0]
! 792: desc = ""
! 793: while len(lines) > 0:
! 794: l = lines[0]
! 795: while len(l) > 0 and l[0] == '*':
! 796: l = l[1:]
! 797: l = l.strip()
! 798: desc = desc + " " + l
! 799: del lines[0]
! 800:
! 801: desc = desc.strip()
! 802:
! 803: if quiet == 0:
! 804: if desc == "":
! 805: self.warning("Macro comment for %s lack description of the macro" % (name))
1.1 misho 806:
1.1.1.3 ! misho 807: return((args, desc))
1.1 misho 808:
809: #
810: # Parse a comment block and merge the informations found in the
811: # parameters descriptions, finally returns a block as complete
812: # as possible
813: #
814: def mergeFunctionComment(self, name, description, quiet = 0):
815: if name == 'main':
1.1.1.3 ! misho 816: quiet = 1
1.1 misho 817: if name[0:2] == '__':
1.1.1.3 ! misho 818: quiet = 1
1.1 misho 819:
1.1.1.3 ! misho 820: (ret, args) = description
! 821: desc = ""
! 822: retdesc = ""
1.1 misho 823:
824: if self.comment == None:
1.1.1.3 ! misho 825: if not quiet:
! 826: self.warning("Missing comment for function %s" % (name))
! 827: return(((ret[0], retdesc), args, desc))
1.1 misho 828: if self.comment[0] != '*':
1.1.1.3 ! misho 829: if not quiet:
! 830: self.warning("Missing * in function comment for %s" % (name))
! 831: return(((ret[0], retdesc), args, desc))
! 832: lines = self.comment.split('\n')
! 833: if lines[0] == '*':
! 834: del lines[0]
! 835: if lines[0] != "* %s:" % (name):
! 836: if not quiet:
! 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))
! 840: del lines[0]
! 841: while lines[0] == '*':
! 842: del lines[0]
! 843: nbargs = len(args)
! 844: while len(lines) > 0 and lines[0][0:3] == '* @':
! 845: l = lines[0][3:]
! 846: try:
! 847: (arg, desc) = l.split(':', 1)
! 848: desc=desc.strip()
! 849: arg=arg.strip()
1.1 misho 850: except:
1.1.1.3 ! misho 851: if not quiet:
! 852: self.warning("Misformatted function comment for %s" % (name))
! 853: self.warning(" problem with '%s'" % (lines[0]))
! 854: del lines[0]
! 855: continue
! 856: del lines[0]
! 857: l = lines[0].strip()
! 858: while len(l) > 2 and l[0:3] != '* @':
! 859: while l[0] == '*':
! 860: l = l[1:]
! 861: desc = desc + ' ' + l.strip()
! 862: del lines[0]
! 863: if len(lines) == 0:
! 864: break
! 865: l = lines[0]
! 866: i = 0
! 867: while i < nbargs:
! 868: if args[i][1] == arg:
! 869: args[i] = (args[i][0], arg, desc)
! 870: break;
! 871: i = i + 1
! 872: if i >= nbargs:
! 873: if not quiet:
! 874: self.warning("Unable to find arg %s from function comment for %s" % (
! 875: arg, name))
! 876: while len(lines) > 0 and lines[0] == '*':
! 877: del lines[0]
! 878: desc = ""
! 879: while len(lines) > 0:
! 880: l = lines[0]
! 881: while len(l) > 0 and l[0] == '*':
! 882: l = l[1:]
! 883: l = l.strip()
! 884: if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
! 885: try:
! 886: l = l.split(' ', 1)[1]
! 887: except:
! 888: l = ""
! 889: retdesc = l.strip()
! 890: del lines[0]
! 891: while len(lines) > 0:
! 892: l = lines[0]
! 893: while len(l) > 0 and l[0] == '*':
! 894: l = l[1:]
! 895: l = l.strip()
! 896: retdesc = retdesc + " " + l
! 897: del lines[0]
! 898: else:
! 899: desc = desc + " " + l
! 900: del lines[0]
! 901:
! 902: retdesc = retdesc.strip()
! 903: desc = desc.strip()
1.1 misho 904:
1.1.1.3 ! misho 905: if quiet == 0:
! 906: #
! 907: # report missing comments
! 908: #
! 909: i = 0
! 910: while i < nbargs:
! 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]))
! 914: i = i + 1
! 915: if retdesc == "" and ret[0] != "void":
! 916: self.warning("Function comment for %s lacks description of return value" % (name))
! 917: if desc == "":
! 918: self.warning("Function comment for %s lacks description of the function" % (name))
! 919:
! 920: return(((ret[0], retdesc), args, desc))
1.1 misho 921:
922: def parsePreproc(self, token):
1.1.1.3 ! misho 923: if debug:
! 924: print("=> preproc ", token, self.lexer.tokens)
1.1 misho 925: name = token[1]
1.1.1.3 ! misho 926: if name == "#include":
! 927: token = self.lexer.token()
! 928: if token == None:
! 929: return None
! 930: if token[0] == 'preproc':
! 931: self.index_add(token[1], self.filename, not self.is_header,
! 932: "include")
! 933: return self.lexer.token()
! 934: return token
! 935: if name == "#define":
! 936: token = self.lexer.token()
! 937: if token == None:
! 938: return None
! 939: if token[0] == 'preproc':
! 940: # TODO macros with arguments
! 941: name = token[1]
! 942: lst = []
! 943: token = self.lexer.token()
! 944: while token != None and token[0] == 'preproc' and \
! 945: token[1][0] != '#':
! 946: lst.append(token[1])
! 947: token = self.lexer.token()
1.1 misho 948: try:
1.1.1.3 ! misho 949: name = name.split('(') [0]
1.1 misho 950: except:
951: pass
952: info = self.parseMacroComment(name, not self.is_header)
1.1.1.3 ! misho 953: self.index_add(name, self.filename, not self.is_header,
! 954: "macro", info)
! 955: return token
! 956:
! 957: #
! 958: # Processing of conditionals modified by Bill 1/1/05
! 959: #
! 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.
! 965: #
! 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'
! 973: #
! 974: if name == "#ifdef":
! 975: apstr = self.lexer.tokens[0][1]
! 976: try:
! 977: self.defines.append(apstr)
! 978: if apstr.find('ENABLED') != -1:
! 979: self.conditionals.append("defined(%s)" % apstr)
! 980: except:
! 981: pass
! 982: elif name == "#ifndef":
! 983: apstr = self.lexer.tokens[0][1]
! 984: try:
! 985: self.defines.append(apstr)
! 986: if apstr.find('ENABLED') != -1:
! 987: self.conditionals.append("!defined(%s)" % apstr)
! 988: except:
! 989: pass
! 990: elif name == "#if":
! 991: apstr = ""
! 992: for tok in self.lexer.tokens:
! 993: if apstr != "":
! 994: apstr = apstr + " "
! 995: apstr = apstr + tok[1]
! 996: try:
! 997: self.defines.append(apstr)
! 998: if apstr.find('ENABLED') != -1:
! 999: self.conditionals.append(apstr)
! 1000: except:
! 1001: pass
! 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 \
! 1013: token[1][0] != '#':
! 1014: token = self.lexer.token()
! 1015: return token
1.1 misho 1016:
1017: #
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.
1021: #
1022: def token(self):
1023: global ignored_words
1024:
1025: token = self.lexer.token()
1.1.1.3 ! misho 1026: while token != None:
! 1027: if token[0] == 'comment':
! 1028: token = self.parseComment(token)
! 1029: continue
! 1030: elif token[0] == 'preproc':
! 1031: token = self.parsePreproc(token)
! 1032: continue
! 1033: elif token[0] == "name" and token[1] == "__const":
! 1034: token = ("name", "const")
! 1035: return token
! 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()
! 1040: return token
! 1041: elif token[0] == "name" and token[1] in ignored_words:
! 1042: (n, info) = ignored_words[token[1]]
! 1043: i = 0
! 1044: while i < n:
! 1045: token = self.lexer.token()
! 1046: i = i + 1
! 1047: token = self.lexer.token()
! 1048: continue
! 1049: else:
! 1050: if debug:
! 1051: print("=> ", token)
! 1052: return token
! 1053: return None
1.1 misho 1054:
1055: #
1056: # Parse a typedef, it records the type and its name.
1057: #
1058: def parseTypedef(self, token):
1059: if token == None:
1.1.1.3 ! misho 1060: return None
! 1061: token = self.parseType(token)
! 1062: if token == None:
! 1063: self.error("parsing typedef")
! 1064: return None
! 1065: base_type = self.type
! 1066: type = base_type
! 1067: #self.debug("end typedef type", token)
! 1068: while token != None:
! 1069: if token[0] == "name":
! 1070: name = token[1]
! 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,
! 1077: "functype", d)
! 1078: else:
! 1079: if base_type == "struct":
! 1080: self.index_add(name, self.filename, not self.is_header,
! 1081: "struct", type)
! 1082: base_type = "struct " + name
! 1083: else:
! 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()
! 1089: else:
! 1090: self.error("parsing typedef: expecting a name")
! 1091: return token
! 1092: #self.debug("end typedef", token)
! 1093: if token != None and token[0] == 'sep' and token[1] == ',':
! 1094: type = base_type
! 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] == ';':
! 1100: break;
! 1101: elif token != None and token[0] == 'name':
! 1102: type = base_type
! 1103: continue;
! 1104: else:
! 1105: self.error("parsing typedef: expecting ';'", token)
! 1106: return token
! 1107: token = self.token()
! 1108: return token
1.1 misho 1109:
1110: #
1111: # Parse a C code block, used for functions it parse till
1112: # the balancing } included
1113: #
1114: def parseBlock(self, token):
1115: while token != None:
1.1.1.3 ! misho 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] == "}":
! 1120: self.comment = None
! 1121: token = self.token()
! 1122: return token
! 1123: else:
! 1124: if self.collect_ref == 1:
! 1125: oldtok = token
! 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,
! 1130: 0, "function")
! 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,
! 1137: 0, "type")
! 1138: elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
! 1139: self.index_add_ref(oldtok[1], self.filename,
! 1140: 0, "typedef")
! 1141: elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
! 1142: self.index_add_ref(oldtok[1], self.filename,
! 1143: 0, "typedef")
! 1144:
! 1145: else:
! 1146: token = self.token()
! 1147: return token
1.1 misho 1148:
1149: #
1150: # Parse a C struct definition till the balancing }
1151: #
1152: def parseStruct(self, token):
1153: fields = []
1.1.1.3 ! misho 1154: #self.debug("start parseStruct", token)
1.1 misho 1155: while token != None:
1.1.1.3 ! misho 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)
! 1162: #print fields
! 1163: token = self.token()
! 1164: return token
! 1165: else:
! 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":
! 1171: fname = token[1]
! 1172: token = self.token()
! 1173: if token[0] == "sep" and token[1] == ";":
! 1174: self.comment = None
! 1175: token = self.token()
! 1176: fields.append((self.type, fname, self.comment))
! 1177: self.comment = None
! 1178: else:
! 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()
! 1187: else:
! 1188: self.error("parseStruct: expecting ;", token)
! 1189: else:
! 1190: self.error("parseStruct: name", token)
! 1191: token = self.token()
! 1192: self.type = base_type;
1.1 misho 1193: self.struct_fields = fields
1.1.1.3 ! misho 1194: #self.debug("end parseStruct", token)
! 1195: #print fields
! 1196: return token
1.1 misho 1197:
1198: #
1199: # Parse a C enum block, parse till the balancing }
1200: #
1201: def parseEnumBlock(self, token):
1202: self.enums = []
1.1.1.3 ! misho 1203: name = None
! 1204: self.comment = None
! 1205: comment = ""
! 1206: value = "0"
1.1 misho 1207: while token != None:
1.1.1.3 ! misho 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] == "}":
! 1212: if name != None:
! 1213: if self.comment != None:
! 1214: comment = self.comment
! 1215: self.comment = None
! 1216: self.enums.append((name, value, comment))
! 1217: token = self.token()
! 1218: return token
! 1219: elif token[0] == "name":
! 1220: if name != None:
! 1221: if self.comment != None:
! 1222: comment = self.comment.strip()
! 1223: self.comment = None
! 1224: self.enums.append((name, value, comment))
! 1225: name = token[1]
! 1226: comment = ""
! 1227: token = self.token()
! 1228: if token[0] == "op" and token[1][0] == "=":
! 1229: value = ""
! 1230: if len(token[1]) > 1:
! 1231: value = token[1][1:]
! 1232: token = self.token()
! 1233: while token[0] != "sep" or (token[1] != ',' and
! 1234: token[1] != '}'):
! 1235: value = value + token[1]
! 1236: token = self.token()
! 1237: else:
! 1238: try:
! 1239: value = "%d" % (int(value) + 1)
! 1240: except:
! 1241: self.warning("Failed to compute value of enum %s" % (name))
! 1242: value=""
! 1243: if token[0] == "sep" and token[1] == ",":
! 1244: token = self.token()
! 1245: else:
! 1246: token = self.token()
! 1247: return token
1.1 misho 1248:
1249: #
1250: # Parse a C definition block, used for structs it parse till
1251: # the balancing }
1252: #
1253: def parseTypeBlock(self, token):
1254: while token != None:
1.1.1.3 ! misho 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()
! 1260: return token
! 1261: else:
! 1262: token = self.token()
! 1263: return token
1.1 misho 1264:
1265: #
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
1269: #
1270: def parseType(self, token):
1271: self.type = ""
1.1.1.3 ! misho 1272: self.struct_fields = []
1.1 misho 1273: self.signature = None
1.1.1.3 ! misho 1274: if token == None:
! 1275: return token
1.1 misho 1276:
1.1.1.3 ! misho 1277: while token[0] == "name" and (
! 1278: token[1] == "const" or \
! 1279: token[1] == "unsigned" or \
! 1280: token[1] == "signed"):
! 1281: if self.type == "":
! 1282: self.type = token[1]
! 1283: else:
! 1284: self.type = self.type + " " + token[1]
! 1285: token = self.token()
1.1 misho 1286:
1287: if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1.1.1.3 ! misho 1288: if self.type == "":
! 1289: self.type = token[1]
! 1290: else:
! 1291: self.type = self.type + " " + token[1]
! 1292: if token[0] == "name" and token[1] == "int":
! 1293: if self.type == "":
! 1294: self.type = tmp[1]
! 1295: else:
! 1296: self.type = self.type + " " + tmp[1]
1.1 misho 1297:
1298: elif token[0] == "name" and token[1] == "struct":
1.1.1.3 ! misho 1299: if self.type == "":
! 1300: self.type = token[1]
! 1301: else:
! 1302: self.type = self.type + " " + token[1]
! 1303: token = self.token()
! 1304: nametok = None
! 1305: if token[0] == "name":
! 1306: nametok = token
! 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":
! 1318: nametok = token
! 1319: token = self.token()
! 1320: else:
! 1321: self.error("struct : expecting name", token)
! 1322: return token
! 1323: elif token != None and token[0] == "name" and nametok != None:
! 1324: self.type = self.type + " " + nametok[1]
! 1325: return token
! 1326:
! 1327: if nametok != None:
! 1328: self.lexer.push(token)
! 1329: token = nametok
! 1330: return token
1.1 misho 1331:
1332: elif token[0] == "name" and token[1] == "enum":
1.1.1.3 ! misho 1333: if self.type == "":
! 1334: self.type = token[1]
! 1335: else:
! 1336: self.type = self.type + " " + token[1]
! 1337: self.enums = []
! 1338: token = self.token()
! 1339: if token != None and token[0] == "sep" and token[1] == "{":
! 1340: token = self.token()
! 1341: token = self.parseEnumBlock(token)
! 1342: else:
! 1343: self.error("parsing enum: expecting '{'", token)
! 1344: enum_type = None
! 1345: if token != None and token[0] != "name":
! 1346: self.lexer.push(token)
! 1347: token = ("name", "enum")
! 1348: else:
! 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))
! 1354: return token
! 1355:
! 1356: elif token[0] == "name":
! 1357: if self.type == "":
! 1358: self.type = token[1]
! 1359: else:
! 1360: self.type = self.type + " " + token[1]
! 1361: else:
! 1362: self.error("parsing type %s: expecting a name" % (self.type),
! 1363: token)
! 1364: return token
! 1365: token = self.token()
1.1 misho 1366: while token != None and (token[0] == "op" or
1.1.1.3 ! misho 1367: token[0] == "name" and token[1] == "const"):
! 1368: self.type = self.type + " " + token[1]
! 1369: token = self.token()
! 1370:
! 1371: #
! 1372: # if there is a parenthesis here, this means a function type
! 1373: #
! 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);
! 1382: return token
! 1383: self.type = self.type + token[1]
! 1384: nametok = token
! 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()
! 1391: type = self.type;
! 1392: token = self.parseSignature(token);
! 1393: self.type = type;
! 1394: else:
! 1395: self.error("parsing function type, '(' expected", token);
! 1396: return token
! 1397: else:
! 1398: self.error("parsing function type, ')' expected", token);
! 1399: return token
! 1400: self.lexer.push(token)
! 1401: token = nametok
! 1402: return token
1.1 misho 1403:
1404: #
1.1.1.3 ! misho 1405: # do some lookahead for arrays
! 1406: #
! 1407: if token != None and token[0] == "name":
! 1408: nametok = token
! 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()
! 1422: else:
! 1423: self.error("parsing array type, ']' expected", token);
! 1424: return 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)
! 1430: token = nametok
1.1 misho 1431:
1.1.1.3 ! misho 1432: return token
1.1 misho 1433:
1434: #
1435: # Parse a signature: '(' has been parsed and we scan the type definition
1436: # up to the ')' included
1437: def parseSignature(self, token):
1438: signature = []
1.1.1.3 ! misho 1439: if token != None and token[0] == "sep" and token[1] == ')':
! 1440: self.signature = []
! 1441: token = self.token()
! 1442: return 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()
! 1450: continue
! 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))
! 1455: else:
! 1456: signature.append((self.type, None, None))
! 1457: if token != None and token[0] == "sep":
! 1458: if token[1] == ',':
! 1459: token = self.token()
! 1460: continue
! 1461: elif token[1] == ')':
! 1462: token = self.token()
! 1463: break
! 1464: self.signature = signature
! 1465: return token
1.1 misho 1466:
1467: #
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.
1470: #
1471: def parseGlobal(self, token):
1472: static = 0
1473: if token[1] == 'extern':
1.1.1.3 ! misho 1474: token = self.token()
! 1475: if token == None:
! 1476: return token
! 1477: if token[0] == 'string':
! 1478: if token[1] == 'C':
! 1479: token = self.token()
! 1480: if token == None:
! 1481: return 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
! 1486: token[1] != "}"):
! 1487: if token[0] == 'name':
! 1488: token = self.parseGlobal(token)
! 1489: else:
! 1490: self.error(
! 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()
! 1496: return token
! 1497: else:
! 1498: return token
! 1499: elif token[1] == 'static':
! 1500: static = 1
! 1501: token = self.token()
! 1502: if token == None or token[0] != 'name':
! 1503: return token
! 1504:
! 1505: if token[1] == 'typedef':
! 1506: token = self.token()
! 1507: return self.parseTypedef(token)
! 1508: else:
! 1509: token = self.parseType(token)
! 1510: type_orig = self.type
! 1511: if token == None or token[0] != "name":
! 1512: return token
! 1513: type = type_orig
! 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":
! 1518: if token[1] == "[":
! 1519: type = type + token[1]
! 1520: token = self.token()
! 1521: while token != None and (token[0] != "sep" or \
! 1522: token[1] != ";"):
! 1523: type = type + token[1]
! 1524: token = self.token()
! 1525:
! 1526: if token != None and token[0] == "op" and token[1] == "=":
! 1527: #
! 1528: # Skip the initialization of the variable
! 1529: #
! 1530: token = self.token()
! 1531: if token[0] == 'sep' and token[1] == '{':
! 1532: token = self.token()
! 1533: token = self.parseBlock(token)
! 1534: else:
! 1535: self.comment = None
! 1536: while token != None and (token[0] != "sep" or \
! 1537: (token[1] != ';' and token[1] != ',')):
! 1538: token = self.token()
! 1539: self.comment = None
! 1540: if token == None or token[0] != "sep" or (token[1] != ';' and
! 1541: token[1] != ','):
! 1542: self.error("missing ';' or ',' after value")
! 1543:
! 1544: if token != None and token[0] == "sep":
! 1545: if token[1] == ";":
! 1546: self.comment = None
! 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)
! 1551: else:
! 1552: self.index_add(self.name, self.filename,
! 1553: not self.is_header, "variable", type)
! 1554: break
! 1555: elif token[1] == "(":
! 1556: token = self.token()
! 1557: token = self.parseSignature(token)
! 1558: if token == None:
! 1559: return None
! 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,
! 1564: "function", d)
! 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,
! 1570: "function", d)
! 1571: token = self.token()
! 1572: token = self.parseBlock(token);
! 1573: elif token[1] == ',':
! 1574: self.comment = None
! 1575: self.index_add(self.name, self.filename, static,
! 1576: "variable", type)
! 1577: type = type_orig
! 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()
! 1585: else:
! 1586: break
1.1 misho 1587:
1.1.1.3 ! misho 1588: return token
1.1 misho 1589:
1590: def parse(self):
1591: self.warning("Parsing %s" % (self.filename))
1592: token = self.token()
1.1.1.3 ! misho 1593: while token != None:
1.1 misho 1594: if token[0] == 'name':
1.1.1.3 ! misho 1595: token = self.parseGlobal(token)
1.1 misho 1596: else:
1.1.1.3 ! misho 1597: self.error("token %s %s unexpected at the top level" % (
! 1598: token[0], token[1]))
! 1599: token = self.parseGlobal(token)
! 1600: return
! 1601: self.parseTopComment(self.top_comment)
1.1 misho 1602: return self.index
1603:
1604:
1605: class docBuilder:
1606: """A documentation builder"""
1607: def __init__(self, name, directories=['.'], excludes=[]):
1608: self.name = name
1609: self.directories = directories
1.1.1.3 ! misho 1610: self.excludes = excludes + list(ignored_files.keys())
! 1611: self.modules = {}
! 1612: self.headers = {}
! 1613: self.idx = index()
1.1 misho 1614: self.xref = {}
1.1.1.3 ! misho 1615: self.index = {}
! 1616: if name == 'libxml2':
! 1617: self.basename = 'libxml'
! 1618: else:
! 1619: self.basename = name
1.1 misho 1620:
1621: def indexString(self, id, str):
1.1.1.3 ! misho 1622: if str == None:
! 1623: return
! 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:
! 1641: try:
! 1642: c = token[0]
! 1643: if string.ascii_letters.find(c) < 0:
! 1644: pass
! 1645: elif len(token) < 3:
! 1646: pass
! 1647: else:
! 1648: lower = token.lower()
! 1649: # TODO: generalize this a bit
! 1650: if lower == 'and' or lower == 'the':
! 1651: pass
! 1652: elif token in self.xref:
! 1653: self.xref[token].append(id)
! 1654: else:
! 1655: self.xref[token] = [id]
! 1656: except:
! 1657: pass
1.1 misho 1658:
1659: def analyze(self):
1.1.1.3 ! misho 1660: print("Project %s : %d headers, %d modules" % (self.name, len(list(self.headers.keys())), len(list(self.modules.keys()))))
! 1661: self.idx.analyze()
1.1 misho 1662:
1663: def scanHeaders(self):
1.1.1.3 ! misho 1664: for header in list(self.headers.keys()):
! 1665: parser = CParser(header)
! 1666: idx = parser.parse()
! 1667: self.headers[header] = idx;
! 1668: self.idx.merge(idx)
1.1 misho 1669:
1670: def scanModules(self):
1.1.1.3 ! misho 1671: for module in list(self.modules.keys()):
! 1672: parser = CParser(module)
! 1673: idx = parser.parse()
! 1674: # idx.analyze()
! 1675: self.modules[module] = idx
! 1676: self.idx.merge_public(idx)
1.1 misho 1677:
1678: def scan(self):
1679: for directory in self.directories:
1.1.1.3 ! misho 1680: files = glob.glob(directory + "/*.c")
! 1681: for file in files:
! 1682: skip = 0
! 1683: for excl in self.excludes:
! 1684: if file.find(excl) != -1:
! 1685: print("Skipping %s" % file)
! 1686: skip = 1
! 1687: break
! 1688: if skip == 0:
! 1689: self.modules[file] = None;
! 1690: files = glob.glob(directory + "/*.h")
! 1691: for file in files:
! 1692: skip = 0
! 1693: for excl in self.excludes:
! 1694: if file.find(excl) != -1:
! 1695: print("Skipping %s" % file)
! 1696: skip = 1
! 1697: break
! 1698: if skip == 0:
! 1699: self.headers[file] = None;
! 1700: self.scanHeaders()
! 1701: self.scanModules()
1.1 misho 1702:
1703: def modulename_file(self, file):
1704: module = os.path.basename(file)
1.1.1.3 ! misho 1705: if module[-2:] == '.h':
! 1706: module = module[:-2]
! 1707: elif module[-2:] == '.c':
! 1708: module = module[:-2]
! 1709: return module
1.1 misho 1710:
1711: def serialize_enum(self, output, name):
1712: id = self.idx.enums[name]
1713: output.write(" <enum name='%s' file='%s'" % (name,
1.1.1.3 ! misho 1714: self.modulename_file(id.header)))
! 1715: if id.info != None:
! 1716: info = id.info
! 1717: if info[0] != None and info[0] != '':
! 1718: try:
! 1719: val = eval(info[0])
! 1720: except:
! 1721: val = 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]));
1.1 misho 1727: output.write("/>\n")
1728:
1729: def serialize_macro(self, output, name):
1730: id = self.idx.macros[name]
1731: output.write(" <macro name='%s' file='%s'>\n" % (name,
1.1.1.3 ! misho 1732: self.modulename_file(id.header)))
! 1733: if id.info != None:
1.1 misho 1734: try:
1.1.1.3 ! misho 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)
! 1739: for arg in args:
! 1740: (name, desc) = arg
! 1741: if desc != None and desc != "":
! 1742: output.write(" <arg name='%s' info='%s'/>\n" % (
! 1743: name, escape(desc)))
! 1744: self.indexString(name, desc)
! 1745: else:
! 1746: output.write(" <arg name='%s'/>\n" % (name))
1.1 misho 1747: except:
1748: pass
1749: output.write(" </macro>\n")
1750:
1751: def serialize_typedef(self, output, name):
1752: id = self.idx.typedefs[name]
1.1.1.3 ! misho 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))
! 1756: name = id.info[7:]
! 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");
! 1761: try:
! 1762: for field in self.idx.structs[name].info:
! 1763: desc = field[2]
! 1764: self.indexString(name, desc)
! 1765: if desc == None:
! 1766: desc = ''
! 1767: else:
! 1768: desc = escape(desc)
! 1769: output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
! 1770: except:
! 1771: print("Failed to serialize struct %s" % (name))
! 1772: output.write(" </struct>\n")
! 1773: else:
! 1774: output.write("/>\n");
! 1775: else :
! 1776: output.write(" <typedef name='%s' file='%s' type='%s'" % (
! 1777: name, self.modulename_file(id.header), id.info))
1.1 misho 1778: try:
1.1.1.3 ! misho 1779: desc = id.extra
! 1780: if desc != None and desc != "":
! 1781: output.write(">\n <info>%s</info>\n" % (escape(desc)))
! 1782: output.write(" </typedef>\n")
! 1783: else:
! 1784: output.write("/>\n")
! 1785: except:
! 1786: output.write("/>\n")
1.1 misho 1787:
1788: def serialize_variable(self, output, name):
1789: id = self.idx.variables[name]
1.1.1.3 ! misho 1790: if id.info != None:
! 1791: output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
! 1792: name, self.modulename_file(id.header), id.info))
! 1793: else:
! 1794: output.write(" <variable name='%s' file='%s'/>\n" % (
! 1795: name, self.modulename_file(id.header)))
1.1 misho 1796:
1797: def serialize_function(self, output, name):
1798: id = self.idx.functions[name]
1.1.1.3 ! misho 1799: if name == debugsym:
! 1800: print("=>", id)
1.1 misho 1801:
1802: output.write(" <%s name='%s' file='%s' module='%s'>\n" % (id.type,
1.1.1.3 ! misho 1803: name, self.modulename_file(id.header),
! 1804: self.modulename_file(id.module)))
! 1805: #
! 1806: # Processing of conditionals modified by Bill 1/1/05
! 1807: #
! 1808: if id.conditionals != None:
! 1809: apstr = ""
! 1810: for cond in id.conditionals:
! 1811: if apstr != "":
! 1812: apstr = apstr + " && "
! 1813: apstr = apstr + cond
! 1814: output.write(" <cond>%s</cond>\n"% (apstr));
! 1815: try:
! 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)))
! 1821:
! 1822: output.write(" <info>%s</info>\n" % (escape(desc)))
! 1823: self.indexString(name, desc)
! 1824: if ret[0] != None:
! 1825: if ret[0] == "void":
! 1826: output.write(" <return type='void'/>\n")
! 1827: else:
! 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':
! 1833: continue
! 1834: if param[2] == None:
! 1835: output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
! 1836: else:
! 1837: output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
! 1838: self.indexString(name, param[2])
! 1839: except:
! 1840: print("Failed to save function %s info: " % name, repr(id.info))
1.1 misho 1841: output.write(" </%s>\n" % (id.type))
1842:
1843: def serialize_exports(self, output, file):
1844: module = self.modulename_file(file)
1.1.1.3 ! misho 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'):
! 1849: try:
! 1850: output.write(" <%s>%s</%s>\n" % (
! 1851: data.lower(),
! 1852: escape(dict.info[data]),
! 1853: data.lower()))
! 1854: except:
! 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")
! 1860:
! 1861: ids = list(dict.macros.keys())
! 1862: ids.sort()
! 1863: for id in uniq(ids):
! 1864: # Macros are sometime used to masquerade other types.
! 1865: if id in dict.functions:
! 1866: continue
! 1867: if id in dict.variables:
! 1868: continue
! 1869: if id in dict.typedefs:
! 1870: continue
! 1871: if id in dict.structs:
! 1872: continue
! 1873: if id in dict.enums:
! 1874: continue
! 1875: output.write(" <exports symbol='%s' type='macro'/>\n" % (id))
! 1876: ids = list(dict.enums.keys())
! 1877: ids.sort()
! 1878: for id in uniq(ids):
! 1879: output.write(" <exports symbol='%s' type='enum'/>\n" % (id))
! 1880: ids = list(dict.typedefs.keys())
! 1881: ids.sort()
! 1882: for id in uniq(ids):
! 1883: output.write(" <exports symbol='%s' type='typedef'/>\n" % (id))
! 1884: ids = list(dict.structs.keys())
! 1885: ids.sort()
! 1886: for id in uniq(ids):
! 1887: output.write(" <exports symbol='%s' type='struct'/>\n" % (id))
! 1888: ids = list(dict.variables.keys())
! 1889: ids.sort()
! 1890: for id in uniq(ids):
! 1891: output.write(" <exports symbol='%s' type='variable'/>\n" % (id))
! 1892: ids = list(dict.functions.keys())
! 1893: ids.sort()
! 1894: for id in uniq(ids):
! 1895: output.write(" <exports symbol='%s' type='function'/>\n" % (id))
! 1896: output.write(" </file>\n")
1.1 misho 1897:
1898: def serialize_xrefs_files(self, output):
1.1.1.3 ! misho 1899: headers = list(self.headers.keys())
1.1 misho 1900: headers.sort()
1901: for file in headers:
1.1.1.3 ! misho 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()))
! 1908: ids.sort()
! 1909: for id in ids:
! 1910: output.write(" <ref name='%s'/>\n" % (id))
! 1911: output.write(" </file>\n")
1.1 misho 1912: pass
1913:
1914: def serialize_xrefs_functions(self, output):
1915: funcs = {}
1.1.1.3 ! misho 1916: for name in list(self.idx.functions.keys()):
! 1917: id = self.idx.functions[name]
! 1918: try:
! 1919: (ret, params, desc) = id.info
! 1920: for param in params:
! 1921: if param[0] == 'void':
! 1922: continue
! 1923: if param[0] in funcs:
! 1924: funcs[param[0]].append(name)
! 1925: else:
! 1926: funcs[param[0]] = [name]
! 1927: except:
! 1928: pass
! 1929: typ = list(funcs.keys())
! 1930: typ.sort()
! 1931: for type in typ:
! 1932: if type == '' or type == 'void' or type == "int" or \
! 1933: type == "char *" or type == "const char *" :
! 1934: continue
! 1935: output.write(" <type name='%s'>\n" % (type))
! 1936: ids = funcs[type]
! 1937: ids.sort()
! 1938: pid = '' # not sure why we have dups, but get rid of them!
! 1939: for id in ids:
! 1940: if id != pid:
! 1941: output.write(" <ref name='%s'/>\n" % (id))
! 1942: pid = id
! 1943: output.write(" </type>\n")
1.1 misho 1944:
1945: def serialize_xrefs_constructors(self, output):
1946: funcs = {}
1.1.1.3 ! misho 1947: for name in list(self.idx.functions.keys()):
! 1948: id = self.idx.functions[name]
! 1949: try:
! 1950: (ret, params, desc) = id.info
! 1951: if ret[0] == "void":
! 1952: continue
! 1953: if ret[0] in funcs:
! 1954: funcs[ret[0]].append(name)
! 1955: else:
! 1956: funcs[ret[0]] = [name]
! 1957: except:
! 1958: pass
! 1959: typ = list(funcs.keys())
! 1960: typ.sort()
! 1961: for type in typ:
! 1962: if type == '' or type == 'void' or type == "int" or \
! 1963: type == "char *" or type == "const char *" :
! 1964: continue
! 1965: output.write(" <type name='%s'>\n" % (type))
! 1966: ids = funcs[type]
! 1967: ids.sort()
! 1968: for id in ids:
! 1969: output.write(" <ref name='%s'/>\n" % (id))
! 1970: output.write(" </type>\n")
1.1 misho 1971:
1972: def serialize_xrefs_alpha(self, output):
1.1.1.3 ! misho 1973: letter = None
! 1974: ids = list(self.idx.identifiers.keys())
! 1975: ids.sort()
! 1976: for id in ids:
! 1977: if id[0] != letter:
! 1978: if letter != None:
! 1979: output.write(" </letter>\n")
! 1980: letter = id[0]
! 1981: output.write(" <letter name='%s'>\n" % (letter))
! 1982: output.write(" <ref name='%s'/>\n" % (id))
! 1983: if letter != None:
! 1984: output.write(" </letter>\n")
1.1 misho 1985:
1986: def serialize_xrefs_references(self, output):
1.1.1.3 ! misho 1987: typ = list(self.idx.identifiers.keys())
! 1988: typ.sort()
! 1989: for id in typ:
! 1990: idf = self.idx.identifiers[id]
! 1991: module = idf.header
! 1992: output.write(" <reference name='%s' href='%s'/>\n" % (id,
! 1993: 'html/' + self.basename + '-' +
! 1994: self.modulename_file(module) + '.html#' +
! 1995: id))
1.1 misho 1996:
1997: def serialize_xrefs_index(self, output):
1998: index = self.xref
1.1.1.3 ! misho 1999: typ = list(index.keys())
! 2000: typ.sort()
! 2001: letter = None
! 2002: count = 0
! 2003: chunk = 0
! 2004: chunks = []
! 2005: for id in typ:
! 2006: if len(index[id]) > 30:
! 2007: continue
! 2008: if id[0] != letter:
! 2009: if letter == None or count > 200:
! 2010: if letter != None:
! 2011: output.write(" </letter>\n")
! 2012: output.write(" </chunk>\n")
! 2013: count = 0
! 2014: chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
! 2015: output.write(" <chunk name='chunk%s'>\n" % (chunk))
! 2016: first_letter = id[0]
! 2017: chunk = chunk + 1
! 2018: elif letter != None:
! 2019: output.write(" </letter>\n")
! 2020: letter = id[0]
! 2021: output.write(" <letter name='%s'>\n" % (letter))
! 2022: output.write(" <word name='%s'>\n" % (id))
! 2023: tokens = index[id];
! 2024: tokens.sort()
! 2025: tok = None
! 2026: for token in tokens:
! 2027: if tok == token:
! 2028: continue
! 2029: tok = token
! 2030: output.write(" <ref name='%s'/>\n" % (token))
! 2031: count = count + 1
! 2032: output.write(" </word>\n")
! 2033: if letter != None:
! 2034: output.write(" </letter>\n")
! 2035: output.write(" </chunk>\n")
! 2036: if count != 0:
! 2037: chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
! 2038: output.write(" <chunks>\n")
! 2039: for ch in chunks:
! 2040: output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
! 2041: ch[0], ch[1], ch[2]))
! 2042: output.write(" </chunks>\n")
1.1 misho 2043:
2044: def serialize_xrefs(self, output):
1.1.1.3 ! misho 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")
1.1 misho 2063:
2064: def serialize(self):
2065: filename = "%s-api.xml" % self.name
1.1.1.3 ! misho 2066: print("Saving XML description %s" % (filename))
1.1 misho 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")
1.1.1.3 ! misho 2071: headers = list(self.headers.keys())
1.1 misho 2072: headers.sort()
2073: for file in headers:
2074: self.serialize_exports(output, file)
2075: output.write(" </files>\n")
2076: output.write(" <symbols>\n")
1.1.1.3 ! misho 2077: macros = list(self.idx.macros.keys())
1.1 misho 2078: macros.sort()
2079: for macro in macros:
2080: self.serialize_macro(output, macro)
1.1.1.3 ! misho 2081: enums = list(self.idx.enums.keys())
1.1 misho 2082: enums.sort()
2083: for enum in enums:
2084: self.serialize_enum(output, enum)
1.1.1.3 ! misho 2085: typedefs = list(self.idx.typedefs.keys())
1.1 misho 2086: typedefs.sort()
2087: for typedef in typedefs:
2088: self.serialize_typedef(output, typedef)
1.1.1.3 ! misho 2089: variables = list(self.idx.variables.keys())
1.1 misho 2090: variables.sort()
2091: for variable in variables:
2092: self.serialize_variable(output, variable)
1.1.1.3 ! misho 2093: functions = list(self.idx.functions.keys())
1.1 misho 2094: functions.sort()
2095: for function in functions:
2096: self.serialize_function(output, function)
2097: output.write(" </symbols>\n")
2098: output.write("</api>\n")
2099: output.close()
2100:
2101: filename = "%s-refs.xml" % self.name
1.1.1.3 ! misho 2102: print("Saving XML Cross References %s" % (filename))
1.1 misho 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")
2108: output.close()
2109:
2110:
2111: def rebuild():
2112: builder = None
2113: if glob.glob("parser.c") != [] :
1.1.1.3 ! misho 2114: print("Rebuilding API description for libxml2")
! 2115: builder = docBuilder("libxml2", [".", "."],
! 2116: ["xmlwin32version.h", "tst.c"])
1.1 misho 2117: elif glob.glob("../parser.c") != [] :
1.1.1.3 ! misho 2118: print("Rebuilding API description for libxml2")
! 2119: builder = docBuilder("libxml2", ["..", "../include/libxml"],
! 2120: ["xmlwin32version.h", "tst.c"])
1.1 misho 2121: elif glob.glob("../libxslt/transform.c") != [] :
1.1.1.3 ! misho 2122: print("Rebuilding API description for libxslt")
! 2123: builder = docBuilder("libxslt", ["../libxslt"],
! 2124: ["win32config.h", "libxslt.h", "tst.c"])
1.1 misho 2125: else:
1.1.1.3 ! misho 2126: print("rebuild() failed, unable to guess the module")
! 2127: return None
1.1 misho 2128: builder.scan()
2129: builder.analyze()
2130: builder.serialize()
2131: if glob.glob("../libexslt/exslt.c") != [] :
2132: extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1.1.1.3 ! misho 2133: extra.scan()
! 2134: extra.analyze()
! 2135: extra.serialize()
1.1 misho 2136: return builder
2137:
2138: #
2139: # for debugging the parser
2140: #
2141: def parse(filename):
2142: parser = CParser(filename)
2143: idx = parser.parse()
2144: return idx
2145:
2146: if __name__ == "__main__":
2147: if len(sys.argv) > 1:
2148: debug = 1
2149: parse(sys.argv[1])
2150: else:
1.1.1.3 ! misho 2151: rebuild()
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>