blob: e3989859ab4573e42868f67cb79ac54c05d5c284 [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 Veillardde0a0a52003-04-24 17:12:57 +000035}
36
37ignored_words = {
38 "WINAPI": (0, "Windows keyword"),
39 "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
William M. Brackcdfa2862003-08-29 06:03:38 +000040 "XMLPUBVAR": (0, "Special macro for extern vars for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000041 "XSLTPUBVAR": (0, "Special macro for extern vars for win32"),
42 "EXSLTPUBVAR": (0, "Special macro for extern vars for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000043 "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000044 "XSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
45 "EXSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000046 "XMLCALL": (0, "Special macro for win32 calls"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000047 "XSLTCALL": (0, "Special macro for win32 calls"),
48 "EXSLTCALL": (0, "Special macro for win32 calls"),
Daniel Veillardde0a0a52003-04-24 17:12:57 +000049 "__declspec": (3, "Windows keyword"),
Daniel Veillarda2351322004-06-27 12:08:10 +000050 "__stdcall": (0, "Windows keyword"),
Daniel Veillardde0a0a52003-04-24 17:12:57 +000051 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
52 "LIBEXSLT_PUBLIC": (0, "macro keyword"),
53 "X_IN_Y": (5, "macro function builder"),
54}
55
Daniel Veillarda9b66d02002-12-11 14:23:49 +000056def escape(raw):
57 raw = string.replace(raw, '&', '&')
58 raw = string.replace(raw, '<', '&lt;')
59 raw = string.replace(raw, '>', '&gt;')
60 raw = string.replace(raw, "'", '&apos;')
61 raw = string.replace(raw, '"', '&quot;')
62 return raw
63
Daniel Veillard2925c0a2003-11-17 13:58:17 +000064def uniq(items):
65 d = {}
66 for item in items:
67 d[item]=1
68 return d.keys()
69
Daniel Veillarda9b66d02002-12-11 14:23:49 +000070class identifier:
Daniel Veillardbe586972003-11-18 20:56:51 +000071 def __init__(self, name, module=None, type=None, lineno = 0,
Daniel Veillarda2351322004-06-27 12:08:10 +000072 info=None, extra=None, conditionals = None):
Daniel Veillardbe586972003-11-18 20:56:51 +000073 self.name = name
74 self.module = module
75 self.type = type
76 self.info = info
77 self.extra = extra
78 self.lineno = lineno
79 self.static = 0
Daniel Veillarda2351322004-06-27 12:08:10 +000080 if conditionals == None or len(conditionals) == 0:
81 self.conditionals = None
82 else:
83 self.conditionals = conditionals[:]
84 if self.name == debugsym:
85 print "=> define %s : %s" % (debugsym, (module, type, info,
86 extra, conditionals))
Daniel Veillarda9b66d02002-12-11 14:23:49 +000087
Daniel Veillardbe586972003-11-18 20:56:51 +000088 def __repr__(self):
89 r = "%s %s:" % (self.type, self.name)
90 if self.static:
91 r = r + " static"
92 if self.module != None:
93 r = r + " from %s" % (self.module)
94 if self.info != None:
95 r = r + " " + `self.info`
96 if self.extra != None:
97 r = r + " " + `self.extra`
Daniel Veillarda2351322004-06-27 12:08:10 +000098 if self.conditionals != None:
99 r = r + " " + `self.conditionals`
Daniel Veillardbe586972003-11-18 20:56:51 +0000100 return r
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000101
102
Daniel Veillardbe586972003-11-18 20:56:51 +0000103 def set_module(self, module):
104 self.module = module
105 def set_type(self, type):
106 self.type = type
107 def set_info(self, info):
108 self.info = info
109 def set_extra(self, extra):
110 self.extra = extra
111 def set_lineno(self, lineno):
112 self.lineno = lineno
113 def set_static(self, static):
114 self.static = static
Daniel Veillarda2351322004-06-27 12:08:10 +0000115 def set_conditionals(self, conditionals):
116 if conditionals == None or len(conditionals) == 0:
117 self.conditionals = None
118 else:
119 self.conditionals = conditionals[:]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000120
Daniel Veillardbe586972003-11-18 20:56:51 +0000121 def get_name(self):
122 return self.name
123 def get_module(self):
124 return self.module
125 def get_type(self):
126 return self.type
127 def get_info(self):
128 return self.info
129 def get_lineno(self):
130 return self.lineno
131 def get_extra(self):
132 return self.extra
133 def get_static(self):
134 return self.static
Daniel Veillarda2351322004-06-27 12:08:10 +0000135 def get_conditionals(self):
136 return self.conditionals
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000137
Daniel Veillarda2351322004-06-27 12:08:10 +0000138 def update(self, module, type = None, info = None, extra=None,
139 conditionals=None):
140 if self.name == debugsym:
141 print "=> update %s : %s" % (debugsym, (module, type, info,
142 extra, conditionals))
Daniel Veillardbe586972003-11-18 20:56:51 +0000143 if module != None and self.module == None:
144 self.set_module(module)
145 if type != None and self.type == None:
146 self.set_type(type)
147 if info != None:
148 self.set_info(info)
149 if extra != None:
150 self.set_extra(extra)
Daniel Veillarda2351322004-06-27 12:08:10 +0000151 if conditionals != None:
152 self.set_conditionals(conditionals)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000153
154
155class index:
Daniel Veillardbe586972003-11-18 20:56:51 +0000156 def __init__(self, name = "noname"):
157 self.name = name
158 self.identifiers = {}
159 self.functions = {}
160 self.variables = {}
161 self.includes = {}
162 self.structs = {}
163 self.enums = {}
164 self.typedefs = {}
165 self.macros = {}
166 self.references = {}
167 self.info = {}
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000168
Daniel Veillarda2351322004-06-27 12:08:10 +0000169 def add_ref(self, name, module, static, type, lineno, info=None, extra=None, conditionals = None):
Daniel Veillardbe586972003-11-18 20:56:51 +0000170 if name[0:2] == '__':
171 return None
172 d = None
173 try:
174 d = self.identifiers[name]
Daniel Veillarda2351322004-06-27 12:08:10 +0000175 d.update(module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000176 except:
Daniel Veillarda2351322004-06-27 12:08:10 +0000177 d = identifier(name, module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000178 self.identifiers[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000179
Daniel Veillardbe586972003-11-18 20:56:51 +0000180 if d != None and static == 1:
181 d.set_static(1)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000182
Daniel Veillardbe586972003-11-18 20:56:51 +0000183 if d != None and name != None and type != None:
184 self.references[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000185
Daniel Veillarda2351322004-06-27 12:08:10 +0000186 if name == debugsym:
187 print "New ref: %s" % (d)
188
189 return d
190
191 def add(self, name, module, static, type, lineno, info=None, extra=None, conditionals = None):
Daniel Veillardbe586972003-11-18 20:56:51 +0000192 if name[0:2] == '__':
193 return None
194 d = None
195 try:
196 d = self.identifiers[name]
Daniel Veillarda2351322004-06-27 12:08:10 +0000197 d.update(module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000198 except:
Daniel Veillarda2351322004-06-27 12:08:10 +0000199 d = identifier(name, module, type, lineno, info, extra, conditionals)
Daniel Veillardbe586972003-11-18 20:56:51 +0000200 self.identifiers[name] = d
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000201
Daniel Veillardbe586972003-11-18 20:56:51 +0000202 if d != None and static == 1:
203 d.set_static(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000204
Daniel Veillardbe586972003-11-18 20:56:51 +0000205 if d != None and name != None and type != None:
206 if type == "function":
207 self.functions[name] = d
208 elif type == "functype":
209 self.functions[name] = d
210 elif type == "variable":
211 self.variables[name] = d
212 elif type == "include":
213 self.includes[name] = d
214 elif type == "struct":
215 self.structs[name] = d
216 elif type == "enum":
217 self.enums[name] = d
218 elif type == "typedef":
219 self.typedefs[name] = d
220 elif type == "macro":
221 self.macros[name] = d
222 else:
223 print "Unable to register type ", type
Daniel Veillarda2351322004-06-27 12:08:10 +0000224
225 if name == debugsym:
226 print "New symbol: %s" % (d)
227
Daniel Veillardbe586972003-11-18 20:56:51 +0000228 return d
229
230 def merge(self, idx):
231 for id in idx.functions.keys():
232 #
233 # macro might be used to override functions or variables
234 # definitions
235 #
236 if self.macros.has_key(id):
237 del self.macros[id]
238 if self.functions.has_key(id):
239 print "function %s from %s redeclared in %s" % (
240 id, self.functions[id].module, idx.functions[id].module)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000241 else:
Daniel Veillardbe586972003-11-18 20:56:51 +0000242 self.functions[id] = idx.functions[id]
243 self.identifiers[id] = idx.functions[id]
244 for id in idx.variables.keys():
245 #
246 # macro might be used to override functions or variables
247 # definitions
248 #
249 if self.macros.has_key(id):
250 del self.macros[id]
251 if self.variables.has_key(id):
252 print "variable %s from %s redeclared in %s" % (
253 id, self.variables[id].module, idx.variables[id].module)
254 else:
255 self.variables[id] = idx.variables[id]
256 self.identifiers[id] = idx.variables[id]
257 for id in idx.structs.keys():
258 if self.structs.has_key(id):
259 print "struct %s from %s redeclared in %s" % (
260 id, self.structs[id].module, idx.structs[id].module)
261 else:
262 self.structs[id] = idx.structs[id]
263 self.identifiers[id] = idx.structs[id]
264 for id in idx.typedefs.keys():
265 if self.typedefs.has_key(id):
266 print "typedef %s from %s redeclared in %s" % (
267 id, self.typedefs[id].module, idx.typedefs[id].module)
268 else:
269 self.typedefs[id] = idx.typedefs[id]
270 self.identifiers[id] = idx.typedefs[id]
271 for id in idx.macros.keys():
272 #
273 # macro might be used to override functions or variables
274 # definitions
275 #
276 if self.variables.has_key(id):
277 continue
278 if self.functions.has_key(id):
279 continue
280 if self.enums.has_key(id):
281 continue
282 if self.macros.has_key(id):
283 print "macro %s from %s redeclared in %s" % (
284 id, self.macros[id].module, idx.macros[id].module)
285 else:
286 self.macros[id] = idx.macros[id]
287 self.identifiers[id] = idx.macros[id]
288 for id in idx.enums.keys():
289 if self.enums.has_key(id):
290 print "enum %s from %s redeclared in %s" % (
291 id, self.enums[id].module, idx.enums[id].module)
292 else:
293 self.enums[id] = idx.enums[id]
294 self.identifiers[id] = idx.enums[id]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000295
Daniel Veillardbe586972003-11-18 20:56:51 +0000296 def merge_public(self, idx):
297 for id in idx.functions.keys():
298 if self.functions.has_key(id):
299 up = idx.functions[id]
300 self.functions[id].update(None, up.type, up.info, up.extra)
Daniel Veillardc1eed322002-12-12 11:01:32 +0000301 # else:
302 # print "Function %s from %s is not declared in headers" % (
303 # id, idx.functions[id].module)
304 # TODO: do the same for variables.
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000305
Daniel Veillardbe586972003-11-18 20:56:51 +0000306 def analyze_dict(self, type, dict):
307 count = 0
308 public = 0
309 for name in dict.keys():
310 id = dict[name]
311 count = count + 1
312 if id.static == 0:
313 public = public + 1
314 if count != public:
315 print " %d %s , %d public" % (count, type, public)
316 elif count != 0:
317 print " %d public %s" % (count, type)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000318
319
Daniel Veillardbe586972003-11-18 20:56:51 +0000320 def analyze(self):
321 self.analyze_dict("functions", self.functions)
322 self.analyze_dict("variables", self.variables)
323 self.analyze_dict("structs", self.structs)
324 self.analyze_dict("typedefs", self.typedefs)
325 self.analyze_dict("macros", self.macros)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000326
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000327class CLexer:
Daniel Veillardbe586972003-11-18 20:56:51 +0000328 """A lexer for the C language, tokenize the input by reading and
329 analyzing it line by line"""
330 def __init__(self, input):
331 self.input = input
332 self.tokens = []
333 self.line = ""
334 self.lineno = 0
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000335
Daniel Veillardbe586972003-11-18 20:56:51 +0000336 def getline(self):
337 line = ''
338 while line == '':
339 line = self.input.readline()
340 if not line:
341 return None
342 self.lineno = self.lineno + 1
343 line = string.lstrip(line)
344 line = string.rstrip(line)
345 if line == '':
346 continue
347 while line[-1] == '\\':
348 line = line[:-1]
349 n = self.input.readline()
350 self.lineno = self.lineno + 1
351 n = string.lstrip(n)
352 n = string.rstrip(n)
353 if not n:
354 break
355 else:
356 line = line + n
357 return line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000358
Daniel Veillardbe586972003-11-18 20:56:51 +0000359 def getlineno(self):
360 return self.lineno
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000361
Daniel Veillardbe586972003-11-18 20:56:51 +0000362 def push(self, token):
363 self.tokens.insert(0, token);
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000364
Daniel Veillardbe586972003-11-18 20:56:51 +0000365 def debug(self):
366 print "Last token: ", self.last
367 print "Token queue: ", self.tokens
368 print "Line %d end: " % (self.lineno), self.line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000369
Daniel Veillardbe586972003-11-18 20:56:51 +0000370 def token(self):
371 while self.tokens == []:
372 if self.line == "":
373 line = self.getline()
374 else:
375 line = self.line
376 self.line = ""
377 if line == None:
378 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000379
Daniel Veillardbe586972003-11-18 20:56:51 +0000380 if line[0] == '#':
381 self.tokens = map((lambda x: ('preproc', x)),
382 string.split(line))
383 break;
384 l = len(line)
385 if line[0] == '"' or line[0] == "'":
386 end = line[0]
387 line = line[1:]
388 found = 0
389 tok = ""
390 while found == 0:
391 i = 0
392 l = len(line)
393 while i < l:
394 if line[i] == end:
395 self.line = line[i+1:]
396 line = line[:i]
397 l = i
398 found = 1
399 break
400 if line[i] == '\\':
401 i = i + 1
402 i = i + 1
403 tok = tok + line
404 if found == 0:
405 line = self.getline()
406 if line == None:
407 return None
408 self.last = ('string', tok)
409 return self.last
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000410
Daniel Veillardbe586972003-11-18 20:56:51 +0000411 if l >= 2 and line[0] == '/' and line[1] == '*':
412 line = line[2:]
413 found = 0
414 tok = ""
415 while found == 0:
416 i = 0
417 l = len(line)
418 while i < l:
419 if line[i] == '*' and i+1 < l and line[i+1] == '/':
420 self.line = line[i+2:]
421 line = line[:i-1]
422 l = i
423 found = 1
424 break
425 i = i + 1
426 if tok != "":
427 tok = tok + "\n"
428 tok = tok + line
429 if found == 0:
430 line = self.getline()
431 if line == None:
432 return None
433 self.last = ('comment', tok)
434 return self.last
435 if l >= 2 and line[0] == '/' and line[1] == '/':
436 line = line[2:]
437 self.last = ('comment', line)
438 return self.last
439 i = 0
440 while i < l:
441 if line[i] == '/' and i+1 < l and line[i+1] == '/':
442 self.line = line[i:]
443 line = line[:i]
444 break
445 if line[i] == '/' and i+1 < l and line[i+1] == '*':
446 self.line = line[i:]
447 line = line[:i]
448 break
449 if line[i] == '"' or line[i] == "'":
450 self.line = line[i:]
451 line = line[:i]
452 break
453 i = i + 1
454 l = len(line)
455 i = 0
456 while i < l:
457 if line[i] == ' ' or line[i] == '\t':
458 i = i + 1
459 continue
460 o = ord(line[i])
461 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
462 (o >= 48 and o <= 57):
463 s = i
464 while i < l:
465 o = ord(line[i])
466 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
467 (o >= 48 and o <= 57) or string.find(
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000468 " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1:
Daniel Veillardbe586972003-11-18 20:56:51 +0000469 i = i + 1
470 else:
471 break
472 self.tokens.append(('name', line[s:i]))
473 continue
474 if string.find("(){}:;,[]", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000475# if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
476# line[i] == '}' or line[i] == ':' or line[i] == ';' or \
477# line[i] == ',' or line[i] == '[' or line[i] == ']':
Daniel Veillardbe586972003-11-18 20:56:51 +0000478 self.tokens.append(('sep', line[i]))
479 i = i + 1
480 continue
481 if string.find("+-*><=/%&!|.", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000482# if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
483# 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] == '.':
Daniel Veillardbe586972003-11-18 20:56:51 +0000486 if line[i] == '.' and i + 2 < l and \
487 line[i+1] == '.' and line[i+2] == '.':
488 self.tokens.append(('name', '...'))
489 i = i + 3
490 continue
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000491
Daniel Veillardbe586972003-11-18 20:56:51 +0000492 j = i + 1
493 if j < l and (
494 string.find("+-*><=/%&!|", line[j]) != -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000495# line[j] == '+' or line[j] == '-' or line[j] == '*' or \
496# 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] == '|'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000499 self.tokens.append(('op', line[i:j+1]))
500 i = j + 1
501 else:
502 self.tokens.append(('op', line[i]))
503 i = i + 1
504 continue
505 s = i
506 while i < l:
507 o = ord(line[i])
508 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
509 (o >= 48 and o <= 57) or (
510 string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000511# line[i] != ' ' and line[i] != '\t' and
512# line[i] != '(' and line[i] != ')' 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] != '<'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000523 i = i + 1
524 else:
525 break
526 self.tokens.append(('name', line[s:i]))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000527
Daniel Veillardbe586972003-11-18 20:56:51 +0000528 tok = self.tokens[0]
529 self.tokens = self.tokens[1:]
530 self.last = tok
531 return tok
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000532
533class CParser:
Daniel Veillardbe586972003-11-18 20:56:51 +0000534 """The C module parser"""
535 def __init__(self, filename, idx = None):
536 self.filename = filename
537 if len(filename) > 2 and filename[-2:] == '.h':
538 self.is_header = 1
539 else:
540 self.is_header = 0
541 self.input = open(filename)
542 self.lexer = CLexer(self.input)
543 if idx == None:
544 self.index = index()
545 else:
546 self.index = idx
547 self.top_comment = ""
548 self.last_comment = ""
549 self.comment = None
550 self.collect_ref = 0
Daniel Veillard1e906612003-12-05 14:57:46 +0000551 self.no_error = 0
Daniel Veillarda2351322004-06-27 12:08:10 +0000552 self.conditionals = []
553 self.defines = []
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000554
Daniel Veillardbe586972003-11-18 20:56:51 +0000555 def collect_references(self):
556 self.collect_ref = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000557
Daniel Veillard1e906612003-12-05 14:57:46 +0000558 def stop_error(self):
559 self.no_error = 1
560
561 def start_error(self):
562 self.no_error = 0
563
Daniel Veillardbe586972003-11-18 20:56:51 +0000564 def lineno(self):
565 return self.lexer.getlineno()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000566
Daniel Veillardbe586972003-11-18 20:56:51 +0000567 def index_add(self, name, module, static, type, info=None, extra = None):
568 self.index.add(name, module, static, type, self.lineno(),
Daniel Veillarda2351322004-06-27 12:08:10 +0000569 info, extra, self.conditionals)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000570
Daniel Veillardbe586972003-11-18 20:56:51 +0000571 def index_add_ref(self, name, module, static, type, info=None,
572 extra = None):
573 self.index.add_ref(name, module, static, type, self.lineno(),
Daniel Veillarda2351322004-06-27 12:08:10 +0000574 info, extra, self.conditionals)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000575
Daniel Veillard1e906612003-12-05 14:57:46 +0000576 def warning(self, msg):
577 if self.no_error:
578 return
579 print msg
580
Daniel Veillardbe586972003-11-18 20:56:51 +0000581 def error(self, msg, token=-1):
Daniel Veillard1e906612003-12-05 14:57:46 +0000582 if self.no_error:
583 return
584
Daniel Veillardbe586972003-11-18 20:56:51 +0000585 print "Parse Error: " + msg
586 if token != -1:
587 print "Got token ", token
588 self.lexer.debug()
589 sys.exit(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000590
Daniel Veillardbe586972003-11-18 20:56:51 +0000591 def debug(self, msg, token=-1):
592 print "Debug: " + msg
593 if token != -1:
594 print "Got token ", token
595 self.lexer.debug()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000596
Daniel Veillardbe586972003-11-18 20:56:51 +0000597 def parseTopComment(self, comment):
598 res = {}
599 lines = string.split(comment, "\n")
600 item = None
601 for line in lines:
602 while line != "" and (line[0] == ' ' or line[0] == '\t'):
603 line = line[1:]
604 while line != "" and line[0] == '*':
605 line = line[1:]
606 while line != "" and (line[0] == ' ' or line[0] == '\t'):
607 line = line[1:]
608 try:
609 (it, line) = string.split(line, ":", 1)
610 item = it
611 while line != "" and (line[0] == ' ' or line[0] == '\t'):
612 line = line[1:]
613 if res.has_key(item):
614 res[item] = res[item] + " " + line
615 else:
616 res[item] = line
617 except:
618 if item != None:
619 if res.has_key(item):
620 res[item] = res[item] + " " + line
621 else:
622 res[item] = line
623 self.index.info = res
624
625 def parseComment(self, token):
626 if self.top_comment == "":
627 self.top_comment = token[1]
628 if self.comment == None or token[1][0] == '*':
629 self.comment = token[1];
630 else:
631 self.comment = self.comment + token[1]
632 token = self.lexer.token()
Daniel Veillard1e906612003-12-05 14:57:46 +0000633
634 if string.find(self.comment, "DOC_DISABLE") != -1:
635 self.stop_error()
636
637 if string.find(self.comment, "DOC_ENABLE") != -1:
638 self.start_error()
639
Daniel Veillardbe586972003-11-18 20:56:51 +0000640 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000641
642 #
643 # Parse a comment block associate to a macro
644 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000645 def parseMacroComment(self, name, quiet = 0):
646 if name[0:2] == '__':
647 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000648
Daniel Veillardbe586972003-11-18 20:56:51 +0000649 args = []
650 desc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000651
Daniel Veillardbe586972003-11-18 20:56:51 +0000652 if self.comment == None:
653 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000654 self.warning("Missing comment for macro %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000655 return((args, desc))
656 if self.comment[0] != '*':
657 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000658 self.warning("Missing * in macro comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000659 return((args, desc))
660 lines = string.split(self.comment, '\n')
661 if lines[0] == '*':
662 del lines[0]
663 if lines[0] != "* %s:" % (name):
664 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000665 self.warning("Misformatted macro comment for %s" % (name))
666 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000667 return((args, desc))
668 del lines[0]
669 while lines[0] == '*':
670 del lines[0]
671 while len(lines) > 0 and lines[0][0:3] == '* @':
672 l = lines[0][3:]
673 try:
674 (arg, desc) = string.split(l, ':', 1)
675 desc=string.strip(desc)
676 arg=string.strip(arg)
677 except:
678 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000679 self.warning("Misformatted macro comment for %s" % (name))
680 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000681 del lines[0]
682 continue
683 del lines[0]
684 l = string.strip(lines[0])
685 while len(l) > 2 and l[0:3] != '* @':
686 while l[0] == '*':
687 l = l[1:]
688 desc = desc + ' ' + string.strip(l)
689 del lines[0]
690 if len(lines) == 0:
691 break
692 l = lines[0]
693 args.append((arg, desc))
694 while len(lines) > 0 and lines[0] == '*':
695 del lines[0]
696 desc = ""
697 while len(lines) > 0:
698 l = lines[0]
699 while len(l) > 0 and l[0] == '*':
700 l = l[1:]
701 l = string.strip(l)
702 desc = desc + " " + l
703 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000704
Daniel Veillardbe586972003-11-18 20:56:51 +0000705 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000706
Daniel Veillardbe586972003-11-18 20:56:51 +0000707 if quiet == 0:
708 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000709 self.warning("Macro comment for %s lack description of the macro" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000710
Daniel Veillardbe586972003-11-18 20:56:51 +0000711 return((args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000712
713 #
714 # Parse a comment block and merge the informations found in the
715 # parameters descriptions, finally returns a block as complete
716 # as possible
717 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000718 def mergeFunctionComment(self, name, description, quiet = 0):
719 if name == 'main':
720 quiet = 1
721 if name[0:2] == '__':
722 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000723
Daniel Veillardbe586972003-11-18 20:56:51 +0000724 (ret, args) = description
725 desc = ""
726 retdesc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000727
Daniel Veillardbe586972003-11-18 20:56:51 +0000728 if self.comment == None:
729 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000730 self.warning("Missing comment for function %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000731 return(((ret[0], retdesc), args, desc))
732 if self.comment[0] != '*':
733 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000734 self.warning("Missing * in function comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000735 return(((ret[0], retdesc), args, desc))
736 lines = string.split(self.comment, '\n')
737 if lines[0] == '*':
738 del lines[0]
739 if lines[0] != "* %s:" % (name):
740 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000741 self.warning("Misformatted function comment for %s" % (name))
742 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000743 return(((ret[0], retdesc), args, desc))
744 del lines[0]
745 while lines[0] == '*':
746 del lines[0]
747 nbargs = len(args)
748 while len(lines) > 0 and lines[0][0:3] == '* @':
749 l = lines[0][3:]
750 try:
751 (arg, desc) = string.split(l, ':', 1)
752 desc=string.strip(desc)
753 arg=string.strip(arg)
754 except:
755 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000756 self.warning("Misformatted function comment for %s" % (name))
757 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000758 del lines[0]
759 continue
760 del lines[0]
761 l = string.strip(lines[0])
762 while len(l) > 2 and l[0:3] != '* @':
763 while l[0] == '*':
764 l = l[1:]
765 desc = desc + ' ' + string.strip(l)
766 del lines[0]
767 if len(lines) == 0:
768 break
769 l = lines[0]
770 i = 0
771 while i < nbargs:
772 if args[i][1] == arg:
773 args[i] = (args[i][0], arg, desc)
774 break;
775 i = i + 1
776 if i >= nbargs:
777 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000778 self.warning("Unable to find arg %s from function comment for %s" % (
779 arg, name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000780 while len(lines) > 0 and lines[0] == '*':
781 del lines[0]
782 desc = ""
783 while len(lines) > 0:
784 l = lines[0]
785 while len(l) > 0 and l[0] == '*':
786 l = l[1:]
787 l = string.strip(l)
788 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
789 try:
790 l = string.split(l, ' ', 1)[1]
791 except:
792 l = ""
793 retdesc = string.strip(l)
794 del lines[0]
795 while len(lines) > 0:
796 l = lines[0]
797 while len(l) > 0 and l[0] == '*':
798 l = l[1:]
799 l = string.strip(l)
800 retdesc = retdesc + " " + l
801 del lines[0]
802 else:
803 desc = desc + " " + l
804 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000805
Daniel Veillardbe586972003-11-18 20:56:51 +0000806 retdesc = string.strip(retdesc)
807 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000808
Daniel Veillardbe586972003-11-18 20:56:51 +0000809 if quiet == 0:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000810 #
811 # report missing comments
812 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000813 i = 0
814 while i < nbargs:
815 if args[i][2] == None and args[i][0] != "void" and args[i][1] != None:
Daniel Veillard1e906612003-12-05 14:57:46 +0000816 self.warning("Function comment for %s lack description of arg %s" % (name, args[i][1]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000817 i = i + 1
818 if retdesc == "" and ret[0] != "void":
Daniel Veillard1e906612003-12-05 14:57:46 +0000819 self.warning("Function comment for %s lack description of return value" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000820 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000821 self.warning("Function comment for %s lack description of the function" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000822
823
Daniel Veillardbe586972003-11-18 20:56:51 +0000824 return(((ret[0], retdesc), args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000825
Daniel Veillardbe586972003-11-18 20:56:51 +0000826 def parsePreproc(self, token):
Daniel Veillarda2351322004-06-27 12:08:10 +0000827 if debug:
828 print "=> preproc ", token, self.lexer.tokens
Daniel Veillardbe586972003-11-18 20:56:51 +0000829 name = token[1]
830 if name == "#include":
831 token = self.lexer.token()
832 if token == None:
833 return None
834 if token[0] == 'preproc':
835 self.index_add(token[1], self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000836 "include")
Daniel Veillardbe586972003-11-18 20:56:51 +0000837 return self.lexer.token()
838 return token
839 if name == "#define":
840 token = self.lexer.token()
841 if token == None:
842 return None
843 if token[0] == 'preproc':
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000844 # TODO macros with arguments
Daniel Veillardbe586972003-11-18 20:56:51 +0000845 name = token[1]
846 lst = []
847 token = self.lexer.token()
848 while token != None and token[0] == 'preproc' and \
849 token[1][0] != '#':
850 lst.append(token[1])
851 token = self.lexer.token()
852 try:
853 name = string.split(name, '(') [0]
854 except:
855 pass
856 info = self.parseMacroComment(name, not self.is_header)
857 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000858 "macro", info)
Daniel Veillardbe586972003-11-18 20:56:51 +0000859 return token
Daniel Veillarda2351322004-06-27 12:08:10 +0000860 if name == "#ifdef" and self.is_header:
861 try:
862 self.defines.append(self.lexer.tokens[0][1])
863 if string.find(self.lexer.tokens[0][1], 'ENABLED') != -1:
864 self.conditionals.append(self.lexer.tokens[0][1])
865# print self.conditionals
866# print self.defines
867 except:
868 pass
869 if name == "#endif" and self.is_header:
870 if self.conditionals != [] and self.defines != [] and \
871 self.defines[-1] == self.conditionals[-1]:
872 self.conditionals = self.conditionals[:-1]
873 self.defines = self.defines[:-1]
874# print self.defines
875# print self.conditionals
Daniel Veillardbe586972003-11-18 20:56:51 +0000876 token = self.lexer.token()
877 while token != None and token[0] == 'preproc' and \
878 token[1][0] != '#':
879 token = self.lexer.token()
880 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000881
882 #
883 # token acquisition on top of the lexer, it handle internally
884 # preprocessor and comments since they are logically not part of
885 # the program structure.
886 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000887 def token(self):
888 global ignored_words
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000889
Daniel Veillardbe586972003-11-18 20:56:51 +0000890 token = self.lexer.token()
891 while token != None:
892 if token[0] == 'comment':
893 token = self.parseComment(token)
894 continue
895 elif token[0] == 'preproc':
896 token = self.parsePreproc(token)
897 continue
898 elif token[0] == "name" and ignored_words.has_key(token[1]):
899 (n, info) = ignored_words[token[1]]
900 i = 0
901 while i < n:
902 token = self.lexer.token()
903 i = i + 1
904 token = self.lexer.token()
905 continue
906 else:
907 if debug:
908 print "=> ", token
909 return token
910 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000911
912 #
913 # Parse a typedef, it records the type and its name.
914 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000915 def parseTypedef(self, token):
916 if token == None:
917 return None
918 token = self.parseType(token)
919 if token == None:
920 self.error("parsing typedef")
921 return None
922 base_type = self.type
923 type = base_type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000924 #self.debug("end typedef type", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000925 while token != None:
926 if token[0] == "name":
927 name = token[1]
928 signature = self.signature
929 if signature != None:
930 type = string.split(type, '(')[0]
931 d = self.mergeFunctionComment(name,
932 ((type, None), signature), 1)
933 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000934 "functype", d)
Daniel Veillardbe586972003-11-18 20:56:51 +0000935 else:
936 if base_type == "struct":
937 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000938 "struct", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000939 base_type = "struct " + name
940 else:
941 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000942 "typedef", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000943 token = self.token()
944 else:
945 self.error("parsing typedef: expecting a name")
946 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000947 #self.debug("end typedef", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000948 if token != None and token[0] == 'sep' and token[1] == ',':
949 type = base_type
950 token = self.token()
951 while token != None and token[0] == "op":
952 type = type + token[1]
953 token = self.token()
954 elif token != None and token[0] == 'sep' and token[1] == ';':
955 break;
956 elif token != None and token[0] == 'name':
957 type = base_type
958 continue;
959 else:
960 self.error("parsing typedef: expecting ';'", token)
961 return token
962 token = self.token()
963 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000964
965 #
966 # Parse a C code block, used for functions it parse till
967 # the balancing } included
968 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000969 def parseBlock(self, token):
970 while token != None:
971 if token[0] == "sep" and token[1] == "{":
972 token = self.token()
973 token = self.parseBlock(token)
974 elif token[0] == "sep" and token[1] == "}":
975 self.comment = None
976 token = self.token()
977 return token
978 else:
979 if self.collect_ref == 1:
980 oldtok = token
981 token = self.token()
982 if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
983 if token[0] == "sep" and token[1] == "(":
984 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000985 0, "function")
Daniel Veillardbe586972003-11-18 20:56:51 +0000986 token = self.token()
987 elif token[0] == "name":
988 token = self.token()
989 if token[0] == "sep" and (token[1] == ";" or
990 token[1] == "," or token[1] == "="):
991 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000992 0, "type")
Daniel Veillardbe586972003-11-18 20:56:51 +0000993 elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
994 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000995 0, "typedef")
Daniel Veillardbe586972003-11-18 20:56:51 +0000996 elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
997 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000998 0, "typedef")
999
Daniel Veillardbe586972003-11-18 20:56:51 +00001000 else:
1001 token = self.token()
1002 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001003
1004 #
1005 # Parse a C struct definition till the balancing }
1006 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001007 def parseStruct(self, token):
1008 fields = []
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001009 #self.debug("start parseStruct", token)
Daniel Veillardbe586972003-11-18 20:56:51 +00001010 while token != None:
1011 if token[0] == "sep" and token[1] == "{":
1012 token = self.token()
1013 token = self.parseTypeBlock(token)
1014 elif token[0] == "sep" and token[1] == "}":
1015 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001016 #self.debug("end parseStruct", token)
1017 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +00001018 token = self.token()
1019 return token
1020 else:
1021 base_type = self.type
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001022 #self.debug("before parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +00001023 token = self.parseType(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001024 #self.debug("after parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +00001025 if token != None and token[0] == "name":
1026 fname = token[1]
1027 token = self.token()
1028 if token[0] == "sep" and token[1] == ";":
1029 self.comment = None
1030 token = self.token()
1031 fields.append((self.type, fname, self.comment))
1032 self.comment = None
1033 else:
1034 self.error("parseStruct: expecting ;", token)
1035 elif token != None and token[0] == "sep" and token[1] == "{":
1036 token = self.token()
1037 token = self.parseTypeBlock(token)
1038 if token != None and token[0] == "name":
1039 token = self.token()
1040 if token != None and token[0] == "sep" and token[1] == ";":
1041 token = self.token()
1042 else:
1043 self.error("parseStruct: expecting ;", token)
1044 else:
1045 self.error("parseStruct: name", token)
1046 token = self.token()
1047 self.type = base_type;
1048 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001049 #self.debug("end parseStruct", token)
1050 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +00001051 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001052
1053 #
1054 # Parse a C enum block, parse till the balancing }
1055 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001056 def parseEnumBlock(self, token):
1057 self.enums = []
1058 name = None
1059 self.comment = None
1060 comment = ""
1061 value = "0"
1062 while token != None:
1063 if token[0] == "sep" and token[1] == "{":
1064 token = self.token()
1065 token = self.parseTypeBlock(token)
1066 elif token[0] == "sep" and token[1] == "}":
1067 if name != None:
1068 if self.comment != None:
1069 comment = self.comment
1070 self.comment = None
1071 self.enums.append((name, value, comment))
1072 token = self.token()
1073 return token
1074 elif token[0] == "name":
1075 if name != None:
1076 if self.comment != None:
1077 comment = string.strip(self.comment)
1078 self.comment = None
1079 self.enums.append((name, value, comment))
1080 name = token[1]
1081 comment = ""
1082 token = self.token()
1083 if token[0] == "op" and token[1][0] == "=":
1084 value = ""
1085 if len(token[1]) > 1:
1086 value = token[1][1:]
1087 token = self.token()
1088 while token[0] != "sep" or (token[1] != ',' and
1089 token[1] != '}'):
1090 value = value + token[1]
1091 token = self.token()
1092 else:
1093 try:
1094 value = "%d" % (int(value) + 1)
1095 except:
Daniel Veillard1e906612003-12-05 14:57:46 +00001096 self.warning("Failed to compute value of enum %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +00001097 value=""
1098 if token[0] == "sep" and token[1] == ",":
1099 token = self.token()
1100 else:
1101 token = self.token()
1102 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001103
1104 #
1105 # Parse a C definition block, used for structs it parse till
1106 # the balancing }
1107 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001108 def parseTypeBlock(self, token):
1109 while token != None:
1110 if token[0] == "sep" and token[1] == "{":
1111 token = self.token()
1112 token = self.parseTypeBlock(token)
1113 elif token[0] == "sep" and token[1] == "}":
1114 token = self.token()
1115 return token
1116 else:
1117 token = self.token()
1118 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001119
1120 #
1121 # Parse a type: the fact that the type name can either occur after
1122 # the definition or within the definition makes it a little harder
1123 # if inside, the name token is pushed back before returning
1124 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001125 def parseType(self, token):
1126 self.type = ""
1127 self.struct_fields = []
1128 self.signature = None
1129 if token == None:
1130 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001131
Daniel Veillardbe586972003-11-18 20:56:51 +00001132 while token[0] == "name" and (
1133 token[1] == "const" or token[1] == "unsigned"):
1134 if self.type == "":
1135 self.type = token[1]
1136 else:
1137 self.type = self.type + " " + token[1]
1138 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001139
Daniel Veillardbe586972003-11-18 20:56:51 +00001140 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1141 if self.type == "":
1142 self.type = token[1]
1143 else:
1144 self.type = self.type + " " + token[1]
1145 if token[0] == "name" and token[1] == "int":
1146 if self.type == "":
1147 self.type = tmp[1]
1148 else:
1149 self.type = self.type + " " + tmp[1]
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001150
Daniel Veillardbe586972003-11-18 20:56:51 +00001151 elif token[0] == "name" and token[1] == "struct":
1152 if self.type == "":
1153 self.type = token[1]
1154 else:
1155 self.type = self.type + " " + token[1]
1156 token = self.token()
1157 nametok = None
1158 if token[0] == "name":
1159 nametok = token
1160 token = self.token()
1161 if token != None and token[0] == "sep" and token[1] == "{":
1162 token = self.token()
1163 token = self.parseStruct(token)
1164 elif token != None and token[0] == "op" and token[1] == "*":
1165 self.type = self.type + " " + nametok[1] + " *"
1166 token = self.token()
1167 while token != None and token[0] == "op" and token[1] == "*":
1168 self.type = self.type + " *"
1169 token = self.token()
1170 if token[0] == "name":
1171 nametok = token
1172 token = self.token()
1173 else:
1174 self.error("struct : expecting name", token)
1175 return token
1176 elif token != None and token[0] == "name" and nametok != None:
1177 self.type = self.type + " " + nametok[1]
1178 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001179
Daniel Veillardbe586972003-11-18 20:56:51 +00001180 if nametok != None:
1181 self.lexer.push(token)
1182 token = nametok
1183 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001184
Daniel Veillardbe586972003-11-18 20:56:51 +00001185 elif token[0] == "name" and token[1] == "enum":
1186 if self.type == "":
1187 self.type = token[1]
1188 else:
1189 self.type = self.type + " " + token[1]
1190 self.enums = []
1191 token = self.token()
1192 if token != None and token[0] == "sep" and token[1] == "{":
1193 token = self.token()
1194 token = self.parseEnumBlock(token)
1195 else:
1196 self.error("parsing enum: expecting '{'", token)
1197 enum_type = None
1198 if token != None and token[0] != "name":
1199 self.lexer.push(token)
1200 token = ("name", "enum")
1201 else:
1202 enum_type = token[1]
1203 for enum in self.enums:
1204 self.index_add(enum[0], self.filename,
1205 not self.is_header, "enum",
1206 (enum[1], enum[2], enum_type))
1207 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001208
Daniel Veillardbe586972003-11-18 20:56:51 +00001209 elif token[0] == "name":
1210 if self.type == "":
1211 self.type = token[1]
1212 else:
1213 self.type = self.type + " " + token[1]
1214 else:
1215 self.error("parsing type %s: expecting a name" % (self.type),
1216 token)
1217 return token
1218 token = self.token()
1219 while token != None and (token[0] == "op" or
1220 token[0] == "name" and token[1] == "const"):
1221 self.type = self.type + " " + token[1]
1222 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001223
1224 #
1225 # if there is a parenthesis here, this means a function type
1226 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001227 if token != None and token[0] == "sep" and token[1] == '(':
1228 self.type = self.type + token[1]
1229 token = self.token()
1230 while token != None and token[0] == "op" and token[1] == '*':
1231 self.type = self.type + token[1]
1232 token = self.token()
1233 if token == None or token[0] != "name" :
1234 self.error("parsing function type, name expected", token);
1235 return token
1236 self.type = self.type + token[1]
1237 nametok = token
1238 token = self.token()
1239 if token != None and token[0] == "sep" and token[1] == ')':
1240 self.type = self.type + token[1]
1241 token = self.token()
1242 if token != None and token[0] == "sep" and token[1] == '(':
1243 token = self.token()
1244 type = self.type;
1245 token = self.parseSignature(token);
1246 self.type = type;
1247 else:
1248 self.error("parsing function type, '(' expected", token);
1249 return token
1250 else:
1251 self.error("parsing function type, ')' expected", token);
1252 return token
1253 self.lexer.push(token)
1254 token = nametok
1255 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001256
1257 #
1258 # do some lookahead for arrays
1259 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001260 if token != None and token[0] == "name":
1261 nametok = token
1262 token = self.token()
1263 if token != None and token[0] == "sep" and token[1] == '[':
1264 self.type = self.type + nametok[1]
1265 while token != None and token[0] == "sep" and token[1] == '[':
1266 self.type = self.type + token[1]
1267 token = self.token()
1268 while token != None and token[0] != 'sep' and \
1269 token[1] != ']' and token[1] != ';':
1270 self.type = self.type + token[1]
1271 token = self.token()
1272 if token != None and token[0] == 'sep' and token[1] == ']':
1273 self.type = self.type + token[1]
1274 token = self.token()
1275 else:
1276 self.error("parsing array type, ']' expected", token);
1277 return token
1278 elif token != None and token[0] == "sep" and token[1] == ':':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001279 # remove :12 in case it's a limited int size
Daniel Veillardbe586972003-11-18 20:56:51 +00001280 token = self.token()
1281 token = self.token()
1282 self.lexer.push(token)
1283 token = nametok
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001284
Daniel Veillardbe586972003-11-18 20:56:51 +00001285 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001286
1287 #
1288 # Parse a signature: '(' has been parsed and we scan the type definition
1289 # up to the ')' included
Daniel Veillardbe586972003-11-18 20:56:51 +00001290 def parseSignature(self, token):
1291 signature = []
1292 if token != None and token[0] == "sep" and token[1] == ')':
1293 self.signature = []
1294 token = self.token()
1295 return token
1296 while token != None:
1297 token = self.parseType(token)
1298 if token != None and token[0] == "name":
1299 signature.append((self.type, token[1], None))
1300 token = self.token()
1301 elif token != None and token[0] == "sep" and token[1] == ',':
1302 token = self.token()
1303 continue
1304 elif token != None and token[0] == "sep" and token[1] == ')':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001305 # only the type was provided
Daniel Veillardbe586972003-11-18 20:56:51 +00001306 if self.type == "...":
1307 signature.append((self.type, "...", None))
1308 else:
1309 signature.append((self.type, None, None))
1310 if token != None and token[0] == "sep":
1311 if token[1] == ',':
1312 token = self.token()
1313 continue
1314 elif token[1] == ')':
1315 token = self.token()
1316 break
1317 self.signature = signature
1318 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001319
1320 #
1321 # Parse a global definition, be it a type, variable or function
1322 # the extern "C" blocks are a bit nasty and require it to recurse.
1323 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001324 def parseGlobal(self, token):
1325 static = 0
1326 if token[1] == 'extern':
1327 token = self.token()
1328 if token == None:
1329 return token
1330 if token[0] == 'string':
1331 if token[1] == 'C':
1332 token = self.token()
1333 if token == None:
1334 return token
1335 if token[0] == 'sep' and token[1] == "{":
1336 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001337# print 'Entering extern "C line ', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001338 while token != None and (token[0] != 'sep' or
1339 token[1] != "}"):
1340 if token[0] == 'name':
1341 token = self.parseGlobal(token)
1342 else:
1343 self.error(
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001344 "token %s %s unexpected at the top level" % (
1345 token[0], token[1]))
Daniel Veillardbe586972003-11-18 20:56:51 +00001346 token = self.parseGlobal(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001347# print 'Exiting extern "C" line', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001348 token = self.token()
1349 return token
1350 else:
1351 return token
1352 elif token[1] == 'static':
1353 static = 1
1354 token = self.token()
1355 if token == None or token[0] != 'name':
1356 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001357
Daniel Veillardbe586972003-11-18 20:56:51 +00001358 if token[1] == 'typedef':
1359 token = self.token()
1360 return self.parseTypedef(token)
1361 else:
1362 token = self.parseType(token)
1363 type_orig = self.type
1364 if token == None or token[0] != "name":
1365 return token
1366 type = type_orig
1367 self.name = token[1]
1368 token = self.token()
1369 while token != None and (token[0] == "sep" or token[0] == "op"):
1370 if token[0] == "sep":
1371 if token[1] == "[":
1372 type = type + token[1]
1373 token = self.token()
1374 while token != None and (token[0] != "sep" or \
1375 token[1] != ";"):
1376 type = type + token[1]
1377 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001378
Daniel Veillardbe586972003-11-18 20:56:51 +00001379 if token != None and token[0] == "op" and token[1] == "=":
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001380 #
1381 # Skip the initialization of the variable
1382 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001383 token = self.token()
1384 if token[0] == 'sep' and token[1] == '{':
1385 token = self.token()
1386 token = self.parseBlock(token)
1387 else:
1388 self.comment = None
1389 while token != None and (token[0] != "sep" or \
1390 (token[1] != ';' and token[1] != ',')):
1391 token = self.token()
1392 self.comment = None
1393 if token == None or token[0] != "sep" or (token[1] != ';' and
1394 token[1] != ','):
1395 self.error("missing ';' or ',' after value")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001396
Daniel Veillardbe586972003-11-18 20:56:51 +00001397 if token != None and token[0] == "sep":
1398 if token[1] == ";":
1399 self.comment = None
1400 token = self.token()
1401 if type == "struct":
1402 self.index_add(self.name, self.filename,
1403 not self.is_header, "struct", self.struct_fields)
1404 else:
1405 self.index_add(self.name, self.filename,
1406 not self.is_header, "variable", type)
1407 break
1408 elif token[1] == "(":
1409 token = self.token()
1410 token = self.parseSignature(token)
1411 if token == None:
1412 return None
1413 if token[0] == "sep" and token[1] == ";":
1414 d = self.mergeFunctionComment(self.name,
1415 ((type, None), self.signature), 1)
1416 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001417 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001418 token = self.token()
1419 elif token[0] == "sep" and token[1] == "{":
1420 d = self.mergeFunctionComment(self.name,
1421 ((type, None), self.signature), static)
1422 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001423 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001424 token = self.token()
1425 token = self.parseBlock(token);
1426 elif token[1] == ',':
1427 self.comment = None
1428 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001429 "variable", type)
Daniel Veillardbe586972003-11-18 20:56:51 +00001430 type = type_orig
1431 token = self.token()
1432 while token != None and token[0] == "sep":
1433 type = type + token[1]
1434 token = self.token()
1435 if token != None and token[0] == "name":
1436 self.name = token[1]
1437 token = self.token()
1438 else:
1439 break
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001440
Daniel Veillardbe586972003-11-18 20:56:51 +00001441 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001442
Daniel Veillardbe586972003-11-18 20:56:51 +00001443 def parse(self):
Daniel Veillard1e906612003-12-05 14:57:46 +00001444 self.warning("Parsing %s" % (self.filename))
Daniel Veillardbe586972003-11-18 20:56:51 +00001445 token = self.token()
1446 while token != None:
1447 if token[0] == 'name':
1448 token = self.parseGlobal(token)
1449 else:
1450 self.error("token %s %s unexpected at the top level" % (
1451 token[0], token[1]))
1452 token = self.parseGlobal(token)
1453 return
1454 self.parseTopComment(self.top_comment)
1455 return self.index
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001456
1457
1458class docBuilder:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001459 """A documentation builder"""
1460 def __init__(self, name, directories=['.'], excludes=[]):
1461 self.name = name
1462 self.directories = directories
1463 self.excludes = excludes + ignored_files.keys()
1464 self.modules = {}
1465 self.headers = {}
1466 self.idx = index()
1467 self.xref = {}
1468 self.index = {}
1469 if name == 'libxml2':
1470 self.basename = 'libxml'
1471 else:
1472 self.basename = name
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001473
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001474 def indexString(self, id, str):
1475 if str == None:
1476 return
1477 str = string.replace(str, "'", ' ')
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 tokens = string.split(str)
1493 for token in tokens:
1494 try:
1495 c = token[0]
1496 if string.find(string.letters, c) < 0:
1497 pass
1498 elif len(token) < 3:
1499 pass
1500 else:
1501 lower = string.lower(token)
1502 # TODO: generalize this a bit
1503 if lower == 'and' or lower == 'the':
1504 pass
1505 elif self.xref.has_key(token):
1506 self.xref[token].append(id)
1507 else:
1508 self.xref[token] = [id]
1509 except:
1510 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001511
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001512 def analyze(self):
1513 print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
1514 self.idx.analyze()
1515
1516 def scanHeaders(self):
1517 for header in self.headers.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001518 parser = CParser(header)
1519 idx = parser.parse()
1520 self.headers[header] = idx;
1521 self.idx.merge(idx)
1522
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001523 def scanModules(self):
1524 for module in self.modules.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001525 parser = CParser(module)
1526 idx = parser.parse()
1527 # idx.analyze()
1528 self.modules[module] = idx
1529 self.idx.merge_public(idx)
1530
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001531 def scan(self):
1532 for directory in self.directories:
1533 files = glob.glob(directory + "/*.c")
1534 for file in files:
1535 skip = 0
1536 for excl in self.excludes:
1537 if string.find(file, excl) != -1:
1538 skip = 1;
1539 break
1540 if skip == 0:
1541 self.modules[file] = None;
1542 files = glob.glob(directory + "/*.h")
1543 for file in files:
1544 skip = 0
1545 for excl in self.excludes:
1546 if string.find(file, excl) != -1:
1547 skip = 1;
1548 break
1549 if skip == 0:
1550 self.headers[file] = None;
1551 self.scanHeaders()
1552 self.scanModules()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001553
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001554 def modulename_file(self, file):
1555 module = os.path.basename(file)
1556 if module[-2:] == '.h':
1557 module = module[:-2]
1558 return module
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001559
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001560 def serialize_enum(self, output, name):
1561 id = self.idx.enums[name]
1562 output.write(" <enum name='%s' file='%s'" % (name,
1563 self.modulename_file(id.module)))
1564 if id.info != None:
1565 info = id.info
1566 if info[0] != None and info[0] != '':
1567 try:
1568 val = eval(info[0])
1569 except:
1570 val = info[0]
1571 output.write(" value='%s'" % (val));
1572 if info[2] != None and info[2] != '':
1573 output.write(" type='%s'" % info[2]);
1574 if info[1] != None and info[1] != '':
1575 output.write(" info='%s'" % escape(info[1]));
1576 output.write("/>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001577
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001578 def serialize_macro(self, output, name):
1579 id = self.idx.macros[name]
1580 output.write(" <macro name='%s' file='%s'>\n" % (name,
1581 self.modulename_file(id.module)))
1582 if id.info != None:
1583 try:
1584 (args, desc) = id.info
1585 if desc != None and desc != "":
1586 output.write(" <info>%s</info>\n" % (escape(desc)))
1587 self.indexString(name, desc)
1588 for arg in args:
1589 (name, desc) = arg
1590 if desc != None and desc != "":
1591 output.write(" <arg name='%s' info='%s'/>\n" % (
1592 name, escape(desc)))
1593 self.indexString(name, desc)
1594 else:
1595 output.write(" <arg name='%s'/>\n" % (name))
1596 except:
1597 pass
1598 output.write(" </macro>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001599
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001600 def serialize_typedef(self, output, name):
1601 id = self.idx.typedefs[name]
1602 if id.info[0:7] == 'struct ':
1603 output.write(" <struct name='%s' file='%s' type='%s'" % (
1604 name, self.modulename_file(id.module), id.info))
1605 name = id.info[7:]
1606 if self.idx.structs.has_key(name) and ( \
1607 type(self.idx.structs[name].info) == type(()) or
Daniel Veillardc1eed322002-12-12 11:01:32 +00001608 type(self.idx.structs[name].info) == type([])):
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001609 output.write(">\n");
1610 try:
1611 for field in self.idx.structs[name].info:
1612 desc = field[2]
1613 self.indexString(name, desc)
1614 if desc == None:
1615 desc = ''
1616 else:
1617 desc = escape(desc)
1618 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1619 except:
1620 print "Failed to serialize struct %s" % (name)
1621 output.write(" </struct>\n")
1622 else:
1623 output.write("/>\n");
1624 else :
1625 output.write(" <typedef name='%s' file='%s' type='%s'/>\n" % (
1626 name, self.modulename_file(id.module), id.info))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001627
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001628 def serialize_variable(self, output, name):
1629 id = self.idx.variables[name]
1630 if id.info != None:
1631 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1632 name, self.modulename_file(id.module), id.info))
1633 else:
1634 output.write(" <variable name='%s' file='%s'/>\n" % (
1635 name, self.modulename_file(id.module)))
Daniel Veillardc1eed322002-12-12 11:01:32 +00001636
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001637 def serialize_function(self, output, name):
1638 id = self.idx.functions[name]
Daniel Veillarda2351322004-06-27 12:08:10 +00001639 if name == debugsym:
1640 print "=>", id
1641
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001642 output.write(" <%s name='%s' file='%s'>\n" % (id.type, name,
1643 self.modulename_file(id.module)))
Daniel Veillarda2351322004-06-27 12:08:10 +00001644 if id.conditionals != None:
1645 for cond in id.conditionals:
1646 output.write(" <cond>%s</cond>\n"% (cond));
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001647 try:
1648 (ret, params, desc) = id.info
1649 output.write(" <info>%s</info>\n" % (escape(desc)))
1650 self.indexString(name, desc)
1651 if ret[0] != None:
1652 if ret[0] == "void":
1653 output.write(" <return type='void'/>\n")
1654 else:
1655 output.write(" <return type='%s' info='%s'/>\n" % (
1656 ret[0], escape(ret[1])))
1657 self.indexString(name, ret[1])
1658 for param in params:
1659 if param[0] == 'void':
1660 continue
1661 if param[2] == None:
1662 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1663 else:
1664 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1665 self.indexString(name, param[2])
1666 except:
1667 print "Failed to save function %s info: " % name, `id.info`
1668 output.write(" </%s>\n" % (id.type))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001669
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001670 def serialize_exports(self, output, file):
1671 module = self.modulename_file(file)
1672 output.write(" <file name='%s'>\n" % (module))
1673 dict = self.headers[file]
Daniel Veillardbe586972003-11-18 20:56:51 +00001674 if dict.info != None:
1675 for data in ('Summary', 'Description', 'Author'):
1676 try:
1677 output.write(" <%s>%s</%s>\n" % (
1678 string.lower(data),
1679 escape(dict.info[data]),
1680 string.lower(data)))
1681 except:
1682 print "Header %s lacks a %s description" % (module, data)
1683 if dict.info.has_key('Description'):
1684 desc = dict.info['Description']
1685 if string.find(desc, "DEPRECATED") != -1:
1686 output.write(" <deprecated/>\n")
1687
Daniel Veillard1a792412003-11-18 23:52:38 +00001688 ids = dict.macros.keys()
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001689 ids.sort()
1690 for id in uniq(ids):
Daniel Veillard1a792412003-11-18 23:52:38 +00001691 # Macros are sometime used to masquerade other types.
1692 if dict.functions.has_key(id):
1693 continue
1694 if dict.variables.has_key(id):
1695 continue
1696 if dict.typedefs.has_key(id):
1697 continue
1698 if dict.structs.has_key(id):
1699 continue
1700 if dict.enums.has_key(id):
1701 continue
1702 output.write(" <exports symbol='%s' type='macro'/>\n" % (id))
1703 ids = dict.enums.keys()
1704 ids.sort()
1705 for id in uniq(ids):
1706 output.write(" <exports symbol='%s' type='enum'/>\n" % (id))
1707 ids = dict.typedefs.keys()
1708 ids.sort()
1709 for id in uniq(ids):
1710 output.write(" <exports symbol='%s' type='typedef'/>\n" % (id))
1711 ids = dict.structs.keys()
1712 ids.sort()
1713 for id in uniq(ids):
1714 output.write(" <exports symbol='%s' type='struct'/>\n" % (id))
1715 ids = dict.variables.keys()
1716 ids.sort()
1717 for id in uniq(ids):
1718 output.write(" <exports symbol='%s' type='variable'/>\n" % (id))
1719 ids = dict.functions.keys()
1720 ids.sort()
1721 for id in uniq(ids):
1722 output.write(" <exports symbol='%s' type='function'/>\n" % (id))
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001723 output.write(" </file>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001724
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001725 def serialize_xrefs_files(self, output):
1726 headers = self.headers.keys()
1727 headers.sort()
1728 for file in headers:
1729 module = self.modulename_file(file)
1730 output.write(" <file name='%s'>\n" % (module))
1731 dict = self.headers[file]
William M. Bracka2e844a2004-01-06 11:52:13 +00001732 ids = uniq(dict.functions.keys() + dict.variables.keys() + \
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001733 dict.macros.keys() + dict.typedefs.keys() + \
William M. Bracka2e844a2004-01-06 11:52:13 +00001734 dict.structs.keys() + dict.enums.keys())
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001735 ids.sort()
William M. Bracka2e844a2004-01-06 11:52:13 +00001736 for id in ids:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001737 output.write(" <ref name='%s'/>\n" % (id))
1738 output.write(" </file>\n")
1739 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001740
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001741 def serialize_xrefs_functions(self, output):
1742 funcs = {}
1743 for name in self.idx.functions.keys():
1744 id = self.idx.functions[name]
1745 try:
1746 (ret, params, desc) = id.info
1747 for param in params:
1748 if param[0] == 'void':
1749 continue
1750 if funcs.has_key(param[0]):
1751 funcs[param[0]].append(name)
1752 else:
1753 funcs[param[0]] = [name]
1754 except:
1755 pass
1756 typ = funcs.keys()
1757 typ.sort()
1758 for type in typ:
1759 if type == '' or type == 'void' or type == "int" or \
1760 type == "char *" or type == "const char *" :
1761 continue
1762 output.write(" <type name='%s'>\n" % (type))
1763 ids = funcs[type]
1764 ids.sort()
William M. Brackcf9eadf2003-12-25 13:24:05 +00001765 pid = '' # not sure why we have dups, but get rid of them!
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001766 for id in ids:
William M. Brackcf9eadf2003-12-25 13:24:05 +00001767 if id != pid:
1768 output.write(" <ref name='%s'/>\n" % (id))
1769 pid = id
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001770 output.write(" </type>\n")
1771
1772 def serialize_xrefs_constructors(self, output):
1773 funcs = {}
1774 for name in self.idx.functions.keys():
1775 id = self.idx.functions[name]
1776 try:
1777 (ret, params, desc) = id.info
1778 if ret[0] == "void":
1779 continue
1780 if funcs.has_key(ret[0]):
1781 funcs[ret[0]].append(name)
1782 else:
1783 funcs[ret[0]] = [name]
1784 except:
1785 pass
1786 typ = funcs.keys()
1787 typ.sort()
1788 for type in typ:
1789 if type == '' or type == 'void' or type == "int" or \
1790 type == "char *" or type == "const char *" :
1791 continue
1792 output.write(" <type name='%s'>\n" % (type))
1793 ids = funcs[type]
William M. Brack09a4d0a2004-01-05 14:28:43 +00001794 ids.sort()
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001795 for id in ids:
1796 output.write(" <ref name='%s'/>\n" % (id))
1797 output.write(" </type>\n")
1798
1799 def serialize_xrefs_alpha(self, output):
1800 letter = None
1801 ids = self.idx.identifiers.keys()
1802 ids.sort()
1803 for id in ids:
1804 if id[0] != letter:
1805 if letter != None:
1806 output.write(" </letter>\n")
1807 letter = id[0]
1808 output.write(" <letter name='%s'>\n" % (letter))
1809 output.write(" <ref name='%s'/>\n" % (id))
1810 if letter != None:
1811 output.write(" </letter>\n")
1812
1813 def serialize_xrefs_references(self, output):
1814 typ = self.idx.identifiers.keys()
1815 typ.sort()
1816 for id in typ:
1817 idf = self.idx.identifiers[id]
1818 module = idf.module
1819 output.write(" <reference name='%s' href='%s'/>\n" % (id,
1820 'html/' + self.basename + '-' +
1821 self.modulename_file(module) + '.html#' +
1822 id))
1823
1824 def serialize_xrefs_index(self, output):
1825 index = self.xref
1826 typ = index.keys()
1827 typ.sort()
1828 letter = None
1829 count = 0
1830 chunk = 0
1831 chunks = []
1832 for id in typ:
1833 if len(index[id]) > 30:
1834 continue
1835 if id[0] != letter:
1836 if letter == None or count > 200:
1837 if letter != None:
1838 output.write(" </letter>\n")
1839 output.write(" </chunk>\n")
1840 count = 0
1841 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
1842 output.write(" <chunk name='chunk%s'>\n" % (chunk))
1843 first_letter = id[0]
1844 chunk = chunk + 1
1845 elif letter != None:
1846 output.write(" </letter>\n")
1847 letter = id[0]
1848 output.write(" <letter name='%s'>\n" % (letter))
1849 output.write(" <word name='%s'>\n" % (id))
1850 tokens = index[id];
1851 tokens.sort()
1852 tok = None
William M. Bracka2e844a2004-01-06 11:52:13 +00001853 for token in tokens:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001854 if tok == token:
1855 continue
1856 tok = token
1857 output.write(" <ref name='%s'/>\n" % (token))
1858 count = count + 1
1859 output.write(" </word>\n")
1860 if letter != None:
1861 output.write(" </letter>\n")
1862 output.write(" </chunk>\n")
William M. Brack966668a2003-12-20 02:10:28 +00001863 if count != 0:
1864 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001865 output.write(" <chunks>\n")
1866 for ch in chunks:
1867 output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
1868 ch[0], ch[1], ch[2]))
1869 output.write(" </chunks>\n")
1870
1871 def serialize_xrefs(self, output):
1872 output.write(" <references>\n")
1873 self.serialize_xrefs_references(output)
1874 output.write(" </references>\n")
1875 output.write(" <alpha>\n")
1876 self.serialize_xrefs_alpha(output)
1877 output.write(" </alpha>\n")
1878 output.write(" <constructors>\n")
1879 self.serialize_xrefs_constructors(output)
1880 output.write(" </constructors>\n")
1881 output.write(" <functions>\n")
1882 self.serialize_xrefs_functions(output)
1883 output.write(" </functions>\n")
1884 output.write(" <files>\n")
1885 self.serialize_xrefs_files(output)
1886 output.write(" </files>\n")
1887 output.write(" <index>\n")
1888 self.serialize_xrefs_index(output)
1889 output.write(" </index>\n")
1890
1891 def serialize(self):
1892 filename = "%s-api.xml" % self.name
1893 print "Saving XML description %s" % (filename)
1894 output = open(filename, "w")
1895 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1896 output.write("<api name='%s'>\n" % self.name)
1897 output.write(" <files>\n")
1898 headers = self.headers.keys()
1899 headers.sort()
1900 for file in headers:
1901 self.serialize_exports(output, file)
1902 output.write(" </files>\n")
1903 output.write(" <symbols>\n")
1904 macros = self.idx.macros.keys()
1905 macros.sort()
1906 for macro in macros:
1907 self.serialize_macro(output, macro)
1908 enums = self.idx.enums.keys()
1909 enums.sort()
1910 for enum in enums:
1911 self.serialize_enum(output, enum)
1912 typedefs = self.idx.typedefs.keys()
1913 typedefs.sort()
1914 for typedef in typedefs:
1915 self.serialize_typedef(output, typedef)
1916 variables = self.idx.variables.keys()
1917 variables.sort()
1918 for variable in variables:
1919 self.serialize_variable(output, variable)
1920 functions = self.idx.functions.keys()
1921 functions.sort()
1922 for function in functions:
1923 self.serialize_function(output, function)
1924 output.write(" </symbols>\n")
1925 output.write("</api>\n")
1926 output.close()
1927
1928 filename = "%s-refs.xml" % self.name
1929 print "Saving XML Cross References %s" % (filename)
1930 output = open(filename, "w")
1931 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1932 output.write("<apirefs name='%s'>\n" % self.name)
1933 self.serialize_xrefs(output)
1934 output.write("</apirefs>\n")
1935 output.close()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001936
1937
1938def rebuild():
1939 builder = None
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001940 if glob.glob("parser.c") != [] :
1941 print "Rebuilding API description for libxml2"
1942 builder = docBuilder("libxml2", [".", "."],
1943 ["xmlwin32version.h", "tst.c"])
1944 elif glob.glob("../parser.c") != [] :
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001945 print "Rebuilding API description for libxml2"
1946 builder = docBuilder("libxml2", ["..", "../include/libxml"],
Daniel Veillardd4330462003-04-29 12:40:16 +00001947 ["xmlwin32version.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001948 elif glob.glob("../libxslt/transform.c") != [] :
1949 print "Rebuilding API description for libxslt"
1950 builder = docBuilder("libxslt", ["../libxslt"],
Daniel Veillard024b5702002-12-12 00:15:55 +00001951 ["win32config.h", "libxslt.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001952 else:
1953 print "rebuild() failed, unable to guess the module"
1954 return None
1955 builder.scan()
1956 builder.analyze()
1957 builder.serialize()
Daniel Veillard024b5702002-12-12 00:15:55 +00001958 if glob.glob("../libexslt/exslt.c") != [] :
1959 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1960 extra.scan()
1961 extra.analyze()
1962 extra.serialize()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001963 return builder
1964
1965#
1966# for debugging the parser
1967#
1968def parse(filename):
1969 parser = CParser(filename)
1970 idx = parser.parse()
1971 return idx
1972
1973if __name__ == "__main__":
Daniel Veillarda2351322004-06-27 12:08:10 +00001974 if len(sys.argv) > 1:
1975 debug = 1
1976 parse(sys.argv[1])
1977 else:
1978 rebuild()