blob: 57a205f4e2a583b8bac0b2934b11b1970ebfa5bb [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 Veillardfc8dc352003-10-18 09:07:46 +000030 "pattern.c": "not integrated yet",
31 "pattern.h": "not integrated yet",
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 Veillardd8cf9062003-11-11 21:12:36 +0000516
Daniel Veillardbe586972003-11-18 20:56:51 +0000517 def collect_references(self):
518 self.collect_ref = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000519
Daniel Veillardbe586972003-11-18 20:56:51 +0000520 def lineno(self):
521 return self.lexer.getlineno()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000522
Daniel Veillardbe586972003-11-18 20:56:51 +0000523 def index_add(self, name, module, static, type, info=None, extra = None):
524 self.index.add(name, module, static, type, self.lineno(),
525 info, extra)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000526
Daniel Veillardbe586972003-11-18 20:56:51 +0000527 def index_add_ref(self, name, module, static, type, info=None,
528 extra = None):
529 self.index.add_ref(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 error(self, msg, token=-1):
533 print "Parse Error: " + msg
534 if token != -1:
535 print "Got token ", token
536 self.lexer.debug()
537 sys.exit(1)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000538
Daniel Veillardbe586972003-11-18 20:56:51 +0000539 def debug(self, msg, token=-1):
540 print "Debug: " + msg
541 if token != -1:
542 print "Got token ", token
543 self.lexer.debug()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000544
Daniel Veillardbe586972003-11-18 20:56:51 +0000545 def parseTopComment(self, comment):
546 res = {}
547 lines = string.split(comment, "\n")
548 item = None
549 for line in lines:
550 while line != "" and (line[0] == ' ' or line[0] == '\t'):
551 line = line[1:]
552 while line != "" and line[0] == '*':
553 line = line[1:]
554 while line != "" and (line[0] == ' ' or line[0] == '\t'):
555 line = line[1:]
556 try:
557 (it, line) = string.split(line, ":", 1)
558 item = it
559 while line != "" and (line[0] == ' ' or line[0] == '\t'):
560 line = line[1:]
561 if res.has_key(item):
562 res[item] = res[item] + " " + line
563 else:
564 res[item] = line
565 except:
566 if item != None:
567 if res.has_key(item):
568 res[item] = res[item] + " " + line
569 else:
570 res[item] = line
571 self.index.info = res
572
573 def parseComment(self, token):
574 if self.top_comment == "":
575 self.top_comment = token[1]
576 if self.comment == None or token[1][0] == '*':
577 self.comment = token[1];
578 else:
579 self.comment = self.comment + token[1]
580 token = self.lexer.token()
581 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000582
583 #
584 # Parse a comment block associate to a macro
585 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000586 def parseMacroComment(self, name, quiet = 0):
587 if name[0:2] == '__':
588 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000589
Daniel Veillardbe586972003-11-18 20:56:51 +0000590 args = []
591 desc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000592
Daniel Veillardbe586972003-11-18 20:56:51 +0000593 if self.comment == None:
594 if not quiet:
595 print "Missing comment for macro %s" % (name)
596 return((args, desc))
597 if self.comment[0] != '*':
598 if not quiet:
599 print "Missing * in macro comment for %s" % (name)
600 return((args, desc))
601 lines = string.split(self.comment, '\n')
602 if lines[0] == '*':
603 del lines[0]
604 if lines[0] != "* %s:" % (name):
605 if not quiet:
606 print "Misformatted macro comment for %s" % (name)
607 print " Expecting '* %s:' got '%s'" % (name, lines[0])
608 return((args, desc))
609 del lines[0]
610 while lines[0] == '*':
611 del lines[0]
612 while len(lines) > 0 and lines[0][0:3] == '* @':
613 l = lines[0][3:]
614 try:
615 (arg, desc) = string.split(l, ':', 1)
616 desc=string.strip(desc)
617 arg=string.strip(arg)
618 except:
619 if not quiet:
620 print "Misformatted macro comment for %s" % (name)
621 print " problem with '%s'" % (lines[0])
622 del lines[0]
623 continue
624 del lines[0]
625 l = string.strip(lines[0])
626 while len(l) > 2 and l[0:3] != '* @':
627 while l[0] == '*':
628 l = l[1:]
629 desc = desc + ' ' + string.strip(l)
630 del lines[0]
631 if len(lines) == 0:
632 break
633 l = lines[0]
634 args.append((arg, desc))
635 while len(lines) > 0 and lines[0] == '*':
636 del lines[0]
637 desc = ""
638 while len(lines) > 0:
639 l = lines[0]
640 while len(l) > 0 and l[0] == '*':
641 l = l[1:]
642 l = string.strip(l)
643 desc = desc + " " + l
644 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000645
Daniel Veillardbe586972003-11-18 20:56:51 +0000646 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000647
Daniel Veillardbe586972003-11-18 20:56:51 +0000648 if quiet == 0:
649 if desc == "":
650 print "Macro comment for %s lack description of the macro" % (name)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000651
Daniel Veillardbe586972003-11-18 20:56:51 +0000652 return((args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000653
654 #
655 # Parse a comment block and merge the informations found in the
656 # parameters descriptions, finally returns a block as complete
657 # as possible
658 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000659 def mergeFunctionComment(self, name, description, quiet = 0):
660 if name == 'main':
661 quiet = 1
662 if name[0:2] == '__':
663 quiet = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000664
Daniel Veillardbe586972003-11-18 20:56:51 +0000665 (ret, args) = description
666 desc = ""
667 retdesc = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000668
Daniel Veillardbe586972003-11-18 20:56:51 +0000669 if self.comment == None:
670 if not quiet:
671 print "Missing comment for function %s" % (name)
672 return(((ret[0], retdesc), args, desc))
673 if self.comment[0] != '*':
674 if not quiet:
675 print "Missing * in function comment for %s" % (name)
676 return(((ret[0], retdesc), args, desc))
677 lines = string.split(self.comment, '\n')
678 if lines[0] == '*':
679 del lines[0]
680 if lines[0] != "* %s:" % (name):
681 if not quiet:
682 print "Misformatted function comment for %s" % (name)
683 print " Expecting '* %s:' got '%s'" % (name, lines[0])
684 return(((ret[0], retdesc), args, desc))
685 del lines[0]
686 while lines[0] == '*':
687 del lines[0]
688 nbargs = len(args)
689 while len(lines) > 0 and lines[0][0:3] == '* @':
690 l = lines[0][3:]
691 try:
692 (arg, desc) = string.split(l, ':', 1)
693 desc=string.strip(desc)
694 arg=string.strip(arg)
695 except:
696 if not quiet:
697 print "Misformatted function comment for %s" % (name)
698 print " problem with '%s'" % (lines[0])
699 del lines[0]
700 continue
701 del lines[0]
702 l = string.strip(lines[0])
703 while len(l) > 2 and l[0:3] != '* @':
704 while l[0] == '*':
705 l = l[1:]
706 desc = desc + ' ' + string.strip(l)
707 del lines[0]
708 if len(lines) == 0:
709 break
710 l = lines[0]
711 i = 0
712 while i < nbargs:
713 if args[i][1] == arg:
714 args[i] = (args[i][0], arg, desc)
715 break;
716 i = i + 1
717 if i >= nbargs:
718 if not quiet:
719 print "Unable to find arg %s from function comment for %s" % (
720 arg, name)
721 while len(lines) > 0 and lines[0] == '*':
722 del lines[0]
723 desc = ""
724 while len(lines) > 0:
725 l = lines[0]
726 while len(l) > 0 and l[0] == '*':
727 l = l[1:]
728 l = string.strip(l)
729 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
730 try:
731 l = string.split(l, ' ', 1)[1]
732 except:
733 l = ""
734 retdesc = string.strip(l)
735 del lines[0]
736 while len(lines) > 0:
737 l = lines[0]
738 while len(l) > 0 and l[0] == '*':
739 l = l[1:]
740 l = string.strip(l)
741 retdesc = retdesc + " " + l
742 del lines[0]
743 else:
744 desc = desc + " " + l
745 del lines[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000746
Daniel Veillardbe586972003-11-18 20:56:51 +0000747 retdesc = string.strip(retdesc)
748 desc = string.strip(desc)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000749
Daniel Veillardbe586972003-11-18 20:56:51 +0000750 if quiet == 0:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000751 #
752 # report missing comments
753 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000754 i = 0
755 while i < nbargs:
756 if args[i][2] == None and args[i][0] != "void" and args[i][1] != None:
757 print "Function comment for %s lack description of arg %s" % (name, args[i][1])
758 i = i + 1
759 if retdesc == "" and ret[0] != "void":
760 print "Function comment for %s lack description of return value" % (name)
761 if desc == "":
762 print "Function comment for %s lack description of the function" % (name)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000763
764
Daniel Veillardbe586972003-11-18 20:56:51 +0000765 return(((ret[0], retdesc), args, desc))
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000766
Daniel Veillardbe586972003-11-18 20:56:51 +0000767 def parsePreproc(self, token):
768 name = token[1]
769 if name == "#include":
770 token = self.lexer.token()
771 if token == None:
772 return None
773 if token[0] == 'preproc':
774 self.index_add(token[1], self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000775 "include")
Daniel Veillardbe586972003-11-18 20:56:51 +0000776 return self.lexer.token()
777 return token
778 if name == "#define":
779 token = self.lexer.token()
780 if token == None:
781 return None
782 if token[0] == 'preproc':
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000783 # TODO macros with arguments
Daniel Veillardbe586972003-11-18 20:56:51 +0000784 name = token[1]
785 lst = []
786 token = self.lexer.token()
787 while token != None and token[0] == 'preproc' and \
788 token[1][0] != '#':
789 lst.append(token[1])
790 token = self.lexer.token()
791 try:
792 name = string.split(name, '(') [0]
793 except:
794 pass
795 info = self.parseMacroComment(name, not self.is_header)
796 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000797 "macro", info)
Daniel Veillardbe586972003-11-18 20:56:51 +0000798 return token
799 token = self.lexer.token()
800 while token != None and token[0] == 'preproc' and \
801 token[1][0] != '#':
802 token = self.lexer.token()
803 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000804
805 #
806 # token acquisition on top of the lexer, it handle internally
807 # preprocessor and comments since they are logically not part of
808 # the program structure.
809 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000810 def token(self):
811 global ignored_words
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000812
Daniel Veillardbe586972003-11-18 20:56:51 +0000813 token = self.lexer.token()
814 while token != None:
815 if token[0] == 'comment':
816 token = self.parseComment(token)
817 continue
818 elif token[0] == 'preproc':
819 token = self.parsePreproc(token)
820 continue
821 elif token[0] == "name" and ignored_words.has_key(token[1]):
822 (n, info) = ignored_words[token[1]]
823 i = 0
824 while i < n:
825 token = self.lexer.token()
826 i = i + 1
827 token = self.lexer.token()
828 continue
829 else:
830 if debug:
831 print "=> ", token
832 return token
833 return None
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000834
835 #
836 # Parse a typedef, it records the type and its name.
837 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000838 def parseTypedef(self, token):
839 if token == None:
840 return None
841 token = self.parseType(token)
842 if token == None:
843 self.error("parsing typedef")
844 return None
845 base_type = self.type
846 type = base_type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000847 #self.debug("end typedef type", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000848 while token != None:
849 if token[0] == "name":
850 name = token[1]
851 signature = self.signature
852 if signature != None:
853 type = string.split(type, '(')[0]
854 d = self.mergeFunctionComment(name,
855 ((type, None), signature), 1)
856 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000857 "functype", d)
Daniel Veillardbe586972003-11-18 20:56:51 +0000858 else:
859 if base_type == "struct":
860 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000861 "struct", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000862 base_type = "struct " + name
863 else:
864 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000865 "typedef", type)
Daniel Veillardbe586972003-11-18 20:56:51 +0000866 token = self.token()
867 else:
868 self.error("parsing typedef: expecting a name")
869 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000870 #self.debug("end typedef", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000871 if token != None and token[0] == 'sep' and token[1] == ',':
872 type = base_type
873 token = self.token()
874 while token != None and token[0] == "op":
875 type = type + token[1]
876 token = self.token()
877 elif token != None and token[0] == 'sep' and token[1] == ';':
878 break;
879 elif token != None and token[0] == 'name':
880 type = base_type
881 continue;
882 else:
883 self.error("parsing typedef: expecting ';'", token)
884 return token
885 token = self.token()
886 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000887
888 #
889 # Parse a C code block, used for functions it parse till
890 # the balancing } included
891 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000892 def parseBlock(self, token):
893 while token != None:
894 if token[0] == "sep" and token[1] == "{":
895 token = self.token()
896 token = self.parseBlock(token)
897 elif token[0] == "sep" and token[1] == "}":
898 self.comment = None
899 token = self.token()
900 return token
901 else:
902 if self.collect_ref == 1:
903 oldtok = token
904 token = self.token()
905 if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
906 if token[0] == "sep" and token[1] == "(":
907 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000908 0, "function")
Daniel Veillardbe586972003-11-18 20:56:51 +0000909 token = self.token()
910 elif token[0] == "name":
911 token = self.token()
912 if token[0] == "sep" and (token[1] == ";" or
913 token[1] == "," or token[1] == "="):
914 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000915 0, "type")
Daniel Veillardbe586972003-11-18 20:56:51 +0000916 elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
917 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000918 0, "typedef")
Daniel Veillardbe586972003-11-18 20:56:51 +0000919 elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
920 self.index_add_ref(oldtok[1], self.filename,
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000921 0, "typedef")
922
Daniel Veillardbe586972003-11-18 20:56:51 +0000923 else:
924 token = self.token()
925 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000926
927 #
928 # Parse a C struct definition till the balancing }
929 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000930 def parseStruct(self, token):
931 fields = []
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000932 #self.debug("start parseStruct", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000933 while token != None:
934 if token[0] == "sep" and token[1] == "{":
935 token = self.token()
936 token = self.parseTypeBlock(token)
937 elif token[0] == "sep" and token[1] == "}":
938 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000939 #self.debug("end parseStruct", token)
940 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +0000941 token = self.token()
942 return token
943 else:
944 base_type = self.type
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000945 #self.debug("before parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000946 token = self.parseType(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000947 #self.debug("after parseType", token)
Daniel Veillardbe586972003-11-18 20:56:51 +0000948 if token != None and token[0] == "name":
949 fname = token[1]
950 token = self.token()
951 if token[0] == "sep" and token[1] == ";":
952 self.comment = None
953 token = self.token()
954 fields.append((self.type, fname, self.comment))
955 self.comment = None
956 else:
957 self.error("parseStruct: expecting ;", token)
958 elif token != None and token[0] == "sep" and token[1] == "{":
959 token = self.token()
960 token = self.parseTypeBlock(token)
961 if token != None and token[0] == "name":
962 token = self.token()
963 if token != None and token[0] == "sep" and token[1] == ";":
964 token = self.token()
965 else:
966 self.error("parseStruct: expecting ;", token)
967 else:
968 self.error("parseStruct: name", token)
969 token = self.token()
970 self.type = base_type;
971 self.struct_fields = fields
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000972 #self.debug("end parseStruct", token)
973 #print fields
Daniel Veillardbe586972003-11-18 20:56:51 +0000974 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000975
976 #
977 # Parse a C enum block, parse till the balancing }
978 #
Daniel Veillardbe586972003-11-18 20:56:51 +0000979 def parseEnumBlock(self, token):
980 self.enums = []
981 name = None
982 self.comment = None
983 comment = ""
984 value = "0"
985 while token != None:
986 if token[0] == "sep" and token[1] == "{":
987 token = self.token()
988 token = self.parseTypeBlock(token)
989 elif token[0] == "sep" and token[1] == "}":
990 if name != None:
991 if self.comment != None:
992 comment = self.comment
993 self.comment = None
994 self.enums.append((name, value, comment))
995 token = self.token()
996 return token
997 elif token[0] == "name":
998 if name != None:
999 if self.comment != None:
1000 comment = string.strip(self.comment)
1001 self.comment = None
1002 self.enums.append((name, value, comment))
1003 name = token[1]
1004 comment = ""
1005 token = self.token()
1006 if token[0] == "op" and token[1][0] == "=":
1007 value = ""
1008 if len(token[1]) > 1:
1009 value = token[1][1:]
1010 token = self.token()
1011 while token[0] != "sep" or (token[1] != ',' and
1012 token[1] != '}'):
1013 value = value + token[1]
1014 token = self.token()
1015 else:
1016 try:
1017 value = "%d" % (int(value) + 1)
1018 except:
1019 print "Failed to compute value of enum %s" % (name)
1020 value=""
1021 if token[0] == "sep" and token[1] == ",":
1022 token = self.token()
1023 else:
1024 token = self.token()
1025 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001026
1027 #
1028 # Parse a C definition block, used for structs it parse till
1029 # the balancing }
1030 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001031 def parseTypeBlock(self, token):
1032 while token != None:
1033 if token[0] == "sep" and token[1] == "{":
1034 token = self.token()
1035 token = self.parseTypeBlock(token)
1036 elif token[0] == "sep" and token[1] == "}":
1037 token = self.token()
1038 return token
1039 else:
1040 token = self.token()
1041 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001042
1043 #
1044 # Parse a type: the fact that the type name can either occur after
1045 # the definition or within the definition makes it a little harder
1046 # if inside, the name token is pushed back before returning
1047 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001048 def parseType(self, token):
1049 self.type = ""
1050 self.struct_fields = []
1051 self.signature = None
1052 if token == None:
1053 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001054
Daniel Veillardbe586972003-11-18 20:56:51 +00001055 while token[0] == "name" and (
1056 token[1] == "const" or token[1] == "unsigned"):
1057 if self.type == "":
1058 self.type = token[1]
1059 else:
1060 self.type = self.type + " " + token[1]
1061 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001062
Daniel Veillardbe586972003-11-18 20:56:51 +00001063 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1064 if self.type == "":
1065 self.type = token[1]
1066 else:
1067 self.type = self.type + " " + token[1]
1068 if token[0] == "name" and token[1] == "int":
1069 if self.type == "":
1070 self.type = tmp[1]
1071 else:
1072 self.type = self.type + " " + tmp[1]
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001073
Daniel Veillardbe586972003-11-18 20:56:51 +00001074 elif token[0] == "name" and token[1] == "struct":
1075 if self.type == "":
1076 self.type = token[1]
1077 else:
1078 self.type = self.type + " " + token[1]
1079 token = self.token()
1080 nametok = None
1081 if token[0] == "name":
1082 nametok = token
1083 token = self.token()
1084 if token != None and token[0] == "sep" and token[1] == "{":
1085 token = self.token()
1086 token = self.parseStruct(token)
1087 elif token != None and token[0] == "op" and token[1] == "*":
1088 self.type = self.type + " " + nametok[1] + " *"
1089 token = self.token()
1090 while token != None and token[0] == "op" and token[1] == "*":
1091 self.type = self.type + " *"
1092 token = self.token()
1093 if token[0] == "name":
1094 nametok = token
1095 token = self.token()
1096 else:
1097 self.error("struct : expecting name", token)
1098 return token
1099 elif token != None and token[0] == "name" and nametok != None:
1100 self.type = self.type + " " + nametok[1]
1101 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001102
Daniel Veillardbe586972003-11-18 20:56:51 +00001103 if nametok != None:
1104 self.lexer.push(token)
1105 token = nametok
1106 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001107
Daniel Veillardbe586972003-11-18 20:56:51 +00001108 elif token[0] == "name" and token[1] == "enum":
1109 if self.type == "":
1110 self.type = token[1]
1111 else:
1112 self.type = self.type + " " + token[1]
1113 self.enums = []
1114 token = self.token()
1115 if token != None and token[0] == "sep" and token[1] == "{":
1116 token = self.token()
1117 token = self.parseEnumBlock(token)
1118 else:
1119 self.error("parsing enum: expecting '{'", token)
1120 enum_type = None
1121 if token != None and token[0] != "name":
1122 self.lexer.push(token)
1123 token = ("name", "enum")
1124 else:
1125 enum_type = token[1]
1126 for enum in self.enums:
1127 self.index_add(enum[0], self.filename,
1128 not self.is_header, "enum",
1129 (enum[1], enum[2], enum_type))
1130 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001131
Daniel Veillardbe586972003-11-18 20:56:51 +00001132 elif token[0] == "name":
1133 if self.type == "":
1134 self.type = token[1]
1135 else:
1136 self.type = self.type + " " + token[1]
1137 else:
1138 self.error("parsing type %s: expecting a name" % (self.type),
1139 token)
1140 return token
1141 token = self.token()
1142 while token != None and (token[0] == "op" or
1143 token[0] == "name" and token[1] == "const"):
1144 self.type = self.type + " " + token[1]
1145 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001146
1147 #
1148 # if there is a parenthesis here, this means a function type
1149 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001150 if token != None and token[0] == "sep" and token[1] == '(':
1151 self.type = self.type + token[1]
1152 token = self.token()
1153 while token != None and token[0] == "op" and token[1] == '*':
1154 self.type = self.type + token[1]
1155 token = self.token()
1156 if token == None or token[0] != "name" :
1157 self.error("parsing function type, name expected", token);
1158 return token
1159 self.type = self.type + token[1]
1160 nametok = token
1161 token = self.token()
1162 if token != None and token[0] == "sep" and token[1] == ')':
1163 self.type = self.type + token[1]
1164 token = self.token()
1165 if token != None and token[0] == "sep" and token[1] == '(':
1166 token = self.token()
1167 type = self.type;
1168 token = self.parseSignature(token);
1169 self.type = type;
1170 else:
1171 self.error("parsing function type, '(' expected", token);
1172 return token
1173 else:
1174 self.error("parsing function type, ')' expected", token);
1175 return token
1176 self.lexer.push(token)
1177 token = nametok
1178 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001179
1180 #
1181 # do some lookahead for arrays
1182 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001183 if token != None and token[0] == "name":
1184 nametok = token
1185 token = self.token()
1186 if token != None and token[0] == "sep" and token[1] == '[':
1187 self.type = self.type + nametok[1]
1188 while token != None and token[0] == "sep" and token[1] == '[':
1189 self.type = self.type + token[1]
1190 token = self.token()
1191 while token != None and token[0] != 'sep' and \
1192 token[1] != ']' and token[1] != ';':
1193 self.type = self.type + token[1]
1194 token = self.token()
1195 if token != None and token[0] == 'sep' and token[1] == ']':
1196 self.type = self.type + token[1]
1197 token = self.token()
1198 else:
1199 self.error("parsing array type, ']' expected", token);
1200 return token
1201 elif token != None and token[0] == "sep" and token[1] == ':':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001202 # remove :12 in case it's a limited int size
Daniel Veillardbe586972003-11-18 20:56:51 +00001203 token = self.token()
1204 token = self.token()
1205 self.lexer.push(token)
1206 token = nametok
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001207
Daniel Veillardbe586972003-11-18 20:56:51 +00001208 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001209
1210 #
1211 # Parse a signature: '(' has been parsed and we scan the type definition
1212 # up to the ')' included
Daniel Veillardbe586972003-11-18 20:56:51 +00001213 def parseSignature(self, token):
1214 signature = []
1215 if token != None and token[0] == "sep" and token[1] == ')':
1216 self.signature = []
1217 token = self.token()
1218 return token
1219 while token != None:
1220 token = self.parseType(token)
1221 if token != None and token[0] == "name":
1222 signature.append((self.type, token[1], None))
1223 token = self.token()
1224 elif token != None and token[0] == "sep" and token[1] == ',':
1225 token = self.token()
1226 continue
1227 elif token != None and token[0] == "sep" and token[1] == ')':
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001228 # only the type was provided
Daniel Veillardbe586972003-11-18 20:56:51 +00001229 if self.type == "...":
1230 signature.append((self.type, "...", None))
1231 else:
1232 signature.append((self.type, None, None))
1233 if token != None and token[0] == "sep":
1234 if token[1] == ',':
1235 token = self.token()
1236 continue
1237 elif token[1] == ')':
1238 token = self.token()
1239 break
1240 self.signature = signature
1241 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001242
1243 #
1244 # Parse a global definition, be it a type, variable or function
1245 # the extern "C" blocks are a bit nasty and require it to recurse.
1246 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001247 def parseGlobal(self, token):
1248 static = 0
1249 if token[1] == 'extern':
1250 token = self.token()
1251 if token == None:
1252 return token
1253 if token[0] == 'string':
1254 if token[1] == 'C':
1255 token = self.token()
1256 if token == None:
1257 return token
1258 if token[0] == 'sep' and token[1] == "{":
1259 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001260# print 'Entering extern "C line ', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001261 while token != None and (token[0] != 'sep' or
1262 token[1] != "}"):
1263 if token[0] == 'name':
1264 token = self.parseGlobal(token)
1265 else:
1266 self.error(
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001267 "token %s %s unexpected at the top level" % (
1268 token[0], token[1]))
Daniel Veillardbe586972003-11-18 20:56:51 +00001269 token = self.parseGlobal(token)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001270# print 'Exiting extern "C" line', self.lineno()
Daniel Veillardbe586972003-11-18 20:56:51 +00001271 token = self.token()
1272 return token
1273 else:
1274 return token
1275 elif token[1] == 'static':
1276 static = 1
1277 token = self.token()
1278 if token == None or token[0] != 'name':
1279 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001280
Daniel Veillardbe586972003-11-18 20:56:51 +00001281 if token[1] == 'typedef':
1282 token = self.token()
1283 return self.parseTypedef(token)
1284 else:
1285 token = self.parseType(token)
1286 type_orig = self.type
1287 if token == None or token[0] != "name":
1288 return token
1289 type = type_orig
1290 self.name = token[1]
1291 token = self.token()
1292 while token != None and (token[0] == "sep" or token[0] == "op"):
1293 if token[0] == "sep":
1294 if token[1] == "[":
1295 type = type + token[1]
1296 token = self.token()
1297 while token != None and (token[0] != "sep" or \
1298 token[1] != ";"):
1299 type = type + token[1]
1300 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001301
Daniel Veillardbe586972003-11-18 20:56:51 +00001302 if token != None and token[0] == "op" and token[1] == "=":
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001303 #
1304 # Skip the initialization of the variable
1305 #
Daniel Veillardbe586972003-11-18 20:56:51 +00001306 token = self.token()
1307 if token[0] == 'sep' and token[1] == '{':
1308 token = self.token()
1309 token = self.parseBlock(token)
1310 else:
1311 self.comment = None
1312 while token != None and (token[0] != "sep" or \
1313 (token[1] != ';' and token[1] != ',')):
1314 token = self.token()
1315 self.comment = None
1316 if token == None or token[0] != "sep" or (token[1] != ';' and
1317 token[1] != ','):
1318 self.error("missing ';' or ',' after value")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001319
Daniel Veillardbe586972003-11-18 20:56:51 +00001320 if token != None and token[0] == "sep":
1321 if token[1] == ";":
1322 self.comment = None
1323 token = self.token()
1324 if type == "struct":
1325 self.index_add(self.name, self.filename,
1326 not self.is_header, "struct", self.struct_fields)
1327 else:
1328 self.index_add(self.name, self.filename,
1329 not self.is_header, "variable", type)
1330 break
1331 elif token[1] == "(":
1332 token = self.token()
1333 token = self.parseSignature(token)
1334 if token == None:
1335 return None
1336 if token[0] == "sep" and token[1] == ";":
1337 d = self.mergeFunctionComment(self.name,
1338 ((type, None), self.signature), 1)
1339 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001340 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001341 token = self.token()
1342 elif token[0] == "sep" and token[1] == "{":
1343 d = self.mergeFunctionComment(self.name,
1344 ((type, None), self.signature), static)
1345 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001346 "function", d)
Daniel Veillardbe586972003-11-18 20:56:51 +00001347 token = self.token()
1348 token = self.parseBlock(token);
1349 elif token[1] == ',':
1350 self.comment = None
1351 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001352 "variable", type)
Daniel Veillardbe586972003-11-18 20:56:51 +00001353 type = type_orig
1354 token = self.token()
1355 while token != None and token[0] == "sep":
1356 type = type + token[1]
1357 token = self.token()
1358 if token != None and token[0] == "name":
1359 self.name = token[1]
1360 token = self.token()
1361 else:
1362 break
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001363
Daniel Veillardbe586972003-11-18 20:56:51 +00001364 return token
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001365
Daniel Veillardbe586972003-11-18 20:56:51 +00001366 def parse(self):
1367 print "Parsing %s" % (self.filename)
1368 token = self.token()
1369 while token != None:
1370 if token[0] == 'name':
1371 token = self.parseGlobal(token)
1372 else:
1373 self.error("token %s %s unexpected at the top level" % (
1374 token[0], token[1]))
1375 token = self.parseGlobal(token)
1376 return
1377 self.parseTopComment(self.top_comment)
1378 return self.index
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001379
1380
1381class docBuilder:
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001382 """A documentation builder"""
1383 def __init__(self, name, directories=['.'], excludes=[]):
1384 self.name = name
1385 self.directories = directories
1386 self.excludes = excludes + ignored_files.keys()
1387 self.modules = {}
1388 self.headers = {}
1389 self.idx = index()
1390 self.xref = {}
1391 self.index = {}
1392 if name == 'libxml2':
1393 self.basename = 'libxml'
1394 else:
1395 self.basename = name
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001396
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001397 def indexString(self, id, str):
1398 if str == None:
1399 return
1400 str = string.replace(str, "'", ' ')
1401 str = string.replace(str, '"', ' ')
1402 str = string.replace(str, "/", ' ')
1403 str = string.replace(str, '*', ' ')
1404 str = string.replace(str, "[", ' ')
1405 str = string.replace(str, "]", ' ')
1406 str = string.replace(str, "(", ' ')
1407 str = string.replace(str, ")", ' ')
1408 str = string.replace(str, "<", ' ')
1409 str = string.replace(str, '>', ' ')
1410 str = string.replace(str, "&", ' ')
1411 str = string.replace(str, '#', ' ')
1412 str = string.replace(str, ",", ' ')
1413 str = string.replace(str, '.', ' ')
1414 str = string.replace(str, ';', ' ')
1415 tokens = string.split(str)
1416 for token in tokens:
1417 try:
1418 c = token[0]
1419 if string.find(string.letters, c) < 0:
1420 pass
1421 elif len(token) < 3:
1422 pass
1423 else:
1424 lower = string.lower(token)
1425 # TODO: generalize this a bit
1426 if lower == 'and' or lower == 'the':
1427 pass
1428 elif self.xref.has_key(token):
1429 self.xref[token].append(id)
1430 else:
1431 self.xref[token] = [id]
1432 except:
1433 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001434
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001435 def analyze(self):
1436 print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
1437 self.idx.analyze()
1438
1439 def scanHeaders(self):
1440 for header in self.headers.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001441 parser = CParser(header)
1442 idx = parser.parse()
1443 self.headers[header] = idx;
1444 self.idx.merge(idx)
1445
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001446 def scanModules(self):
1447 for module in self.modules.keys():
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001448 parser = CParser(module)
1449 idx = parser.parse()
1450 # idx.analyze()
1451 self.modules[module] = idx
1452 self.idx.merge_public(idx)
1453
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001454 def scan(self):
1455 for directory in self.directories:
1456 files = glob.glob(directory + "/*.c")
1457 for file in files:
1458 skip = 0
1459 for excl in self.excludes:
1460 if string.find(file, excl) != -1:
1461 skip = 1;
1462 break
1463 if skip == 0:
1464 self.modules[file] = None;
1465 files = glob.glob(directory + "/*.h")
1466 for file in files:
1467 skip = 0
1468 for excl in self.excludes:
1469 if string.find(file, excl) != -1:
1470 skip = 1;
1471 break
1472 if skip == 0:
1473 self.headers[file] = None;
1474 self.scanHeaders()
1475 self.scanModules()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001476
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001477 def modulename_file(self, file):
1478 module = os.path.basename(file)
1479 if module[-2:] == '.h':
1480 module = module[:-2]
1481 return module
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001482
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001483 def serialize_enum(self, output, name):
1484 id = self.idx.enums[name]
1485 output.write(" <enum name='%s' file='%s'" % (name,
1486 self.modulename_file(id.module)))
1487 if id.info != None:
1488 info = id.info
1489 if info[0] != None and info[0] != '':
1490 try:
1491 val = eval(info[0])
1492 except:
1493 val = info[0]
1494 output.write(" value='%s'" % (val));
1495 if info[2] != None and info[2] != '':
1496 output.write(" type='%s'" % info[2]);
1497 if info[1] != None and info[1] != '':
1498 output.write(" info='%s'" % escape(info[1]));
1499 output.write("/>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001500
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001501 def serialize_macro(self, output, name):
1502 id = self.idx.macros[name]
1503 output.write(" <macro name='%s' file='%s'>\n" % (name,
1504 self.modulename_file(id.module)))
1505 if id.info != None:
1506 try:
1507 (args, desc) = id.info
1508 if desc != None and desc != "":
1509 output.write(" <info>%s</info>\n" % (escape(desc)))
1510 self.indexString(name, desc)
1511 for arg in args:
1512 (name, desc) = arg
1513 if desc != None and desc != "":
1514 output.write(" <arg name='%s' info='%s'/>\n" % (
1515 name, escape(desc)))
1516 self.indexString(name, desc)
1517 else:
1518 output.write(" <arg name='%s'/>\n" % (name))
1519 except:
1520 pass
1521 output.write(" </macro>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001522
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001523 def serialize_typedef(self, output, name):
1524 id = self.idx.typedefs[name]
1525 if id.info[0:7] == 'struct ':
1526 output.write(" <struct name='%s' file='%s' type='%s'" % (
1527 name, self.modulename_file(id.module), id.info))
1528 name = id.info[7:]
1529 if self.idx.structs.has_key(name) and ( \
1530 type(self.idx.structs[name].info) == type(()) or
Daniel Veillardc1eed322002-12-12 11:01:32 +00001531 type(self.idx.structs[name].info) == type([])):
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001532 output.write(">\n");
1533 try:
1534 for field in self.idx.structs[name].info:
1535 desc = field[2]
1536 self.indexString(name, desc)
1537 if desc == None:
1538 desc = ''
1539 else:
1540 desc = escape(desc)
1541 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1542 except:
1543 print "Failed to serialize struct %s" % (name)
1544 output.write(" </struct>\n")
1545 else:
1546 output.write("/>\n");
1547 else :
1548 output.write(" <typedef name='%s' file='%s' type='%s'/>\n" % (
1549 name, self.modulename_file(id.module), id.info))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001550
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001551 def serialize_variable(self, output, name):
1552 id = self.idx.variables[name]
1553 if id.info != None:
1554 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1555 name, self.modulename_file(id.module), id.info))
1556 else:
1557 output.write(" <variable name='%s' file='%s'/>\n" % (
1558 name, self.modulename_file(id.module)))
Daniel Veillardc1eed322002-12-12 11:01:32 +00001559
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001560 def serialize_function(self, output, name):
1561 id = self.idx.functions[name]
1562 output.write(" <%s name='%s' file='%s'>\n" % (id.type, name,
1563 self.modulename_file(id.module)))
1564 try:
1565 (ret, params, desc) = id.info
1566 output.write(" <info>%s</info>\n" % (escape(desc)))
1567 self.indexString(name, desc)
1568 if ret[0] != None:
1569 if ret[0] == "void":
1570 output.write(" <return type='void'/>\n")
1571 else:
1572 output.write(" <return type='%s' info='%s'/>\n" % (
1573 ret[0], escape(ret[1])))
1574 self.indexString(name, ret[1])
1575 for param in params:
1576 if param[0] == 'void':
1577 continue
1578 if param[2] == None:
1579 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1580 else:
1581 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1582 self.indexString(name, param[2])
1583 except:
1584 print "Failed to save function %s info: " % name, `id.info`
1585 output.write(" </%s>\n" % (id.type))
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001586
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001587 def serialize_exports(self, output, file):
1588 module = self.modulename_file(file)
1589 output.write(" <file name='%s'>\n" % (module))
1590 dict = self.headers[file]
Daniel Veillardbe586972003-11-18 20:56:51 +00001591 if dict.info != None:
1592 for data in ('Summary', 'Description', 'Author'):
1593 try:
1594 output.write(" <%s>%s</%s>\n" % (
1595 string.lower(data),
1596 escape(dict.info[data]),
1597 string.lower(data)))
1598 except:
1599 print "Header %s lacks a %s description" % (module, data)
1600 if dict.info.has_key('Description'):
1601 desc = dict.info['Description']
1602 if string.find(desc, "DEPRECATED") != -1:
1603 output.write(" <deprecated/>\n")
1604
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001605 ids = dict.functions.keys() + dict.variables.keys() + \
1606 dict.macros.keys() + dict.typedefs.keys() + \
1607 dict.structs.keys() + dict.enums.keys()
1608 ids.sort()
1609 for id in uniq(ids):
1610 output.write(" <exports symbol='%s'/>\n" % (id))
1611 output.write(" </file>\n")
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001612
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001613 def serialize_xrefs_files(self, output):
1614 headers = self.headers.keys()
1615 headers.sort()
1616 for file in headers:
1617 module = self.modulename_file(file)
1618 output.write(" <file name='%s'>\n" % (module))
1619 dict = self.headers[file]
1620 ids = dict.functions.keys() + dict.variables.keys() + \
1621 dict.macros.keys() + dict.typedefs.keys() + \
1622 dict.structs.keys() + dict.enums.keys()
1623 ids.sort()
1624 for id in uniq(ids):
1625 output.write(" <ref name='%s'/>\n" % (id))
1626 output.write(" </file>\n")
1627 pass
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001628
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001629 def serialize_xrefs_functions(self, output):
1630 funcs = {}
1631 for name in self.idx.functions.keys():
1632 id = self.idx.functions[name]
1633 try:
1634 (ret, params, desc) = id.info
1635 for param in params:
1636 if param[0] == 'void':
1637 continue
1638 if funcs.has_key(param[0]):
1639 funcs[param[0]].append(name)
1640 else:
1641 funcs[param[0]] = [name]
1642 except:
1643 pass
1644 typ = funcs.keys()
1645 typ.sort()
1646 for type in typ:
1647 if type == '' or type == 'void' or type == "int" or \
1648 type == "char *" or type == "const char *" :
1649 continue
1650 output.write(" <type name='%s'>\n" % (type))
1651 ids = funcs[type]
1652 ids.sort()
1653 for id in ids:
1654 output.write(" <ref name='%s'/>\n" % (id))
1655 output.write(" </type>\n")
1656
1657 def serialize_xrefs_constructors(self, output):
1658 funcs = {}
1659 for name in self.idx.functions.keys():
1660 id = self.idx.functions[name]
1661 try:
1662 (ret, params, desc) = id.info
1663 if ret[0] == "void":
1664 continue
1665 if funcs.has_key(ret[0]):
1666 funcs[ret[0]].append(name)
1667 else:
1668 funcs[ret[0]] = [name]
1669 except:
1670 pass
1671 typ = funcs.keys()
1672 typ.sort()
1673 for type in typ:
1674 if type == '' or type == 'void' or type == "int" or \
1675 type == "char *" or type == "const char *" :
1676 continue
1677 output.write(" <type name='%s'>\n" % (type))
1678 ids = funcs[type]
1679 for id in ids:
1680 output.write(" <ref name='%s'/>\n" % (id))
1681 output.write(" </type>\n")
1682
1683 def serialize_xrefs_alpha(self, output):
1684 letter = None
1685 ids = self.idx.identifiers.keys()
1686 ids.sort()
1687 for id in ids:
1688 if id[0] != letter:
1689 if letter != None:
1690 output.write(" </letter>\n")
1691 letter = id[0]
1692 output.write(" <letter name='%s'>\n" % (letter))
1693 output.write(" <ref name='%s'/>\n" % (id))
1694 if letter != None:
1695 output.write(" </letter>\n")
1696
1697 def serialize_xrefs_references(self, output):
1698 typ = self.idx.identifiers.keys()
1699 typ.sort()
1700 for id in typ:
1701 idf = self.idx.identifiers[id]
1702 module = idf.module
1703 output.write(" <reference name='%s' href='%s'/>\n" % (id,
1704 'html/' + self.basename + '-' +
1705 self.modulename_file(module) + '.html#' +
1706 id))
1707
1708 def serialize_xrefs_index(self, output):
1709 index = self.xref
1710 typ = index.keys()
1711 typ.sort()
1712 letter = None
1713 count = 0
1714 chunk = 0
1715 chunks = []
1716 for id in typ:
1717 if len(index[id]) > 30:
1718 continue
1719 if id[0] != letter:
1720 if letter == None or count > 200:
1721 if letter != None:
1722 output.write(" </letter>\n")
1723 output.write(" </chunk>\n")
1724 count = 0
1725 chunks.append(["chunk%s" % (chunk -1), first_letter, letter])
1726 output.write(" <chunk name='chunk%s'>\n" % (chunk))
1727 first_letter = id[0]
1728 chunk = chunk + 1
1729 elif letter != None:
1730 output.write(" </letter>\n")
1731 letter = id[0]
1732 output.write(" <letter name='%s'>\n" % (letter))
1733 output.write(" <word name='%s'>\n" % (id))
1734 tokens = index[id];
1735 tokens.sort()
1736 tok = None
1737 for token in index[id]:
1738 if tok == token:
1739 continue
1740 tok = token
1741 output.write(" <ref name='%s'/>\n" % (token))
1742 count = count + 1
1743 output.write(" </word>\n")
1744 if letter != None:
1745 output.write(" </letter>\n")
1746 output.write(" </chunk>\n")
1747 output.write(" <chunks>\n")
1748 for ch in chunks:
1749 output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
1750 ch[0], ch[1], ch[2]))
1751 output.write(" </chunks>\n")
1752
1753 def serialize_xrefs(self, output):
1754 output.write(" <references>\n")
1755 self.serialize_xrefs_references(output)
1756 output.write(" </references>\n")
1757 output.write(" <alpha>\n")
1758 self.serialize_xrefs_alpha(output)
1759 output.write(" </alpha>\n")
1760 output.write(" <constructors>\n")
1761 self.serialize_xrefs_constructors(output)
1762 output.write(" </constructors>\n")
1763 output.write(" <functions>\n")
1764 self.serialize_xrefs_functions(output)
1765 output.write(" </functions>\n")
1766 output.write(" <files>\n")
1767 self.serialize_xrefs_files(output)
1768 output.write(" </files>\n")
1769 output.write(" <index>\n")
1770 self.serialize_xrefs_index(output)
1771 output.write(" </index>\n")
1772
1773 def serialize(self):
1774 filename = "%s-api.xml" % self.name
1775 print "Saving XML description %s" % (filename)
1776 output = open(filename, "w")
1777 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1778 output.write("<api name='%s'>\n" % self.name)
1779 output.write(" <files>\n")
1780 headers = self.headers.keys()
1781 headers.sort()
1782 for file in headers:
1783 self.serialize_exports(output, file)
1784 output.write(" </files>\n")
1785 output.write(" <symbols>\n")
1786 macros = self.idx.macros.keys()
1787 macros.sort()
1788 for macro in macros:
1789 self.serialize_macro(output, macro)
1790 enums = self.idx.enums.keys()
1791 enums.sort()
1792 for enum in enums:
1793 self.serialize_enum(output, enum)
1794 typedefs = self.idx.typedefs.keys()
1795 typedefs.sort()
1796 for typedef in typedefs:
1797 self.serialize_typedef(output, typedef)
1798 variables = self.idx.variables.keys()
1799 variables.sort()
1800 for variable in variables:
1801 self.serialize_variable(output, variable)
1802 functions = self.idx.functions.keys()
1803 functions.sort()
1804 for function in functions:
1805 self.serialize_function(output, function)
1806 output.write(" </symbols>\n")
1807 output.write("</api>\n")
1808 output.close()
1809
1810 filename = "%s-refs.xml" % self.name
1811 print "Saving XML Cross References %s" % (filename)
1812 output = open(filename, "w")
1813 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1814 output.write("<apirefs name='%s'>\n" % self.name)
1815 self.serialize_xrefs(output)
1816 output.write("</apirefs>\n")
1817 output.close()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001818
1819
1820def rebuild():
1821 builder = None
Daniel Veillarde8ba84e2003-11-18 13:54:15 +00001822 if glob.glob("parser.c") != [] :
1823 print "Rebuilding API description for libxml2"
1824 builder = docBuilder("libxml2", [".", "."],
1825 ["xmlwin32version.h", "tst.c"])
1826 elif glob.glob("../parser.c") != [] :
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001827 print "Rebuilding API description for libxml2"
1828 builder = docBuilder("libxml2", ["..", "../include/libxml"],
Daniel Veillardd4330462003-04-29 12:40:16 +00001829 ["xmlwin32version.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001830 elif glob.glob("../libxslt/transform.c") != [] :
1831 print "Rebuilding API description for libxslt"
1832 builder = docBuilder("libxslt", ["../libxslt"],
Daniel Veillard024b5702002-12-12 00:15:55 +00001833 ["win32config.h", "libxslt.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001834 else:
1835 print "rebuild() failed, unable to guess the module"
1836 return None
1837 builder.scan()
1838 builder.analyze()
1839 builder.serialize()
Daniel Veillard024b5702002-12-12 00:15:55 +00001840 if glob.glob("../libexslt/exslt.c") != [] :
1841 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1842 extra.scan()
1843 extra.analyze()
1844 extra.serialize()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001845 return builder
1846
1847#
1848# for debugging the parser
1849#
1850def parse(filename):
1851 parser = CParser(filename)
1852 idx = parser.parse()
1853 return idx
1854
1855if __name__ == "__main__":
1856 rebuild()