blob: 688403fe828c8fd4142d3e2c7cc75c0b334749a0 [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
15
Daniel Veillardde0a0a52003-04-24 17:12:57 +000016#
17# C parser analysis code
18#
19ignored_files = {
20 "trio": "too many non standard macros",
21 "trio.c": "too many non standard macros",
22 "trionan.c": "too many non standard macros",
23 "triostr.c": "too many non standard macros",
24 "acconfig.h": "generated portability layer",
25 "config.h": "generated portability layer",
26 "libxml.h": "internal only",
Daniel Veillard92fc02c2003-04-24 23:12:35 +000027 "testOOM.c": "out of memory tester",
28 "testOOMlib.h": "out of memory tester",
29 "testOOMlib.c": "out of memory tester",
Daniel Veillard189f46b2004-01-25 21:03:04 +000030 "rngparser.c": "not yet integrated",
31 "rngparser.h": "not yet integrated",
Daniel Veillardde0a0a52003-04-24 17:12:57 +000032}
33
34ignored_words = {
35 "WINAPI": (0, "Windows keyword"),
36 "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
William M. Brackcdfa2862003-08-29 06:03:38 +000037 "XMLPUBVAR": (0, "Special macro for extern vars for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000038 "XSLTPUBVAR": (0, "Special macro for extern vars for win32"),
39 "EXSLTPUBVAR": (0, "Special macro for extern vars for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000040 "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000041 "XSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
42 "EXSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000043 "XMLCALL": (0, "Special macro for win32 calls"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000044 "XSLTCALL": (0, "Special macro for win32 calls"),
45 "EXSLTCALL": (0, "Special macro for win32 calls"),
Daniel Veillardde0a0a52003-04-24 17:12:57 +000046 "__declspec": (3, "Windows keyword"),
47 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
48 "LIBEXSLT_PUBLIC": (0, "macro keyword"),
49 "X_IN_Y": (5, "macro function builder"),
50}
51
Daniel Veillarda9b66d02002-12-11 14:23:49 +000052def escape(raw):
53 raw = string.replace(raw, '&', '&')
54 raw = string.replace(raw, '<', '&lt;')
55 raw = string.replace(raw, '>', '&gt;')
56 raw = string.replace(raw, "'", '&apos;')
57 raw = string.replace(raw, '"', '&quot;')
58 return raw
59
Daniel Veillard2925c0a2003-11-17 13:58:17 +000060def uniq(items):
61 d = {}
62 for item in items:
63 d[item]=1
64 return d.keys()
65
Daniel Veillarda9b66d02002-12-11 14:23:49 +000066class identifier:
Daniel Veillardbe586972003-11-18 20:56:51 +000067 def __init__(self, name, module=None, type=None, lineno = 0,
68 info=None, extra=None):
69 self.name = name
70 self.module = module
71 self.type = type
72 self.info = info
73 self.extra = extra
74 self.lineno = lineno
75 self.static = 0
Daniel Veillarda9b66d02002-12-11 14:23:49 +000076
Daniel Veillardbe586972003-11-18 20:56:51 +000077 def __repr__(self):
78 r = "%s %s:" % (self.type, self.name)
79 if self.static:
80 r = r + " static"
81 if self.module != None:
82 r = r + " from %s" % (self.module)
83 if self.info != None:
84 r = r + " " + `self.info`
85 if self.extra != None:
86 r = r + " " + `self.extra`
87 return r
Daniel Veillarda9b66d02002-12-11 14:23:49 +000088
89
Daniel Veillardbe586972003-11-18 20:56:51 +000090 def set_module(self, module):
91 self.module = module
92 def set_type(self, type):
93 self.type = type
94 def set_info(self, info):
95 self.info = info
96 def set_extra(self, extra):
97 self.extra = extra
98 def set_lineno(self, lineno):
99 self.lineno = lineno
100 def set_static(self, static):
101 self.static = static
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000102
Daniel Veillardbe586972003-11-18 20:56:51 +0000103 def get_name(self):
104 return self.name
105 def get_module(self):
106 return self.module
107 def get_type(self):
108 return self.type
109 def get_info(self):
110 return self.info
111 def get_lineno(self):
112 return self.lineno
113 def get_extra(self):
114 return self.extra
115 def get_static(self):
116 return self.static
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000117
Daniel Veillardbe586972003-11-18 20:56:51 +0000118 def update(self, module, type = None, info = None, extra=None):
119 if module != None and self.module == None:
120 self.set_module(module)
121 if type != None and self.type == None:
122 self.set_type(type)
123 if info != None:
124 self.set_info(info)
125 if extra != None:
126 self.set_extra(extra)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000127
128
129class index:
Daniel Veillardbe586972003-11-18 20:56:51 +0000130 def __init__(self, name = "noname"):
131 self.name = name
132 self.identifiers = {}
133 self.functions = {}
134 self.variables = {}
135 self.includes = {}
136 self.structs = {}
137 self.enums = {}
138 self.typedefs = {}
139 self.macros = {}
140 self.references = {}
141 self.info = {}
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000142
Daniel Veillardbe586972003-11-18 20:56:51 +0000143 def add_ref(self, name, module, static, type, lineno, info=None, extra=None):
144 if name[0:2] == '__':
145 return None
146 d = None
147 try:
148 d = self.identifiers[name]
149 d.update(module, type, lineno, info, extra)
150 except:
151 d = identifier(name, module, type, lineno, info, extra)
152 self.identifiers[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000153
Daniel Veillardbe586972003-11-18 20:56:51 +0000154 if d != None and static == 1:
155 d.set_static(1)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000156
Daniel Veillardbe586972003-11-18 20:56:51 +0000157 if d != None and name != None and type != None:
158 self.references[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000159
Daniel Veillardbe586972003-11-18 20:56:51 +0000160 def add(self, name, module, static, type, lineno, info=None, extra=None):
161 if name[0:2] == '__':
162 return None
163 d = None
164 try:
165 d = self.identifiers[name]
166 d.update(module, type, lineno, info, extra)
167 except:
168 d = identifier(name, module, type, lineno, info, extra)
169 self.identifiers[name] = d
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000170
Daniel Veillardbe586972003-11-18 20:56:51 +0000171 if d != None and static == 1:
172 d.set_static(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000173
Daniel Veillardbe586972003-11-18 20:56:51 +0000174 if d != None and name != None and type != None:
175 if type == "function":
176 self.functions[name] = d
177 elif type == "functype":
178 self.functions[name] = d
179 elif type == "variable":
180 self.variables[name] = d
181 elif type == "include":
182 self.includes[name] = d
183 elif type == "struct":
184 self.structs[name] = d
185 elif type == "enum":
186 self.enums[name] = d
187 elif type == "typedef":
188 self.typedefs[name] = d
189 elif type == "macro":
190 self.macros[name] = d
191 else:
192 print "Unable to register type ", type
193 return d
194
195 def merge(self, idx):
196 for id in idx.functions.keys():
197 #
198 # macro might be used to override functions or variables
199 # definitions
200 #
201 if self.macros.has_key(id):
202 del self.macros[id]
203 if self.functions.has_key(id):
204 print "function %s from %s redeclared in %s" % (
205 id, self.functions[id].module, idx.functions[id].module)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000206 else:
Daniel Veillardbe586972003-11-18 20:56:51 +0000207 self.functions[id] = idx.functions[id]
208 self.identifiers[id] = idx.functions[id]
209 for id in idx.variables.keys():
210 #
211 # macro might be used to override functions or variables
212 # definitions
213 #
214 if self.macros.has_key(id):
215 del self.macros[id]
216 if self.variables.has_key(id):
217 print "variable %s from %s redeclared in %s" % (
218 id, self.variables[id].module, idx.variables[id].module)
219 else:
220 self.variables[id] = idx.variables[id]
221 self.identifiers[id] = idx.variables[id]
222 for id in idx.structs.keys():
223 if self.structs.has_key(id):
224 print "struct %s from %s redeclared in %s" % (
225 id, self.structs[id].module, idx.structs[id].module)
226 else:
227 self.structs[id] = idx.structs[id]
228 self.identifiers[id] = idx.structs[id]
229 for id in idx.typedefs.keys():
230 if self.typedefs.has_key(id):
231 print "typedef %s from %s redeclared in %s" % (
232 id, self.typedefs[id].module, idx.typedefs[id].module)
233 else:
234 self.typedefs[id] = idx.typedefs[id]
235 self.identifiers[id] = idx.typedefs[id]
236 for id in idx.macros.keys():
237 #
238 # macro might be used to override functions or variables
239 # definitions
240 #
241 if self.variables.has_key(id):
242 continue
243 if self.functions.has_key(id):
244 continue
245 if self.enums.has_key(id):
246 continue
247 if self.macros.has_key(id):
248 print "macro %s from %s redeclared in %s" % (
249 id, self.macros[id].module, idx.macros[id].module)
250 else:
251 self.macros[id] = idx.macros[id]
252 self.identifiers[id] = idx.macros[id]
253 for id in idx.enums.keys():
254 if self.enums.has_key(id):
255 print "enum %s from %s redeclared in %s" % (
256 id, self.enums[id].module, idx.enums[id].module)
257 else:
258 self.enums[id] = idx.enums[id]
259 self.identifiers[id] = idx.enums[id]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000260
Daniel Veillardbe586972003-11-18 20:56:51 +0000261 def merge_public(self, idx):
262 for id in idx.functions.keys():
263 if self.functions.has_key(id):
264 up = idx.functions[id]
265 self.functions[id].update(None, up.type, up.info, up.extra)
Daniel Veillardc1eed322002-12-12 11:01:32 +0000266 # else:
267 # print "Function %s from %s is not declared in headers" % (
268 # id, idx.functions[id].module)
269 # TODO: do the same for variables.
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000270
Daniel Veillardbe586972003-11-18 20:56:51 +0000271 def analyze_dict(self, type, dict):
272 count = 0
273 public = 0
274 for name in dict.keys():
275 id = dict[name]
276 count = count + 1
277 if id.static == 0:
278 public = public + 1
279 if count != public:
280 print " %d %s , %d public" % (count, type, public)
281 elif count != 0:
282 print " %d public %s" % (count, type)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000283
284
Daniel Veillardbe586972003-11-18 20:56:51 +0000285 def analyze(self):
286 self.analyze_dict("functions", self.functions)
287 self.analyze_dict("variables", self.variables)
288 self.analyze_dict("structs", self.structs)
289 self.analyze_dict("typedefs", self.typedefs)
290 self.analyze_dict("macros", self.macros)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000291
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000292class CLexer:
Daniel Veillardbe586972003-11-18 20:56:51 +0000293 """A lexer for the C language, tokenize the input by reading and
294 analyzing it line by line"""
295 def __init__(self, input):
296 self.input = input
297 self.tokens = []
298 self.line = ""
299 self.lineno = 0
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000300
Daniel Veillardbe586972003-11-18 20:56:51 +0000301 def getline(self):
302 line = ''
303 while line == '':
304 line = self.input.readline()
305 if not line:
306 return None
307 self.lineno = self.lineno + 1
308 line = string.lstrip(line)
309 line = string.rstrip(line)
310 if line == '':
311 continue
312 while line[-1] == '\\':
313 line = line[:-1]
314 n = self.input.readline()
315 self.lineno = self.lineno + 1
316 n = string.lstrip(n)
317 n = string.rstrip(n)
318 if not n:
319 break
320 else:
321 line = line + n
322 return line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000323
Daniel Veillardbe586972003-11-18 20:56:51 +0000324 def getlineno(self):
325 return self.lineno
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000326
Daniel Veillardbe586972003-11-18 20:56:51 +0000327 def push(self, token):
328 self.tokens.insert(0, token);
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000329
Daniel Veillardbe586972003-11-18 20:56:51 +0000330 def debug(self):
331 print "Last token: ", self.last
332 print "Token queue: ", self.tokens
333 print "Line %d end: " % (self.lineno), self.line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000334
Daniel Veillardbe586972003-11-18 20:56:51 +0000335 def token(self):
336 while self.tokens == []:
337 if self.line == "":
338 line = self.getline()
339 else:
340 line = self.line
341 self.line = ""
342 if line == None:
343 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000344
Daniel Veillardbe586972003-11-18 20:56:51 +0000345 if line[0] == '#':
346 self.tokens = map((lambda x: ('preproc', x)),
347 string.split(line))
348 break;
349 l = len(line)
350 if line[0] == '"' or line[0] == "'":
351 end = line[0]
352 line = line[1:]
353 found = 0
354 tok = ""
355 while found == 0:
356 i = 0
357 l = len(line)
358 while i < l:
359 if line[i] == end:
360 self.line = line[i+1:]
361 line = line[:i]
362 l = i
363 found = 1
364 break
365 if line[i] == '\\':
366 i = i + 1
367 i = i + 1
368 tok = tok + line
369 if found == 0:
370 line = self.getline()
371 if line == None:
372 return None
373 self.last = ('string', tok)
374 return self.last
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000375
Daniel Veillardbe586972003-11-18 20:56:51 +0000376 if l >= 2 and line[0] == '/' and line[1] == '*':
377 line = line[2:]
378 found = 0
379 tok = ""
380 while found == 0:
381 i = 0
382 l = len(line)
383 while i < l:
384 if line[i] == '*' and i+1 < l and line[i+1] == '/':
385 self.line = line[i+2:]
386 line = line[:i-1]
387 l = i
388 found = 1
389 break
390 i = i + 1
391 if tok != "":
392 tok = tok + "\n"
393 tok = tok + line
394 if found == 0:
395 line = self.getline()
396 if line == None:
397 return None
398 self.last = ('comment', tok)
399 return self.last
400 if l >= 2 and line[0] == '/' and line[1] == '/':
401 line = line[2:]
402 self.last = ('comment', line)
403 return self.last
404 i = 0
405 while i < l:
406 if line[i] == '/' and i+1 < l and line[i+1] == '/':
407 self.line = line[i:]
408 line = line[:i]
409 break
410 if line[i] == '/' and i+1 < l and line[i+1] == '*':
411 self.line = line[i:]
412 line = line[:i]
413 break
414 if line[i] == '"' or line[i] == "'":
415 self.line = line[i:]
416 line = line[:i]
417 break
418 i = i + 1
419 l = len(line)
420 i = 0
421 while i < l:
422 if line[i] == ' ' or line[i] == '\t':
423 i = i + 1
424 continue
425 o = ord(line[i])
426 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
427 (o >= 48 and o <= 57):
428 s = i
429 while i < l:
430 o = ord(line[i])
431 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
432 (o >= 48 and o <= 57) or string.find(
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000433 " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1:
Daniel Veillardbe586972003-11-18 20:56:51 +0000434 i = i + 1
435 else:
436 break
437 self.tokens.append(('name', line[s:i]))
438 continue
439 if string.find("(){}:;,[]", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000440# if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
441# line[i] == '}' or line[i] == ':' or line[i] == ';' or \
442# line[i] == ',' or line[i] == '[' or line[i] == ']':
Daniel Veillardbe586972003-11-18 20:56:51 +0000443 self.tokens.append(('sep', line[i]))
444 i = i + 1
445 continue
446 if string.find("+-*><=/%&!|.", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000447# if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
448# line[i] == '>' or line[i] == '<' or line[i] == '=' or \
449# line[i] == '/' or line[i] == '%' or line[i] == '&' or \
450# line[i] == '!' or line[i] == '|' or line[i] == '.':
Daniel Veillardbe586972003-11-18 20:56:51 +0000451 if line[i] == '.' and i + 2 < l and \
452 line[i+1] == '.' and line[i+2] == '.':
453 self.tokens.append(('name', '...'))
454 i = i + 3
455 continue
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000456
Daniel Veillardbe586972003-11-18 20:56:51 +0000457 j = i + 1
458 if j < l and (
459 string.find("+-*><=/%&!|", line[j]) != -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000460# line[j] == '+' or line[j] == '-' or line[j] == '*' or \
461# line[j] == '>' or line[j] == '<' or line[j] == '=' or \
462# line[j] == '/' or line[j] == '%' or line[j] == '&' or \
463# line[j] == '!' or line[j] == '|'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000464 self.tokens.append(('op', line[i:j+1]))
465 i = j + 1
466 else:
467 self.tokens.append(('op', line[i]))
468 i = i + 1
469 continue
470 s = i
471 while i < l:
472 o = ord(line[i])
473 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
474 (o >= 48 and o <= 57) or (
475 string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000476# line[i] != ' ' and line[i] != '\t' and
477# line[i] != '(' and line[i] != ')' and
478# line[i] != '{' and line[i] != '}' and
479# line[i] != ':' and line[i] != ';' and
480# line[i] != ',' and line[i] != '+' and
481# line[i] != '-' and line[i] != '*' and
482# line[i] != '/' and line[i] != '%' and
483# line[i] != '&' and line[i] != '!' and
484# line[i] != '|' and line[i] != '[' and
485# line[i] != ']' and line[i] != '=' and
486# line[i] != '*' and line[i] != '>' and
487# line[i] != '<'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000488 i = i + 1
489 else:
490 break
491 self.tokens.append(('name', line[s:i]))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000492
Daniel Veillardbe586972003-11-18 20:56:51 +0000493 tok = self.tokens[0]
494 self.tokens = self.tokens[1:]
495 self.last = tok
496 return tok
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000497
498class CParser:
Daniel Veillardbe586972003-11-18 20:56:51 +0000499 """The C module parser"""
500 def __init__(self, filename, idx = None):
501 self.filename = filename
502 if len(filename) > 2 and filename[-2:] == '.h':
503 self.is_header = 1
504 else:
505 self.is_header = 0
506 self.input = open(filename)
507 self.lexer = CLexer(self.input)
508 if idx == None:
509 self.index = index()
510 else:
511 self.index = idx
512 self.top_comment = ""
513 self.last_comment = ""
514 self.comment = None
515 self.collect_ref = 0
Daniel Veillard1e906612003-12-05 14:57:46 +0000516 self.no_error = 0
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000517
Daniel Veillardbe586972003-11-18 20:56:51 +0000518 def collect_references(self):
519 self.collect_ref = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000520
Daniel Veillard1e906612003-12-05 14:57:46 +0000521 def stop_error(self):
522 self.no_error = 1
523
524 def start_error(self):
525 self.no_error = 0
526
Daniel Veillardbe586972003-11-18 20:56:51 +0000527 def lineno(self):
528 return self.lexer.getlineno()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000529
Daniel Veillardbe586972003-11-18 20:56:51 +0000530 def index_add(self, name, module, static, type, info=None, extra = None):
531 self.index.add(name, module, static, type, self.lineno(),
532 info, extra)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000533
Daniel Veillardbe586972003-11-18 20:56:51 +0000534 def index_add_ref(self, name, module, static, type, info=None,
535 extra = None):
536 self.index.add_ref(name, module, static, type, self.lineno(),
537 info, extra)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000538
Daniel Veillard1e906612003-12-05 14:57:46 +0000539 def warning(self, msg):
540 if self.no_error:
541 return
542 print msg
543
Daniel Veillardbe586972003-11-18 20:56:51 +0000544 def error(self, msg, token=-1):
Daniel Veillard1e906612003-12-05 14:57:46 +0000545 if self.no_error:
546 return
547
Daniel Veillardbe586972003-11-18 20:56:51 +0000548 print "Parse Error: " + msg
549 if token != -1:
550 print "Got token ", token
551 self.lexer.debug()
552 sys.exit(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000553
Daniel Veillardbe586972003-11-18 20:56:51 +0000554 def debug(self, msg, token=-1):
555 print "Debug: " + msg
556 if token != -1:
557 print "Got token ", token
558 self.lexer.debug()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000559
Daniel Veillardbe586972003-11-18 20:56:51 +0000560 def parseTopComment(self, comment):
561 res = {}
562 lines = string.split(comment, "\n")
563 item = None
564 for line in lines:
565 while line != "" and (line[0] == ' ' or line[0] == '\t'):
566 line = line[1:]
567 while line != "" and line[0] == '*':
568 line = line[1:]
569 while line != "" and (line[0] == ' ' or line[0] == '\t'):
570 line = line[1:]
571 try:
572 (it, line) = string.split(line, ":", 1)
573 item = it
574 while line != "" and (line[0] == ' ' or line[0] == '\t'):
575 line = line[1:]
576 if res.has_key(item):
577 res[item] = res[item] + " " + line
578 else:
579 res[item] = line
580 except:
581 if item != None:
582 if res.has_key(item):
583 res[item] = res[item] + " " + line
584 else:
585 res[item] = line
586 self.index.info = res
587
588 def parseComment(self, token):
589 if self.top_comment == "":
590 self.top_comment = token[1]
591 if self.comment == None or token[1][0] == '*':
592 self.comment = token[1];
593 else:
594 self.comment = self.comment + token[1]
595 token = self.lexer.token()
Daniel Veillard1e906612003-12-05 14:57:46 +0000596
597 if string.find(self.comment, "DOC_DISABLE") != -1:
598 self.stop_error()
599
600 if string.find(self.comment, "DOC_ENABLE") != -1:
601 self.start_error()
602
Daniel Veillardbe586972003-11-18 20:56:51 +0000603 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000604
605 #
606 # Parse a comment block associate to a macro
607 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000608 def parseMacroComment(self, name, quiet = 0):
609 if name[0:2] == '__':
610 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000611
Daniel Veillardbe586972003-11-18 20:56:51 +0000612 args = []
613 desc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000614
Daniel Veillardbe586972003-11-18 20:56:51 +0000615 if self.comment == None:
616 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000617 self.warning("Missing comment for macro %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000618 return((args, desc))
619 if self.comment[0] != '*':
620 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000621 self.warning("Missing * in macro comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000622 return((args, desc))
623 lines = string.split(self.comment, '\n')
624 if lines[0] == '*':
625 del lines[0]
626 if lines[0] != "* %s:" % (name):
627 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000628 self.warning("Misformatted macro comment for %s" % (name))
629 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000630 return((args, desc))
631 del lines[0]
632 while lines[0] == '*':
633 del lines[0]
634 while len(lines) > 0 and lines[0][0:3] == '* @':
635 l = lines[0][3:]
636 try:
637 (arg, desc) = string.split(l, ':', 1)
638 desc=string.strip(desc)
639 arg=string.strip(arg)
640 except:
641 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000642 self.warning("Misformatted macro comment for %s" % (name))
643 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000644 del lines[0]
645 continue
646 del lines[0]
647 l = string.strip(lines[0])
648 while len(l) > 2 and l[0:3] != '* @':
649 while l[0] == '*':
650 l = l[1:]
651 desc = desc + ' ' + string.strip(l)
652 del lines[0]
653 if len(lines) == 0:
654 break
655 l = lines[0]
656 args.append((arg, desc))
657 while len(lines) > 0 and lines[0] == '*':
658 del lines[0]
659 desc = ""
660 while len(lines) > 0:
661 l = lines[0]
662 while len(l) > 0 and l[0] == '*':
663 l = l[1:]
664 l = string.strip(l)
665 desc = desc + " " + l
666 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000667
Daniel Veillardbe586972003-11-18 20:56:51 +0000668 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000669
Daniel Veillardbe586972003-11-18 20:56:51 +0000670 if quiet == 0:
671 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000672 self.warning("Macro comment for %s lack description of the macro" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000673
Daniel Veillardbe586972003-11-18 20:56:51 +0000674 return((args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000675
676 #
677 # Parse a comment block and merge the informations found in the
678 # parameters descriptions, finally returns a block as complete
679 # as possible
680 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000681 def mergeFunctionComment(self, name, description, quiet = 0):
682 if name == 'main':
683 quiet = 1
684 if name[0:2] == '__':
685 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000686
Daniel Veillardbe586972003-11-18 20:56:51 +0000687 (ret, args) = description
688 desc = ""
689 retdesc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000690
Daniel Veillardbe586972003-11-18 20:56:51 +0000691 if self.comment == None:
692 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000693 self.warning("Missing comment for function %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000694 return(((ret[0], retdesc), args, desc))
695 if self.comment[0] != '*':
696 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000697 self.warning("Missing * in function comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000698 return(((ret[0], retdesc), args, desc))
699 lines = string.split(self.comment, '\n')
700 if lines[0] == '*':
701 del lines[0]
702 if lines[0] != "* %s:" % (name):
703 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000704 self.warning("Misformatted function comment for %s" % (name))
705 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000706 return(((ret[0], retdesc), args, desc))
707 del lines[0]
708 while lines[0] == '*':
709 del lines[0]
710 nbargs = len(args)
711 while len(lines) > 0 and lines[0][0:3] == '* @':
712 l = lines[0][3:]
713 try:
714 (arg, desc) = string.split(l, ':', 1)
715 desc=string.strip(desc)
716 arg=string.strip(arg)
717 except:
718 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000719 self.warning("Misformatted function comment for %s" % (name))
720 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000721 del lines[0]
722 continue
723 del lines[0]
724 l = string.strip(lines[0])
725 while len(l) > 2 and l[0:3] != '* @':
726 while l[0] == '*':
727 l = l[1:]
728 desc = desc + ' ' + string.strip(l)
729 del lines[0]
730 if len(lines) == 0:
731 break
732 l = lines[0]
733 i = 0
734 while i < nbargs:
735 if args[i][1] == arg:
736 args[i] = (args[i][0], arg, desc)
737 break;
738 i = i + 1
739 if i >= nbargs:
740 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000741 self.warning("Unable to find arg %s from function comment for %s" % (
742 arg, name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000743 while len(lines) > 0 and lines[0] == '*':
744 del lines[0]
745 desc = ""
746 while len(lines) > 0:
747 l = lines[0]
748 while len(l) > 0 and l[0] == '*':
749 l = l[1:]
750 l = string.strip(l)
751 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
752 try:
753 l = string.split(l, ' ', 1)[1]
754 except:
755 l = ""
756 retdesc = string.strip(l)
757 del lines[0]
758 while len(lines) > 0:
759 l = lines[0]
760 while len(l) > 0 and l[0] == '*':
761 l = l[1:]
762 l = string.strip(l)
763 retdesc = retdesc + " " + l
764 del lines[0]
765 else:
766 desc = desc + " " + l
767 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000768
Daniel Veillardbe586972003-11-18 20:56:51 +0000769 retdesc = string.strip(retdesc)
770 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000771
Daniel Veillardbe586972003-11-18 20:56:51 +0000772 if quiet == 0:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000773 #
774 # report missing comments
775 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000776 i = 0
777 while i < nbargs:
778 if args[i][2] == None and args[i][0] != "void" and args[i][1] != None:
Daniel Veillard1e906612003-12-05 14:57:46 +0000779 self.warning("Function comment for %s lack description of arg %s" % (name, args[i][1]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000780 i = i + 1
781 if retdesc == "" and ret[0] != "void":
Daniel Veillard1e906612003-12-05 14:57:46 +0000782 self.warning("Function comment for %s lack description of return value" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000783 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000784 self.warning("Function comment for %s lack description of the function" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000785
786
Daniel Veillardbe586972003-11-18 20:56:51 +0000787 return(((ret[0], retdesc), args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000788
Daniel Veillardbe586972003-11-18 20:56:51 +0000789 def parsePreproc(self, token):
790 name = token[1]
791 if name == "#include":
792 token = self.lexer.token()
793 if token == None:
794 return None
795 if token[0] == 'preproc':
796 self.index_add(token[1], self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000797 "include")
Daniel Veillardbe586972003-11-18 20:56:51 +0000798 return self.lexer.token()
799 return token
800 if name == "#define":
801 token = self.lexer.token()
802 if token == None:
803 return None
804 if token[0] == 'preproc':
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000805 # TODO macros with arguments
Daniel Veillardbe586972003-11-18 20:56:51 +0000806 name = token[1]
807 lst = []
808 token = self.lexer.token()
809 while token != None and token[0] == 'preproc' and \
810 token[1][0] != '#':
811 lst.append(token[1])
812 token = self.lexer.token()
813 try:
814 name = string.split(name, '(') [0]
815 except:
816 pass
817 info = self.parseMacroComment(name, not self.is_header)
818 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000819 "macro", info)
Daniel Veillardbe586972003-11-18 20:56:51 +0000820 return token
821 token = self.lexer.token()
822 while token != None and token[0] == 'preproc' and \
823 token[1][0] != '#':
824 token = self.lexer.token()
825 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000826
827 #
828 # token acquisition on top of the lexer, it handle internally
829 # preprocessor and comments since they are logically not part of
830 # the program structure.
831 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000832 def token(self):
833 global ignored_words
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000834
Daniel Veillardbe586972003-11-18 20:56:51 +0000835 token = self.lexer.token()
836 while token != None:
837 if token[0] == 'comment':
838 token = self.parseComment(token)
839 continue
840 elif token[0] == 'preproc':
841 token = self.parsePreproc(token)
842 continue
843 elif token[0] == "name" and ignored_words.has_key(token[1]):
844 (n, info) = ignored_words[token[1]]
845 i = 0
846 while i < n:
847 token = self.lexer.token()
848 i = i + 1
849 token = self.lexer.token()
850 continue
851 else:
852 if debug:
853 print "=> ", token
854 return token
855 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000856
857 #
858 # Parse a typedef, it records the type and its name.
859 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000860 def parseTypedef(self, token):
861 if token == None:
862 return None
863 token = self.parseType(token)
864 if token == None:
865 self.error("parsing typedef")
866 return None
867 base_type = self.type
868 type = base_type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000869 #self.debug("end typedef type", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000870 while token != None:
871 if token[0] == "name":
872 name = token[1]
873 signature = self.signature
874 if signature != None:
875 type = string.split(type, '(')[0]
876 d = self.mergeFunctionComment(name,
877 ((type, None), signature), 1)
878 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000879 "functype", d)
Daniel Veillardbe586972003-11-18 20:56:51 +0000880 else:
881 if base_type == "struct":
882 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000883 "struct", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000884 base_type = "struct " + name
885 else:
886 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000887 "typedef", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000888 token = self.token()
889 else:
890 self.error("parsing typedef: expecting a name")
891 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000892 #self.debug("end typedef", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000893 if token != None and token[0] == 'sep' and token[1] == ',':
894 type = base_type
895 token = self.token()
896 while token != None and token[0] == "op":
897 type = type + token[1]
898 token = self.token()
899 elif token != None and token[0] == 'sep' and token[1] == ';':
900 break;
901 elif token != None and token[0] == 'name':
902 type = base_type
903 continue;
904 else:
905 self.error("parsing typedef: expecting ';'", token)
906 return token
907 token = self.token()
908 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000909
910 #
911 # Parse a C code block, used for functions it parse till
912 # the balancing } included
913 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000914 def parseBlock(self, token):
915 while token != None:
916 if token[0] == "sep" and token[1] == "{":
917 token = self.token()
918 token = self.parseBlock(token)
919 elif token[0] == "sep" and token[1] == "}":
920 self.comment = None
921 token = self.token()
922 return token
923 else:
924 if self.collect_ref == 1:
925 oldtok = token
926 token = self.token()
927 if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
928 if token[0] == "sep" and token[1] == "(":
929 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000930 0, "function")
Daniel Veillardbe586972003-11-18 20:56:51 +0000931 token = self.token()
932 elif token[0] == "name":
933 token = self.token()
934 if token[0] == "sep" and (token[1] == ";" or
935 token[1] == "," or token[1] == "="):
936 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000937 0, "type")
Daniel Veillardbe586972003-11-18 20:56:51 +0000938 elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
939 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000940 0, "typedef")
Daniel Veillardbe586972003-11-18 20:56:51 +0000941 elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
942 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000943 0, "typedef")
944
Daniel Veillardbe586972003-11-18 20:56:51 +0000945 else:
946 token = self.token()
947 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000948
949 #
950 # Parse a C struct definition till the balancing }
951 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000952 def parseStruct(self, token):
953 fields = []
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000954 #self.debug("start parseStruct", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000955 while token != None:
956 if token[0] == "sep" and token[1] == "{":
957 token = self.token()
958 token = self.parseTypeBlock(token)
959 elif token[0] == "sep" and token[1] == "}":
960 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000961 #self.debug("end parseStruct", token)
962 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +0000963 token = self.token()
964 return token
965 else:
966 base_type = self.type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000967 #self.debug("before parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000968 token = self.parseType(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000969 #self.debug("after parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000970 if token != None and token[0] == "name":
971 fname = token[1]
972 token = self.token()
973 if token[0] == "sep" and token[1] == ";":
974 self.comment = None
975 token = self.token()
976 fields.append((self.type, fname, self.comment))
977 self.comment = None
978 else:
979 self.error("parseStruct: expecting ;", token)
980 elif token != None and token[0] == "sep" and token[1] == "{":
981 token = self.token()
982 token = self.parseTypeBlock(token)
983 if token != None and token[0] == "name":
984 token = self.token()
985 if token != None and token[0] == "sep" and token[1] == ";":
986 token = self.token()
987 else:
988 self.error("parseStruct: expecting ;", token)
989 else:
990 self.error("parseStruct: name", token)
991 token = self.token()
992 self.type = base_type;
993 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000994 #self.debug("end parseStruct", token)
995 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +0000996 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000997
998 #
999 # Parse a C enum block, parse till the balancing }
1000 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001001 def parseEnumBlock(self, token):
1002 self.enums = []
1003 name = None
1004 self.comment = None
1005 comment = ""
1006 value = "0"
1007 while token != None:
1008 if token[0] == "sep" and token[1] == "{":
1009 token = self.token()
1010 token = self.parseTypeBlock(token)
1011 elif token[0] == "sep" and token[1] == "}":
1012 if name != None:
1013 if self.comment != None:
1014 comment = self.comment
1015 self.comment = None
1016 self.enums.append((name, value, comment))
1017 token = self.token()
1018 return token
1019 elif token[0] == "name":
1020 if name != None:
1021 if self.comment != None:
1022 comment = string.strip(self.comment)
1023 self.comment = None
1024 self.enums.append((name, value, comment))
1025 name = token[1]
1026 comment = ""
1027 token = self.token()
1028 if token[0] == "op" and token[1][0] == "=":
1029 value = ""
1030 if len(token[1]) > 1:
1031 value = token[1][1:]
1032 token = self.token()
1033 while token[0] != "sep" or (token[1] != ',' and
1034 token[1] != '}'):
1035 value = value + token[1]
1036 token = self.token()
1037 else:
1038 try:
1039 value = "%d" % (int(value) + 1)
1040 except:
Daniel Veillard1e906612003-12-05 14:57:46 +00001041 self.warning("Failed to compute value of enum %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +00001042 value=""
1043 if token[0] == "sep" and token[1] == ",":
1044 token = self.token()
1045 else:
1046 token = self.token()
1047 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001048
1049 #
1050 # Parse a C definition block, used for structs it parse till
1051 # the balancing }
1052 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001053 def parseTypeBlock(self, token):
1054 while token != None:
1055 if token[0] == "sep" and token[1] == "{":
1056 token = self.token()
1057 token = self.parseTypeBlock(token)
1058 elif token[0] == "sep" and token[1] == "}":
1059 token = self.token()
1060 return token
1061 else:
1062 token = self.token()
1063 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001064
1065 #
1066 # Parse a type: the fact that the type name can either occur after
1067 # the definition or within the definition makes it a little harder
1068 # if inside, the name token is pushed back before returning
1069 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001070 def parseType(self, token):
1071 self.type = ""
1072 self.struct_fields = []
1073 self.signature = None
1074 if token == None:
1075 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001076
Daniel Veillardbe586972003-11-18 20:56:51 +00001077 while token[0] == "name" and (
1078 token[1] == "const" or token[1] == "unsigned"):
1079 if self.type == "":
1080 self.type = token[1]
1081 else:
1082 self.type = self.type + " " + token[1]
1083 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001084
Daniel Veillardbe586972003-11-18 20:56:51 +00001085 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1086 if self.type == "":
1087 self.type = token[1]
1088 else:
1089 self.type = self.type + " " + token[1]
1090 if token[0] == "name" and token[1] == "int":
1091 if self.type == "":
1092 self.type = tmp[1]
1093 else:
1094 self.type = self.type + " " + tmp[1]
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001095
Daniel Veillardbe586972003-11-18 20:56:51 +00001096 elif token[0] == "name" and token[1] == "struct":
1097 if self.type == "":
1098 self.type = token[1]
1099 else:
1100 self.type = self.type + " " + token[1]
1101 token = self.token()
1102 nametok = None
1103 if token[0] == "name":
1104 nametok = token
1105 token = self.token()
1106 if token != None and token[0] == "sep" and token[1] == "{":
1107 token = self.token()
1108 token = self.parseStruct(token)
1109 elif token != None and token[0] == "op" and token[1] == "*":
1110 self.type = self.type + " " + nametok[1] + " *"
1111 token = self.token()
1112 while token != None and token[0] == "op" and token[1] == "*":
1113 self.type = self.type + " *"
1114 token = self.token()
1115 if token[0] == "name":
1116 nametok = token
1117 token = self.token()
1118 else:
1119 self.error("struct : expecting name", token)
1120 return token
1121 elif token != None and token[0] == "name" and nametok != None:
1122 self.type = self.type + " " + nametok[1]
1123 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001124
Daniel Veillardbe586972003-11-18 20:56:51 +00001125 if nametok != None:
1126 self.lexer.push(token)
1127 token = nametok
1128 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001129
Daniel Veillardbe586972003-11-18 20:56:51 +00001130 elif token[0] == "name" and token[1] == "enum":
1131 if self.type == "":
1132 self.type = token[1]
1133 else:
1134 self.type = self.type + " " + token[1]
1135 self.enums = []
1136 token = self.token()
1137 if token != None and token[0] == "sep" and token[1] == "{":
1138 token = self.token()
1139 token = self.parseEnumBlock(token)
1140 else:
1141 self.error("parsing enum: expecting '{'", token)
1142 enum_type = None
1143 if token != None and token[0] != "name":
1144 self.lexer.push(token)
1145 token = ("name", "enum")
1146 else:
1147 enum_type = token[1]
1148 for enum in self.enums:
1149 self.index_add(enum[0], self.filename,
1150 not self.is_header, "enum",
1151 (enum[1], enum[2], enum_type))
1152 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001153
Daniel Veillardbe586972003-11-18 20:56:51 +00001154 elif token[0] == "name":
1155 if self.type == "":
1156 self.type = token[1]
1157 else:
1158 self.type = self.type + " " + token[1]
1159 else:
1160 self.error("parsing type %s: expecting a name" % (self.type),
1161 token)
1162 return token
1163 token = self.token()
1164 while token != None and (token[0] == "op" or
1165 token[0] == "name" and token[1] == "const"):
1166 self.type = self.type + " " + token[1]
1167 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001168
1169 #
1170 # if there is a parenthesis here, this means a function type
1171 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001172 if token != None and token[0] == "sep" and token[1] == '(':
1173 self.type = self.type + token[1]
1174 token = self.token()
1175 while token != None and token[0] == "op" and token[1] == '*':
1176 self.type = self.type + token[1]
1177 token = self.token()
1178 if token == None or token[0] != "name" :
1179 self.error("parsing function type, name expected", token);
1180 return token
1181 self.type = self.type + token[1]
1182 nametok = token
1183 token = self.token()
1184 if token != None and token[0] == "sep" and token[1] == ')':
1185 self.type = self.type + token[1]
1186 token = self.token()
1187 if token != None and token[0] == "sep" and token[1] == '(':
1188 token = self.token()
1189 type = self.type;
1190 token = self.parseSignature(token);
1191 self.type = type;
1192 else:
1193 self.error("parsing function type, '(' expected", token);
1194 return token
1195 else:
1196 self.error("parsing function type, ')' expected", token);
1197 return token
1198 self.lexer.push(token)
1199 token = nametok
1200 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001201
1202 #
1203 # do some lookahead for arrays
1204 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001205 if token != None and token[0] == "name":
1206 nametok = token
1207 token = self.token()
1208 if token != None and token[0] == "sep" and token[1] == '[':
1209 self.type = self.type + nametok[1]
1210 while token != None and token[0] == "sep" and token[1] == '[':
1211 self.type = self.type + token[1]
1212 token = self.token()
1213 while token != None and token[0] != 'sep' and \
1214 token[1] != ']' and token[1] != ';':
1215 self.type = self.type + token[1]
1216 token = self.token()
1217 if token != None and token[0] == 'sep' and token[1] == ']':
1218 self.type = self.type + token[1]
1219 token = self.token()
1220 else:
1221 self.error("parsing array type, ']' expected", token);
1222 return token
1223 elif token != None and token[0] == "sep" and token[1] == ':':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001224 # remove :12 in case it's a limited int size
Daniel Veillardbe586972003-11-18 20:56:51 +00001225 token = self.token()
1226 token = self.token()
1227 self.lexer.push(token)
1228 token = nametok
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001229
Daniel Veillardbe586972003-11-18 20:56:51 +00001230 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001231
1232 #
1233 # Parse a signature: '(' has been parsed and we scan the type definition
1234 # up to the ')' included
Daniel Veillardbe586972003-11-18 20:56:51 +00001235 def parseSignature(self, token):
1236 signature = []
1237 if token != None and token[0] == "sep" and token[1] == ')':
1238 self.signature = []
1239 token = self.token()
1240 return token
1241 while token != None:
1242 token = self.parseType(token)
1243 if token != None and token[0] == "name":
1244 signature.append((self.type, token[1], None))
1245 token = self.token()
1246 elif token != None and token[0] == "sep" and token[1] == ',':
1247 token = self.token()
1248 continue
1249 elif token != None and token[0] == "sep" and token[1] == ')':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001250 # only the type was provided
Daniel Veillardbe586972003-11-18 20:56:51 +00001251 if self.type == "...":
1252 signature.append((self.type, "...", None))
1253 else:
1254 signature.append((self.type, None, None))
1255 if token != None and token[0] == "sep":
1256 if token[1] == ',':
1257 token = self.token()
1258 continue
1259 elif token[1] == ')':
1260 token = self.token()
1261 break
1262 self.signature = signature
1263 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001264
1265 #
1266 # Parse a global definition, be it a type, variable or function
1267 # the extern "C" blocks are a bit nasty and require it to recurse.
1268 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001269 def parseGlobal(self, token):
1270 static = 0
1271 if token[1] == 'extern':
1272 token = self.token()
1273 if token == None:
1274 return token
1275 if token[0] == 'string':
1276 if token[1] == 'C':
1277 token = self.token()
1278 if token == None:
1279 return token
1280 if token[0] == 'sep' and token[1] == "{":
1281 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001282# print 'Entering extern "C line ', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001283 while token != None and (token[0] != 'sep' or
1284 token[1] != "}"):
1285 if token[0] == 'name':
1286 token = self.parseGlobal(token)
1287 else:
1288 self.error(
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001289 "token %s %s unexpected at the top level" % (
1290 token[0], token[1]))
Daniel Veillardbe586972003-11-18 20:56:51 +00001291 token = self.parseGlobal(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001292# print 'Exiting extern "C" line', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001293 token = self.token()
1294 return token
1295 else:
1296 return token
1297 elif token[1] == 'static':
1298 static = 1
1299 token = self.token()
1300 if token == None or token[0] != 'name':
1301 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001302
Daniel Veillardbe586972003-11-18 20:56:51 +00001303 if token[1] == 'typedef':
1304 token = self.token()
1305 return self.parseTypedef(token)
1306 else:
1307 token = self.parseType(token)
1308 type_orig = self.type
1309 if token == None or token[0] != "name":
1310 return token
1311 type = type_orig
1312 self.name = token[1]
1313 token = self.token()
1314 while token != None and (token[0] == "sep" or token[0] == "op"):
1315 if token[0] == "sep":
1316 if token[1] == "[":
1317 type = type + token[1]
1318 token = self.token()
1319 while token != None and (token[0] != "sep" or \
1320 token[1] != ";"):
1321 type = type + token[1]
1322 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001323
Daniel Veillardbe586972003-11-18 20:56:51 +00001324 if token != None and token[0] == "op" and token[1] == "=":
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001325 #
1326 # Skip the initialization of the variable
1327 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001328 token = self.token()
1329 if token[0] == 'sep' and token[1] == '{':
1330 token = self.token()
1331 token = self.parseBlock(token)
1332 else:
1333 self.comment = None
1334 while token != None and (token[0] != "sep" or \
1335 (token[1] != ';' and token[1] != ',')):
1336 token = self.token()
1337 self.comment = None
1338 if token == None or token[0] != "sep" or (token[1] != ';' and
1339 token[1] != ','):
1340 self.error("missing ';' or ',' after value")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001341
Daniel Veillardbe586972003-11-18 20:56:51 +00001342 if token != None and token[0] == "sep":
1343 if token[1] == ";":
1344 self.comment = None
1345 token = self.token()
1346 if type == "struct":
1347 self.index_add(self.name, self.filename,
1348 not self.is_header, "struct", self.struct_fields)
1349 else:
1350 self.index_add(self.name, self.filename,
1351 not self.is_header, "variable", type)
1352 break
1353 elif token[1] == "(":
1354 token = self.token()
1355 token = self.parseSignature(token)
1356 if token == None:
1357 return None
1358 if token[0] == "sep" and token[1] == ";":
1359 d = self.mergeFunctionComment(self.name,
1360 ((type, None), self.signature), 1)
1361 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001362 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001363 token = self.token()
1364 elif token[0] == "sep" and token[1] == "{":
1365 d = self.mergeFunctionComment(self.name,
1366 ((type, None), self.signature), static)
1367 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001368 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001369 token = self.token()
1370 token = self.parseBlock(token);
1371 elif token[1] == ',':
1372 self.comment = None
1373 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001374 "variable", type)
Daniel Veillardbe586972003-11-18 20:56:51 +00001375 type = type_orig
1376 token = self.token()
1377 while token != None and token[0] == "sep":
1378 type = type + token[1]
1379 token = self.token()
1380 if token != None and token[0] == "name":
1381 self.name = token[1]
1382 token = self.token()
1383 else:
1384 break
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001385
Daniel Veillardbe586972003-11-18 20:56:51 +00001386 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001387
Daniel Veillardbe586972003-11-18 20:56:51 +00001388 def parse(self):
Daniel Veillard1e906612003-12-05 14:57:46 +00001389 self.warning("Parsing %s" % (self.filename))
Daniel Veillardbe586972003-11-18 20:56:51 +00001390 token = self.token()
1391 while token != None:
1392 if token[0] == 'name':
1393 token = self.parseGlobal(token)
1394 else:
1395 self.error("token %s %s unexpected at the top level" % (
1396 token[0], token[1]))
1397 token = self.parseGlobal(token)
1398 return
1399 self.parseTopComment(self.top_comment)
1400 return self.index
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001401
1402
1403class docBuilder:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001404 """A documentation builder"""
1405 def __init__(self, name, directories=['.'], excludes=[]):
1406 self.name = name
1407 self.directories = directories
1408 self.excludes = excludes + ignored_files.keys()
1409 self.modules = {}
1410 self.headers = {}
1411 self.idx = index()
1412 self.xref = {}
1413 self.index = {}
1414 if name == 'libxml2':
1415 self.basename = 'libxml'
1416 else:
1417 self.basename = name
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001418
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001419 def indexString(self, id, str):
1420 if str == None:
1421 return
1422 str = string.replace(str, "'", ' ')
1423 str = string.replace(str, '"', ' ')
1424 str = string.replace(str, "/", ' ')
1425 str = string.replace(str, '*', ' ')
1426 str = string.replace(str, "[", ' ')
1427 str = string.replace(str, "]", ' ')
1428 str = string.replace(str, "(", ' ')
1429 str = string.replace(str, ")", ' ')
1430 str = string.replace(str, "<", ' ')
1431 str = string.replace(str, '>', ' ')
1432 str = string.replace(str, "&", ' ')
1433 str = string.replace(str, '#', ' ')
1434 str = string.replace(str, ",", ' ')
1435 str = string.replace(str, '.', ' ')
1436 str = string.replace(str, ';', ' ')
1437 tokens = string.split(str)
1438 for token in tokens:
1439 try:
1440 c = token[0]
1441 if string.find(string.letters, c) < 0:
1442 pass
1443 elif len(token) < 3:
1444 pass
1445 else:
1446 lower = string.lower(token)
1447 # TODO: generalize this a bit
1448 if lower == 'and' or lower == 'the':
1449 pass
1450 elif self.xref.has_key(token):
1451 self.xref[token].append(id)
1452 else:
1453 self.xref[token] = [id]
1454 except:
1455 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001456
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001457 def analyze(self):
1458 print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
1459 self.idx.analyze()
1460
1461 def scanHeaders(self):
1462 for header in self.headers.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001463 parser = CParser(header)
1464 idx = parser.parse()
1465 self.headers[header] = idx;
1466 self.idx.merge(idx)
1467
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001468 def scanModules(self):
1469 for module in self.modules.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001470 parser = CParser(module)
1471 idx = parser.parse()
1472 # idx.analyze()
1473 self.modules[module] = idx
1474 self.idx.merge_public(idx)
1475
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001476 def scan(self):
1477 for directory in self.directories:
1478 files = glob.glob(directory + "/*.c")
1479 for file in files:
1480 skip = 0
1481 for excl in self.excludes:
1482 if string.find(file, excl) != -1:
1483 skip = 1;
1484 break
1485 if skip == 0:
1486 self.modules[file] = None;
1487 files = glob.glob(directory + "/*.h")
1488 for file in files:
1489 skip = 0
1490 for excl in self.excludes:
1491 if string.find(file, excl) != -1:
1492 skip = 1;
1493 break
1494 if skip == 0:
1495 self.headers[file] = None;
1496 self.scanHeaders()
1497 self.scanModules()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001498
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001499 def modulename_file(self, file):
1500 module = os.path.basename(file)
1501 if module[-2:] == '.h':
1502 module = module[:-2]
1503 return module
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001504
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001505 def serialize_enum(self, output, name):
1506 id = self.idx.enums[name]
1507 output.write(" <enum name='%s' file='%s'" % (name,
1508 self.modulename_file(id.module)))
1509 if id.info != None:
1510 info = id.info
1511 if info[0] != None and info[0] != '':
1512 try:
1513 val = eval(info[0])
1514 except:
1515 val = info[0]
1516 output.write(" value='%s'" % (val));
1517 if info[2] != None and info[2] != '':
1518 output.write(" type='%s'" % info[2]);
1519 if info[1] != None and info[1] != '':
1520 output.write(" info='%s'" % escape(info[1]));
1521 output.write("/>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001522
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001523 def serialize_macro(self, output, name):
1524 id = self.idx.macros[name]
1525 output.write(" <macro name='%s' file='%s'>\n" % (name,
1526 self.modulename_file(id.module)))
1527 if id.info != None:
1528 try:
1529 (args, desc) = id.info
1530 if desc != None and desc != "":
1531 output.write(" <info>%s</info>\n" % (escape(desc)))
1532 self.indexString(name, desc)
1533 for arg in args:
1534 (name, desc) = arg
1535 if desc != None and desc != "":
1536 output.write(" <arg name='%s' info='%s'/>\n" % (
1537 name, escape(desc)))
1538 self.indexString(name, desc)
1539 else:
1540 output.write(" <arg name='%s'/>\n" % (name))
1541 except:
1542 pass
1543 output.write(" </macro>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001544
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001545 def serialize_typedef(self, output, name):
1546 id = self.idx.typedefs[name]
1547 if id.info[0:7] == 'struct ':
1548 output.write(" <struct name='%s' file='%s' type='%s'" % (
1549 name, self.modulename_file(id.module), id.info))
1550 name = id.info[7:]
1551 if self.idx.structs.has_key(name) and ( \
1552 type(self.idx.structs[name].info) == type(()) or
Daniel Veillardc1eed322002-12-12 11:01:32 +00001553 type(self.idx.structs[name].info) == type([])):
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001554 output.write(">\n");
1555 try:
1556 for field in self.idx.structs[name].info:
1557 desc = field[2]
1558 self.indexString(name, desc)
1559 if desc == None:
1560 desc = ''
1561 else:
1562 desc = escape(desc)
1563 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1564 except:
1565 print "Failed to serialize struct %s" % (name)
1566 output.write(" </struct>\n")
1567 else:
1568 output.write("/>\n");
1569 else :
1570 output.write(" <typedef name='%s' file='%s' type='%s'/>\n" % (
1571 name, self.modulename_file(id.module), id.info))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001572
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001573 def serialize_variable(self, output, name):
1574 id = self.idx.variables[name]
1575 if id.info != None:
1576 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1577 name, self.modulename_file(id.module), id.info))
1578 else:
1579 output.write(" <variable name='%s' file='%s'/>\n" % (
1580 name, self.modulename_file(id.module)))
Daniel Veillardc1eed322002-12-12 11:01:32 +00001581
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001582 def serialize_function(self, output, name):
1583 id = self.idx.functions[name]
1584 output.write(" <%s name='%s' file='%s'>\n" % (id.type, name,
1585 self.modulename_file(id.module)))
1586 try:
1587 (ret, params, desc) = id.info
1588 output.write(" <info>%s</info>\n" % (escape(desc)))
1589 self.indexString(name, desc)
1590 if ret[0] != None:
1591 if ret[0] == "void":
1592 output.write(" <return type='void'/>\n")
1593 else:
1594 output.write(" <return type='%s' info='%s'/>\n" % (
1595 ret[0], escape(ret[1])))
1596 self.indexString(name, ret[1])
1597 for param in params:
1598 if param[0] == 'void':
1599 continue
1600 if param[2] == None:
1601 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1602 else:
1603 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1604 self.indexString(name, param[2])
1605 except:
1606 print "Failed to save function %s info: " % name, `id.info`
1607 output.write(" </%s>\n" % (id.type))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001608
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001609 def serialize_exports(self, output, file):
1610 module = self.modulename_file(file)
1611 output.write(" <file name='%s'>\n" % (module))
1612 dict = self.headers[file]
Daniel Veillardbe586972003-11-18 20:56:51 +00001613 if dict.info != None:
1614 for data in ('Summary', 'Description', 'Author'):
1615 try:
1616 output.write(" <%s>%s</%s>\n" % (
1617 string.lower(data),
1618 escape(dict.info[data]),
1619 string.lower(data)))
1620 except:
1621 print "Header %s lacks a %s description" % (module, data)
1622 if dict.info.has_key('Description'):
1623 desc = dict.info['Description']
1624 if string.find(desc, "DEPRECATED") != -1:
1625 output.write(" <deprecated/>\n")
1626
Daniel Veillard1a792412003-11-18 23:52:38 +00001627 ids = dict.macros.keys()
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001628 ids.sort()
1629 for id in uniq(ids):
Daniel Veillard1a792412003-11-18 23:52:38 +00001630 # Macros are sometime used to masquerade other types.
1631 if dict.functions.has_key(id):
1632 continue
1633 if dict.variables.has_key(id):
1634 continue
1635 if dict.typedefs.has_key(id):
1636 continue
1637 if dict.structs.has_key(id):
1638 continue
1639 if dict.enums.has_key(id):
1640 continue
1641 output.write(" <exports symbol='%s' type='macro'/>\n" % (id))
1642 ids = dict.enums.keys()
1643 ids.sort()
1644 for id in uniq(ids):
1645 output.write(" <exports symbol='%s' type='enum'/>\n" % (id))
1646 ids = dict.typedefs.keys()
1647 ids.sort()
1648 for id in uniq(ids):
1649 output.write(" <exports symbol='%s' type='typedef'/>\n" % (id))
1650 ids = dict.structs.keys()
1651 ids.sort()
1652 for id in uniq(ids):
1653 output.write(" <exports symbol='%s' type='struct'/>\n" % (id))
1654 ids = dict.variables.keys()
1655 ids.sort()
1656 for id in uniq(ids):
1657 output.write(" <exports symbol='%s' type='variable'/>\n" % (id))
1658 ids = dict.functions.keys()
1659 ids.sort()
1660 for id in uniq(ids):
1661 output.write(" <exports symbol='%s' type='function'/>\n" % (id))
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001662 output.write(" </file>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001663
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001664 def serialize_xrefs_files(self, output):
1665 headers = self.headers.keys()
1666 headers.sort()
1667 for file in headers:
1668 module = self.modulename_file(file)
1669 output.write(" <file name='%s'>\n" % (module))
1670 dict = self.headers[file]
William M. Bracka2e844a2004-01-06 11:52:13 +00001671 ids = uniq(dict.functions.keys() + dict.variables.keys() + \
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001672 dict.macros.keys() + dict.typedefs.keys() + \
William M. Bracka2e844a2004-01-06 11:52:13 +00001673 dict.structs.keys() + dict.enums.keys())
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001674 ids.sort()
William M. Bracka2e844a2004-01-06 11:52:13 +00001675 for id in ids:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001676 output.write(" <ref name='%s'/>\n" % (id))
1677 output.write(" </file>\n")
1678 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001679
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001680 def serialize_xrefs_functions(self, output):
1681 funcs = {}
1682 for name in self.idx.functions.keys():
1683 id = self.idx.functions[name]
1684 try:
1685 (ret, params, desc) = id.info
1686 for param in params:
1687 if param[0] == 'void':
1688 continue
1689 if funcs.has_key(param[0]):
1690 funcs[param[0]].append(name)
1691 else:
1692 funcs[param[0]] = [name]
1693 except:
1694 pass
1695 typ = funcs.keys()
1696 typ.sort()
1697 for type in typ:
1698 if type == '' or type == 'void' or type == "int" or \
1699 type == "char *" or type == "const char *" :
1700 continue
1701 output.write(" <type name='%s'>\n" % (type))
1702 ids = funcs[type]
1703 ids.sort()
William M. Brackcf9eadf2003-12-25 13:24:05 +00001704 pid = '' # not sure why we have dups, but get rid of them!
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001705 for id in ids:
William M. Brackcf9eadf2003-12-25 13:24:05 +00001706 if id != pid:
1707 output.write(" <ref name='%s'/>\n" % (id))
1708 pid = id
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001709 output.write(" </type>\n")
1710
1711 def serialize_xrefs_constructors(self, output):
1712 funcs = {}
1713 for name in self.idx.functions.keys():
1714 id = self.idx.functions[name]
1715 try:
1716 (ret, params, desc) = id.info
1717 if ret[0] == "void":
1718 continue
1719 if funcs.has_key(ret[0]):
1720 funcs[ret[0]].append(name)
1721 else:
1722 funcs[ret[0]] = [name]
1723 except:
1724 pass
1725 typ = funcs.keys()
1726 typ.sort()
1727 for type in typ:
1728 if type == '' or type == 'void' or type == "int" or \
1729 type == "char *" or type == "const char *" :
1730 continue
1731 output.write(" <type name='%s'>\n" % (type))
1732 ids = funcs[type]
William M. Brack09a4d0a2004-01-05 14:28:43 +00001733 ids.sort()
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001734 for id in ids:
1735 output.write(" <ref name='%s'/>\n" % (id))
1736 output.write(" </type>\n")
1737
1738 def serialize_xrefs_alpha(self, output):
1739 letter = None
1740 ids = self.idx.identifiers.keys()
1741 ids.sort()
1742 for id in ids:
1743 if id[0] != letter:
1744 if letter != None:
1745 output.write(" </letter>\n")
1746 letter = id[0]
1747 output.write(" <letter name='%s'>\n" % (letter))
1748 output.write(" <ref name='%s'/>\n" % (id))
1749 if letter != None:
1750 output.write(" </letter>\n")
1751
1752 def serialize_xrefs_references(self, output):
1753 typ = self.idx.identifiers.keys()
1754 typ.sort()
1755 for id in typ:
1756 idf = self.idx.identifiers[id]
1757 module = idf.module
1758 output.write(" <reference name='%s' href='%s'/>\n" % (id,
1759 'html/' + self.basename + '-' +
1760 self.modulename_file(module) + '.html#' +
1761 id))
1762
1763 def serialize_xrefs_index(self, output):
1764 index = self.xref
1765 typ = index.keys()
1766 typ.sort()
1767 letter = None
1768 count = 0
1769 chunk = 0
1770 chunks = []
1771 for id in typ:
1772 if len(index[id]) > 30:
1773 continue
1774 if id[0] != letter:
1775 if letter == None or count > 200:
1776 if letter != None:
1777 output.write(" </letter>\n")
1778 output.write(" </chunk>\n")
1779 count = 0
1780 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
1781 output.write(" <chunk name='chunk%s'>\n" % (chunk))
1782 first_letter = id[0]
1783 chunk = chunk + 1
1784 elif letter != None:
1785 output.write(" </letter>\n")
1786 letter = id[0]
1787 output.write(" <letter name='%s'>\n" % (letter))
1788 output.write(" <word name='%s'>\n" % (id))
1789 tokens = index[id];
1790 tokens.sort()
1791 tok = None
William M. Bracka2e844a2004-01-06 11:52:13 +00001792 for token in tokens:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001793 if tok == token:
1794 continue
1795 tok = token
1796 output.write(" <ref name='%s'/>\n" % (token))
1797 count = count + 1
1798 output.write(" </word>\n")
1799 if letter != None:
1800 output.write(" </letter>\n")
1801 output.write(" </chunk>\n")
William M. Brack966668a2003-12-20 02:10:28 +00001802 if count != 0:
1803 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001804 output.write(" <chunks>\n")
1805 for ch in chunks:
1806 output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
1807 ch[0], ch[1], ch[2]))
1808 output.write(" </chunks>\n")
1809
1810 def serialize_xrefs(self, output):
1811 output.write(" <references>\n")
1812 self.serialize_xrefs_references(output)
1813 output.write(" </references>\n")
1814 output.write(" <alpha>\n")
1815 self.serialize_xrefs_alpha(output)
1816 output.write(" </alpha>\n")
1817 output.write(" <constructors>\n")
1818 self.serialize_xrefs_constructors(output)
1819 output.write(" </constructors>\n")
1820 output.write(" <functions>\n")
1821 self.serialize_xrefs_functions(output)
1822 output.write(" </functions>\n")
1823 output.write(" <files>\n")
1824 self.serialize_xrefs_files(output)
1825 output.write(" </files>\n")
1826 output.write(" <index>\n")
1827 self.serialize_xrefs_index(output)
1828 output.write(" </index>\n")
1829
1830 def serialize(self):
1831 filename = "%s-api.xml" % self.name
1832 print "Saving XML description %s" % (filename)
1833 output = open(filename, "w")
1834 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1835 output.write("<api name='%s'>\n" % self.name)
1836 output.write(" <files>\n")
1837 headers = self.headers.keys()
1838 headers.sort()
1839 for file in headers:
1840 self.serialize_exports(output, file)
1841 output.write(" </files>\n")
1842 output.write(" <symbols>\n")
1843 macros = self.idx.macros.keys()
1844 macros.sort()
1845 for macro in macros:
1846 self.serialize_macro(output, macro)
1847 enums = self.idx.enums.keys()
1848 enums.sort()
1849 for enum in enums:
1850 self.serialize_enum(output, enum)
1851 typedefs = self.idx.typedefs.keys()
1852 typedefs.sort()
1853 for typedef in typedefs:
1854 self.serialize_typedef(output, typedef)
1855 variables = self.idx.variables.keys()
1856 variables.sort()
1857 for variable in variables:
1858 self.serialize_variable(output, variable)
1859 functions = self.idx.functions.keys()
1860 functions.sort()
1861 for function in functions:
1862 self.serialize_function(output, function)
1863 output.write(" </symbols>\n")
1864 output.write("</api>\n")
1865 output.close()
1866
1867 filename = "%s-refs.xml" % self.name
1868 print "Saving XML Cross References %s" % (filename)
1869 output = open(filename, "w")
1870 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1871 output.write("<apirefs name='%s'>\n" % self.name)
1872 self.serialize_xrefs(output)
1873 output.write("</apirefs>\n")
1874 output.close()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001875
1876
1877def rebuild():
1878 builder = None
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001879 if glob.glob("parser.c") != [] :
1880 print "Rebuilding API description for libxml2"
1881 builder = docBuilder("libxml2", [".", "."],
1882 ["xmlwin32version.h", "tst.c"])
1883 elif glob.glob("../parser.c") != [] :
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001884 print "Rebuilding API description for libxml2"
1885 builder = docBuilder("libxml2", ["..", "../include/libxml"],
Daniel Veillardd4330462003-04-29 12:40:16 +00001886 ["xmlwin32version.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001887 elif glob.glob("../libxslt/transform.c") != [] :
1888 print "Rebuilding API description for libxslt"
1889 builder = docBuilder("libxslt", ["../libxslt"],
Daniel Veillard024b5702002-12-12 00:15:55 +00001890 ["win32config.h", "libxslt.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001891 else:
1892 print "rebuild() failed, unable to guess the module"
1893 return None
1894 builder.scan()
1895 builder.analyze()
1896 builder.serialize()
Daniel Veillard024b5702002-12-12 00:15:55 +00001897 if glob.glob("../libexslt/exslt.c") != [] :
1898 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1899 extra.scan()
1900 extra.analyze()
1901 extra.serialize()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001902 return builder
1903
1904#
1905# for debugging the parser
1906#
1907def parse(filename):
1908 parser = CParser(filename)
1909 idx = parser.parse()
1910 return idx
1911
1912if __name__ == "__main__":
1913 rebuild()