blob: 30d69439c401d3ef3089ed9c7adf4b3a49ce74de [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 Veillardde0a0a52003-04-24 17:12:57 +000030}
31
32ignored_words = {
33 "WINAPI": (0, "Windows keyword"),
34 "LIBXML_DLL_IMPORT": (0, "Special macro to flag external keywords"),
William M. Brackcdfa2862003-08-29 06:03:38 +000035 "XMLPUBVAR": (0, "Special macro for extern vars for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000036 "XSLTPUBVAR": (0, "Special macro for extern vars for win32"),
37 "EXSLTPUBVAR": (0, "Special macro for extern vars for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000038 "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000039 "XSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
40 "EXSLTPUBFUN": (0, "Special macro for extern funcs for win32"),
William M. Brackcdfa2862003-08-29 06:03:38 +000041 "XMLCALL": (0, "Special macro for win32 calls"),
Daniel Veillarde8ba84e2003-11-18 13:54:15 +000042 "XSLTCALL": (0, "Special macro for win32 calls"),
43 "EXSLTCALL": (0, "Special macro for win32 calls"),
Daniel Veillardde0a0a52003-04-24 17:12:57 +000044 "__declspec": (3, "Windows keyword"),
45 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
46 "LIBEXSLT_PUBLIC": (0, "macro keyword"),
47 "X_IN_Y": (5, "macro function builder"),
48}
49
Daniel Veillarda9b66d02002-12-11 14:23:49 +000050def escape(raw):
51 raw = string.replace(raw, '&', '&')
52 raw = string.replace(raw, '<', '&lt;')
53 raw = string.replace(raw, '>', '&gt;')
54 raw = string.replace(raw, "'", '&apos;')
55 raw = string.replace(raw, '"', '&quot;')
56 return raw
57
Daniel Veillard2925c0a2003-11-17 13:58:17 +000058def uniq(items):
59 d = {}
60 for item in items:
61 d[item]=1
62 return d.keys()
63
Daniel Veillarda9b66d02002-12-11 14:23:49 +000064class identifier:
Daniel Veillardbe586972003-11-18 20:56:51 +000065 def __init__(self, name, module=None, type=None, lineno = 0,
66 info=None, extra=None):
67 self.name = name
68 self.module = module
69 self.type = type
70 self.info = info
71 self.extra = extra
72 self.lineno = lineno
73 self.static = 0
Daniel Veillarda9b66d02002-12-11 14:23:49 +000074
Daniel Veillardbe586972003-11-18 20:56:51 +000075 def __repr__(self):
76 r = "%s %s:" % (self.type, self.name)
77 if self.static:
78 r = r + " static"
79 if self.module != None:
80 r = r + " from %s" % (self.module)
81 if self.info != None:
82 r = r + " " + `self.info`
83 if self.extra != None:
84 r = r + " " + `self.extra`
85 return r
Daniel Veillarda9b66d02002-12-11 14:23:49 +000086
87
Daniel Veillardbe586972003-11-18 20:56:51 +000088 def set_module(self, module):
89 self.module = module
90 def set_type(self, type):
91 self.type = type
92 def set_info(self, info):
93 self.info = info
94 def set_extra(self, extra):
95 self.extra = extra
96 def set_lineno(self, lineno):
97 self.lineno = lineno
98 def set_static(self, static):
99 self.static = static
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000100
Daniel Veillardbe586972003-11-18 20:56:51 +0000101 def get_name(self):
102 return self.name
103 def get_module(self):
104 return self.module
105 def get_type(self):
106 return self.type
107 def get_info(self):
108 return self.info
109 def get_lineno(self):
110 return self.lineno
111 def get_extra(self):
112 return self.extra
113 def get_static(self):
114 return self.static
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000115
Daniel Veillardbe586972003-11-18 20:56:51 +0000116 def update(self, module, type = None, info = None, extra=None):
117 if module != None and self.module == None:
118 self.set_module(module)
119 if type != None and self.type == None:
120 self.set_type(type)
121 if info != None:
122 self.set_info(info)
123 if extra != None:
124 self.set_extra(extra)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000125
126
127class index:
Daniel Veillardbe586972003-11-18 20:56:51 +0000128 def __init__(self, name = "noname"):
129 self.name = name
130 self.identifiers = {}
131 self.functions = {}
132 self.variables = {}
133 self.includes = {}
134 self.structs = {}
135 self.enums = {}
136 self.typedefs = {}
137 self.macros = {}
138 self.references = {}
139 self.info = {}
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000140
Daniel Veillardbe586972003-11-18 20:56:51 +0000141 def add_ref(self, name, module, static, type, lineno, info=None, extra=None):
142 if name[0:2] == '__':
143 return None
144 d = None
145 try:
146 d = self.identifiers[name]
147 d.update(module, type, lineno, info, extra)
148 except:
149 d = identifier(name, module, type, lineno, info, extra)
150 self.identifiers[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000151
Daniel Veillardbe586972003-11-18 20:56:51 +0000152 if d != None and static == 1:
153 d.set_static(1)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000154
Daniel Veillardbe586972003-11-18 20:56:51 +0000155 if d != None and name != None and type != None:
156 self.references[name] = d
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000157
Daniel Veillardbe586972003-11-18 20:56:51 +0000158 def add(self, name, module, static, type, lineno, info=None, extra=None):
159 if name[0:2] == '__':
160 return None
161 d = None
162 try:
163 d = self.identifiers[name]
164 d.update(module, type, lineno, info, extra)
165 except:
166 d = identifier(name, module, type, lineno, info, extra)
167 self.identifiers[name] = d
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000168
Daniel Veillardbe586972003-11-18 20:56:51 +0000169 if d != None and static == 1:
170 d.set_static(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000171
Daniel Veillardbe586972003-11-18 20:56:51 +0000172 if d != None and name != None and type != None:
173 if type == "function":
174 self.functions[name] = d
175 elif type == "functype":
176 self.functions[name] = d
177 elif type == "variable":
178 self.variables[name] = d
179 elif type == "include":
180 self.includes[name] = d
181 elif type == "struct":
182 self.structs[name] = d
183 elif type == "enum":
184 self.enums[name] = d
185 elif type == "typedef":
186 self.typedefs[name] = d
187 elif type == "macro":
188 self.macros[name] = d
189 else:
190 print "Unable to register type ", type
191 return d
192
193 def merge(self, idx):
194 for id in idx.functions.keys():
195 #
196 # macro might be used to override functions or variables
197 # definitions
198 #
199 if self.macros.has_key(id):
200 del self.macros[id]
201 if self.functions.has_key(id):
202 print "function %s from %s redeclared in %s" % (
203 id, self.functions[id].module, idx.functions[id].module)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000204 else:
Daniel Veillardbe586972003-11-18 20:56:51 +0000205 self.functions[id] = idx.functions[id]
206 self.identifiers[id] = idx.functions[id]
207 for id in idx.variables.keys():
208 #
209 # macro might be used to override functions or variables
210 # definitions
211 #
212 if self.macros.has_key(id):
213 del self.macros[id]
214 if self.variables.has_key(id):
215 print "variable %s from %s redeclared in %s" % (
216 id, self.variables[id].module, idx.variables[id].module)
217 else:
218 self.variables[id] = idx.variables[id]
219 self.identifiers[id] = idx.variables[id]
220 for id in idx.structs.keys():
221 if self.structs.has_key(id):
222 print "struct %s from %s redeclared in %s" % (
223 id, self.structs[id].module, idx.structs[id].module)
224 else:
225 self.structs[id] = idx.structs[id]
226 self.identifiers[id] = idx.structs[id]
227 for id in idx.typedefs.keys():
228 if self.typedefs.has_key(id):
229 print "typedef %s from %s redeclared in %s" % (
230 id, self.typedefs[id].module, idx.typedefs[id].module)
231 else:
232 self.typedefs[id] = idx.typedefs[id]
233 self.identifiers[id] = idx.typedefs[id]
234 for id in idx.macros.keys():
235 #
236 # macro might be used to override functions or variables
237 # definitions
238 #
239 if self.variables.has_key(id):
240 continue
241 if self.functions.has_key(id):
242 continue
243 if self.enums.has_key(id):
244 continue
245 if self.macros.has_key(id):
246 print "macro %s from %s redeclared in %s" % (
247 id, self.macros[id].module, idx.macros[id].module)
248 else:
249 self.macros[id] = idx.macros[id]
250 self.identifiers[id] = idx.macros[id]
251 for id in idx.enums.keys():
252 if self.enums.has_key(id):
253 print "enum %s from %s redeclared in %s" % (
254 id, self.enums[id].module, idx.enums[id].module)
255 else:
256 self.enums[id] = idx.enums[id]
257 self.identifiers[id] = idx.enums[id]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000258
Daniel Veillardbe586972003-11-18 20:56:51 +0000259 def merge_public(self, idx):
260 for id in idx.functions.keys():
261 if self.functions.has_key(id):
262 up = idx.functions[id]
263 self.functions[id].update(None, up.type, up.info, up.extra)
Daniel Veillardc1eed322002-12-12 11:01:32 +0000264 # else:
265 # print "Function %s from %s is not declared in headers" % (
266 # id, idx.functions[id].module)
267 # TODO: do the same for variables.
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000268
Daniel Veillardbe586972003-11-18 20:56:51 +0000269 def analyze_dict(self, type, dict):
270 count = 0
271 public = 0
272 for name in dict.keys():
273 id = dict[name]
274 count = count + 1
275 if id.static == 0:
276 public = public + 1
277 if count != public:
278 print " %d %s , %d public" % (count, type, public)
279 elif count != 0:
280 print " %d public %s" % (count, type)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000281
282
Daniel Veillardbe586972003-11-18 20:56:51 +0000283 def analyze(self):
284 self.analyze_dict("functions", self.functions)
285 self.analyze_dict("variables", self.variables)
286 self.analyze_dict("structs", self.structs)
287 self.analyze_dict("typedefs", self.typedefs)
288 self.analyze_dict("macros", self.macros)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000289
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000290class CLexer:
Daniel Veillardbe586972003-11-18 20:56:51 +0000291 """A lexer for the C language, tokenize the input by reading and
292 analyzing it line by line"""
293 def __init__(self, input):
294 self.input = input
295 self.tokens = []
296 self.line = ""
297 self.lineno = 0
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000298
Daniel Veillardbe586972003-11-18 20:56:51 +0000299 def getline(self):
300 line = ''
301 while line == '':
302 line = self.input.readline()
303 if not line:
304 return None
305 self.lineno = self.lineno + 1
306 line = string.lstrip(line)
307 line = string.rstrip(line)
308 if line == '':
309 continue
310 while line[-1] == '\\':
311 line = line[:-1]
312 n = self.input.readline()
313 self.lineno = self.lineno + 1
314 n = string.lstrip(n)
315 n = string.rstrip(n)
316 if not n:
317 break
318 else:
319 line = line + n
320 return line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000321
Daniel Veillardbe586972003-11-18 20:56:51 +0000322 def getlineno(self):
323 return self.lineno
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000324
Daniel Veillardbe586972003-11-18 20:56:51 +0000325 def push(self, token):
326 self.tokens.insert(0, token);
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000327
Daniel Veillardbe586972003-11-18 20:56:51 +0000328 def debug(self):
329 print "Last token: ", self.last
330 print "Token queue: ", self.tokens
331 print "Line %d end: " % (self.lineno), self.line
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000332
Daniel Veillardbe586972003-11-18 20:56:51 +0000333 def token(self):
334 while self.tokens == []:
335 if self.line == "":
336 line = self.getline()
337 else:
338 line = self.line
339 self.line = ""
340 if line == None:
341 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000342
Daniel Veillardbe586972003-11-18 20:56:51 +0000343 if line[0] == '#':
344 self.tokens = map((lambda x: ('preproc', x)),
345 string.split(line))
346 break;
347 l = len(line)
348 if line[0] == '"' or line[0] == "'":
349 end = line[0]
350 line = line[1:]
351 found = 0
352 tok = ""
353 while found == 0:
354 i = 0
355 l = len(line)
356 while i < l:
357 if line[i] == end:
358 self.line = line[i+1:]
359 line = line[:i]
360 l = i
361 found = 1
362 break
363 if line[i] == '\\':
364 i = i + 1
365 i = i + 1
366 tok = tok + line
367 if found == 0:
368 line = self.getline()
369 if line == None:
370 return None
371 self.last = ('string', tok)
372 return self.last
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000373
Daniel Veillardbe586972003-11-18 20:56:51 +0000374 if l >= 2 and line[0] == '/' and line[1] == '*':
375 line = line[2:]
376 found = 0
377 tok = ""
378 while found == 0:
379 i = 0
380 l = len(line)
381 while i < l:
382 if line[i] == '*' and i+1 < l and line[i+1] == '/':
383 self.line = line[i+2:]
384 line = line[:i-1]
385 l = i
386 found = 1
387 break
388 i = i + 1
389 if tok != "":
390 tok = tok + "\n"
391 tok = tok + line
392 if found == 0:
393 line = self.getline()
394 if line == None:
395 return None
396 self.last = ('comment', tok)
397 return self.last
398 if l >= 2 and line[0] == '/' and line[1] == '/':
399 line = line[2:]
400 self.last = ('comment', line)
401 return self.last
402 i = 0
403 while i < l:
404 if line[i] == '/' and i+1 < l and line[i+1] == '/':
405 self.line = line[i:]
406 line = line[:i]
407 break
408 if line[i] == '/' and i+1 < l and line[i+1] == '*':
409 self.line = line[i:]
410 line = line[:i]
411 break
412 if line[i] == '"' or line[i] == "'":
413 self.line = line[i:]
414 line = line[:i]
415 break
416 i = i + 1
417 l = len(line)
418 i = 0
419 while i < l:
420 if line[i] == ' ' or line[i] == '\t':
421 i = i + 1
422 continue
423 o = ord(line[i])
424 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
425 (o >= 48 and o <= 57):
426 s = i
427 while i < l:
428 o = ord(line[i])
429 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
430 (o >= 48 and o <= 57) or string.find(
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000431 " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1:
Daniel Veillardbe586972003-11-18 20:56:51 +0000432 i = i + 1
433 else:
434 break
435 self.tokens.append(('name', line[s:i]))
436 continue
437 if string.find("(){}:;,[]", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000438# if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
439# line[i] == '}' or line[i] == ':' or line[i] == ';' or \
440# line[i] == ',' or line[i] == '[' or line[i] == ']':
Daniel Veillardbe586972003-11-18 20:56:51 +0000441 self.tokens.append(('sep', line[i]))
442 i = i + 1
443 continue
444 if string.find("+-*><=/%&!|.", line[i]) != -1:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000445# if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
446# line[i] == '>' or line[i] == '<' or line[i] == '=' or \
447# line[i] == '/' or line[i] == '%' or line[i] == '&' or \
448# line[i] == '!' or line[i] == '|' or line[i] == '.':
Daniel Veillardbe586972003-11-18 20:56:51 +0000449 if line[i] == '.' and i + 2 < l and \
450 line[i+1] == '.' and line[i+2] == '.':
451 self.tokens.append(('name', '...'))
452 i = i + 3
453 continue
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000454
Daniel Veillardbe586972003-11-18 20:56:51 +0000455 j = i + 1
456 if j < l and (
457 string.find("+-*><=/%&!|", line[j]) != -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000458# line[j] == '+' or line[j] == '-' or line[j] == '*' or \
459# line[j] == '>' or line[j] == '<' or line[j] == '=' or \
460# line[j] == '/' or line[j] == '%' or line[j] == '&' or \
461# line[j] == '!' or line[j] == '|'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000462 self.tokens.append(('op', line[i:j+1]))
463 i = j + 1
464 else:
465 self.tokens.append(('op', line[i]))
466 i = i + 1
467 continue
468 s = i
469 while i < l:
470 o = ord(line[i])
471 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
472 (o >= 48 and o <= 57) or (
473 string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000474# line[i] != ' ' and line[i] != '\t' and
475# line[i] != '(' and line[i] != ')' and
476# line[i] != '{' and line[i] != '}' 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] != '<'):
Daniel Veillardbe586972003-11-18 20:56:51 +0000486 i = i + 1
487 else:
488 break
489 self.tokens.append(('name', line[s:i]))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000490
Daniel Veillardbe586972003-11-18 20:56:51 +0000491 tok = self.tokens[0]
492 self.tokens = self.tokens[1:]
493 self.last = tok
494 return tok
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000495
496class CParser:
Daniel Veillardbe586972003-11-18 20:56:51 +0000497 """The C module parser"""
498 def __init__(self, filename, idx = None):
499 self.filename = filename
500 if len(filename) > 2 and filename[-2:] == '.h':
501 self.is_header = 1
502 else:
503 self.is_header = 0
504 self.input = open(filename)
505 self.lexer = CLexer(self.input)
506 if idx == None:
507 self.index = index()
508 else:
509 self.index = idx
510 self.top_comment = ""
511 self.last_comment = ""
512 self.comment = None
513 self.collect_ref = 0
Daniel Veillard1e906612003-12-05 14:57:46 +0000514 self.no_error = 0
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000515
Daniel Veillardbe586972003-11-18 20:56:51 +0000516 def collect_references(self):
517 self.collect_ref = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000518
Daniel Veillard1e906612003-12-05 14:57:46 +0000519 def stop_error(self):
520 self.no_error = 1
521
522 def start_error(self):
523 self.no_error = 0
524
Daniel Veillardbe586972003-11-18 20:56:51 +0000525 def lineno(self):
526 return self.lexer.getlineno()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000527
Daniel Veillardbe586972003-11-18 20:56:51 +0000528 def index_add(self, name, module, static, type, info=None, extra = None):
529 self.index.add(name, module, static, type, self.lineno(),
530 info, extra)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000531
Daniel Veillardbe586972003-11-18 20:56:51 +0000532 def index_add_ref(self, name, module, static, type, info=None,
533 extra = None):
534 self.index.add_ref(name, module, static, type, self.lineno(),
535 info, extra)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000536
Daniel Veillard1e906612003-12-05 14:57:46 +0000537 def warning(self, msg):
538 if self.no_error:
539 return
540 print msg
541
Daniel Veillardbe586972003-11-18 20:56:51 +0000542 def error(self, msg, token=-1):
Daniel Veillard1e906612003-12-05 14:57:46 +0000543 if self.no_error:
544 return
545
Daniel Veillardbe586972003-11-18 20:56:51 +0000546 print "Parse Error: " + msg
547 if token != -1:
548 print "Got token ", token
549 self.lexer.debug()
550 sys.exit(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000551
Daniel Veillardbe586972003-11-18 20:56:51 +0000552 def debug(self, msg, token=-1):
553 print "Debug: " + msg
554 if token != -1:
555 print "Got token ", token
556 self.lexer.debug()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000557
Daniel Veillardbe586972003-11-18 20:56:51 +0000558 def parseTopComment(self, comment):
559 res = {}
560 lines = string.split(comment, "\n")
561 item = None
562 for line in lines:
563 while line != "" and (line[0] == ' ' or line[0] == '\t'):
564 line = line[1:]
565 while line != "" and line[0] == '*':
566 line = line[1:]
567 while line != "" and (line[0] == ' ' or line[0] == '\t'):
568 line = line[1:]
569 try:
570 (it, line) = string.split(line, ":", 1)
571 item = it
572 while line != "" and (line[0] == ' ' or line[0] == '\t'):
573 line = line[1:]
574 if res.has_key(item):
575 res[item] = res[item] + " " + line
576 else:
577 res[item] = line
578 except:
579 if item != None:
580 if res.has_key(item):
581 res[item] = res[item] + " " + line
582 else:
583 res[item] = line
584 self.index.info = res
585
586 def parseComment(self, token):
587 if self.top_comment == "":
588 self.top_comment = token[1]
589 if self.comment == None or token[1][0] == '*':
590 self.comment = token[1];
591 else:
592 self.comment = self.comment + token[1]
593 token = self.lexer.token()
Daniel Veillard1e906612003-12-05 14:57:46 +0000594
595 if string.find(self.comment, "DOC_DISABLE") != -1:
596 self.stop_error()
597
598 if string.find(self.comment, "DOC_ENABLE") != -1:
599 self.start_error()
600
Daniel Veillardbe586972003-11-18 20:56:51 +0000601 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000602
603 #
604 # Parse a comment block associate to a macro
605 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000606 def parseMacroComment(self, name, quiet = 0):
607 if name[0:2] == '__':
608 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000609
Daniel Veillardbe586972003-11-18 20:56:51 +0000610 args = []
611 desc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000612
Daniel Veillardbe586972003-11-18 20:56:51 +0000613 if self.comment == None:
614 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000615 self.warning("Missing comment for macro %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000616 return((args, desc))
617 if self.comment[0] != '*':
618 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000619 self.warning("Missing * in macro comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000620 return((args, desc))
621 lines = string.split(self.comment, '\n')
622 if lines[0] == '*':
623 del lines[0]
624 if lines[0] != "* %s:" % (name):
625 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000626 self.warning("Misformatted macro comment for %s" % (name))
627 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000628 return((args, desc))
629 del lines[0]
630 while lines[0] == '*':
631 del lines[0]
632 while len(lines) > 0 and lines[0][0:3] == '* @':
633 l = lines[0][3:]
634 try:
635 (arg, desc) = string.split(l, ':', 1)
636 desc=string.strip(desc)
637 arg=string.strip(arg)
638 except:
639 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000640 self.warning("Misformatted macro comment for %s" % (name))
641 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000642 del lines[0]
643 continue
644 del lines[0]
645 l = string.strip(lines[0])
646 while len(l) > 2 and l[0:3] != '* @':
647 while l[0] == '*':
648 l = l[1:]
649 desc = desc + ' ' + string.strip(l)
650 del lines[0]
651 if len(lines) == 0:
652 break
653 l = lines[0]
654 args.append((arg, desc))
655 while len(lines) > 0 and lines[0] == '*':
656 del lines[0]
657 desc = ""
658 while len(lines) > 0:
659 l = lines[0]
660 while len(l) > 0 and l[0] == '*':
661 l = l[1:]
662 l = string.strip(l)
663 desc = desc + " " + l
664 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000665
Daniel Veillardbe586972003-11-18 20:56:51 +0000666 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000667
Daniel Veillardbe586972003-11-18 20:56:51 +0000668 if quiet == 0:
669 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000670 self.warning("Macro comment for %s lack description of the macro" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000671
Daniel Veillardbe586972003-11-18 20:56:51 +0000672 return((args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000673
674 #
675 # Parse a comment block and merge the informations found in the
676 # parameters descriptions, finally returns a block as complete
677 # as possible
678 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000679 def mergeFunctionComment(self, name, description, quiet = 0):
680 if name == 'main':
681 quiet = 1
682 if name[0:2] == '__':
683 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000684
Daniel Veillardbe586972003-11-18 20:56:51 +0000685 (ret, args) = description
686 desc = ""
687 retdesc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000688
Daniel Veillardbe586972003-11-18 20:56:51 +0000689 if self.comment == None:
690 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000691 self.warning("Missing comment for function %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000692 return(((ret[0], retdesc), args, desc))
693 if self.comment[0] != '*':
694 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000695 self.warning("Missing * in function comment for %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000696 return(((ret[0], retdesc), args, desc))
697 lines = string.split(self.comment, '\n')
698 if lines[0] == '*':
699 del lines[0]
700 if lines[0] != "* %s:" % (name):
701 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000702 self.warning("Misformatted function comment for %s" % (name))
703 self.warning(" Expecting '* %s:' got '%s'" % (name, lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000704 return(((ret[0], retdesc), args, desc))
705 del lines[0]
706 while lines[0] == '*':
707 del lines[0]
708 nbargs = len(args)
709 while len(lines) > 0 and lines[0][0:3] == '* @':
710 l = lines[0][3:]
711 try:
712 (arg, desc) = string.split(l, ':', 1)
713 desc=string.strip(desc)
714 arg=string.strip(arg)
715 except:
716 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000717 self.warning("Misformatted function comment for %s" % (name))
718 self.warning(" problem with '%s'" % (lines[0]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000719 del lines[0]
720 continue
721 del lines[0]
722 l = string.strip(lines[0])
723 while len(l) > 2 and l[0:3] != '* @':
724 while l[0] == '*':
725 l = l[1:]
726 desc = desc + ' ' + string.strip(l)
727 del lines[0]
728 if len(lines) == 0:
729 break
730 l = lines[0]
731 i = 0
732 while i < nbargs:
733 if args[i][1] == arg:
734 args[i] = (args[i][0], arg, desc)
735 break;
736 i = i + 1
737 if i >= nbargs:
738 if not quiet:
Daniel Veillard1e906612003-12-05 14:57:46 +0000739 self.warning("Unable to find arg %s from function comment for %s" % (
740 arg, name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000741 while len(lines) > 0 and lines[0] == '*':
742 del lines[0]
743 desc = ""
744 while len(lines) > 0:
745 l = lines[0]
746 while len(l) > 0 and l[0] == '*':
747 l = l[1:]
748 l = string.strip(l)
749 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
750 try:
751 l = string.split(l, ' ', 1)[1]
752 except:
753 l = ""
754 retdesc = string.strip(l)
755 del lines[0]
756 while len(lines) > 0:
757 l = lines[0]
758 while len(l) > 0 and l[0] == '*':
759 l = l[1:]
760 l = string.strip(l)
761 retdesc = retdesc + " " + l
762 del lines[0]
763 else:
764 desc = desc + " " + l
765 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000766
Daniel Veillardbe586972003-11-18 20:56:51 +0000767 retdesc = string.strip(retdesc)
768 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000769
Daniel Veillardbe586972003-11-18 20:56:51 +0000770 if quiet == 0:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000771 #
772 # report missing comments
773 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000774 i = 0
775 while i < nbargs:
776 if args[i][2] == None and args[i][0] != "void" and args[i][1] != None:
Daniel Veillard1e906612003-12-05 14:57:46 +0000777 self.warning("Function comment for %s lack description of arg %s" % (name, args[i][1]))
Daniel Veillardbe586972003-11-18 20:56:51 +0000778 i = i + 1
779 if retdesc == "" and ret[0] != "void":
Daniel Veillard1e906612003-12-05 14:57:46 +0000780 self.warning("Function comment for %s lack description of return value" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +0000781 if desc == "":
Daniel Veillard1e906612003-12-05 14:57:46 +0000782 self.warning("Function comment for %s lack description of the function" % (name))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000783
784
Daniel Veillardbe586972003-11-18 20:56:51 +0000785 return(((ret[0], retdesc), args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000786
Daniel Veillardbe586972003-11-18 20:56:51 +0000787 def parsePreproc(self, token):
788 name = token[1]
789 if name == "#include":
790 token = self.lexer.token()
791 if token == None:
792 return None
793 if token[0] == 'preproc':
794 self.index_add(token[1], self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000795 "include")
Daniel Veillardbe586972003-11-18 20:56:51 +0000796 return self.lexer.token()
797 return token
798 if name == "#define":
799 token = self.lexer.token()
800 if token == None:
801 return None
802 if token[0] == 'preproc':
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000803 # TODO macros with arguments
Daniel Veillardbe586972003-11-18 20:56:51 +0000804 name = token[1]
805 lst = []
806 token = self.lexer.token()
807 while token != None and token[0] == 'preproc' and \
808 token[1][0] != '#':
809 lst.append(token[1])
810 token = self.lexer.token()
811 try:
812 name = string.split(name, '(') [0]
813 except:
814 pass
815 info = self.parseMacroComment(name, not self.is_header)
816 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000817 "macro", info)
Daniel Veillardbe586972003-11-18 20:56:51 +0000818 return token
819 token = self.lexer.token()
820 while token != None and token[0] == 'preproc' and \
821 token[1][0] != '#':
822 token = self.lexer.token()
823 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000824
825 #
826 # token acquisition on top of the lexer, it handle internally
827 # preprocessor and comments since they are logically not part of
828 # the program structure.
829 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000830 def token(self):
831 global ignored_words
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000832
Daniel Veillardbe586972003-11-18 20:56:51 +0000833 token = self.lexer.token()
834 while token != None:
835 if token[0] == 'comment':
836 token = self.parseComment(token)
837 continue
838 elif token[0] == 'preproc':
839 token = self.parsePreproc(token)
840 continue
841 elif token[0] == "name" and ignored_words.has_key(token[1]):
842 (n, info) = ignored_words[token[1]]
843 i = 0
844 while i < n:
845 token = self.lexer.token()
846 i = i + 1
847 token = self.lexer.token()
848 continue
849 else:
850 if debug:
851 print "=> ", token
852 return token
853 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000854
855 #
856 # Parse a typedef, it records the type and its name.
857 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000858 def parseTypedef(self, token):
859 if token == None:
860 return None
861 token = self.parseType(token)
862 if token == None:
863 self.error("parsing typedef")
864 return None
865 base_type = self.type
866 type = base_type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000867 #self.debug("end typedef type", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000868 while token != None:
869 if token[0] == "name":
870 name = token[1]
871 signature = self.signature
872 if signature != None:
873 type = string.split(type, '(')[0]
874 d = self.mergeFunctionComment(name,
875 ((type, None), signature), 1)
876 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000877 "functype", d)
Daniel Veillardbe586972003-11-18 20:56:51 +0000878 else:
879 if base_type == "struct":
880 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000881 "struct", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000882 base_type = "struct " + name
883 else:
884 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000885 "typedef", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000886 token = self.token()
887 else:
888 self.error("parsing typedef: expecting a name")
889 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000890 #self.debug("end typedef", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000891 if token != None and token[0] == 'sep' and token[1] == ',':
892 type = base_type
893 token = self.token()
894 while token != None and token[0] == "op":
895 type = type + token[1]
896 token = self.token()
897 elif token != None and token[0] == 'sep' and token[1] == ';':
898 break;
899 elif token != None and token[0] == 'name':
900 type = base_type
901 continue;
902 else:
903 self.error("parsing typedef: expecting ';'", token)
904 return token
905 token = self.token()
906 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000907
908 #
909 # Parse a C code block, used for functions it parse till
910 # the balancing } included
911 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000912 def parseBlock(self, token):
913 while token != None:
914 if token[0] == "sep" and token[1] == "{":
915 token = self.token()
916 token = self.parseBlock(token)
917 elif token[0] == "sep" and token[1] == "}":
918 self.comment = None
919 token = self.token()
920 return token
921 else:
922 if self.collect_ref == 1:
923 oldtok = token
924 token = self.token()
925 if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
926 if token[0] == "sep" and token[1] == "(":
927 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000928 0, "function")
Daniel Veillardbe586972003-11-18 20:56:51 +0000929 token = self.token()
930 elif token[0] == "name":
931 token = self.token()
932 if token[0] == "sep" and (token[1] == ";" or
933 token[1] == "," or token[1] == "="):
934 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000935 0, "type")
Daniel Veillardbe586972003-11-18 20:56:51 +0000936 elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
937 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000938 0, "typedef")
Daniel Veillardbe586972003-11-18 20:56:51 +0000939 elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
940 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000941 0, "typedef")
942
Daniel Veillardbe586972003-11-18 20:56:51 +0000943 else:
944 token = self.token()
945 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000946
947 #
948 # Parse a C struct definition till the balancing }
949 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000950 def parseStruct(self, token):
951 fields = []
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000952 #self.debug("start parseStruct", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000953 while token != None:
954 if token[0] == "sep" and token[1] == "{":
955 token = self.token()
956 token = self.parseTypeBlock(token)
957 elif token[0] == "sep" and token[1] == "}":
958 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000959 #self.debug("end parseStruct", token)
960 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +0000961 token = self.token()
962 return token
963 else:
964 base_type = self.type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000965 #self.debug("before parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000966 token = self.parseType(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000967 #self.debug("after parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000968 if token != None and token[0] == "name":
969 fname = token[1]
970 token = self.token()
971 if token[0] == "sep" and token[1] == ";":
972 self.comment = None
973 token = self.token()
974 fields.append((self.type, fname, self.comment))
975 self.comment = None
976 else:
977 self.error("parseStruct: expecting ;", token)
978 elif token != None and token[0] == "sep" and token[1] == "{":
979 token = self.token()
980 token = self.parseTypeBlock(token)
981 if token != None and token[0] == "name":
982 token = self.token()
983 if token != None and token[0] == "sep" and token[1] == ";":
984 token = self.token()
985 else:
986 self.error("parseStruct: expecting ;", token)
987 else:
988 self.error("parseStruct: name", token)
989 token = self.token()
990 self.type = base_type;
991 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000992 #self.debug("end parseStruct", token)
993 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +0000994 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000995
996 #
997 # Parse a C enum block, parse till the balancing }
998 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000999 def parseEnumBlock(self, token):
1000 self.enums = []
1001 name = None
1002 self.comment = None
1003 comment = ""
1004 value = "0"
1005 while token != None:
1006 if token[0] == "sep" and token[1] == "{":
1007 token = self.token()
1008 token = self.parseTypeBlock(token)
1009 elif token[0] == "sep" and token[1] == "}":
1010 if name != None:
1011 if self.comment != None:
1012 comment = self.comment
1013 self.comment = None
1014 self.enums.append((name, value, comment))
1015 token = self.token()
1016 return token
1017 elif token[0] == "name":
1018 if name != None:
1019 if self.comment != None:
1020 comment = string.strip(self.comment)
1021 self.comment = None
1022 self.enums.append((name, value, comment))
1023 name = token[1]
1024 comment = ""
1025 token = self.token()
1026 if token[0] == "op" and token[1][0] == "=":
1027 value = ""
1028 if len(token[1]) > 1:
1029 value = token[1][1:]
1030 token = self.token()
1031 while token[0] != "sep" or (token[1] != ',' and
1032 token[1] != '}'):
1033 value = value + token[1]
1034 token = self.token()
1035 else:
1036 try:
1037 value = "%d" % (int(value) + 1)
1038 except:
Daniel Veillard1e906612003-12-05 14:57:46 +00001039 self.warning("Failed to compute value of enum %s" % (name))
Daniel Veillardbe586972003-11-18 20:56:51 +00001040 value=""
1041 if token[0] == "sep" and token[1] == ",":
1042 token = self.token()
1043 else:
1044 token = self.token()
1045 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001046
1047 #
1048 # Parse a C definition block, used for structs it parse till
1049 # the balancing }
1050 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001051 def parseTypeBlock(self, token):
1052 while token != None:
1053 if token[0] == "sep" and token[1] == "{":
1054 token = self.token()
1055 token = self.parseTypeBlock(token)
1056 elif token[0] == "sep" and token[1] == "}":
1057 token = self.token()
1058 return token
1059 else:
1060 token = self.token()
1061 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001062
1063 #
1064 # Parse a type: the fact that the type name can either occur after
1065 # the definition or within the definition makes it a little harder
1066 # if inside, the name token is pushed back before returning
1067 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001068 def parseType(self, token):
1069 self.type = ""
1070 self.struct_fields = []
1071 self.signature = None
1072 if token == None:
1073 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001074
Daniel Veillardbe586972003-11-18 20:56:51 +00001075 while token[0] == "name" and (
1076 token[1] == "const" or token[1] == "unsigned"):
1077 if self.type == "":
1078 self.type = token[1]
1079 else:
1080 self.type = self.type + " " + token[1]
1081 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001082
Daniel Veillardbe586972003-11-18 20:56:51 +00001083 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1084 if self.type == "":
1085 self.type = token[1]
1086 else:
1087 self.type = self.type + " " + token[1]
1088 if token[0] == "name" and token[1] == "int":
1089 if self.type == "":
1090 self.type = tmp[1]
1091 else:
1092 self.type = self.type + " " + tmp[1]
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001093
Daniel Veillardbe586972003-11-18 20:56:51 +00001094 elif token[0] == "name" and token[1] == "struct":
1095 if self.type == "":
1096 self.type = token[1]
1097 else:
1098 self.type = self.type + " " + token[1]
1099 token = self.token()
1100 nametok = None
1101 if token[0] == "name":
1102 nametok = token
1103 token = self.token()
1104 if token != None and token[0] == "sep" and token[1] == "{":
1105 token = self.token()
1106 token = self.parseStruct(token)
1107 elif token != None and token[0] == "op" and token[1] == "*":
1108 self.type = self.type + " " + nametok[1] + " *"
1109 token = self.token()
1110 while token != None and token[0] == "op" and token[1] == "*":
1111 self.type = self.type + " *"
1112 token = self.token()
1113 if token[0] == "name":
1114 nametok = token
1115 token = self.token()
1116 else:
1117 self.error("struct : expecting name", token)
1118 return token
1119 elif token != None and token[0] == "name" and nametok != None:
1120 self.type = self.type + " " + nametok[1]
1121 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001122
Daniel Veillardbe586972003-11-18 20:56:51 +00001123 if nametok != None:
1124 self.lexer.push(token)
1125 token = nametok
1126 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001127
Daniel Veillardbe586972003-11-18 20:56:51 +00001128 elif token[0] == "name" and token[1] == "enum":
1129 if self.type == "":
1130 self.type = token[1]
1131 else:
1132 self.type = self.type + " " + token[1]
1133 self.enums = []
1134 token = self.token()
1135 if token != None and token[0] == "sep" and token[1] == "{":
1136 token = self.token()
1137 token = self.parseEnumBlock(token)
1138 else:
1139 self.error("parsing enum: expecting '{'", token)
1140 enum_type = None
1141 if token != None and token[0] != "name":
1142 self.lexer.push(token)
1143 token = ("name", "enum")
1144 else:
1145 enum_type = token[1]
1146 for enum in self.enums:
1147 self.index_add(enum[0], self.filename,
1148 not self.is_header, "enum",
1149 (enum[1], enum[2], enum_type))
1150 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001151
Daniel Veillardbe586972003-11-18 20:56:51 +00001152 elif token[0] == "name":
1153 if self.type == "":
1154 self.type = token[1]
1155 else:
1156 self.type = self.type + " " + token[1]
1157 else:
1158 self.error("parsing type %s: expecting a name" % (self.type),
1159 token)
1160 return token
1161 token = self.token()
1162 while token != None and (token[0] == "op" or
1163 token[0] == "name" and token[1] == "const"):
1164 self.type = self.type + " " + token[1]
1165 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001166
1167 #
1168 # if there is a parenthesis here, this means a function type
1169 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001170 if token != None and token[0] == "sep" and token[1] == '(':
1171 self.type = self.type + token[1]
1172 token = self.token()
1173 while token != None and token[0] == "op" and token[1] == '*':
1174 self.type = self.type + token[1]
1175 token = self.token()
1176 if token == None or token[0] != "name" :
1177 self.error("parsing function type, name expected", token);
1178 return token
1179 self.type = self.type + token[1]
1180 nametok = token
1181 token = self.token()
1182 if token != None and token[0] == "sep" and token[1] == ')':
1183 self.type = self.type + token[1]
1184 token = self.token()
1185 if token != None and token[0] == "sep" and token[1] == '(':
1186 token = self.token()
1187 type = self.type;
1188 token = self.parseSignature(token);
1189 self.type = type;
1190 else:
1191 self.error("parsing function type, '(' expected", token);
1192 return token
1193 else:
1194 self.error("parsing function type, ')' expected", token);
1195 return token
1196 self.lexer.push(token)
1197 token = nametok
1198 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001199
1200 #
1201 # do some lookahead for arrays
1202 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001203 if token != None and token[0] == "name":
1204 nametok = token
1205 token = self.token()
1206 if token != None and token[0] == "sep" and token[1] == '[':
1207 self.type = self.type + nametok[1]
1208 while token != None and token[0] == "sep" and token[1] == '[':
1209 self.type = self.type + token[1]
1210 token = self.token()
1211 while token != None and token[0] != 'sep' and \
1212 token[1] != ']' and token[1] != ';':
1213 self.type = self.type + token[1]
1214 token = self.token()
1215 if token != None and token[0] == 'sep' and token[1] == ']':
1216 self.type = self.type + token[1]
1217 token = self.token()
1218 else:
1219 self.error("parsing array type, ']' expected", token);
1220 return token
1221 elif token != None and token[0] == "sep" and token[1] == ':':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001222 # remove :12 in case it's a limited int size
Daniel Veillardbe586972003-11-18 20:56:51 +00001223 token = self.token()
1224 token = self.token()
1225 self.lexer.push(token)
1226 token = nametok
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001227
Daniel Veillardbe586972003-11-18 20:56:51 +00001228 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001229
1230 #
1231 # Parse a signature: '(' has been parsed and we scan the type definition
1232 # up to the ')' included
Daniel Veillardbe586972003-11-18 20:56:51 +00001233 def parseSignature(self, token):
1234 signature = []
1235 if token != None and token[0] == "sep" and token[1] == ')':
1236 self.signature = []
1237 token = self.token()
1238 return token
1239 while token != None:
1240 token = self.parseType(token)
1241 if token != None and token[0] == "name":
1242 signature.append((self.type, token[1], None))
1243 token = self.token()
1244 elif token != None and token[0] == "sep" and token[1] == ',':
1245 token = self.token()
1246 continue
1247 elif token != None and token[0] == "sep" and token[1] == ')':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001248 # only the type was provided
Daniel Veillardbe586972003-11-18 20:56:51 +00001249 if self.type == "...":
1250 signature.append((self.type, "...", None))
1251 else:
1252 signature.append((self.type, None, None))
1253 if token != None and token[0] == "sep":
1254 if token[1] == ',':
1255 token = self.token()
1256 continue
1257 elif token[1] == ')':
1258 token = self.token()
1259 break
1260 self.signature = signature
1261 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001262
1263 #
1264 # Parse a global definition, be it a type, variable or function
1265 # the extern "C" blocks are a bit nasty and require it to recurse.
1266 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001267 def parseGlobal(self, token):
1268 static = 0
1269 if token[1] == 'extern':
1270 token = self.token()
1271 if token == None:
1272 return token
1273 if token[0] == 'string':
1274 if token[1] == 'C':
1275 token = self.token()
1276 if token == None:
1277 return token
1278 if token[0] == 'sep' and token[1] == "{":
1279 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001280# print 'Entering extern "C line ', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001281 while token != None and (token[0] != 'sep' or
1282 token[1] != "}"):
1283 if token[0] == 'name':
1284 token = self.parseGlobal(token)
1285 else:
1286 self.error(
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001287 "token %s %s unexpected at the top level" % (
1288 token[0], token[1]))
Daniel Veillardbe586972003-11-18 20:56:51 +00001289 token = self.parseGlobal(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001290# print 'Exiting extern "C" line', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001291 token = self.token()
1292 return token
1293 else:
1294 return token
1295 elif token[1] == 'static':
1296 static = 1
1297 token = self.token()
1298 if token == None or token[0] != 'name':
1299 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001300
Daniel Veillardbe586972003-11-18 20:56:51 +00001301 if token[1] == 'typedef':
1302 token = self.token()
1303 return self.parseTypedef(token)
1304 else:
1305 token = self.parseType(token)
1306 type_orig = self.type
1307 if token == None or token[0] != "name":
1308 return token
1309 type = type_orig
1310 self.name = token[1]
1311 token = self.token()
1312 while token != None and (token[0] == "sep" or token[0] == "op"):
1313 if token[0] == "sep":
1314 if token[1] == "[":
1315 type = type + token[1]
1316 token = self.token()
1317 while token != None and (token[0] != "sep" or \
1318 token[1] != ";"):
1319 type = type + token[1]
1320 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001321
Daniel Veillardbe586972003-11-18 20:56:51 +00001322 if token != None and token[0] == "op" and token[1] == "=":
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001323 #
1324 # Skip the initialization of the variable
1325 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001326 token = self.token()
1327 if token[0] == 'sep' and token[1] == '{':
1328 token = self.token()
1329 token = self.parseBlock(token)
1330 else:
1331 self.comment = None
1332 while token != None and (token[0] != "sep" or \
1333 (token[1] != ';' and token[1] != ',')):
1334 token = self.token()
1335 self.comment = None
1336 if token == None or token[0] != "sep" or (token[1] != ';' and
1337 token[1] != ','):
1338 self.error("missing ';' or ',' after value")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001339
Daniel Veillardbe586972003-11-18 20:56:51 +00001340 if token != None and token[0] == "sep":
1341 if token[1] == ";":
1342 self.comment = None
1343 token = self.token()
1344 if type == "struct":
1345 self.index_add(self.name, self.filename,
1346 not self.is_header, "struct", self.struct_fields)
1347 else:
1348 self.index_add(self.name, self.filename,
1349 not self.is_header, "variable", type)
1350 break
1351 elif token[1] == "(":
1352 token = self.token()
1353 token = self.parseSignature(token)
1354 if token == None:
1355 return None
1356 if token[0] == "sep" and token[1] == ";":
1357 d = self.mergeFunctionComment(self.name,
1358 ((type, None), self.signature), 1)
1359 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001360 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001361 token = self.token()
1362 elif token[0] == "sep" and token[1] == "{":
1363 d = self.mergeFunctionComment(self.name,
1364 ((type, None), self.signature), static)
1365 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001366 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001367 token = self.token()
1368 token = self.parseBlock(token);
1369 elif token[1] == ',':
1370 self.comment = None
1371 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001372 "variable", type)
Daniel Veillardbe586972003-11-18 20:56:51 +00001373 type = type_orig
1374 token = self.token()
1375 while token != None and token[0] == "sep":
1376 type = type + token[1]
1377 token = self.token()
1378 if token != None and token[0] == "name":
1379 self.name = token[1]
1380 token = self.token()
1381 else:
1382 break
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001383
Daniel Veillardbe586972003-11-18 20:56:51 +00001384 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001385
Daniel Veillardbe586972003-11-18 20:56:51 +00001386 def parse(self):
Daniel Veillard1e906612003-12-05 14:57:46 +00001387 self.warning("Parsing %s" % (self.filename))
Daniel Veillardbe586972003-11-18 20:56:51 +00001388 token = self.token()
1389 while token != None:
1390 if token[0] == 'name':
1391 token = self.parseGlobal(token)
1392 else:
1393 self.error("token %s %s unexpected at the top level" % (
1394 token[0], token[1]))
1395 token = self.parseGlobal(token)
1396 return
1397 self.parseTopComment(self.top_comment)
1398 return self.index
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001399
1400
1401class docBuilder:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001402 """A documentation builder"""
1403 def __init__(self, name, directories=['.'], excludes=[]):
1404 self.name = name
1405 self.directories = directories
1406 self.excludes = excludes + ignored_files.keys()
1407 self.modules = {}
1408 self.headers = {}
1409 self.idx = index()
1410 self.xref = {}
1411 self.index = {}
1412 if name == 'libxml2':
1413 self.basename = 'libxml'
1414 else:
1415 self.basename = name
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001416
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001417 def indexString(self, id, str):
1418 if str == None:
1419 return
1420 str = string.replace(str, "'", ' ')
1421 str = string.replace(str, '"', ' ')
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 tokens = string.split(str)
1436 for token in tokens:
1437 try:
1438 c = token[0]
1439 if string.find(string.letters, c) < 0:
1440 pass
1441 elif len(token) < 3:
1442 pass
1443 else:
1444 lower = string.lower(token)
1445 # TODO: generalize this a bit
1446 if lower == 'and' or lower == 'the':
1447 pass
1448 elif self.xref.has_key(token):
1449 self.xref[token].append(id)
1450 else:
1451 self.xref[token] = [id]
1452 except:
1453 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001454
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001455 def analyze(self):
1456 print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
1457 self.idx.analyze()
1458
1459 def scanHeaders(self):
1460 for header in self.headers.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001461 parser = CParser(header)
1462 idx = parser.parse()
1463 self.headers[header] = idx;
1464 self.idx.merge(idx)
1465
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001466 def scanModules(self):
1467 for module in self.modules.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001468 parser = CParser(module)
1469 idx = parser.parse()
1470 # idx.analyze()
1471 self.modules[module] = idx
1472 self.idx.merge_public(idx)
1473
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001474 def scan(self):
1475 for directory in self.directories:
1476 files = glob.glob(directory + "/*.c")
1477 for file in files:
1478 skip = 0
1479 for excl in self.excludes:
1480 if string.find(file, excl) != -1:
1481 skip = 1;
1482 break
1483 if skip == 0:
1484 self.modules[file] = None;
1485 files = glob.glob(directory + "/*.h")
1486 for file in files:
1487 skip = 0
1488 for excl in self.excludes:
1489 if string.find(file, excl) != -1:
1490 skip = 1;
1491 break
1492 if skip == 0:
1493 self.headers[file] = None;
1494 self.scanHeaders()
1495 self.scanModules()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001496
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001497 def modulename_file(self, file):
1498 module = os.path.basename(file)
1499 if module[-2:] == '.h':
1500 module = module[:-2]
1501 return module
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001502
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001503 def serialize_enum(self, output, name):
1504 id = self.idx.enums[name]
1505 output.write(" <enum name='%s' file='%s'" % (name,
1506 self.modulename_file(id.module)))
1507 if id.info != None:
1508 info = id.info
1509 if info[0] != None and info[0] != '':
1510 try:
1511 val = eval(info[0])
1512 except:
1513 val = info[0]
1514 output.write(" value='%s'" % (val));
1515 if info[2] != None and info[2] != '':
1516 output.write(" type='%s'" % info[2]);
1517 if info[1] != None and info[1] != '':
1518 output.write(" info='%s'" % escape(info[1]));
1519 output.write("/>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001520
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001521 def serialize_macro(self, output, name):
1522 id = self.idx.macros[name]
1523 output.write(" <macro name='%s' file='%s'>\n" % (name,
1524 self.modulename_file(id.module)))
1525 if id.info != None:
1526 try:
1527 (args, desc) = id.info
1528 if desc != None and desc != "":
1529 output.write(" <info>%s</info>\n" % (escape(desc)))
1530 self.indexString(name, desc)
1531 for arg in args:
1532 (name, desc) = arg
1533 if desc != None and desc != "":
1534 output.write(" <arg name='%s' info='%s'/>\n" % (
1535 name, escape(desc)))
1536 self.indexString(name, desc)
1537 else:
1538 output.write(" <arg name='%s'/>\n" % (name))
1539 except:
1540 pass
1541 output.write(" </macro>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001542
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001543 def serialize_typedef(self, output, name):
1544 id = self.idx.typedefs[name]
1545 if id.info[0:7] == 'struct ':
1546 output.write(" <struct name='%s' file='%s' type='%s'" % (
1547 name, self.modulename_file(id.module), id.info))
1548 name = id.info[7:]
1549 if self.idx.structs.has_key(name) and ( \
1550 type(self.idx.structs[name].info) == type(()) or
Daniel Veillardc1eed322002-12-12 11:01:32 +00001551 type(self.idx.structs[name].info) == type([])):
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001552 output.write(">\n");
1553 try:
1554 for field in self.idx.structs[name].info:
1555 desc = field[2]
1556 self.indexString(name, desc)
1557 if desc == None:
1558 desc = ''
1559 else:
1560 desc = escape(desc)
1561 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1562 except:
1563 print "Failed to serialize struct %s" % (name)
1564 output.write(" </struct>\n")
1565 else:
1566 output.write("/>\n");
1567 else :
1568 output.write(" <typedef name='%s' file='%s' type='%s'/>\n" % (
1569 name, self.modulename_file(id.module), id.info))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001570
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001571 def serialize_variable(self, output, name):
1572 id = self.idx.variables[name]
1573 if id.info != None:
1574 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1575 name, self.modulename_file(id.module), id.info))
1576 else:
1577 output.write(" <variable name='%s' file='%s'/>\n" % (
1578 name, self.modulename_file(id.module)))
Daniel Veillardc1eed322002-12-12 11:01:32 +00001579
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001580 def serialize_function(self, output, name):
1581 id = self.idx.functions[name]
1582 output.write(" <%s name='%s' file='%s'>\n" % (id.type, name,
1583 self.modulename_file(id.module)))
1584 try:
1585 (ret, params, desc) = id.info
1586 output.write(" <info>%s</info>\n" % (escape(desc)))
1587 self.indexString(name, desc)
1588 if ret[0] != None:
1589 if ret[0] == "void":
1590 output.write(" <return type='void'/>\n")
1591 else:
1592 output.write(" <return type='%s' info='%s'/>\n" % (
1593 ret[0], escape(ret[1])))
1594 self.indexString(name, ret[1])
1595 for param in params:
1596 if param[0] == 'void':
1597 continue
1598 if param[2] == None:
1599 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1600 else:
1601 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1602 self.indexString(name, param[2])
1603 except:
1604 print "Failed to save function %s info: " % name, `id.info`
1605 output.write(" </%s>\n" % (id.type))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001606
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001607 def serialize_exports(self, output, file):
1608 module = self.modulename_file(file)
1609 output.write(" <file name='%s'>\n" % (module))
1610 dict = self.headers[file]
Daniel Veillardbe586972003-11-18 20:56:51 +00001611 if dict.info != None:
1612 for data in ('Summary', 'Description', 'Author'):
1613 try:
1614 output.write(" <%s>%s</%s>\n" % (
1615 string.lower(data),
1616 escape(dict.info[data]),
1617 string.lower(data)))
1618 except:
1619 print "Header %s lacks a %s description" % (module, data)
1620 if dict.info.has_key('Description'):
1621 desc = dict.info['Description']
1622 if string.find(desc, "DEPRECATED") != -1:
1623 output.write(" <deprecated/>\n")
1624
Daniel Veillard1a792412003-11-18 23:52:38 +00001625 ids = dict.macros.keys()
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001626 ids.sort()
1627 for id in uniq(ids):
Daniel Veillard1a792412003-11-18 23:52:38 +00001628 # Macros are sometime used to masquerade other types.
1629 if dict.functions.has_key(id):
1630 continue
1631 if dict.variables.has_key(id):
1632 continue
1633 if dict.typedefs.has_key(id):
1634 continue
1635 if dict.structs.has_key(id):
1636 continue
1637 if dict.enums.has_key(id):
1638 continue
1639 output.write(" <exports symbol='%s' type='macro'/>\n" % (id))
1640 ids = dict.enums.keys()
1641 ids.sort()
1642 for id in uniq(ids):
1643 output.write(" <exports symbol='%s' type='enum'/>\n" % (id))
1644 ids = dict.typedefs.keys()
1645 ids.sort()
1646 for id in uniq(ids):
1647 output.write(" <exports symbol='%s' type='typedef'/>\n" % (id))
1648 ids = dict.structs.keys()
1649 ids.sort()
1650 for id in uniq(ids):
1651 output.write(" <exports symbol='%s' type='struct'/>\n" % (id))
1652 ids = dict.variables.keys()
1653 ids.sort()
1654 for id in uniq(ids):
1655 output.write(" <exports symbol='%s' type='variable'/>\n" % (id))
1656 ids = dict.functions.keys()
1657 ids.sort()
1658 for id in uniq(ids):
1659 output.write(" <exports symbol='%s' type='function'/>\n" % (id))
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001660 output.write(" </file>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001661
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001662 def serialize_xrefs_files(self, output):
1663 headers = self.headers.keys()
1664 headers.sort()
1665 for file in headers:
1666 module = self.modulename_file(file)
1667 output.write(" <file name='%s'>\n" % (module))
1668 dict = self.headers[file]
1669 ids = dict.functions.keys() + dict.variables.keys() + \
1670 dict.macros.keys() + dict.typedefs.keys() + \
1671 dict.structs.keys() + dict.enums.keys()
1672 ids.sort()
1673 for id in uniq(ids):
1674 output.write(" <ref name='%s'/>\n" % (id))
1675 output.write(" </file>\n")
1676 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001677
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001678 def serialize_xrefs_functions(self, output):
1679 funcs = {}
1680 for name in self.idx.functions.keys():
1681 id = self.idx.functions[name]
1682 try:
1683 (ret, params, desc) = id.info
1684 for param in params:
1685 if param[0] == 'void':
1686 continue
1687 if funcs.has_key(param[0]):
1688 funcs[param[0]].append(name)
1689 else:
1690 funcs[param[0]] = [name]
1691 except:
1692 pass
1693 typ = funcs.keys()
1694 typ.sort()
1695 for type in typ:
1696 if type == '' or type == 'void' or type == "int" or \
1697 type == "char *" or type == "const char *" :
1698 continue
1699 output.write(" <type name='%s'>\n" % (type))
1700 ids = funcs[type]
1701 ids.sort()
William M. Brackcf9eadf2003-12-25 13:24:05 +00001702 pid = '' # not sure why we have dups, but get rid of them!
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001703 for id in ids:
William M. Brackcf9eadf2003-12-25 13:24:05 +00001704 if id != pid:
1705 output.write(" <ref name='%s'/>\n" % (id))
1706 pid = id
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001707 output.write(" </type>\n")
1708
1709 def serialize_xrefs_constructors(self, output):
1710 funcs = {}
1711 for name in self.idx.functions.keys():
1712 id = self.idx.functions[name]
1713 try:
1714 (ret, params, desc) = id.info
1715 if ret[0] == "void":
1716 continue
1717 if funcs.has_key(ret[0]):
1718 funcs[ret[0]].append(name)
1719 else:
1720 funcs[ret[0]] = [name]
1721 except:
1722 pass
1723 typ = funcs.keys()
1724 typ.sort()
1725 for type in typ:
1726 if type == '' or type == 'void' or type == "int" or \
1727 type == "char *" or type == "const char *" :
1728 continue
1729 output.write(" <type name='%s'>\n" % (type))
1730 ids = funcs[type]
1731 for id in ids:
1732 output.write(" <ref name='%s'/>\n" % (id))
1733 output.write(" </type>\n")
1734
1735 def serialize_xrefs_alpha(self, output):
1736 letter = None
1737 ids = self.idx.identifiers.keys()
1738 ids.sort()
1739 for id in ids:
1740 if id[0] != letter:
1741 if letter != None:
1742 output.write(" </letter>\n")
1743 letter = id[0]
1744 output.write(" <letter name='%s'>\n" % (letter))
1745 output.write(" <ref name='%s'/>\n" % (id))
1746 if letter != None:
1747 output.write(" </letter>\n")
1748
1749 def serialize_xrefs_references(self, output):
1750 typ = self.idx.identifiers.keys()
1751 typ.sort()
1752 for id in typ:
1753 idf = self.idx.identifiers[id]
1754 module = idf.module
1755 output.write(" <reference name='%s' href='%s'/>\n" % (id,
1756 'html/' + self.basename + '-' +
1757 self.modulename_file(module) + '.html#' +
1758 id))
1759
1760 def serialize_xrefs_index(self, output):
1761 index = self.xref
1762 typ = index.keys()
1763 typ.sort()
1764 letter = None
1765 count = 0
1766 chunk = 0
1767 chunks = []
1768 for id in typ:
1769 if len(index[id]) > 30:
1770 continue
1771 if id[0] != letter:
1772 if letter == None or count > 200:
1773 if letter != None:
1774 output.write(" </letter>\n")
1775 output.write(" </chunk>\n")
1776 count = 0
1777 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
1778 output.write(" <chunk name='chunk%s'>\n" % (chunk))
1779 first_letter = id[0]
1780 chunk = chunk + 1
1781 elif letter != None:
1782 output.write(" </letter>\n")
1783 letter = id[0]
1784 output.write(" <letter name='%s'>\n" % (letter))
1785 output.write(" <word name='%s'>\n" % (id))
1786 tokens = index[id];
1787 tokens.sort()
1788 tok = None
1789 for token in index[id]:
1790 if tok == token:
1791 continue
1792 tok = token
1793 output.write(" <ref name='%s'/>\n" % (token))
1794 count = count + 1
1795 output.write(" </word>\n")
1796 if letter != None:
1797 output.write(" </letter>\n")
1798 output.write(" </chunk>\n")
William M. Brack966668a2003-12-20 02:10:28 +00001799 if count != 0:
1800 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001801 output.write(" <chunks>\n")
1802 for ch in chunks:
1803 output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
1804 ch[0], ch[1], ch[2]))
1805 output.write(" </chunks>\n")
1806
1807 def serialize_xrefs(self, output):
1808 output.write(" <references>\n")
1809 self.serialize_xrefs_references(output)
1810 output.write(" </references>\n")
1811 output.write(" <alpha>\n")
1812 self.serialize_xrefs_alpha(output)
1813 output.write(" </alpha>\n")
1814 output.write(" <constructors>\n")
1815 self.serialize_xrefs_constructors(output)
1816 output.write(" </constructors>\n")
1817 output.write(" <functions>\n")
1818 self.serialize_xrefs_functions(output)
1819 output.write(" </functions>\n")
1820 output.write(" <files>\n")
1821 self.serialize_xrefs_files(output)
1822 output.write(" </files>\n")
1823 output.write(" <index>\n")
1824 self.serialize_xrefs_index(output)
1825 output.write(" </index>\n")
1826
1827 def serialize(self):
1828 filename = "%s-api.xml" % self.name
1829 print "Saving XML description %s" % (filename)
1830 output = open(filename, "w")
1831 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1832 output.write("<api name='%s'>\n" % self.name)
1833 output.write(" <files>\n")
1834 headers = self.headers.keys()
1835 headers.sort()
1836 for file in headers:
1837 self.serialize_exports(output, file)
1838 output.write(" </files>\n")
1839 output.write(" <symbols>\n")
1840 macros = self.idx.macros.keys()
1841 macros.sort()
1842 for macro in macros:
1843 self.serialize_macro(output, macro)
1844 enums = self.idx.enums.keys()
1845 enums.sort()
1846 for enum in enums:
1847 self.serialize_enum(output, enum)
1848 typedefs = self.idx.typedefs.keys()
1849 typedefs.sort()
1850 for typedef in typedefs:
1851 self.serialize_typedef(output, typedef)
1852 variables = self.idx.variables.keys()
1853 variables.sort()
1854 for variable in variables:
1855 self.serialize_variable(output, variable)
1856 functions = self.idx.functions.keys()
1857 functions.sort()
1858 for function in functions:
1859 self.serialize_function(output, function)
1860 output.write(" </symbols>\n")
1861 output.write("</api>\n")
1862 output.close()
1863
1864 filename = "%s-refs.xml" % self.name
1865 print "Saving XML Cross References %s" % (filename)
1866 output = open(filename, "w")
1867 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1868 output.write("<apirefs name='%s'>\n" % self.name)
1869 self.serialize_xrefs(output)
1870 output.write("</apirefs>\n")
1871 output.close()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001872
1873
1874def rebuild():
1875 builder = None
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001876 if glob.glob("parser.c") != [] :
1877 print "Rebuilding API description for libxml2"
1878 builder = docBuilder("libxml2", [".", "."],
1879 ["xmlwin32version.h", "tst.c"])
1880 elif glob.glob("../parser.c") != [] :
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001881 print "Rebuilding API description for libxml2"
1882 builder = docBuilder("libxml2", ["..", "../include/libxml"],
Daniel Veillardd4330462003-04-29 12:40:16 +00001883 ["xmlwin32version.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001884 elif glob.glob("../libxslt/transform.c") != [] :
1885 print "Rebuilding API description for libxslt"
1886 builder = docBuilder("libxslt", ["../libxslt"],
Daniel Veillard024b5702002-12-12 00:15:55 +00001887 ["win32config.h", "libxslt.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001888 else:
1889 print "rebuild() failed, unable to guess the module"
1890 return None
1891 builder.scan()
1892 builder.analyze()
1893 builder.serialize()
Daniel Veillard024b5702002-12-12 00:15:55 +00001894 if glob.glob("../libexslt/exslt.c") != [] :
1895 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1896 extra.scan()
1897 extra.analyze()
1898 extra.serialize()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001899 return builder
1900
1901#
1902# for debugging the parser
1903#
1904def parse(filename):
1905 parser = CParser(filename)
1906 idx = parser.parse()
1907 return idx
1908
1909if __name__ == "__main__":
1910 rebuild()