blob: 520ef09ae7c2c16bcf35e63d825632f9adc0bf24 [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 Veillardde0a0a52003-04-24 17:12:57 +000014#
15# C parser analysis code
16#
17ignored_files = {
18 "trio": "too many non standard macros",
19 "trio.c": "too many non standard macros",
20 "trionan.c": "too many non standard macros",
21 "triostr.c": "too many non standard macros",
22 "acconfig.h": "generated portability layer",
23 "config.h": "generated portability layer",
24 "libxml.h": "internal only",
Daniel Veillard92fc02c2003-04-24 23:12:35 +000025 "testOOM.c": "out of memory tester",
26 "testOOMlib.h": "out of memory tester",
27 "testOOMlib.c": "out of memory tester",
Daniel Veillardfc8dc352003-10-18 09:07:46 +000028 "pattern.c": "not integrated yet",
29 "pattern.h": "not integrated yet",
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"),
36 "XMLPUBFUN": (0, "Special macro for extern funcs for win32"),
37 "XMLCALL": (0, "Special macro for win32 calls"),
Daniel Veillardde0a0a52003-04-24 17:12:57 +000038 "__declspec": (3, "Windows keyword"),
39 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
40 "LIBEXSLT_PUBLIC": (0, "macro keyword"),
41 "X_IN_Y": (5, "macro function builder"),
42}
43
Daniel Veillarda9b66d02002-12-11 14:23:49 +000044def escape(raw):
45 raw = string.replace(raw, '&', '&')
46 raw = string.replace(raw, '<', '&lt;')
47 raw = string.replace(raw, '>', '&gt;')
48 raw = string.replace(raw, "'", '&apos;')
49 raw = string.replace(raw, '"', '&quot;')
50 return raw
51
52class identifier:
Daniel Veillardd8cf9062003-11-11 21:12:36 +000053 def __init__(self, name, module=None, type=None, lineno = 0,
54 info=None, extra=None):
Daniel Veillarda9b66d02002-12-11 14:23:49 +000055 self.name = name
56 self.module = module
57 self.type = type
58 self.info = info
59 self.extra = extra
Daniel Veillardd8cf9062003-11-11 21:12:36 +000060 self.lineno = lineno
Daniel Veillarda9b66d02002-12-11 14:23:49 +000061 self.static = 0
62
63 def __repr__(self):
64 r = "%s %s:" % (self.type, self.name)
65 if self.static:
66 r = r + " static"
67 if self.module != None:
68 r = r + " from %s" % (self.module)
69 if self.info != None:
70 r = r + " " + `self.info`
71 if self.extra != None:
72 r = r + " " + `self.extra`
73 return r
74
75
76 def set_module(self, module):
77 self.module = module
78 def set_type(self, type):
79 self.type = type
80 def set_info(self, info):
81 self.info = info
82 def set_extra(self, extra):
83 self.extra = extra
Daniel Veillardd8cf9062003-11-11 21:12:36 +000084 def set_lineno(self, lineno):
85 self.lineno = lineno
Daniel Veillarda9b66d02002-12-11 14:23:49 +000086 def set_static(self, static):
87 self.static = static
88
Daniel Veillardd8cf9062003-11-11 21:12:36 +000089 def get_name(self):
90 return self.name
91 def get_module(self):
92 return self.module
93 def get_type(self):
94 return self.type
95 def get_info(self):
96 return self.info
97 def get_lineno(self):
98 return self.lineno
99 def get_extra(self):
100 return self.extra
101 def get_static(self):
102 return self.static
103
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000104 def update(self, module, type = None, info = None, extra=None):
105 if module != None and self.module == None:
106 self.set_module(module)
107 if type != None and self.type == None:
108 self.set_type(type)
109 if info != None:
110 self.set_info(info)
111 if extra != None:
112 self.set_extra(extra)
113
114
115class index:
116 def __init__(self, name = "noname"):
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000117 self.name = name
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000118 self.identifiers = {}
119 self.functions = {}
120 self.variables = {}
121 self.includes = {}
122 self.structs = {}
123 self.enums = {}
124 self.typedefs = {}
125 self.macros = {}
126 self.references = {}
127
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000128 def add_ref(self, name, module, static, type, lineno, info=None, extra=None):
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000129 if name[0:2] == '__':
130 return None
131 d = None
132 try:
133 d = self.identifiers[name]
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000134 d.update(module, type, lineno, info, extra)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000135 except:
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000136 d = identifier(name, module, type, lineno, info, extra)
137 self.identifiers[name] = d
138
139 if d != None and static == 1:
140 d.set_static(1)
141
142 if d != None and name != None and type != None:
143 self.references[name] = d
144
145 def add(self, name, module, static, type, lineno, info=None, extra=None):
146 if name[0:2] == '__':
147 return None
148 d = None
149 try:
150 d = self.identifiers[name]
151 d.update(module, type, lineno, info, extra)
152 except:
153 d = identifier(name, module, type, lineno, info, extra)
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000154 self.identifiers[name] = d
155
156 if d != None and static == 1:
157 d.set_static(1)
158
159 if d != None and name != None and type != None:
160 if type == "function":
161 self.functions[name] = d
162 elif type == "functype":
163 self.functions[name] = d
164 elif type == "variable":
165 self.variables[name] = d
166 elif type == "include":
167 self.includes[name] = d
168 elif type == "struct":
169 self.structs[name] = d
170 elif type == "enum":
171 self.enums[name] = d
172 elif type == "typedef":
173 self.typedefs[name] = d
174 elif type == "macro":
175 self.macros[name] = d
176 else:
177 print "Unable to register type ", type
178 return d
179
180 def merge(self, idx):
181 for id in idx.functions.keys():
182 #
183 # macro might be used to override functions or variables
184 # definitions
185 #
186 if self.macros.has_key(id):
187 del self.macros[id]
188 if self.functions.has_key(id):
189 print "function %s from %s redeclared in %s" % (
190 id, self.functions[id].module, idx.functions[id].module)
191 else:
192 self.functions[id] = idx.functions[id]
193 self.identifiers[id] = idx.functions[id]
194 for id in idx.variables.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.variables.has_key(id):
202 print "variable %s from %s redeclared in %s" % (
203 id, self.variables[id].module, idx.variables[id].module)
204 else:
205 self.variables[id] = idx.variables[id]
206 self.identifiers[id] = idx.variables[id]
207 for id in idx.structs.keys():
208 if self.structs.has_key(id):
209 print "struct %s from %s redeclared in %s" % (
210 id, self.structs[id].module, idx.structs[id].module)
211 else:
212 self.structs[id] = idx.structs[id]
213 self.identifiers[id] = idx.structs[id]
214 for id in idx.typedefs.keys():
215 if self.typedefs.has_key(id):
216 print "typedef %s from %s redeclared in %s" % (
217 id, self.typedefs[id].module, idx.typedefs[id].module)
218 else:
219 self.typedefs[id] = idx.typedefs[id]
220 self.identifiers[id] = idx.typedefs[id]
221 for id in idx.macros.keys():
222 #
223 # macro might be used to override functions or variables
224 # definitions
225 #
226 if self.variables.has_key(id):
227 continue
228 if self.functions.has_key(id):
229 continue
230 if self.enums.has_key(id):
231 continue
232 if self.macros.has_key(id):
233 print "macro %s from %s redeclared in %s" % (
234 id, self.macros[id].module, idx.macros[id].module)
235 else:
236 self.macros[id] = idx.macros[id]
237 self.identifiers[id] = idx.macros[id]
238 for id in idx.enums.keys():
239 if self.enums.has_key(id):
240 print "enum %s from %s redeclared in %s" % (
241 id, self.enums[id].module, idx.enums[id].module)
242 else:
243 self.enums[id] = idx.enums[id]
244 self.identifiers[id] = idx.enums[id]
245
246 def merge_public(self, idx):
247 for id in idx.functions.keys():
248 if self.functions.has_key(id):
249 up = idx.functions[id]
250 self.functions[id].update(None, up.type, up.info, up.extra)
Daniel Veillardc1eed322002-12-12 11:01:32 +0000251 # else:
252 # print "Function %s from %s is not declared in headers" % (
253 # id, idx.functions[id].module)
254 # TODO: do the same for variables.
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000255
256 def analyze_dict(self, type, dict):
257 count = 0
258 public = 0
259 for name in dict.keys():
260 id = dict[name]
261 count = count + 1
262 if id.static == 0:
263 public = public + 1
264 if count != public:
265 print " %d %s , %d public" % (count, type, public)
266 elif count != 0:
267 print " %d public %s" % (count, type)
268
269
270 def analyze(self):
271 self.analyze_dict("functions", self.functions)
272 self.analyze_dict("variables", self.variables)
273 self.analyze_dict("structs", self.structs)
274 self.analyze_dict("typedefs", self.typedefs)
275 self.analyze_dict("macros", self.macros)
276
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000277class CLexer:
278 """A lexer for the C language, tokenize the input by reading and
279 analyzing it line by line"""
280 def __init__(self, input):
281 self.input = input
282 self.tokens = []
283 self.line = ""
284 self.lineno = 0
285
286 def getline(self):
287 line = ''
288 while line == '':
289 line = self.input.readline()
290 if not line:
291 return None
292 self.lineno = self.lineno + 1
293 line = string.lstrip(line)
294 line = string.rstrip(line)
295 if line == '':
296 continue
297 while line[-1] == '\\':
298 line = line[:-1]
299 n = self.input.readline()
300 self.lineno = self.lineno + 1
301 n = string.lstrip(n)
302 n = string.rstrip(n)
303 if not n:
304 break
305 else:
306 line = line + n
307 return line
308
309 def getlineno(self):
310 return self.lineno
311
312 def push(self, token):
313 self.tokens.insert(0, token);
314
315 def debug(self):
316 print "Last token: ", self.last
317 print "Token queue: ", self.tokens
318 print "Line %d end: " % (self.lineno), self.line
319
320 def token(self):
321 while self.tokens == []:
322 if self.line == "":
323 line = self.getline()
324 else:
325 line = self.line
326 self.line = ""
327 if line == None:
328 return None
329
330 if line[0] == '#':
331 self.tokens = map((lambda x: ('preproc', x)),
332 string.split(line))
333 break;
334 l = len(line)
335 if line[0] == '"' or line[0] == "'":
336 end = line[0]
337 line = line[1:]
338 found = 0
339 tok = ""
340 while found == 0:
341 i = 0
342 l = len(line)
343 while i < l:
344 if line[i] == end:
345 self.line = line[i+1:]
346 line = line[:i]
347 l = i
348 found = 1
349 break
350 if line[i] == '\\':
351 i = i + 1
352 i = i + 1
353 tok = tok + line
354 if found == 0:
355 line = self.getline()
356 if line == None:
357 return None
358 self.last = ('string', tok)
359 return self.last
360
361 if l >= 2 and line[0] == '/' and line[1] == '*':
362 line = line[2:]
363 found = 0
364 tok = ""
365 while found == 0:
366 i = 0
367 l = len(line)
368 while i < l:
369 if line[i] == '*' and i+1 < l and line[i+1] == '/':
370 self.line = line[i+2:]
371 line = line[:i-1]
372 l = i
373 found = 1
374 break
375 i = i + 1
376 if tok != "":
377 tok = tok + "\n"
378 tok = tok + line
379 if found == 0:
380 line = self.getline()
381 if line == None:
382 return None
383 self.last = ('comment', tok)
384 return self.last
385 if l >= 2 and line[0] == '/' and line[1] == '/':
386 line = line[2:]
387 self.last = ('comment', line)
388 return self.last
389 i = 0
390 while i < l:
391 if line[i] == '/' and i+1 < l and line[i+1] == '/':
392 self.line = line[i:]
393 line = line[:i]
394 break
395 if line[i] == '/' and i+1 < l and line[i+1] == '*':
396 self.line = line[i:]
397 line = line[:i]
398 break
399 if line[i] == '"' or line[i] == "'":
400 self.line = line[i:]
401 line = line[:i]
402 break
403 i = i + 1
404 l = len(line)
405 i = 0
406 while i < l:
407 if line[i] == ' ' or line[i] == '\t':
408 i = i + 1
409 continue
410 o = ord(line[i])
411 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
412 (o >= 48 and o <= 57):
413 s = i
414 while i < l:
415 o = ord(line[i])
416 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
417 (o >= 48 and o <= 57) or string.find(
418 " \t(){}:;,+-*/%&!|[]=><", line[i]) == -1:
419 i = i + 1
420 else:
421 break
422 self.tokens.append(('name', line[s:i]))
423 continue
424 if string.find("(){}:;,[]", line[i]) != -1:
425# if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
426# line[i] == '}' or line[i] == ':' or line[i] == ';' or \
427# line[i] == ',' or line[i] == '[' or line[i] == ']':
428 self.tokens.append(('sep', line[i]))
429 i = i + 1
430 continue
431 if string.find("+-*><=/%&!|.", line[i]) != -1:
432# if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
433# line[i] == '>' or line[i] == '<' or line[i] == '=' or \
434# line[i] == '/' or line[i] == '%' or line[i] == '&' or \
435# line[i] == '!' or line[i] == '|' or line[i] == '.':
436 if line[i] == '.' and i + 2 < l and \
437 line[i+1] == '.' and line[i+2] == '.':
438 self.tokens.append(('name', '...'))
439 i = i + 3
440 continue
441
442 j = i + 1
443 if j < l and (
444 string.find("+-*><=/%&!|", line[j]) != -1):
445# line[j] == '+' or line[j] == '-' or line[j] == '*' or \
446# line[j] == '>' or line[j] == '<' or line[j] == '=' or \
447# line[j] == '/' or line[j] == '%' or line[j] == '&' or \
448# line[j] == '!' or line[j] == '|'):
449 self.tokens.append(('op', line[i:j+1]))
450 i = j + 1
451 else:
452 self.tokens.append(('op', line[i]))
453 i = i + 1
454 continue
455 s = i
456 while i < l:
457 o = ord(line[i])
458 if (o >= 97 and o <= 122) or (o >= 65 and o <= 90) or \
459 (o >= 48 and o <= 57) or (
460 string.find(" \t(){}:;,+-*/%&!|[]=><", line[i]) == -1):
461# line[i] != ' ' and line[i] != '\t' and
462# line[i] != '(' and line[i] != ')' and
463# line[i] != '{' and line[i] != '}' and
464# line[i] != ':' and line[i] != ';' and
465# line[i] != ',' and line[i] != '+' and
466# line[i] != '-' and line[i] != '*' and
467# line[i] != '/' and line[i] != '%' and
468# line[i] != '&' and line[i] != '!' and
469# line[i] != '|' and line[i] != '[' and
470# line[i] != ']' and line[i] != '=' and
471# line[i] != '*' and line[i] != '>' and
472# line[i] != '<'):
473 i = i + 1
474 else:
475 break
476 self.tokens.append(('name', line[s:i]))
477
478 tok = self.tokens[0]
479 self.tokens = self.tokens[1:]
480 self.last = tok
481 return tok
482
483class CParser:
484 """The C module parser"""
485 def __init__(self, filename, idx = None):
486 self.filename = filename
487 if len(filename) > 2 and filename[-2:] == '.h':
488 self.is_header = 1
489 else:
490 self.is_header = 0
491 self.input = open(filename)
492 self.lexer = CLexer(self.input)
493 if idx == None:
494 self.index = index()
495 else:
496 self.index = idx
497 self.top_comment = ""
498 self.last_comment = ""
499 self.comment = None
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000500 self.collect_ref = 0
501
502 def collect_references(self):
503 self.collect_ref = 1
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000504
505 def lineno(self):
506 return self.lexer.getlineno()
507
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000508 def index_add(self, name, module, static, type, info=None, extra = None):
509 self.index.add(name, module, static, type, self.lineno(),
510 info, extra)
511
512 def index_add_ref(self, name, module, static, type, info=None,
513 extra = None):
514 self.index.add_ref(name, module, static, type, self.lineno(),
515 info, extra)
516
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000517 def error(self, msg, token=-1):
518 print "Parse Error: " + msg
519 if token != -1:
520 print "Got token ", token
521 self.lexer.debug()
522 sys.exit(1)
523
524 def debug(self, msg, token=-1):
525 print "Debug: " + msg
526 if token != -1:
527 print "Got token ", token
528 self.lexer.debug()
529
530 def parseComment(self, token):
531 if self.top_comment == "":
532 self.top_comment = token[1]
533 if self.comment == None or token[1][0] == '*':
534 self.comment = token[1];
535 else:
536 self.comment = self.comment + token[1]
537 token = self.lexer.token()
538 return token
539
540 #
541 # Parse a comment block associate to a macro
542 #
543 def parseMacroComment(self, name, quiet = 0):
544 if name[0:2] == '__':
545 quiet = 1
546
547 args = []
548 desc = ""
549
550 if self.comment == None:
551 if not quiet:
552 print "Missing comment for macro %s" % (name)
553 return((args, desc))
554 if self.comment[0] != '*':
555 if not quiet:
556 print "Missing * in macro comment for %s" % (name)
557 return((args, desc))
558 lines = string.split(self.comment, '\n')
559 if lines[0] == '*':
560 del lines[0]
561 if lines[0] != "* %s:" % (name):
562 if not quiet:
563 print "Misformatted macro comment for %s" % (name)
564 print " Expecting '* %s:' got '%s'" % (name, lines[0])
565 return((args, desc))
566 del lines[0]
567 while lines[0] == '*':
568 del lines[0]
569 while len(lines) > 0 and lines[0][0:3] == '* @':
570 l = lines[0][3:]
571 try:
572 (arg, desc) = string.split(l, ':', 1)
573 desc=string.strip(desc)
574 arg=string.strip(arg)
575 except:
576 if not quiet:
577 print "Misformatted macro comment for %s" % (name)
578 print " problem with '%s'" % (lines[0])
579 del lines[0]
580 continue
581 del lines[0]
582 l = string.strip(lines[0])
583 while len(l) > 2 and l[0:3] != '* @':
584 while l[0] == '*':
585 l = l[1:]
586 desc = desc + ' ' + string.strip(l)
587 del lines[0]
588 if len(lines) == 0:
589 break
590 l = lines[0]
591 args.append((arg, desc))
592 while len(lines) > 0 and lines[0] == '*':
593 del lines[0]
594 desc = ""
595 while len(lines) > 0:
596 l = lines[0]
597 while len(l) > 0 and l[0] == '*':
598 l = l[1:]
599 l = string.strip(l)
600 desc = desc + " " + l
601 del lines[0]
602
603 desc = string.strip(desc)
604
605 if quiet == 0:
606 if desc == "":
607 print "Macro comment for %s lack description of the macro" % (name)
608
609 return((args, desc))
610
611 #
612 # Parse a comment block and merge the informations found in the
613 # parameters descriptions, finally returns a block as complete
614 # as possible
615 #
616 def mergeFunctionComment(self, name, description, quiet = 0):
617 if name == 'main':
618 quiet = 1
619 if name[0:2] == '__':
620 quiet = 1
621
622 (ret, args) = description
623 desc = ""
624 retdesc = ""
625
626 if self.comment == None:
627 if not quiet:
628 print "Missing comment for function %s" % (name)
629 return(((ret[0], retdesc), args, desc))
630 if self.comment[0] != '*':
631 if not quiet:
632 print "Missing * in function comment for %s" % (name)
633 return(((ret[0], retdesc), args, desc))
634 lines = string.split(self.comment, '\n')
635 if lines[0] == '*':
636 del lines[0]
637 if lines[0] != "* %s:" % (name):
638 if not quiet:
639 print "Misformatted function comment for %s" % (name)
640 print " Expecting '* %s:' got '%s'" % (name, lines[0])
641 return(((ret[0], retdesc), args, desc))
642 del lines[0]
643 while lines[0] == '*':
644 del lines[0]
645 nbargs = len(args)
646 while len(lines) > 0 and lines[0][0:3] == '* @':
647 l = lines[0][3:]
648 try:
649 (arg, desc) = string.split(l, ':', 1)
650 desc=string.strip(desc)
651 arg=string.strip(arg)
652 except:
653 if not quiet:
654 print "Misformatted function comment for %s" % (name)
655 print " problem with '%s'" % (lines[0])
656 del lines[0]
657 continue
658 del lines[0]
659 l = string.strip(lines[0])
660 while len(l) > 2 and l[0:3] != '* @':
661 while l[0] == '*':
662 l = l[1:]
663 desc = desc + ' ' + string.strip(l)
664 del lines[0]
665 if len(lines) == 0:
666 break
667 l = lines[0]
668 i = 0
669 while i < nbargs:
670 if args[i][1] == arg:
671 args[i] = (args[i][0], arg, desc)
672 break;
673 i = i + 1
674 if i >= nbargs:
675 if not quiet:
676 print "Uname to find arg %s from function comment for %s" % (
677 arg, name)
678 while len(lines) > 0 and lines[0] == '*':
679 del lines[0]
680 desc = ""
681 while len(lines) > 0:
682 l = lines[0]
683 while len(l) > 0 and l[0] == '*':
684 l = l[1:]
685 l = string.strip(l)
686 if len(l) >= 6 and l[0:6] == "return" or l[0:6] == "Return":
687 try:
688 l = string.split(l, ' ', 1)[1]
689 except:
690 l = ""
691 retdesc = string.strip(l)
692 del lines[0]
693 while len(lines) > 0:
694 l = lines[0]
695 while len(l) > 0 and l[0] == '*':
696 l = l[1:]
697 l = string.strip(l)
698 retdesc = retdesc + " " + l
699 del lines[0]
700 else:
701 desc = desc + " " + l
702 del lines[0]
703
704 retdesc = string.strip(retdesc)
705 desc = string.strip(desc)
706
707 if quiet == 0:
708 #
709 # report missing comments
710 #
711 i = 0
712 while i < nbargs:
713 if args[i][2] == None and args[i][0] != "void" and args[i][1] != None:
714 print "Function comment for %s lack description of arg %s" % (name, args[i][1])
715 i = i + 1
716 if retdesc == "" and ret[0] != "void":
717 print "Function comment for %s lack description of return value" % (name)
718 if desc == "":
719 print "Function comment for %s lack description of the function" % (name)
720
721
722 return(((ret[0], retdesc), args, desc))
723
724 def parsePreproc(self, token):
725 name = token[1]
726 if name == "#include":
727 token = self.lexer.token()
728 if token == None:
729 return None
730 if token[0] == 'preproc':
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000731 self.index_add(token[1], self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000732 "include")
733 return self.lexer.token()
734 return token
735 if name == "#define":
736 token = self.lexer.token()
737 if token == None:
738 return None
739 if token[0] == 'preproc':
740 # TODO macros with arguments
741 name = token[1]
742 lst = []
743 token = self.lexer.token()
744 while token != None and token[0] == 'preproc' and \
745 token[1][0] != '#':
746 lst.append(token[1])
747 token = self.lexer.token()
748 try:
749 name = string.split(name, '(') [0]
750 except:
751 pass
752 info = self.parseMacroComment(name, not self.is_header)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000753 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000754 "macro", info)
755 return token
756 token = self.lexer.token()
757 while token != None and token[0] == 'preproc' and \
758 token[1][0] != '#':
759 token = self.lexer.token()
760 return token
761
762 #
763 # token acquisition on top of the lexer, it handle internally
764 # preprocessor and comments since they are logically not part of
765 # the program structure.
766 #
767 def token(self):
768 global ignored_words
769
770 token = self.lexer.token()
771 while token != None:
772 if token[0] == 'comment':
773 token = self.parseComment(token)
774 continue
775 elif token[0] == 'preproc':
776 token = self.parsePreproc(token)
777 continue
778 elif token[0] == "name" and ignored_words.has_key(token[1]):
779 (n, info) = ignored_words[token[1]]
780 i = 0
781 while i < n:
782 token = self.lexer.token()
783 i = i + 1
784 token = self.lexer.token()
785 continue
786 else:
787 #print "=> ", token
788 return token
789 return None
790
791 #
792 # Parse a typedef, it records the type and its name.
793 #
794 def parseTypedef(self, token):
795 if token == None:
796 return None
797 token = self.parseType(token)
798 if token == None:
799 self.error("parsing typedef")
800 return None
801 base_type = self.type
802 type = base_type
803 #self.debug("end typedef type", token)
804 while token != None:
805 if token[0] == "name":
806 name = token[1]
807 signature = self.signature
808 if signature != None:
Daniel Veillard000eafb2002-12-12 10:04:22 +0000809 type = string.split(type, '(')[0]
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000810 d = self.mergeFunctionComment(name,
811 ((type, None), signature), 1)
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000812 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000813 "functype", d)
814 else:
815 if base_type == "struct":
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000816 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000817 "struct", type)
818 base_type = "struct " + name
819 else:
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000820 self.index_add(name, self.filename, not self.is_header,
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000821 "typedef", type)
822 token = self.token()
823 else:
824 self.error("parsing typedef: expecting a name")
825 return token
826 #self.debug("end typedef", token)
827 if token != None and token[0] == 'sep' and token[1] == ',':
828 type = base_type
829 token = self.token()
830 while token != None and token[0] == "op":
831 type = type + token[1]
832 token = self.token()
833 elif token != None and token[0] == 'sep' and token[1] == ';':
834 break;
835 elif token != None and token[0] == 'name':
836 type = base_type
837 continue;
838 else:
839 self.error("parsing typedef: expecting ';'", token)
840 return token
841 token = self.token()
842 return token
843
844 #
845 # Parse a C code block, used for functions it parse till
846 # the balancing } included
847 #
848 def parseBlock(self, token):
849 while token != None:
850 if token[0] == "sep" and token[1] == "{":
851 token = self.token()
852 token = self.parseBlock(token)
853 elif token[0] == "sep" and token[1] == "}":
854 self.comment = None
855 token = self.token()
856 return token
857 else:
Daniel Veillardd8cf9062003-11-11 21:12:36 +0000858 if self.collect_ref == 1:
859 oldtok = token
860 token = self.token()
861 if oldtok[0] == "name" and oldtok[1][0:3] == "xml":
862 if token[0] == "sep" and token[1] == "(":
863 self.index_add_ref(oldtok[1], self.filename,
864 0, "function")
865 token = self.token()
866 elif token[0] == "name":
867 token = self.token()
868 if token[0] == "sep" and (token[1] == ";" or
869 token[1] == "," or token[1] == "="):
870 self.index_add_ref(oldtok[1], self.filename,
871 0, "type")
872 elif oldtok[0] == "name" and oldtok[1][0:4] == "XML_":
873 self.index_add_ref(oldtok[1], self.filename,
874 0, "typedef")
875 elif oldtok[0] == "name" and oldtok[1][0:7] == "LIBXML_":
876 self.index_add_ref(oldtok[1], self.filename,
877 0, "typedef")
878
879 else:
880 token = self.token()
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000881 return token
882
883 #
884 # Parse a C struct definition till the balancing }
885 #
886 def parseStruct(self, token):
887 fields = []
888 #self.debug("start parseStruct", token)
889 while token != None:
890 if token[0] == "sep" and token[1] == "{":
891 token = self.token()
892 token = self.parseTypeBlock(token)
893 elif token[0] == "sep" and token[1] == "}":
894 self.struct_fields = fields
895 #self.debug("end parseStruct", token)
896 #print fields
897 token = self.token()
898 return token
899 else:
900 base_type = self.type
901 #self.debug("before parseType", token)
902 token = self.parseType(token)
903 #self.debug("after parseType", token)
904 if token != None and token[0] == "name":
905 fname = token[1]
906 token = self.token()
907 if token[0] == "sep" and token[1] == ";":
908 self.comment = None
909 token = self.token()
910 fields.append((self.type, fname, self.comment))
911 self.comment = None
912 else:
913 self.error("parseStruct: expecting ;", token)
914 elif token != None and token[0] == "sep" and token[1] == "{":
915 token = self.token()
916 token = self.parseTypeBlock(token)
917 if token != None and token[0] == "name":
918 token = self.token()
919 if token != None and token[0] == "sep" and token[1] == ";":
920 token = self.token()
921 else:
922 self.error("parseStruct: expecting ;", token)
923 else:
924 self.error("parseStruct: name", token)
925 token = self.token()
926 self.type = base_type;
927 self.struct_fields = fields
928 #self.debug("end parseStruct", token)
929 #print fields
930 return token
931
932 #
933 # Parse a C enum block, parse till the balancing }
934 #
935 def parseEnumBlock(self, token):
936 self.enums = []
937 name = None
938 self.comment = None
939 comment = ""
Daniel Veillard000eafb2002-12-12 10:04:22 +0000940 value = "0"
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000941 while token != None:
942 if token[0] == "sep" and token[1] == "{":
943 token = self.token()
944 token = self.parseTypeBlock(token)
945 elif token[0] == "sep" and token[1] == "}":
946 if name != None:
947 if self.comment != None:
948 comment = self.comment
949 self.comment = None
950 self.enums.append((name, value, comment))
951 token = self.token()
952 return token
953 elif token[0] == "name":
954 if name != None:
955 if self.comment != None:
956 comment = string.strip(self.comment)
957 self.comment = None
958 self.enums.append((name, value, comment))
959 name = token[1]
960 comment = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000961 token = self.token()
962 if token[0] == "op" and token[1][0] == "=":
Daniel Veillard000eafb2002-12-12 10:04:22 +0000963 value = ""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000964 if len(token[1]) > 1:
965 value = token[1][1:]
966 token = self.token()
967 while token[0] != "sep" or (token[1] != ',' and
968 token[1] != '}'):
969 value = value + token[1]
970 token = self.token()
Daniel Veillard000eafb2002-12-12 10:04:22 +0000971 else:
972 try:
973 value = "%d" % (int(value) + 1)
974 except:
975 print "Failed to compute value of enum %s" % (name)
976 value=""
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000977 if token[0] == "sep" and token[1] == ",":
978 token = self.token()
979 else:
980 token = self.token()
981 return token
982
983 #
984 # Parse a C definition block, used for structs it parse till
985 # the balancing }
986 #
987 def parseTypeBlock(self, token):
988 while token != None:
989 if token[0] == "sep" and token[1] == "{":
990 token = self.token()
991 token = self.parseTypeBlock(token)
992 elif token[0] == "sep" and token[1] == "}":
993 token = self.token()
994 return token
995 else:
996 token = self.token()
997 return token
998
999 #
1000 # Parse a type: the fact that the type name can either occur after
1001 # the definition or within the definition makes it a little harder
1002 # if inside, the name token is pushed back before returning
1003 #
1004 def parseType(self, token):
1005 self.type = ""
1006 self.struct_fields = []
1007 self.signature = None
1008 if token == None:
1009 return token
1010
1011 while token[0] == "name" and (
1012 token[1] == "const" or token[1] == "unsigned"):
1013 if self.type == "":
1014 self.type = token[1]
1015 else:
1016 self.type = self.type + " " + token[1]
1017 token = self.token()
1018
1019 if token[0] == "name" and (token[1] == "long" or token[1] == "short"):
1020 if self.type == "":
1021 self.type = token[1]
1022 else:
1023 self.type = self.type + " " + token[1]
1024 if token[0] == "name" and token[1] == "int":
1025 if self.type == "":
1026 self.type = tmp[1]
1027 else:
1028 self.type = self.type + " " + tmp[1]
1029
1030 elif token[0] == "name" and token[1] == "struct":
1031 if self.type == "":
1032 self.type = token[1]
1033 else:
1034 self.type = self.type + " " + token[1]
1035 token = self.token()
1036 nametok = None
1037 if token[0] == "name":
1038 nametok = token
1039 token = self.token()
1040 if token != None and token[0] == "sep" and token[1] == "{":
1041 token = self.token()
1042 token = self.parseStruct(token)
1043 elif token != None and token[0] == "op" and token[1] == "*":
1044 self.type = self.type + " " + nametok[1] + " *"
1045 token = self.token()
1046 while token != None and token[0] == "op" and token[1] == "*":
1047 self.type = self.type + " *"
1048 token = self.token()
1049 if token[0] == "name":
1050 nametok = token
1051 token = self.token()
1052 else:
1053 self.error("struct : expecting name", token)
1054 return token
1055 elif token != None and token[0] == "name" and nametok != None:
1056 self.type = self.type + " " + nametok[1]
1057 return token
1058
1059 if nametok != None:
1060 self.lexer.push(token)
1061 token = nametok
1062 return token
1063
1064 elif token[0] == "name" and token[1] == "enum":
1065 if self.type == "":
1066 self.type = token[1]
1067 else:
1068 self.type = self.type + " " + token[1]
1069 self.enums = []
1070 token = self.token()
1071 if token != None and token[0] == "sep" and token[1] == "{":
1072 token = self.token()
1073 token = self.parseEnumBlock(token)
1074 else:
1075 self.error("parsing enum: expecting '{'", token)
1076 enum_type = None
1077 if token != None and token[0] != "name":
1078 self.lexer.push(token)
1079 token = ("name", "enum")
1080 else:
1081 enum_type = token[1]
1082 for enum in self.enums:
Daniel Veillardd8cf9062003-11-11 21:12:36 +00001083 self.index_add(enum[0], self.filename,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001084 not self.is_header, "enum",
1085 (enum[1], enum[2], enum_type))
1086 return token
1087
1088 elif token[0] == "name":
1089 if self.type == "":
1090 self.type = token[1]
1091 else:
1092 self.type = self.type + " " + token[1]
1093 else:
1094 self.error("parsing type %s: expecting a name" % (self.type),
1095 token)
1096 return token
1097 token = self.token()
1098 while token != None and (token[0] == "op" or
1099 token[0] == "name" and token[1] == "const"):
1100 self.type = self.type + " " + token[1]
1101 token = self.token()
1102
1103 #
1104 # if there is a parenthesis here, this means a function type
1105 #
1106 if token != None and token[0] == "sep" and token[1] == '(':
1107 self.type = self.type + token[1]
1108 token = self.token()
1109 while token != None and token[0] == "op" and token[1] == '*':
1110 self.type = self.type + token[1]
1111 token = self.token()
1112 if token == None or token[0] != "name" :
1113 self.error("parsing function type, name expected", token);
1114 return token
1115 self.type = self.type + token[1]
1116 nametok = token
1117 token = self.token()
1118 if token != None and token[0] == "sep" and token[1] == ')':
1119 self.type = self.type + token[1]
1120 token = self.token()
1121 if token != None and token[0] == "sep" and token[1] == '(':
1122 token = self.token()
1123 type = self.type;
1124 token = self.parseSignature(token);
1125 self.type = type;
1126 else:
1127 self.error("parsing function type, '(' expected", token);
1128 return token
1129 else:
1130 self.error("parsing function type, ')' expected", token);
1131 return token
1132 self.lexer.push(token)
1133 token = nametok
1134 return token
1135
1136 #
1137 # do some lookahead for arrays
1138 #
1139 if token != None and token[0] == "name":
1140 nametok = token
1141 token = self.token()
1142 if token != None and token[0] == "sep" and token[1] == '[':
1143 self.type = self.type + nametok[1]
1144 while token != None and token[0] == "sep" and token[1] == '[':
1145 self.type = self.type + token[1]
1146 token = self.token()
1147 while token != None and token[0] != 'sep' and \
1148 token[1] != ']' and token[1] != ';':
1149 self.type = self.type + token[1]
1150 token = self.token()
1151 if token != None and token[0] == 'sep' and token[1] == ']':
1152 self.type = self.type + token[1]
1153 token = self.token()
1154 else:
1155 self.error("parsing array type, ']' expected", token);
1156 return token
1157 elif token != None and token[0] == "sep" and token[1] == ':':
1158 # remove :12 in case it's a limited int size
1159 token = self.token()
1160 token = self.token()
1161 self.lexer.push(token)
1162 token = nametok
1163
1164 return token
1165
1166 #
1167 # Parse a signature: '(' has been parsed and we scan the type definition
1168 # up to the ')' included
1169 def parseSignature(self, token):
1170 signature = []
1171 if token != None and token[0] == "sep" and token[1] == ')':
1172 self.signature = []
1173 token = self.token()
1174 return token
1175 while token != None:
1176 token = self.parseType(token)
1177 if token != None and token[0] == "name":
1178 signature.append((self.type, token[1], None))
1179 token = self.token()
1180 elif token != None and token[0] == "sep" and token[1] == ',':
1181 token = self.token()
1182 continue
1183 elif token != None and token[0] == "sep" and token[1] == ')':
1184 # only the type was provided
1185 if self.type == "...":
1186 signature.append((self.type, "...", None))
1187 else:
1188 signature.append((self.type, None, None))
1189 if token != None and token[0] == "sep":
1190 if token[1] == ',':
1191 token = self.token()
1192 continue
1193 elif token[1] == ')':
1194 token = self.token()
1195 break
1196 self.signature = signature
1197 return token
1198
1199 #
1200 # Parse a global definition, be it a type, variable or function
1201 # the extern "C" blocks are a bit nasty and require it to recurse.
1202 #
1203 def parseGlobal(self, token):
1204 static = 0
1205 if token[1] == 'extern':
1206 token = self.token()
1207 if token == None:
1208 return token
1209 if token[0] == 'string':
1210 if token[1] == 'C':
1211 token = self.token()
1212 if token == None:
1213 return token
1214 if token[0] == 'sep' and token[1] == "{":
1215 token = self.token()
1216# print 'Entering extern "C line ', self.lineno()
1217 while token != None and (token[0] != 'sep' or
1218 token[1] != "}"):
1219 if token[0] == 'name':
1220 token = self.parseGlobal(token)
1221 else:
1222 self.error(
1223 "token %s %s unexpected at the top level" % (
1224 token[0], token[1]))
1225 token = self.parseGlobal(token)
1226# print 'Exiting extern "C" line', self.lineno()
1227 token = self.token()
1228 return token
1229 else:
1230 return token
1231 elif token[1] == 'static':
1232 static = 1
1233 token = self.token()
1234 if token == None or token[0] != 'name':
1235 return token
1236
1237 if token[1] == 'typedef':
1238 token = self.token()
1239 return self.parseTypedef(token)
1240 else:
1241 token = self.parseType(token)
1242 type_orig = self.type
1243 if token == None or token[0] != "name":
1244 return token
1245 type = type_orig
1246 self.name = token[1]
1247 token = self.token()
1248 while token != None and (token[0] == "sep" or token[0] == "op"):
1249 if token[0] == "sep":
1250 if token[1] == "[":
1251 type = type + token[1]
1252 token = self.token()
1253 while token != None and (token[0] != "sep" or \
1254 token[1] != ";"):
1255 type = type + token[1]
1256 token = self.token()
1257
1258 if token != None and token[0] == "op" and token[1] == "=":
1259 #
1260 # Skip the initialization of the variable
1261 #
1262 token = self.token()
1263 if token[0] == 'sep' and token[1] == '{':
1264 token = self.token()
1265 token = self.parseBlock(token)
1266 else:
1267 self.comment = None
1268 while token != None and (token[0] != "sep" or \
1269 (token[1] != ';' and token[1] != ',')):
1270 token = self.token()
1271 self.comment = None
1272 if token == None or token[0] != "sep" or (token[1] != ';' and
1273 token[1] != ','):
1274 self.error("missing ';' or ',' after value")
1275
1276 if token != None and token[0] == "sep":
1277 if token[1] == ";":
1278 self.comment = None
1279 token = self.token()
1280 if type == "struct":
Daniel Veillardd8cf9062003-11-11 21:12:36 +00001281 self.index_add(self.name, self.filename,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001282 not self.is_header, "struct", self.struct_fields)
1283 else:
Daniel Veillardd8cf9062003-11-11 21:12:36 +00001284 self.index_add(self.name, self.filename,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001285 not self.is_header, "variable", type)
1286 break
1287 elif token[1] == "(":
1288 token = self.token()
1289 token = self.parseSignature(token)
1290 if token == None:
1291 return None
1292 if token[0] == "sep" and token[1] == ";":
1293 d = self.mergeFunctionComment(self.name,
1294 ((type, None), self.signature), 1)
Daniel Veillardd8cf9062003-11-11 21:12:36 +00001295 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001296 "function", d)
1297 token = self.token()
Daniel Veillard71531f32003-02-05 13:19:53 +00001298 elif token[0] == "sep" and token[1] == "{":
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001299 d = self.mergeFunctionComment(self.name,
1300 ((type, None), self.signature), static)
Daniel Veillardd8cf9062003-11-11 21:12:36 +00001301 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001302 "function", d)
1303 token = self.token()
1304 token = self.parseBlock(token);
1305 elif token[1] == ',':
1306 self.comment = None
Daniel Veillardd8cf9062003-11-11 21:12:36 +00001307 self.index_add(self.name, self.filename, static,
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001308 "variable", type)
1309 type = type_orig
1310 token = self.token()
1311 while token != None and token[0] == "sep":
1312 type = type + token[1]
1313 token = self.token()
1314 if token != None and token[0] == "name":
1315 self.name = token[1]
1316 token = self.token()
1317 else:
1318 break
1319
1320 return token
1321
1322 def parse(self):
1323 print "Parsing %s" % (self.filename)
1324 token = self.token()
1325 while token != None:
1326 if token[0] == 'name':
1327 token = self.parseGlobal(token)
1328 else:
1329 self.error("token %s %s unexpected at the top level" % (
1330 token[0], token[1]))
1331 token = self.parseGlobal(token)
1332 return
1333 return self.index
1334
1335
1336class docBuilder:
1337 """A documentation builder"""
1338 def __init__(self, name, directories=['.'], excludes=[]):
1339 self.name = name
1340 self.directories = directories
1341 self.excludes = excludes + ignored_files.keys()
1342 self.modules = {}
1343 self.headers = {}
1344 self.idx = index()
1345
1346 def analyze(self):
1347 print "Project %s : %d headers, %d modules" % (self.name, len(self.headers.keys()), len(self.modules.keys()))
1348 self.idx.analyze()
1349
1350 def scanHeaders(self):
1351 for header in self.headers.keys():
1352 parser = CParser(header)
1353 idx = parser.parse()
1354 self.headers[header] = idx;
1355 self.idx.merge(idx)
1356
1357 def scanModules(self):
1358 for module in self.modules.keys():
1359 parser = CParser(module)
1360 idx = parser.parse()
1361 # idx.analyze()
1362 self.modules[module] = idx
1363 self.idx.merge_public(idx)
1364
1365 def scan(self):
1366 for directory in self.directories:
1367 files = glob.glob(directory + "/*.c")
1368 for file in files:
1369 skip = 0
1370 for excl in self.excludes:
1371 if string.find(file, excl) != -1:
1372 skip = 1;
1373 break
1374 if skip == 0:
1375 self.modules[file] = None;
1376 files = glob.glob(directory + "/*.h")
1377 for file in files:
1378 skip = 0
1379 for excl in self.excludes:
1380 if string.find(file, excl) != -1:
1381 skip = 1;
1382 break
1383 if skip == 0:
1384 self.headers[file] = None;
1385 self.scanHeaders()
1386 self.scanModules()
1387
1388 def modulename_file(self, file):
Daniel Veillard540a31a2003-01-21 11:21:07 +00001389 module = os.path.basename(file)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001390 if module[-2:] == '.h':
1391 module = module[:-2]
1392 return module
1393
1394 def serialize_enum(self, output, name):
1395 id = self.idx.enums[name]
1396 output.write(" <enum name='%s' file='%s'" % (name,
1397 self.modulename_file(id.module)))
1398 if id.info != None:
1399 info = id.info
1400 if info[0] != None and info[0] != '':
Daniel Veillard16fa96c2003-09-23 21:50:54 +00001401 try:
1402 val = eval(info[0])
1403 except:
1404 val = info[0]
1405 output.write(" value='%s'" % (val));
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001406 if info[2] != None and info[2] != '':
1407 output.write(" type='%s'" % info[2]);
1408 if info[1] != None and info[1] != '':
1409 output.write(" info='%s'" % escape(info[1]));
1410 output.write("/>\n")
1411
1412 def serialize_macro(self, output, name):
1413 id = self.idx.macros[name]
1414 output.write(" <macro name='%s' file='%s'>\n" % (name,
1415 self.modulename_file(id.module)))
1416 if id.info != None:
1417 try:
1418 (args, desc) = id.info
1419 if desc != None and desc != "":
1420 output.write(" <info>%s</info>\n" % (escape(desc)))
1421 for arg in args:
1422 (name, desc) = arg
1423 if desc != None and desc != "":
1424 output.write(" <arg name='%s' info='%s'/>\n" % (
1425 name, escape(desc)))
1426 else:
1427 output.write(" <arg name='%s'/>\n" % (name))
1428 except:
1429 pass
1430 output.write(" </macro>\n")
1431
1432 def serialize_typedef(self, output, name):
1433 id = self.idx.typedefs[name]
1434 if id.info[0:7] == 'struct ':
1435 output.write(" <struct name='%s' file='%s' type='%s'" % (
1436 name, self.modulename_file(id.module), id.info))
1437 name = id.info[7:]
Daniel Veillardc1eed322002-12-12 11:01:32 +00001438 if self.idx.structs.has_key(name) and ( \
1439 type(self.idx.structs[name].info) == type(()) or
1440 type(self.idx.structs[name].info) == type([])):
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001441 output.write(">\n");
Daniel Veillard024b5702002-12-12 00:15:55 +00001442 try:
1443 for field in self.idx.structs[name].info:
Daniel Veillard024b5702002-12-12 00:15:55 +00001444 desc = field[2]
1445 if desc == None:
1446 desc = ''
1447 else:
1448 desc = escape(desc)
1449 output.write(" <field name='%s' type='%s' info='%s'/>\n" % (field[1] , field[0], desc))
1450 except:
1451 print "Failed to serialize struct %s" % (name)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001452 output.write(" </struct>\n")
1453 else:
1454 output.write("/>\n");
1455 else :
1456 output.write(" <typedef name='%s' file='%s' type='%s'/>\n" % (
1457 name, self.modulename_file(id.module), id.info))
1458
Daniel Veillardc1eed322002-12-12 11:01:32 +00001459 def serialize_variable(self, output, name):
1460 id = self.idx.variables[name]
1461 if id.info != None:
1462 output.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
1463 name, self.modulename_file(id.module), id.info))
1464 else:
1465 output.write(" <variable name='%s' file='%s'/>\n" % (
1466 name, self.modulename_file(id.module)))
1467
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001468 def serialize_function(self, output, name):
1469 id = self.idx.functions[name]
1470 output.write(" <%s name='%s' file='%s'>\n" % (id.type, name,
1471 self.modulename_file(id.module)))
1472 try:
1473 (ret, params, desc) = id.info
1474 output.write(" <info>%s</info>\n" % (escape(desc)))
1475 if ret[0] != None:
1476 if ret[0] == "void":
1477 output.write(" <return type='void'/>\n")
1478 else:
1479 output.write(" <return type='%s' info='%s'/>\n" % (
1480 ret[0], escape(ret[1])))
1481 for param in params:
1482 if param[0] == 'void':
1483 continue
1484 if param[2] == None:
1485 output.write(" <arg name='%s' type='%s' info=''/>\n" % (param[1], param[0]))
1486 else:
1487 output.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param[1], param[0], escape(param[2])))
1488 except:
1489 print "Failed to save function %s info: " % name, `id.info`
1490 output.write(" </%s>\n" % (id.type))
1491
1492 def serialize_exports(self, output, file):
1493 module = self.modulename_file(file)
1494 output.write(" <file name='%s'>\n" % (module))
1495 dict = self.headers[file]
1496 ids = dict.functions.keys() + dict.variables.keys() + \
1497 dict.macros.keys() + dict.typedefs.keys() + \
1498 dict.structs.keys() + dict.enums.keys()
1499 ids.sort()
1500 for id in ids:
1501 output.write(" <exports symbol='%s'/>\n" % (id))
1502 output.write(" </file>\n")
1503
1504
1505 def serialize(self, filename = None):
1506 if filename == None:
1507 filename = "%s-api.xml" % self.name
1508 print "Saving XML description %s" % (filename)
1509 output = open(filename, "w")
1510 output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
1511 output.write("<api name='%s'>\n" % self.name)
1512 output.write(" <files>\n")
1513 for file in self.headers.keys():
1514 self.serialize_exports(output, file)
1515 output.write(" </files>\n")
1516 output.write(" <symbols>\n")
1517 macros = self.idx.macros.keys()
1518 macros.sort()
1519 for macro in macros:
1520 self.serialize_macro(output, macro)
1521 enums = self.idx.enums.keys()
1522 enums.sort()
1523 for enum in enums:
1524 self.serialize_enum(output, enum)
1525 typedefs = self.idx.typedefs.keys()
1526 typedefs.sort()
1527 for typedef in typedefs:
1528 self.serialize_typedef(output, typedef)
Daniel Veillardc1eed322002-12-12 11:01:32 +00001529 variables = self.idx.variables.keys()
1530 variables.sort()
1531 for variable in variables:
1532 self.serialize_variable(output, variable)
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001533 functions = self.idx.functions.keys()
1534 functions.sort()
1535 for function in functions:
1536 self.serialize_function(output, function)
1537 output.write(" </symbols>\n")
1538 output.write("</api>\n")
1539 output.close()
1540
1541
1542def rebuild():
1543 builder = None
1544 if glob.glob("../parser.c") != [] :
1545 print "Rebuilding API description for libxml2"
1546 builder = docBuilder("libxml2", ["..", "../include/libxml"],
Daniel Veillardd4330462003-04-29 12:40:16 +00001547 ["xmlwin32version.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001548 elif glob.glob("../libxslt/transform.c") != [] :
1549 print "Rebuilding API description for libxslt"
1550 builder = docBuilder("libxslt", ["../libxslt"],
Daniel Veillard024b5702002-12-12 00:15:55 +00001551 ["win32config.h", "libxslt.h", "tst.c"])
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001552 else:
1553 print "rebuild() failed, unable to guess the module"
1554 return None
1555 builder.scan()
1556 builder.analyze()
1557 builder.serialize()
Daniel Veillard024b5702002-12-12 00:15:55 +00001558 if glob.glob("../libexslt/exslt.c") != [] :
1559 extra = docBuilder("libexslt", ["../libexslt"], ["libexslt.h"])
1560 extra.scan()
1561 extra.analyze()
1562 extra.serialize()
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001563 return builder
1564
1565#
1566# for debugging the parser
1567#
1568def parse(filename):
1569 parser = CParser(filename)
1570 idx = parser.parse()
1571 return idx
1572
1573if __name__ == "__main__":
1574 rebuild()