blob: 2cbf32ff0f21f4458a7ee2bbef4bcc924e4d8703 [file] [log] [blame]
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001#!/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#
Daniel Veillard540a31a2003-01-21 11:21:07 +000010import os, sys
Daniel Veillarda9b66d02002-12-11 14:23:49 +000011import string
12import glob
13
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000014debug=0
Daniel Veillarda2351322004-06-27 12:08:10 +000015#debugsym='ignorableWhitespaceSAXFunc'
16debugsym=None
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000017
Daniel Veillardde0a0a52003-04-24 17:12:57 +000018#
19# C parser analysis code
20#
21ignored_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",
Daniel Veillard92fc02c2003-04-24 23:12:35 +000029 "testOOM.c": "out of memory tester",
30 "testOOMlib.h": "out of memory tester",
31 "testOOMlib.c": "out of memory tester",
Daniel Veillard189f46b2004-01-25 21:03:04 +000032 "rngparser.c": "not yet integrated",
33 "rngparser.h": "not yet integrated",
Daniel Veillarda2351322004-06-27 12:08:10 +000034 "elfgcchack.h": "not a normal header",
Daniel Veillarde43cc572004-11-03 11:50:29 +000035 "testapi.c": "generated regression tests",
Daniel Veillardde0a0a52003-04-24 17:12:57 +000036}
37
38ignored_words = {
39 "WINAPI": (0, "Windows keyword"),
40 "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
William M. Brackcdfa2862003-08-29 06:03:38 +000041 "XMLPUBVAR": (0, "Special macro for extern vars for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000042 "XSLTPUBVAR": (0, "Special macro for extern vars for win32"),
43 "EXSLTPUBVAR": (0, "Special macro for extern vars for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000044 "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000045 "XSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
46 "EXSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000047 "XMLCALL": (0, "Special macro for win32 calls"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000048 "XSLTCALL": (0, "Special macro for win32 calls"),
49 "EXSLTCALL": (0, "Special macro for win32 calls"),
Daniel Veillardde0a0a52003-04-24 17:12:57 +000050 "__declspec": (3, "Windows keyword"),
Daniel Veillarda2351322004-06-27 12:08:10 +000051 "__stdcall": (0, "Windows keyword"),
Daniel Veillardde0a0a52003-04-24 17:12:57 +000052 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
53 "LIBEXSLT_PUBLIC": (0, "macro keyword"),
54 "X_IN_Y": (5, "macro function builder"),
55}
56
Daniel Veillarda9b66d02002-12-11 14:23:49 +000057def escape(raw):
58 raw = string.replace(raw, '&', '&')
59 raw = string.replace(raw, '<', '&lt;')
60 raw = string.replace(raw, '>', '&gt;')
61 raw = string.replace(raw, "'", '&apos;')
62 raw = string.replace(raw, '"', '&quot;')
63 return raw
64
Daniel Veillard2925c0a2003-11-17 13:58:17 +000065def uniq(items):
66 d = {}
67 for item in items:
68 d[item]=1
69 return d.keys()
70
Daniel Veillarda9b66d02002-12-11 14:23:49 +000071class identifier:
Daniel Veillardbe586972003-11-18 20:56:51 +000072 def __init__(self, name, module=None, type=None, lineno = 0,
Daniel Veillarda2351322004-06-27 12:08:10 +000073 info=None, extra=None, conditionals = None):
Daniel Veillardbe586972003-11-18 20:56:51 +000074 self.name = name
75 self.module = module
76 self.type = type
77 self.info = info
78 self.extra = extra
79 self.lineno = lineno
80 self.static = 0
Daniel Veillarda2351322004-06-27 12:08:10 +000081 if conditionals == None or len(conditionals) == 0:
82 self.conditionals = None
83 else:
84 self.conditionals = conditionals[:]
85 if self.name == debugsym:
86 print "=> define %s : %s" % (debugsym, (module, type, info,
87 extra, conditionals))
Daniel Veillarda9b66d02002-12-11 14:23:49 +000088
Daniel Veillardbe586972003-11-18 20:56:51 +000089 def __repr__(self):
90 r = "%s %s:" % (self.type, self.name)
91 if self.static:
92 r = r + " static"
93 if self.module != None:
94 r = r + " from %s" % (self.module)
95 if self.info != None:
96 r = r + " " + `self.info`
97 if self.extra != None:
98 r = r + " " + `self.extra`
Daniel Veillarda2351322004-06-27 12:08:10 +000099 if self.conditionals != None:
100 r = r + " " + `self.conditionals`
Daniel Veillardbe586972003-11-18 20:56:51 +0000101 return r
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000102
103
Daniel Veillardbe586972003-11-18 20:56:51 +0000104 def set_module(self, module):
105 self.module = module
106 def set_type(self, type):
107 self.type = type
108 def set_info(self, info):
109 self.info = info
110 def set_extra(self, extra):
111 self.extra = extra
112 def set_lineno(self, lineno):
113 self.lineno = lineno
114 def set_static(self, static):
115 self.static = static
Daniel Veillarda2351322004-06-27 12:08:10 +0000116 def set_conditionals(self, conditionals):
117 if conditionals == None or len(conditionals) == 0:
118 self.conditionals = None
119 else:
120 self.conditionals = conditionals[:]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000121
Daniel Veillardbe586972003-11-18 20:56:51 +0000122 def get_name(self):
123 return self.name
124 def get_module(self):
125 return self.module
126 def get_type(self):
127 return self.type
128 def get_info(self):
129 return self.info
130 def get_lineno(self):
131 return self.lineno
132 def get_extra(self):
133 return self.extra
134 def get_static(self):
135 return self.static
Daniel Veillarda2351322004-06-27 12:08:10 +0000136 def get_conditionals(self):
137 return self.conditionals
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000138
Daniel Veillarda2351322004-06-27 12:08:10 +0000139 def update(self, module, type = None, info = None, extra=None,
140 conditionals=None):
141 if self.name == debugsym:
142 print "=> update %s : %s" % (debugsym, (module, type, info,
143 extra, conditionals))
Daniel Veillardbe586972003-11-18 20:56:51 +0000144 if module != None and self.module == None:
145 self.set_module(module)
146 if type != None and self.type == None:
147 self.set_type(type)
148 if info != None:
149 self.set_info(info)
150 if extra != None:
151 self.set_extra(extra)
Daniel Veillarda2351322004-06-27 12:08:10 +0000152 if conditionals != None:
153 self.set_conditionals(conditionals)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000154
155
156class index:
Daniel Veillardbe586972003-11-18 20:56:51 +0000157 def __init__(self, name = "noname"):
158 self.name = name
159 self.identifiers = {}
160 self.functions = {}
161 self.variables = {}
162 self.includes = {}
163 self.structs = {}
164 self.enums = {}
165 self.typedefs = {}
166 self.macros = {}
167 self.references = {}
168 self.info = {}
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000169
Daniel Veillarda2351322004-06-27 12:08:10 +0000170 def add_ref(self, name, module, static, type, lineno, info=None, extra=None, conditionals = None):
Daniel Veillardbe586972003-11-18 20:56:51 +0000171 if name[0:2] == '__':
172 return None
173 d = None
174 try:
175 d = self.identifiers[name]
Daniel Veillarda2351322004-06-27 12:08:10 +0000176 d.update(module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000177 except:
Daniel Veillarda2351322004-06-27 12:08:10 +0000178 d = identifier(name, module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000179 self.identifiers[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000180
Daniel Veillardbe586972003-11-18 20:56:51 +0000181 if d != None and static == 1:
182 d.set_static(1)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000183
Daniel Veillardbe586972003-11-18 20:56:51 +0000184 if d != None and name != None and type != None:
185 self.references[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000186
Daniel Veillarda2351322004-06-27 12:08:10 +0000187 if name == debugsym:
188 print "New ref: %s" % (d)
189
190 return d
191
192 def add(self, name, module, static, type, lineno, info=None, extra=None, conditionals = None):
Daniel Veillardbe586972003-11-18 20:56:51 +0000193 if name[0:2] == '__':
194 return None
195 d = None
196 try:
197 d = self.identifiers[name]
Daniel Veillarda2351322004-06-27 12:08:10 +0000198 d.update(module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000199 except:
Daniel Veillarda2351322004-06-27 12:08:10 +0000200 d = identifier(name, module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000201 self.identifiers[name] = d
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000202
Daniel Veillardbe586972003-11-18 20:56:51 +0000203 if d != None and static == 1:
204 d.set_static(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000205
Daniel Veillardbe586972003-11-18 20:56:51 +0000206 if d != None and name != None and type != None:
207 if type == "function":
208 self.functions[name] = d
209 elif type == "functype":
210 self.functions[name] = d
211 elif type == "variable":
212 self.variables[name] = d
213 elif type == "include":
214 self.includes[name] = d
215 elif type == "struct":
216 self.structs[name] = d
217 elif type == "enum":
218 self.enums[name] = d
219 elif type == "typedef":
220 self.typedefs[name] = d
221 elif type == "macro":
222 self.macros[name] = d
223 else:
224 print "Unable to register type ", type
Daniel Veillarda2351322004-06-27 12:08:10 +0000225
226 if name == debugsym:
227 print "New symbol: %s" % (d)
228
Daniel Veillardbe586972003-11-18 20:56:51 +0000229 return d
230
231 def merge(self, idx):
232 for id in idx.functions.keys():
233 #
234 # macro might be used to override functions or variables
235 # definitions
236 #
237 if self.macros.has_key(id):
238 del self.macros[id]
239 if self.functions.has_key(id):
240 print "function %s from %s redeclared in %s" % (
241 id, self.functions[id].module, idx.functions[id].module)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000242 else:
Daniel Veillardbe586972003-11-18 20:56:51 +0000243 self.functions[id] = idx.functions[id]
244 self.identifiers[id] = idx.functions[id]
245 for id in idx.variables.keys():
246 #
247 # macro might be used to override functions or variables
248 # definitions
249 #
250 if self.macros.has_key(id):
251 del self.macros[id]
252 if self.variables.has_key(id):
253 print "variable %s from %s redeclared in %s" % (
254 id, self.variables[id].module, idx.variables[id].module)
255 else:
256 self.variables[id] = idx.variables[id]
257 self.identifiers[id] = idx.variables[id]
258 for id in idx.structs.keys():
259 if self.structs.has_key(id):
260 print "struct %s from %s redeclared in %s" % (
261 id, self.structs[id].module, idx.structs[id].module)
262 else:
263 self.structs[id] = idx.structs[id]
264 self.identifiers[id] = idx.structs[id]
265 for id in idx.typedefs.keys():
266 if self.typedefs.has_key(id):
267 print "typedef %s from %s redeclared in %s" % (
268 id, self.typedefs[id].module, idx.typedefs[id].module)
269 else:
270 self.typedefs[id] = idx.typedefs[id]
271 self.identifiers[id] = idx.typedefs[id]
272 for id in idx.macros.keys():
273 #
274 # macro might be used to override functions or variables
275 # definitions
276 #
277 if self.variables.has_key(id):
278 continue
279 if self.functions.has_key(id):
280 continue
281 if self.enums.has_key(id):
282 continue
283 if self.macros.has_key(id):
284 print "macro %s from %s redeclared in %s" % (
285 id, self.macros[id].module, idx.macros[id].module)
286 else:
287 self.macros[id] = idx.macros[id]
288 self.identifiers[id] = idx.macros[id]
289 for id in idx.enums.keys():
290 if self.enums.has_key(id):
291 print "enum %s from %s redeclared in %s" % (
292 id, self.enums[id].module, idx.enums[id].module)
293 else:
294 self.enums[id] = idx.enums[id]
295 self.identifiers[id] = idx.enums[id]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000296
Daniel Veillardbe586972003-11-18 20:56:51 +0000297 def merge_public(self, idx):
298 for id in idx.functions.keys():
299 if self.functions.has_key(id):
300 up = idx.functions[id]
301 self.functions[id].update(None, up.type, up.info, up.extra)
Daniel Veillardc1eed322002-12-12 11:01:32 +0000302 # else:
303 # print "Function %s from %s is not declared in headers" % (
304 # id, idx.functions[id].module)
305 # TODO: do the same for variables.
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000306
Daniel Veillardbe586972003-11-18 20:56:51 +0000307 def analyze_dict(self, type, dict):
308 count = 0
309 public = 0
310 for name in dict.keys():
311 id = dict[name]
312 count = count + 1
313 if id.static == 0:
314 public = public + 1
315 if count != public:
316 print " %d %s , %d public" % (count, type, public)
317 elif count != 0:
318 print " %d public %s" % (count, type)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000319
320
Daniel Veillardbe586972003-11-18 20:56:51 +0000321 def analyze(self):
322 self.analyze_dict("functions", self.functions)
323 self.analyze_dict("variables", self.variables)
324 self.analyze_dict("structs", self.structs)
325 self.analyze_dict("typedefs", self.typedefs)
326 self.analyze_dict("macros", self.macros)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000327
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000328class CLexer:
Daniel Veillardbe586972003-11-18 20:56:51 +0000329 """A lexer for the C language, tokenize the input by reading and
330 analyzing it line by line"""
331 def __init__(self, input):
332 self.input = input
333 self.tokens = []
334 self.line = ""
335 self.lineno = 0
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000336
Daniel Veillardbe586972003-11-18 20:56:51 +0000337 def getline(self):
338 line = ''
339 while line == '':
340 line = self.input.readline()
341 if not line:
342 return None
343 self.lineno = self.lineno + 1
344 line = string.lstrip(line)
345 line = string.rstrip(line)
346 if line == '':
347 continue
348 while line[-1] == '\\':
349 line = line[:-1]
350 n = self.input.readline()
351 self.lineno = self.lineno + 1
352 n = string.lstrip(n)
353 n = string.rstrip(n)
354 if not n:
355 break
356 else:
357 line = line + n
358 return line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000359
Daniel Veillardbe586972003-11-18 20:56:51 +0000360 def getlineno(self):
361 return self.lineno
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000362
Daniel Veillardbe586972003-11-18 20:56:51 +0000363 def push(self, token):
364 self.tokens.insert(0, token);
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000365
Daniel Veillardbe586972003-11-18 20:56:51 +0000366 def debug(self):
367 print "Last token: ", self.last
368 print "Token queue: ", self.tokens
369 print "Line %d end: " % (self.lineno), self.line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000370
Daniel Veillardbe586972003-11-18 20:56:51 +0000371 def token(self):
372 while self.tokens == []:
373 if self.line == "":
374 line = self.getline()
375 else:
376 line = self.line
377 self.line = ""
378 if line == None:
379 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000380
Daniel Veillardbe586972003-11-18 20:56:51 +0000381 if line[0] == '#':
382 self.tokens = map((lambda x: ('preproc', x)),
383 string.split(line))
384 break;
385 l = len(line)
386 if line[0] == '"' or line[0] == "'":
387 end = line[0]
388 line = line[1:]
389 found = 0
390 tok = ""
391 while found == 0:
392 i = 0
393 l = len(line)
394 while i < l:
395 if line[i] == end:
396 self.line = line[i+1:]
397 line = line[:i]
398 l = i
399 found = 1
400 break
401 if line[i] == '\\':
402 i = i + 1
403 i = i + 1
404 tok = tok + line
405 if found == 0:
406 line = self.getline()
407 if line == None:
408 return None
409 self.last = ('string', tok)
410 return self.last
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000411
Daniel Veillardbe586972003-11-18 20:56:51 +0000412 if l >= 2 and line[0] == '/' and line[1] == '*':
413 line = line[2:]
414 found = 0
415 tok = ""
416 while found == 0:
417 i = 0
418 l = len(line)
419 while i < l:
420 if line[i] == '*' and i+1 < l and line[i+1] == '/':
421 self.line = line[i+2:]
422 line = line[:i-1]
423 l = i
424 found = 1
425 break
426 i = i + 1
427 if tok != "":
428 tok = tok + "\n"
429 tok = tok + line
430 if found == 0:
431 line = self.getline()
432 if line == None:
433 return None
434 self.last = ('comment', tok)
435 return self.last
436 if l >= 2 and line[0] == '/' and line[1] == '/':
437 line = line[2:]
438 self.last = ('comment', line)
439 return self.last
440 i = 0
441 while i < l:
442 if line[i] == '/' and i+1 < l and line[i+1] == '/':
443 self.line = line[i:]
444 line = line[:i]
445 break
446 if line[i] == '/' and i+1 < l and line[i+1] == '*':
447 self.line = line[i:]
448 line = line[:i]
449 break
450 if line[i] == '"' or line[i] == "'":
451 self.line = line[i:]
452 line = line[:i]
453 break
454 i = i + 1
455 l = len(line)
456 i = 0
457 while i < l:
458 if line[i] == ' ' or line[i] == '\t':
459 i = i + 1
460 continue
461 o = ord(line[i])
462 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
463 (o >= 48 and o <= 57):
464 s = i
465 while i < l:
466 o = ord(line[i])
467 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
468 (o >= 48 and o <= 57) or string.find(
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000469 " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1:
Daniel Veillardbe586972003-11-18 20:56:51 +0000470 i = i + 1
471 else:
472 break
473 self.tokens.append(('name', line[s:i]))
474 continue
475 if string.find("(){}:;,[]", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000476# if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
477# line[i] == '}' or line[i] == ':' or line[i] == ';' or \
478# line[i] == ',' or line[i] == '[' or line[i] == ']':
Daniel Veillardbe586972003-11-18 20:56:51 +0000479 self.tokens.append(('sep', line[i]))
480 i = i + 1
481 continue
482 if string.find("+-*><=/%&!|.", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000483# if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
484# line[i] == '>' or line[i] == '<' or line[i] == '=' or \
485# line[i] == '/' or line[i] == '%' or line[i] == '&' or \
486# line[i] == '!' or line[i] == '|' or line[i] == '.':
Daniel Veillardbe586972003-11-18 20:56:51 +0000487 if line[i] == '.' and i + 2 < l and \
488 line[i+1] == '.' and line[i+2] == '.':
489 self.tokens.append(('name', '...'))
490 i = i + 3
491 continue
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000492
Daniel Veillardbe586972003-11-18 20:56:51 +0000493 j = i + 1
494 if j < l and (
495 string.find("+-*><=/%&!|", line[j]) != -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000496# line[j] == '+' or line[j] == '-' or line[j] == '*' or \
497# line[j] == '>' or line[j] == '<' or line[j] == '=' or \
498# line[j] == '/' or line[j] == '%' or line[j] == '&' or \
499# line[j] == '!' or line[j] == '|'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000500 self.tokens.append(('op', line[i:j+1]))
501 i = j + 1
502 else:
503 self.tokens.append(('op', line[i]))
504 i = i + 1
505 continue
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 string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000512# line[i] != ' ' and line[i] != '\t' and
513# line[i] != '(' and line[i] != ')' and
514# line[i] != '{' and line[i] != '}' and
515# line[i] != ':' and line[i] != ';' and
516# line[i] != ',' and line[i] != '+' and
517# line[i] != '-' and line[i] != '*' and
518# line[i] != '/' and line[i] != '%' and
519# line[i] != '&' and line[i] != '!' and
520# line[i] != '|' and line[i] != '[' and
521# line[i] != ']' and line[i] != '=' and
522# line[i] != '*' and line[i] != '>' and
523# line[i] != '<'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000524 i = i + 1
525 else:
526 break
527 self.tokens.append(('name', line[s:i]))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000528
Daniel Veillardbe586972003-11-18 20:56:51 +0000529 tok = self.tokens[0]
530 self.tokens = self.tokens[1:]
531 self.last = tok
532 return tok
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000533
534class CParser:
Daniel Veillardbe586972003-11-18 20:56:51 +0000535 """The C module parser"""
536 def __init__(self, filename, idx = None):
537 self.filename = filename
538 if len(filename) > 2 and filename[-2:] == '.h':
539 self.is_header = 1
540 else:
541 self.is_header = 0
542 self.input = open(filename)
543 self.lexer = CLexer(self.input)
544 if idx == None:
545 self.index = index()
546 else:
547 self.index = idx
548 self.top_comment = ""
549 self.last_comment = ""
550 self.comment = None
551 self.collect_ref = 0
Daniel Veillard1e906612003-12-05 14:57:46 +0000552 self.no_error = 0
Daniel Veillarda2351322004-06-27 12:08:10 +0000553 self.conditionals = []
554 self.defines = []
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000555
Daniel Veillardbe586972003-11-18 20:56:51 +0000556 def collect_references(self):
557 self.collect_ref = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000558
Daniel Veillard1e906612003-12-05 14:57:46 +0000559 def stop_error(self):
560 self.no_error = 1
561
562 def start_error(self):
563 self.no_error = 0
564
Daniel Veillardbe586972003-11-18 20:56:51 +0000565 def lineno(self):
566 return self.lexer.getlineno()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000567
Daniel Veillardbe586972003-11-18 20:56:51 +0000568 def index_add(self, name, module, static, type, info=None, extra = None):
569 self.index.add(name, module, static, type, self.lineno(),
Daniel Veillarda2351322004-06-27 12:08:10 +0000570 info, extra, self.conditionals)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000571
Daniel Veillardbe586972003-11-18 20:56:51 +0000572 def index_add_ref(self, name, module, static, type, info=None,
573 extra = None):
574 self.index.add_ref(name, module, static, type, self.lineno(),
Daniel Veillarda2351322004-06-27 12:08:10 +0000575 info, extra, self.conditionals)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000576
Daniel Veillard1e906612003-12-05 14:57:46 +0000577 def warning(self, msg):
578 if self.no_error:
579 return
580 print msg
581
Daniel Veillardbe586972003-11-18 20:56:51 +0000582 def error(self, msg, token=-1):
Daniel Veillard1e906612003-12-05 14:57:46 +0000583 if self.no_error:
584 return
585
Daniel Veillardbe586972003-11-18 20:56:51 +0000586 print "Parse Error: " + msg
587 if token != -1:
588 print "Got token ", token
589 self.lexer.debug()
590 sys.exit(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000591
Daniel Veillardbe586972003-11-18 20:56:51 +0000592 def debug(self, msg, token=-1):
593 print "Debug: " + msg
594 if token != -1:
595 print "Got token ", token
596 self.lexer.debug()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000597
Daniel Veillardbe586972003-11-18 20:56:51 +0000598 def parseTopComment(self, comment):
599 res = {}
600 lines = string.split(comment, "\n")
601 item = None
602 for line in lines:
603 while line != "" and (line[0] == ' ' or line[0] == '\t'):
604 line = line[1:]
605 while line != "" and line[0] == '*':
606 line = line[1:]
607 while line != "" and (line[0] == ' ' or line[0] == '\t'):
608 line = line[1:]
609 try:
610 (it, line) = string.split(line, ":", 1)
611 item = it
612 while line != "" and (line[0] == ' ' or line[0] == '\t'):
613 line = line[1:]
614 if res.has_key(item):
615 res[item] = res[item] + " " + line
616 else:
617 res[item] = line
618 except:
619 if item != None:
620 if res.has_key(item):
621 res[item] = res[item] + " " + line
622 else:
623 res[item] = line
624 self.index.info = res
625
626 def parseComment(self, token):
627 if self.top_comment == "":
628 self.top_comment = token[1]
629 if self.comment == None or token[1][0] == '*':
630 self.comment = token[1];
631 else:
632 self.comment = self.comment + token[1]
633 token = self.lexer.token()
Daniel Veillard1e906612003-12-05 14:57:46 +0000634
635 if string.find(self.comment, "DOC_DISABLE") != -1:
636 self.stop_error()
637
638 if string.find(self.comment, "DOC_ENABLE") != -1:
639 self.start_error()
640
Daniel Veillardbe586972003-11-18 20:56:51 +0000641 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000642
643 #
644 # Parse a comment block associate to a macro
645 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000646 def parseMacroComment(self, name, quiet = 0):
647 if name[0:2] == '__':
648 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000649
Daniel Veillardbe586972003-11-18 20:56:51 +0000650 args = []
651 desc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000652
Daniel Veillardbe586972003-11-18 20:56:51 +0000653 if self.comment == None:
654 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000655 self.warning("Missing comment for macro %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000656 return((args, desc))
657 if self.comment[0] != '*':
658 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000659 self.warning("Missing * in macro comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000660 return((args, desc))
661 lines = string.split(self.comment, '\n')
662 if lines[0] == '*':
663 del lines[0]
664 if lines[0] != "* %s:" % (name):
665 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000666 self.warning("Misformatted macro comment for %s" % (name))
667 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000668 return((args, desc))
669 del lines[0]
670 while lines[0] == '*':
671 del lines[0]
672 while len(lines) > 0 and lines[0][0:3] == '* @':
673 l = lines[0][3:]
674 try:
675 (arg, desc) = string.split(l, ':', 1)
676 desc=string.strip(desc)
677 arg=string.strip(arg)
678 except:
679 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000680 self.warning("Misformatted macro comment for %s" % (name))
681 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000682 del lines[0]
683 continue
684 del lines[0]
685 l = string.strip(lines[0])
686 while len(l) > 2 and l[0:3] != '* @':
687 while l[0] == '*':
688 l = l[1:]
689 desc = desc + ' ' + string.strip(l)
690 del lines[0]
691 if len(lines) == 0:
692 break
693 l = lines[0]
694 args.append((arg, desc))
695 while len(lines) > 0 and lines[0] == '*':
696 del lines[0]
697 desc = ""
698 while len(lines) > 0:
699 l = lines[0]
700 while len(l) > 0 and l[0] == '*':
701 l = l[1:]
702 l = string.strip(l)
703 desc = desc + " " + l
704 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000705
Daniel Veillardbe586972003-11-18 20:56:51 +0000706 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000707
Daniel Veillardbe586972003-11-18 20:56:51 +0000708 if quiet == 0:
709 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000710 self.warning("Macro comment for %s lack description of the macro" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000711
Daniel Veillardbe586972003-11-18 20:56:51 +0000712 return((args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000713
714 #
715 # Parse a comment block and merge the informations found in the
716 # parameters descriptions, finally returns a block as complete
717 # as possible
718 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000719 def mergeFunctionComment(self, name, description, quiet = 0):
720 if name == 'main':
721 quiet = 1
722 if name[0:2] == '__':
723 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000724
Daniel Veillardbe586972003-11-18 20:56:51 +0000725 (ret, args) = description
726 desc = ""
727 retdesc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000728
Daniel Veillardbe586972003-11-18 20:56:51 +0000729 if self.comment == None:
730 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000731 self.warning("Missing comment for function %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000732 return(((ret[0], retdesc), args, desc))
733 if self.comment[0] != '*':
734 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000735 self.warning("Missing * in function comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000736 return(((ret[0], retdesc), args, desc))
737 lines = string.split(self.comment, '\n')
738 if lines[0] == '*':
739 del lines[0]
740 if lines[0] != "* %s:" % (name):
741 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000742 self.warning("Misformatted function comment for %s" % (name))
743 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000744 return(((ret[0], retdesc), args, desc))
745 del lines[0]
746 while lines[0] == '*':
747 del lines[0]
748 nbargs = len(args)
749 while len(lines) > 0 and lines[0][0:3] == '* @':
750 l = lines[0][3:]
751 try:
752 (arg, desc) = string.split(l, ':', 1)
753 desc=string.strip(desc)
754 arg=string.strip(arg)
755 except:
756 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000757 self.warning("Misformatted function comment for %s" % (name))
758 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000759 del lines[0]
760 continue
761 del lines[0]
762 l = string.strip(lines[0])
763 while len(l) > 2 and l[0:3] != '* @':
764 while l[0] == '*':
765 l = l[1:]
766 desc = desc + ' ' + string.strip(l)
767 del lines[0]
768 if len(lines) == 0:
769 break
770 l = lines[0]
771 i = 0
772 while i < nbargs:
773 if args[i][1] == arg:
774 args[i] = (args[i][0], arg, desc)
775 break;
776 i = i + 1
777 if i >= nbargs:
778 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000779 self.warning("Unable to find arg %s from function comment for %s" % (
780 arg, name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000781 while len(lines) > 0 and lines[0] == '*':
782 del lines[0]
783 desc = ""
784 while len(lines) > 0:
785 l = lines[0]
786 while len(l) > 0 and l[0] == '*':
787 l = l[1:]
788 l = string.strip(l)
789 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
790 try:
791 l = string.split(l, ' ', 1)[1]
792 except:
793 l = ""
794 retdesc = string.strip(l)
795 del lines[0]
796 while len(lines) > 0:
797 l = lines[0]
798 while len(l) > 0 and l[0] == '*':
799 l = l[1:]
800 l = string.strip(l)
801 retdesc = retdesc + " " + l
802 del lines[0]
803 else:
804 desc = desc + " " + l
805 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000806
Daniel Veillardbe586972003-11-18 20:56:51 +0000807 retdesc = string.strip(retdesc)
808 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000809
Daniel Veillardbe586972003-11-18 20:56:51 +0000810 if quiet == 0:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000811 #
812 # report missing comments
813 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000814 i = 0
815 while i < nbargs:
816 if args[i][2] == None and args[i][0] != "void" and args[i][1] != None:
Daniel Veillard1e906612003-12-05 14:57:46 +0000817 self.warning("Function comment for %s lack description of arg %s" % (name, args[i][1]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000818 i = i + 1
819 if retdesc == "" and ret[0] != "void":
Daniel Veillard1e906612003-12-05 14:57:46 +0000820 self.warning("Function comment for %s lack description of return value" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000821 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000822 self.warning("Function comment for %s lack description of the function" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000823
824
Daniel Veillardbe586972003-11-18 20:56:51 +0000825 return(((ret[0], retdesc), args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000826
Daniel Veillardbe586972003-11-18 20:56:51 +0000827 def parsePreproc(self, token):
Daniel Veillarda2351322004-06-27 12:08:10 +0000828 if debug:
829 print "=> preproc ", token, self.lexer.tokens
Daniel Veillardbe586972003-11-18 20:56:51 +0000830 name = token[1]
831 if name == "#include":
832 token = self.lexer.token()
833 if token == None:
834 return None
835 if token[0] == 'preproc':
836 self.index_add(token[1], self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000837 "include")
Daniel Veillardbe586972003-11-18 20:56:51 +0000838 return self.lexer.token()
839 return token
840 if name == "#define":
841 token = self.lexer.token()
842 if token == None:
843 return None
844 if token[0] == 'preproc':
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000845 # TODO macros with arguments
Daniel Veillardbe586972003-11-18 20:56:51 +0000846 name = token[1]
847 lst = []
848 token = self.lexer.token()
849 while token != None and token[0] == 'preproc' and \
850 token[1][0] != '#':
851 lst.append(token[1])
852 token = self.lexer.token()
853 try:
854 name = string.split(name, '(') [0]
855 except:
856 pass
857 info = self.parseMacroComment(name, not self.is_header)
858 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000859 "macro", info)
Daniel Veillardbe586972003-11-18 20:56:51 +0000860 return token
Daniel Veillardadd93d32004-07-06 22:47:07 +0000861 if (name == "#ifdef" or name == "#ifndef") and self.is_header:
Daniel Veillarda2351322004-06-27 12:08:10 +0000862 try:
863 self.defines.append(self.lexer.tokens[0][1])
864 if string.find(self.lexer.tokens[0][1], 'ENABLED') != -1:
865 self.conditionals.append(self.lexer.tokens[0][1])
866# print self.conditionals
867# print self.defines
868 except:
869 pass
870 if name == "#endif" and self.is_header:
871 if self.conditionals != [] and self.defines != [] and \
872 self.defines[-1] == self.conditionals[-1]:
873 self.conditionals = self.conditionals[:-1]
874 self.defines = self.defines[:-1]
875# print self.defines
876# print self.conditionals
Daniel Veillardbe586972003-11-18 20:56:51 +0000877 token = self.lexer.token()
878 while token != None and token[0] == 'preproc' and \
879 token[1][0] != '#':
880 token = self.lexer.token()
881 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000882
883 #
884 # token acquisition on top of the lexer, it handle internally
885 # preprocessor and comments since they are logically not part of
886 # the program structure.
887 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000888 def token(self):
889 global ignored_words
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000890
Daniel Veillardbe586972003-11-18 20:56:51 +0000891 token = self.lexer.token()
892 while token != None:
893 if token[0] == 'comment':
894 token = self.parseComment(token)
895 continue
896 elif token[0] == 'preproc':
897 token = self.parsePreproc(token)
898 continue
899 elif token[0] == "name" and ignored_words.has_key(token[1]):
900 (n, info) = ignored_words[token[1]]
901 i = 0
902 while i < n:
903 token = self.lexer.token()
904 i = i + 1
905 token = self.lexer.token()
906 continue
907 else:
908 if debug:
909 print "=> ", token
910 return token
911 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000912
913 #
914 # Parse a typedef, it records the type and its name.
915 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000916 def parseTypedef(self, token):
917 if token == None:
918 return None
919 token = self.parseType(token)
920 if token == None:
921 self.error("parsing typedef")
922 return None
923 base_type = self.type
924 type = base_type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000925 #self.debug("end typedef type", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000926 while token != None:
927 if token[0] == "name":
928 name = token[1]
929 signature = self.signature
930 if signature != None:
931 type = string.split(type, '(')[0]
932 d = self.mergeFunctionComment(name,
933 ((type, None), signature), 1)
934 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000935 "functype", d)
Daniel Veillardbe586972003-11-18 20:56:51 +0000936 else:
937 if base_type == "struct":
938 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000939 "struct", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000940 base_type = "struct " + name
941 else:
942 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000943 "typedef", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000944 token = self.token()
945 else:
946 self.error("parsing typedef: expecting a name")
947 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000948 #self.debug("end typedef", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000949 if token != None and token[0] == 'sep' and token[1] == ',':
950 type = base_type
951 token = self.token()
952 while token != None and token[0] == "op":
953 type = type + token[1]
954 token = self.token()
955 elif token != None and token[0] == 'sep' and token[1] == ';':
956 break;
957 elif token != None and token[0] == 'name':
958 type = base_type
959 continue;
960 else:
961 self.error("parsing typedef: expecting ';'", token)
962 return token
963 token = self.token()
964 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000965
966 #
967 # Parse a C code block, used for functions it parse till
968 # the balancing } included
969 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000970 def parseBlock(self, token):
971 while token != None:
972 if token[0] == "sep" and token[1] == "{":
973 token = self.token()
974 token = self.parseBlock(token)
975 elif token[0] == "sep" and token[1] == "}":
976 self.comment = None
977 token = self.token()
978 return token
979 else:
980 if self.collect_ref == 1:
981 oldtok = token
982 token = self.token()
983 if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
984 if token[0] == "sep" and token[1] == "(":
985 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000986 0, "function")
Daniel Veillardbe586972003-11-18 20:56:51 +0000987 token = self.token()
988 elif token[0] == "name":
989 token = self.token()
990 if token[0] == "sep" and (token[1] == ";" or
991 token[1] == "," or token[1] == "="):
992 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000993 0, "type")
Daniel Veillardbe586972003-11-18 20:56:51 +0000994 elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
995 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000996 0, "typedef")
Daniel Veillardbe586972003-11-18 20:56:51 +0000997 elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
998 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000999 0, "typedef")
1000
Daniel Veillardbe586972003-11-18 20:56:51 +00001001 else:
1002 token = self.token()
1003 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001004
1005 #
1006 # Parse a C struct definition till the balancing }
1007 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001008 def parseStruct(self, token):
1009 fields = []
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001010 #self.debug("start parseStruct", token)
Daniel Veillardbe586972003-11-18 20:56:51 +00001011 while token != None:
1012 if token[0] == "sep" and token[1] == "{":
1013 token = self.token()
1014 token = self.parseTypeBlock(token)
1015 elif token[0] == "sep" and token[1] == "}":
1016 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001017 #self.debug("end parseStruct", token)
1018 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +00001019 token = self.token()
1020 return token
1021 else:
1022 base_type = self.type
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001023 #self.debug("before parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +00001024 token = self.parseType(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001025 #self.debug("after parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +00001026 if token != None and token[0] == "name":
1027 fname = token[1]
1028 token = self.token()
1029 if token[0] == "sep" and token[1] == ";":
1030 self.comment = None
1031 token = self.token()
1032 fields.append((self.type, fname, self.comment))
1033 self.comment = None
1034 else:
1035 self.error("parseStruct: expecting ;", token)
1036 elif token != None and token[0] == "sep" and token[1] == "{":
1037 token = self.token()
1038 token = self.parseTypeBlock(token)
1039 if token != None and token[0] == "name":
1040 token = self.token()
1041 if token != None and token[0] == "sep" and token[1] == ";":
1042 token = self.token()
1043 else:
1044 self.error("parseStruct: expecting ;", token)
1045 else:
1046 self.error("parseStruct: name", token)
1047 token = self.token()
1048 self.type = base_type;
1049 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001050 #self.debug("end parseStruct", token)
1051 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +00001052 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001053
1054 #
1055 # Parse a C enum block, parse till the balancing }
1056 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001057 def parseEnumBlock(self, token):
1058 self.enums = []
1059 name = None
1060 self.comment = None
1061 comment = ""
1062 value = "0"
1063 while token != None:
1064 if token[0] == "sep" and token[1] == "{":
1065 token = self.token()
1066 token = self.parseTypeBlock(token)
1067 elif token[0] == "sep" and token[1] == "}":
1068 if name != None:
1069 if self.comment != None:
1070 comment = self.comment
1071 self.comment = None
1072 self.enums.append((name, value, comment))
1073 token = self.token()
1074 return token
1075 elif token[0] == "name":
1076 if name != None:
1077 if self.comment != None:
1078 comment = string.strip(self.comment)
1079 self.comment = None
1080 self.enums.append((name, value, comment))
1081 name = token[1]
1082 comment = ""
1083 token = self.token()
1084 if token[0] == "op" and token[1][0] == "=":
1085 value = ""
1086 if len(token[1]) > 1:
1087 value = token[1][1:]
1088 token = self.token()
1089 while token[0] != "sep" or (token[1] != ',' and
1090 token[1] != '}'):
1091 value = value + token[1]
1092 token = self.token()
1093 else:
1094 try:
1095 value = "%d" % (int(value) + 1)
1096 except:
Daniel Veillard1e906612003-12-05 14:57:46 +00001097 self.warning("Failed to compute value of enum %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +00001098 value=""
1099 if token[0] == "sep" and token[1] == ",":
1100 token = self.token()
1101 else:
1102 token = self.token()
1103 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001104
1105 #
1106 # Parse a C definition block, used for structs it parse till
1107 # the balancing }
1108 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001109 def parseTypeBlock(self, token):
1110 while token != None:
1111 if token[0] == "sep" and token[1] == "{":
1112 token = self.token()
1113 token = self.parseTypeBlock(token)
1114 elif token[0] == "sep" and token[1] == "}":
1115 token = self.token()
1116 return token
1117 else:
1118 token = self.token()
1119 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001120
1121 #
1122 # Parse a type: the fact that the type name can either occur after
1123 # the definition or within the definition makes it a little harder
1124 # if inside, the name token is pushed back before returning
1125 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001126 def parseType(self, token):
1127 self.type = ""
1128 self.struct_fields = []
1129 self.signature = None
1130 if token == None:
1131 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001132
Daniel Veillardbe586972003-11-18 20:56:51 +00001133 while token[0] == "name" and (
1134 token[1] == "const" or token[1] == "unsigned"):
1135 if self.type == "":
1136 self.type = token[1]
1137 else:
1138 self.type = self.type + " " + token[1]
1139 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001140
Daniel Veillardbe586972003-11-18 20:56:51 +00001141 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1142 if self.type == "":
1143 self.type = token[1]
1144 else:
1145 self.type = self.type + " " + token[1]
1146 if token[0] == "name" and token[1] == "int":
1147 if self.type == "":
1148 self.type = tmp[1]
1149 else:
1150 self.type = self.type + " " + tmp[1]
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001151
Daniel Veillardbe586972003-11-18 20:56:51 +00001152 elif token[0] == "name" and token[1] == "struct":
1153 if self.type == "":
1154 self.type = token[1]
1155 else:
1156 self.type = self.type + " " + token[1]
1157 token = self.token()
1158 nametok = None
1159 if token[0] == "name":
1160 nametok = token
1161 token = self.token()
1162 if token != None and token[0] == "sep" and token[1] == "{":
1163 token = self.token()
1164 token = self.parseStruct(token)
1165 elif token != None and token[0] == "op" and token[1] == "*":
1166 self.type = self.type + " " + nametok[1] + " *"
1167 token = self.token()
1168 while token != None and token[0] == "op" and token[1] == "*":
1169 self.type = self.type + " *"
1170 token = self.token()
1171 if token[0] == "name":
1172 nametok = token
1173 token = self.token()
1174 else:
1175 self.error("struct : expecting name", token)
1176 return token
1177 elif token != None and token[0] == "name" and nametok != None:
1178 self.type = self.type + " " + nametok[1]
1179 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001180
Daniel Veillardbe586972003-11-18 20:56:51 +00001181 if nametok != None:
1182 self.lexer.push(token)
1183 token = nametok
1184 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001185
Daniel Veillardbe586972003-11-18 20:56:51 +00001186 elif token[0] == "name" and token[1] == "enum":
1187 if self.type == "":
1188 self.type = token[1]
1189 else:
1190 self.type = self.type + " " + token[1]
1191 self.enums = []
1192 token = self.token()
1193 if token != None and token[0] == "sep" and token[1] == "{":
1194 token = self.token()
1195 token = self.parseEnumBlock(token)
1196 else:
1197 self.error("parsing enum: expecting '{'", token)
1198 enum_type = None
1199 if token != None and token[0] != "name":
1200 self.lexer.push(token)
1201 token = ("name", "enum")
1202 else:
1203 enum_type = token[1]
1204 for enum in self.enums:
1205 self.index_add(enum[0], self.filename,
1206 not self.is_header, "enum",
1207 (enum[1], enum[2], enum_type))
1208 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001209
Daniel Veillardbe586972003-11-18 20:56:51 +00001210 elif token[0] == "name":
1211 if self.type == "":
1212 self.type = token[1]
1213 else:
1214 self.type = self.type + " " + token[1]
1215 else:
1216 self.error("parsing type %s: expecting a name" % (self.type),
1217 token)
1218 return token
1219 token = self.token()
1220 while token != None and (token[0] == "op" or
1221 token[0] == "name" and token[1] == "const"):
1222 self.type = self.type + " " + token[1]
1223 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001224
1225 #
1226 # if there is a parenthesis here, this means a function type
1227 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001228 if token != None and token[0] == "sep" and token[1] == '(':
1229 self.type = self.type + token[1]
1230 token = self.token()
1231 while token != None and token[0] == "op" and token[1] == '*':
1232 self.type = self.type + token[1]
1233 token = self.token()
1234 if token == None or token[0] != "name" :
1235 self.error("parsing function type, name expected", token);
1236 return token
1237 self.type = self.type + token[1]
1238 nametok = token
1239 token = self.token()
1240 if token != None and token[0] == "sep" and token[1] == ')':
1241 self.type = self.type + token[1]
1242 token = self.token()
1243 if token != None and token[0] == "sep" and token[1] == '(':
1244 token = self.token()
1245 type = self.type;
1246 token = self.parseSignature(token);
1247 self.type = type;
1248 else:
1249 self.error("parsing function type, '(' expected", token);
1250 return token
1251 else:
1252 self.error("parsing function type, ')' expected", token);
1253 return token
1254 self.lexer.push(token)
1255 token = nametok
1256 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001257
1258 #
1259 # do some lookahead for arrays
1260 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001261 if token != None and token[0] == "name":
1262 nametok = token
1263 token = self.token()
1264 if token != None and token[0] == "sep" and token[1] == '[':
1265 self.type = self.type + nametok[1]
1266 while token != None and token[0] == "sep" and token[1] == '[':
1267 self.type = self.type + token[1]
1268 token = self.token()
1269 while token != None and token[0] != 'sep' and \
1270 token[1] != ']' and token[1] != ';':
1271 self.type = self.type + token[1]
1272 token = self.token()
1273 if token != None and token[0] == 'sep' and token[1] == ']':
1274 self.type = self.type + token[1]
1275 token = self.token()
1276 else:
1277 self.error("parsing array type, ']' expected", token);
1278 return token
1279 elif token != None and token[0] == "sep" and token[1] == ':':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001280 # remove :12 in case it's a limited int size
Daniel Veillardbe586972003-11-18 20:56:51 +00001281 token = self.token()
1282 token = self.token()
1283 self.lexer.push(token)
1284 token = nametok
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001285
Daniel Veillardbe586972003-11-18 20:56:51 +00001286 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001287
1288 #
1289 # Parse a signature: '(' has been parsed and we scan the type definition
1290 # up to the ')' included
Daniel Veillardbe586972003-11-18 20:56:51 +00001291 def parseSignature(self, token):
1292 signature = []
1293 if token != None and token[0] == "sep" and token[1] == ')':
1294 self.signature = []
1295 token = self.token()
1296 return token
1297 while token != None:
1298 token = self.parseType(token)
1299 if token != None and token[0] == "name":
1300 signature.append((self.type, token[1], None))
1301 token = self.token()
1302 elif token != None and token[0] == "sep" and token[1] == ',':
1303 token = self.token()
1304 continue
1305 elif token != None and token[0] == "sep" and token[1] == ')':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001306 # only the type was provided
Daniel Veillardbe586972003-11-18 20:56:51 +00001307 if self.type == "...":
1308 signature.append((self.type, "...", None))
1309 else:
1310 signature.append((self.type, None, None))
1311 if token != None and token[0] == "sep":
1312 if token[1] == ',':
1313 token = self.token()
1314 continue
1315 elif token[1] == ')':
1316 token = self.token()
1317 break
1318 self.signature = signature
1319 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001320
1321 #
1322 # Parse a global definition, be it a type, variable or function
1323 # the extern "C" blocks are a bit nasty and require it to recurse.
1324 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001325 def parseGlobal(self, token):
1326 static = 0
1327 if token[1] == 'extern':
1328 token = self.token()
1329 if token == None:
1330 return token
1331 if token[0] == 'string':
1332 if token[1] == 'C':
1333 token = self.token()
1334 if token == None:
1335 return token
1336 if token[0] == 'sep' and token[1] == "{":
1337 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001338# print 'Entering extern "C line ', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001339 while token != None and (token[0] != 'sep' or
1340 token[1] != "}"):
1341 if token[0] == 'name':
1342 token = self.parseGlobal(token)
1343 else:
1344 self.error(
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001345 "token %s %s unexpected at the top level" % (
1346 token[0], token[1]))
Daniel Veillardbe586972003-11-18 20:56:51 +00001347 token = self.parseGlobal(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001348# print 'Exiting extern "C" line', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001349 token = self.token()
1350 return token
1351 else:
1352 return token
1353 elif token[1] == 'static':
1354 static = 1
1355 token = self.token()
1356 if token == None or token[0] != 'name':
1357 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001358
Daniel Veillardbe586972003-11-18 20:56:51 +00001359 if token[1] == 'typedef':
1360 token = self.token()
1361 return self.parseTypedef(token)
1362 else:
1363 token = self.parseType(token)
1364 type_orig = self.type
1365 if token == None or token[0] != "name":
1366 return token
1367 type = type_orig
1368 self.name = token[1]
1369 token = self.token()
1370 while token != None and (token[0] == "sep" or token[0] == "op"):
1371 if token[0] == "sep":
1372 if token[1] == "[":
1373 type = type + token[1]
1374 token = self.token()
1375 while token != None and (token[0] != "sep" or \
1376 token[1] != ";"):
1377 type = type + token[1]
1378 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001379
Daniel Veillardbe586972003-11-18 20:56:51 +00001380 if token != None and token[0] == "op" and token[1] == "=":
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001381 #
1382 # Skip the initialization of the variable
1383 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001384 token = self.token()
1385 if token[0] == 'sep' and token[1] == '{':
1386 token = self.token()
1387 token = self.parseBlock(token)
1388 else:
1389 self.comment = None
1390 while token != None and (token[0] != "sep" or \
1391 (token[1] != ';' and token[1] != ',')):
1392 token = self.token()
1393 self.comment = None
1394 if token == None or token[0] != "sep" or (token[1] != ';' and
1395 token[1] != ','):
1396 self.error("missing ';' or ',' after value")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001397
Daniel Veillardbe586972003-11-18 20:56:51 +00001398 if token != None and token[0] == "sep":
1399 if token[1] == ";":
1400 self.comment = None
1401 token = self.token()
1402 if type == "struct":
1403 self.index_add(self.name, self.filename,
1404 not self.is_header, "struct", self.struct_fields)
1405 else:
1406 self.index_add(self.name, self.filename,
1407 not self.is_header, "variable", type)
1408 break
1409 elif token[1] == "(":
1410 token = self.token()
1411 token = self.parseSignature(token)
1412 if token == None:
1413 return None
1414 if token[0] == "sep" and token[1] == ";":
1415 d = self.mergeFunctionComment(self.name,
1416 ((type, None), self.signature), 1)
1417 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001418 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001419 token = self.token()
1420 elif token[0] == "sep" and token[1] == "{":
1421 d = self.mergeFunctionComment(self.name,
1422 ((type, None), self.signature), static)
1423 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001424 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001425 token = self.token()
1426 token = self.parseBlock(token);
1427 elif token[1] == ',':
1428 self.comment = None
1429 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001430 "variable", type)
Daniel Veillardbe586972003-11-18 20:56:51 +00001431 type = type_orig
1432 token = self.token()
1433 while token != None and token[0] == "sep":
1434 type = type + token[1]
1435 token = self.token()
1436 if token != None and token[0] == "name":
1437 self.name = token[1]
1438 token = self.token()
1439 else:
1440 break
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001441
Daniel Veillardbe586972003-11-18 20:56:51 +00001442 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001443
Daniel Veillardbe586972003-11-18 20:56:51 +00001444 def parse(self):
Daniel Veillard1e906612003-12-05 14:57:46 +00001445 self.warning("Parsing %s" % (self.filename))
Daniel Veillardbe586972003-11-18 20:56:51 +00001446 token = self.token()
1447 while token != None:
1448 if token[0] == 'name':
1449 token = self.parseGlobal(token)
1450 else:
1451 self.error("token %s %s unexpected at the top level" % (
1452 token[0], token[1]))
1453 token = self.parseGlobal(token)
1454 return
1455 self.parseTopComment(self.top_comment)
1456 return self.index
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001457
1458
1459class docBuilder:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001460 """A documentation builder"""
1461 def __init__(self, name, directories=['.'], excludes=[]):
1462 self.name = name
1463 self.directories = directories
1464 self.excludes = excludes + ignored_files.keys()
1465 self.modules = {}
1466 self.headers = {}
1467 self.idx = index()
1468 self.xref = {}
1469 self.index = {}
1470 if name == 'libxml2':
1471 self.basename = 'libxml'
1472 else:
1473 self.basename = name
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001474
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001475 def indexString(self, id, str):
1476 if str == None:
1477 return
1478 str = string.replace(str, "'", ' ')
1479 str = string.replace(str, '"', ' ')
1480 str = string.replace(str, "/", ' ')
1481 str = string.replace(str, '*', ' ')
1482 str = string.replace(str, "[", ' ')
1483 str = string.replace(str, "]", ' ')
1484 str = string.replace(str, "(", ' ')
1485 str = string.replace(str, ")", ' ')
1486 str = string.replace(str, "<", ' ')
1487 str = string.replace(str, '>', ' ')
1488 str = string.replace(str, "&", ' ')
1489 str = string.replace(str, '#', ' ')
1490 str = string.replace(str, ",", ' ')
1491 str = string.replace(str, '.', ' ')
1492 str = string.replace(str, ';', ' ')
1493 tokens = string.split(str)
1494 for token in tokens:
1495 try:
1496 c = token[0]
1497 if string.find(string.letters, c) < 0:
1498 pass
1499 elif len(token) < 3:
1500 pass
1501 else:
1502 lower = string.lower(token)
1503 # TODO: generalize this a bit
1504 if lower == 'and' or lower == 'the':
1505 pass
1506 elif self.xref.has_key(token):
1507 self.xref[token].append(id)
1508 else:
1509 self.xref[token] = [id]
1510 except:
1511 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001512
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001513 def analyze(self):
1514 print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
1515 self.idx.analyze()
1516
1517 def scanHeaders(self):
1518 for header in self.headers.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001519 parser = CParser(header)
1520 idx = parser.parse()
1521 self.headers[header] = idx;
1522 self.idx.merge(idx)
1523
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001524 def scanModules(self):
1525 for module in self.modules.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001526 parser = CParser(module)
1527 idx = parser.parse()
1528 # idx.analyze()
1529 self.modules[module] = idx
1530 self.idx.merge_public(idx)
1531
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001532 def scan(self):
1533 for directory in self.directories:
1534 files = glob.glob(directory + "/*.c")
1535 for file in files:
1536 skip = 0
1537 for excl in self.excludes:
1538 if string.find(file, excl) != -1:
1539 skip = 1;
1540 break
1541 if skip == 0:
1542 self.modules[file] = None;
1543 files = glob.glob(directory + "/*.h")
1544 for file in files:
1545 skip = 0
1546 for excl in self.excludes:
1547 if string.find(file, excl) != -1:
1548 skip = 1;
1549 break
1550 if skip == 0:
1551 self.headers[file] = None;
1552 self.scanHeaders()
1553 self.scanModules()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001554
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001555 def modulename_file(self, file):
1556 module = os.path.basename(file)
1557 if module[-2:] == '.h':
1558 module = module[:-2]
1559 return module
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001560
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001561 def serialize_enum(self, output, name):
1562 id = self.idx.enums[name]
1563 output.write(" <enum name='%s' file='%s'" % (name,
1564 self.modulename_file(id.module)))
1565 if id.info != None:
1566 info = id.info
1567 if info[0] != None and info[0] != '':
1568 try:
1569 val = eval(info[0])
1570 except:
1571 val = info[0]
1572 output.write(" value='%s'" % (val));
1573 if info[2] != None and info[2] != '':
1574 output.write(" type='%s'" % info[2]);
1575 if info[1] != None and info[1] != '':
1576 output.write(" info='%s'" % escape(info[1]));
1577 output.write("/>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001578
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001579 def serialize_macro(self, output, name):
1580 id = self.idx.macros[name]
1581 output.write(" <macro name='%s' file='%s'>\n" % (name,
1582 self.modulename_file(id.module)))
1583 if id.info != None:
1584 try:
1585 (args, desc) = id.info
1586 if desc != None and desc != "":
1587 output.write(" <info>%s</info>\n" % (escape(desc)))
1588 self.indexString(name, desc)
1589 for arg in args:
1590 (name, desc) = arg
1591 if desc != None and desc != "":
1592 output.write(" <arg name='%s' info='%s'/>\n" % (
1593 name, escape(desc)))
1594 self.indexString(name, desc)
1595 else:
1596 output.write(" <arg name='%s'/>\n" % (name))
1597 except:
1598 pass
1599 output.write(" </macro>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001600
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001601 def serialize_typedef(self, output, name):
1602 id = self.idx.typedefs[name]
1603 if id.info[0:7] == 'struct ':
1604 output.write(" <struct name='%s' file='%s' type='%s'" % (
1605 name, self.modulename_file(id.module), id.info))
1606 name = id.info[7:]
1607 if self.idx.structs.has_key(name) and ( \
1608 type(self.idx.structs[name].info) == type(()) or
Daniel Veillardc1eed322002-12-12 11:01:32 +00001609 type(self.idx.structs[name].info) == type([])):
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001610 output.write(">\n");
1611 try:
1612 for field in self.idx.structs[name].info:
1613 desc = field[2]
1614 self.indexString(name, desc)
1615 if desc == None:
1616 desc = ''
1617 else:
1618 desc = escape(desc)
1619 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1620 except:
1621 print "Failed to serialize struct %s" % (name)
1622 output.write(" </struct>\n")
1623 else:
1624 output.write("/>\n");
1625 else :
1626 output.write(" <typedef name='%s' file='%s' type='%s'/>\n" % (
1627 name, self.modulename_file(id.module), id.info))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001628
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001629 def serialize_variable(self, output, name):
1630 id = self.idx.variables[name]
1631 if id.info != None:
1632 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1633 name, self.modulename_file(id.module), id.info))
1634 else:
1635 output.write(" <variable name='%s' file='%s'/>\n" % (
1636 name, self.modulename_file(id.module)))
Daniel Veillardc1eed322002-12-12 11:01:32 +00001637
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001638 def serialize_function(self, output, name):
1639 id = self.idx.functions[name]
Daniel Veillarda2351322004-06-27 12:08:10 +00001640 if name == debugsym:
1641 print "=>", id
1642
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001643 output.write(" <%s name='%s' file='%s'>\n" % (id.type, name,
1644 self.modulename_file(id.module)))
Daniel Veillarda2351322004-06-27 12:08:10 +00001645 if id.conditionals != None:
1646 for cond in id.conditionals:
1647 output.write(" <cond>%s</cond>\n"% (cond));
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001648 try:
1649 (ret, params, desc) = id.info
1650 output.write(" <info>%s</info>\n" % (escape(desc)))
1651 self.indexString(name, desc)
1652 if ret[0] != None:
1653 if ret[0] == "void":
1654 output.write(" <return type='void'/>\n")
1655 else:
1656 output.write(" <return type='%s' info='%s'/>\n" % (
1657 ret[0], escape(ret[1])))
1658 self.indexString(name, ret[1])
1659 for param in params:
1660 if param[0] == 'void':
1661 continue
1662 if param[2] == None:
1663 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1664 else:
1665 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1666 self.indexString(name, param[2])
1667 except:
1668 print "Failed to save function %s info: " % name, `id.info`
1669 output.write(" </%s>\n" % (id.type))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001670
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001671 def serialize_exports(self, output, file):
1672 module = self.modulename_file(file)
1673 output.write(" <file name='%s'>\n" % (module))
1674 dict = self.headers[file]
Daniel Veillardbe586972003-11-18 20:56:51 +00001675 if dict.info != None:
1676 for data in ('Summary', 'Description', 'Author'):
1677 try:
1678 output.write(" <%s>%s</%s>\n" % (
1679 string.lower(data),
1680 escape(dict.info[data]),
1681 string.lower(data)))
1682 except:
1683 print "Header %s lacks a %s description" % (module, data)
1684 if dict.info.has_key('Description'):
1685 desc = dict.info['Description']
1686 if string.find(desc, "DEPRECATED") != -1:
1687 output.write(" <deprecated/>\n")
1688
Daniel Veillard1a792412003-11-18 23:52:38 +00001689 ids = dict.macros.keys()
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001690 ids.sort()
1691 for id in uniq(ids):
Daniel Veillard1a792412003-11-18 23:52:38 +00001692 # Macros are sometime used to masquerade other types.
1693 if dict.functions.has_key(id):
1694 continue
1695 if dict.variables.has_key(id):
1696 continue
1697 if dict.typedefs.has_key(id):
1698 continue
1699 if dict.structs.has_key(id):
1700 continue
1701 if dict.enums.has_key(id):
1702 continue
1703 output.write(" <exports symbol='%s' type='macro'/>\n" % (id))
1704 ids = dict.enums.keys()
1705 ids.sort()
1706 for id in uniq(ids):
1707 output.write(" <exports symbol='%s' type='enum'/>\n" % (id))
1708 ids = dict.typedefs.keys()
1709 ids.sort()
1710 for id in uniq(ids):
1711 output.write(" <exports symbol='%s' type='typedef'/>\n" % (id))
1712 ids = dict.structs.keys()
1713 ids.sort()
1714 for id in uniq(ids):
1715 output.write(" <exports symbol='%s' type='struct'/>\n" % (id))
1716 ids = dict.variables.keys()
1717 ids.sort()
1718 for id in uniq(ids):
1719 output.write(" <exports symbol='%s' type='variable'/>\n" % (id))
1720 ids = dict.functions.keys()
1721 ids.sort()
1722 for id in uniq(ids):
1723 output.write(" <exports symbol='%s' type='function'/>\n" % (id))
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001724 output.write(" </file>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001725
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001726 def serialize_xrefs_files(self, output):
1727 headers = self.headers.keys()
1728 headers.sort()
1729 for file in headers:
1730 module = self.modulename_file(file)
1731 output.write(" <file name='%s'>\n" % (module))
1732 dict = self.headers[file]
William M. Bracka2e844a2004-01-06 11:52:13 +00001733 ids = uniq(dict.functions.keys() + dict.variables.keys() + \
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001734 dict.macros.keys() + dict.typedefs.keys() + \
William M. Bracka2e844a2004-01-06 11:52:13 +00001735 dict.structs.keys() + dict.enums.keys())
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001736 ids.sort()
William M. Bracka2e844a2004-01-06 11:52:13 +00001737 for id in ids:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001738 output.write(" <ref name='%s'/>\n" % (id))
1739 output.write(" </file>\n")
1740 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001741
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001742 def serialize_xrefs_functions(self, output):
1743 funcs = {}
1744 for name in self.idx.functions.keys():
1745 id = self.idx.functions[name]
1746 try:
1747 (ret, params, desc) = id.info
1748 for param in params:
1749 if param[0] == 'void':
1750 continue
1751 if funcs.has_key(param[0]):
1752 funcs[param[0]].append(name)
1753 else:
1754 funcs[param[0]] = [name]
1755 except:
1756 pass
1757 typ = funcs.keys()
1758 typ.sort()
1759 for type in typ:
1760 if type == '' or type == 'void' or type == "int" or \
1761 type == "char *" or type == "const char *" :
1762 continue
1763 output.write(" <type name='%s'>\n" % (type))
1764 ids = funcs[type]
1765 ids.sort()
William M. Brackcf9eadf2003-12-25 13:24:05 +00001766 pid = '' # not sure why we have dups, but get rid of them!
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001767 for id in ids:
William M. Brackcf9eadf2003-12-25 13:24:05 +00001768 if id != pid:
1769 output.write(" <ref name='%s'/>\n" % (id))
1770 pid = id
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001771 output.write(" </type>\n")
1772
1773 def serialize_xrefs_constructors(self, output):
1774 funcs = {}
1775 for name in self.idx.functions.keys():
1776 id = self.idx.functions[name]
1777 try:
1778 (ret, params, desc) = id.info
1779 if ret[0] == "void":
1780 continue
1781 if funcs.has_key(ret[0]):
1782 funcs[ret[0]].append(name)
1783 else:
1784 funcs[ret[0]] = [name]
1785 except:
1786 pass
1787 typ = funcs.keys()
1788 typ.sort()
1789 for type in typ:
1790 if type == '' or type == 'void' or type == "int" or \
1791 type == "char *" or type == "const char *" :
1792 continue
1793 output.write(" <type name='%s'>\n" % (type))
1794 ids = funcs[type]
William M. Brack09a4d0a2004-01-05 14:28:43 +00001795 ids.sort()
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001796 for id in ids:
1797 output.write(" <ref name='%s'/>\n" % (id))
1798 output.write(" </type>\n")
1799
1800 def serialize_xrefs_alpha(self, output):
1801 letter = None
1802 ids = self.idx.identifiers.keys()
1803 ids.sort()
1804 for id in ids:
1805 if id[0] != letter:
1806 if letter != None:
1807 output.write(" </letter>\n")
1808 letter = id[0]
1809 output.write(" <letter name='%s'>\n" % (letter))
1810 output.write(" <ref name='%s'/>\n" % (id))
1811 if letter != None:
1812 output.write(" </letter>\n")
1813
1814 def serialize_xrefs_references(self, output):
1815 typ = self.idx.identifiers.keys()
1816 typ.sort()
1817 for id in typ:
1818 idf = self.idx.identifiers[id]
1819 module = idf.module
1820 output.write(" <reference name='%s' href='%s'/>\n" % (id,
1821 'html/' + self.basename + '-' +
1822 self.modulename_file(module) + '.html#' +
1823 id))
1824
1825 def serialize_xrefs_index(self, output):
1826 index = self.xref
1827 typ = index.keys()
1828 typ.sort()
1829 letter = None
1830 count = 0
1831 chunk = 0
1832 chunks = []
1833 for id in typ:
1834 if len(index[id]) > 30:
1835 continue
1836 if id[0] != letter:
1837 if letter == None or count > 200:
1838 if letter != None:
1839 output.write(" </letter>\n")
1840 output.write(" </chunk>\n")
1841 count = 0
1842 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
1843 output.write(" <chunk name='chunk%s'>\n" % (chunk))
1844 first_letter = id[0]
1845 chunk = chunk + 1
1846 elif letter != None:
1847 output.write(" </letter>\n")
1848 letter = id[0]
1849 output.write(" <letter name='%s'>\n" % (letter))
1850 output.write(" <word name='%s'>\n" % (id))
1851 tokens = index[id];
1852 tokens.sort()
1853 tok = None
William M. Bracka2e844a2004-01-06 11:52:13 +00001854 for token in tokens:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001855 if tok == token:
1856 continue
1857 tok = token
1858 output.write(" <ref name='%s'/>\n" % (token))
1859 count = count + 1
1860 output.write(" </word>\n")
1861 if letter != None:
1862 output.write(" </letter>\n")
1863 output.write(" </chunk>\n")
William M. Brack966668a2003-12-20 02:10:28 +00001864 if count != 0:
1865 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001866 output.write(" <chunks>\n")
1867 for ch in chunks:
1868 output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
1869 ch[0], ch[1], ch[2]))
1870 output.write(" </chunks>\n")
1871
1872 def serialize_xrefs(self, output):
1873 output.write(" <references>\n")
1874 self.serialize_xrefs_references(output)
1875 output.write(" </references>\n")
1876 output.write(" <alpha>\n")
1877 self.serialize_xrefs_alpha(output)
1878 output.write(" </alpha>\n")
1879 output.write(" <constructors>\n")
1880 self.serialize_xrefs_constructors(output)
1881 output.write(" </constructors>\n")
1882 output.write(" <functions>\n")
1883 self.serialize_xrefs_functions(output)
1884 output.write(" </functions>\n")
1885 output.write(" <files>\n")
1886 self.serialize_xrefs_files(output)
1887 output.write(" </files>\n")
1888 output.write(" <index>\n")
1889 self.serialize_xrefs_index(output)
1890 output.write(" </index>\n")
1891
1892 def serialize(self):
1893 filename = "%s-api.xml" % self.name
1894 print "Saving XML description %s" % (filename)
1895 output = open(filename, "w")
1896 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1897 output.write("<api name='%s'>\n" % self.name)
1898 output.write(" <files>\n")
1899 headers = self.headers.keys()
1900 headers.sort()
1901 for file in headers:
1902 self.serialize_exports(output, file)
1903 output.write(" </files>\n")
1904 output.write(" <symbols>\n")
1905 macros = self.idx.macros.keys()
1906 macros.sort()
1907 for macro in macros:
1908 self.serialize_macro(output, macro)
1909 enums = self.idx.enums.keys()
1910 enums.sort()
1911 for enum in enums:
1912 self.serialize_enum(output, enum)
1913 typedefs = self.idx.typedefs.keys()
1914 typedefs.sort()
1915 for typedef in typedefs:
1916 self.serialize_typedef(output, typedef)
1917 variables = self.idx.variables.keys()
1918 variables.sort()
1919 for variable in variables:
1920 self.serialize_variable(output, variable)
1921 functions = self.idx.functions.keys()
1922 functions.sort()
1923 for function in functions:
1924 self.serialize_function(output, function)
1925 output.write(" </symbols>\n")
1926 output.write("</api>\n")
1927 output.close()
1928
1929 filename = "%s-refs.xml" % self.name
1930 print "Saving XML Cross References %s" % (filename)
1931 output = open(filename, "w")
1932 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1933 output.write("<apirefs name='%s'>\n" % self.name)
1934 self.serialize_xrefs(output)
1935 output.write("</apirefs>\n")
1936 output.close()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001937
1938
1939def rebuild():
1940 builder = None
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001941 if glob.glob("parser.c") != [] :
1942 print "Rebuilding API description for libxml2"
1943 builder = docBuilder("libxml2", [".", "."],
1944 ["xmlwin32version.h", "tst.c"])
1945 elif glob.glob("../parser.c") != [] :
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001946 print "Rebuilding API description for libxml2"
1947 builder = docBuilder("libxml2", ["..", "../include/libxml"],
Daniel Veillardd4330462003-04-29 12:40:16 +00001948 ["xmlwin32version.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001949 elif glob.glob("../libxslt/transform.c") != [] :
1950 print "Rebuilding API description for libxslt"
1951 builder = docBuilder("libxslt", ["../libxslt"],
Daniel Veillard024b5702002-12-12 00:15:55 +00001952 ["win32config.h", "libxslt.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001953 else:
1954 print "rebuild() failed, unable to guess the module"
1955 return None
1956 builder.scan()
1957 builder.analyze()
1958 builder.serialize()
Daniel Veillard024b5702002-12-12 00:15:55 +00001959 if glob.glob("../libexslt/exslt.c") != [] :
1960 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1961 extra.scan()
1962 extra.analyze()
1963 extra.serialize()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001964 return builder
1965
1966#
1967# for debugging the parser
1968#
1969def parse(filename):
1970 parser = CParser(filename)
1971 idx = parser.parse()
1972 return idx
1973
1974if __name__ == "__main__":
Daniel Veillarda2351322004-06-27 12:08:10 +00001975 if len(sys.argv) > 1:
1976 debug = 1
1977 parse(sys.argv[1])
1978 else:
1979 rebuild()