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