3 # This is the API builder, it parses the C sources and build the
4 # API formal description in XML.
6 # See Copyright for the status of this software.
11 from __future__
import print_function
24 # C parser analysis code
27 "libvirt-common.h": "header with general libvirt API definitions",
28 "libvirt-domain.h": "header with general libvirt API definitions",
29 "libvirt-domain-checkpoint.h": "header with general libvirt API definitions",
30 "libvirt-domain-snapshot.h": "header with general libvirt API definitions",
31 "libvirt-event.h": "header with general libvirt API definitions",
32 "libvirt-host.h": "header with general libvirt API definitions",
33 "libvirt-interface.h": "header with general libvirt API definitions",
34 "libvirt-network.h": "header with general libvirt API definitions",
35 "libvirt-nodedev.h": "header with general libvirt API definitions",
36 "libvirt-nwfilter.h": "header with general libvirt API definitions",
37 "libvirt-secret.h": "header with general libvirt API definitions",
38 "libvirt-storage.h": "header with general libvirt API definitions",
39 "libvirt-stream.h": "header with general libvirt API definitions",
40 "virterror.h": "header with error specific API definitions",
41 "libvirt.c": "Main interfaces for the libvirt library",
42 "libvirt-domain.c": "Domain interfaces for the libvirt library",
43 "libvirt-domain-checkpoint.c": "Domain checkpoint interfaces for the libvirt library",
44 "libvirt-domain-snapshot.c": "Domain snapshot interfaces for the libvirt library",
45 "libvirt-host.c": "Host interfaces for the libvirt library",
46 "libvirt-interface.c": "Interface interfaces for the libvirt library",
47 "libvirt-network.c": "Network interfaces for the libvirt library",
48 "libvirt-nodedev.c": "Node device interfaces for the libvirt library",
49 "libvirt-nwfilter.c": "NWFilter interfaces for the libvirt library",
50 "libvirt-secret.c": "Secret interfaces for the libvirt library",
51 "libvirt-storage.c": "Storage interfaces for the libvirt library",
52 "libvirt-stream.c": "Stream interfaces for the libvirt library",
53 "virerror.c": "implements error handling and reporting code for libvirt",
54 "virevent.c": "event loop for monitoring file handles",
55 "virtypedparam.c": "virTypedParameters APIs",
58 qemu_included_files
= {
59 "libvirt-qemu.h": "header with QEMU specific API definitions",
60 "libvirt-qemu.c": "Implementations for the QEMU specific APIs",
63 lxc_included_files
= {
64 "libvirt-lxc.h": "header with LXC specific API definitions",
65 "libvirt-lxc.c": "Implementations for the LXC specific APIs",
68 admin_included_files
= {
69 "libvirt-admin.h": "header with admin specific API definitions",
70 "libvirt-admin.c": "Implementations for the admin specific APIs",
74 "ATTRIBUTE_UNUSED": (0, "macro keyword"),
75 "ATTRIBUTE_SENTINEL": (0, "macro keyword"),
76 "VIR_DEPRECATED": (0, "macro keyword"),
77 "VIR_EXPORT_VAR": (0, "macro keyword"),
78 "WINAPI": (0, "Windows keyword"),
79 "__declspec": (3, "Windows keyword"),
80 "__stdcall": (0, "Windows keyword"),
84 "virConnectSupportsFeature": "private function for remote access",
85 "virDomainMigrateFinish": "private function for migration",
86 "virDomainMigrateFinish2": "private function for migration",
87 "virDomainMigratePerform": "private function for migration",
88 "virDomainMigratePrepare": "private function for migration",
89 "virDomainMigratePrepare2": "private function for migration",
90 "virDomainMigratePrepareTunnel": "private function for tunnelled migration",
91 "virDomainMigrateBegin3": "private function for migration",
92 "virDomainMigrateFinish3": "private function for migration",
93 "virDomainMigratePerform3": "private function for migration",
94 "virDomainMigratePrepare3": "private function for migration",
95 "virDomainMigrateConfirm3": "private function for migration",
96 "virDomainMigratePrepareTunnel3": "private function for tunnelled migration",
97 "DllMain": "specific function for Win32",
98 "virTypedParamsValidate": "internal function in virtypedparam.c",
99 "virTypedParameterValidateSet": "internal function in virtypedparam.c",
100 "virTypedParameterAssign": "internal function in virtypedparam.c",
101 "virTypedParameterAssignFromStr": "internal function in virtypedparam.c",
102 "virTypedParameterToString": "internal function in virtypedparam.c",
103 "virTypedParamsCheck": "internal function in virtypedparam.c",
104 "virTypedParamsCopy": "internal function in virtypedparam.c",
105 "virDomainMigrateBegin3Params": "private function for migration",
106 "virDomainMigrateFinish3Params": "private function for migration",
107 "virDomainMigratePerform3Params": "private function for migration",
108 "virDomainMigratePrepare3Params": "private function for migration",
109 "virDomainMigrateConfirm3Params": "private function for migration",
110 "virDomainMigratePrepareTunnel3Params": "private function for tunnelled migration",
111 "virErrorCopyNew": "private",
115 "_virSchedParameter": "backward compatibility macro for virTypedParameter",
116 "_virBlkioParameter": "backward compatibility macro for virTypedParameter",
117 "_virMemoryParameter": "backward compatibility macro for virTypedParameter",
120 # macros that should be completely skipped
122 "VIR_DEPRECATED": "internal macro to mark deprecated apis",
123 "VIR_EXPORT_VAR": "internal macro to mark exported vars",
127 raw
= raw
.replace('&', '&')
128 raw
= raw
.replace('<', '<')
129 raw
= raw
.replace('>', '>')
130 raw
= raw
.replace("'", ''')
131 raw
= raw
.replace('"', '"')
135 return sorted(set(items
))
138 def __init__(self
, name
, header
=None, module
=None, type=None, lineno
=0,
139 info
=None, extra
=None, conditionals
=None):
148 if conditionals
is None or len(conditionals
) == 0:
149 self
.conditionals
= None
151 self
.conditionals
= conditionals
[:]
152 if self
.name
== debugsym
and not quiet
:
153 print("=> define %s : %s" % (debugsym
, (module
, type, info
,
154 extra
, conditionals
)))
157 r
= "%s %s:" % (self
.type, self
.name
)
160 if self
.module
is not None:
161 r
= r
+ " from %s" % self
.module
162 if self
.info
is not None:
163 r
= r
+ " " + repr(self
.info
)
164 if self
.extra
is not None:
165 r
= r
+ " " + repr(self
.extra
)
166 if self
.conditionals
is not None:
167 r
= r
+ " " + repr(self
.conditionals
)
171 def set_header(self
, header
):
173 def set_module(self
, module
):
175 def set_type(self
, type):
177 def set_info(self
, info
):
179 def set_extra(self
, extra
):
181 def set_lineno(self
, lineno
):
183 def set_static(self
, static
):
185 def set_conditionals(self
, conditionals
):
186 if conditionals
is None or len(conditionals
) == 0:
187 self
.conditionals
= None
189 self
.conditionals
= conditionals
[:]
193 def get_header(self
):
195 def get_module(self
):
201 def get_lineno(self
):
205 def get_static(self
):
207 def get_conditionals(self
):
208 return self
.conditionals
210 def update(self
, header
, module
, type=None, info
=None, extra
=None,
212 if self
.name
== debugsym
and not quiet
:
213 print("=> update %s : %s" % (debugsym
, (module
, type, info
,
214 extra
, conditionals
)))
215 if header
is not None and self
.header
is None:
216 self
.set_header(module
)
217 if module
is not None and (self
.module
is None or self
.header
== self
.module
):
218 self
.set_module(module
)
219 if type is not None and self
.type is None:
223 if extra
is not None:
224 self
.set_extra(extra
)
225 if conditionals
is not None:
226 self
.set_conditionals(conditionals
)
229 def __init__(self
, name
="noname"):
231 self
.identifiers
= {}
243 def warning(self
, msg
):
245 warnings
= warnings
+ 1
248 def add_ref(self
, name
, header
, module
, static
, type, lineno
, info
=None, extra
=None, conditionals
=None):
249 if name
[0:2] == '__':
253 d
= self
.identifiers
[name
]
254 d
.update(header
, module
, type, lineno
, info
, extra
, conditionals
)
256 d
= identifier(name
, header
, module
, type, lineno
, info
, extra
,
258 self
.identifiers
[name
] = d
260 if d
is not None and static
== 1:
263 if d
is not None and name
is not None and type is not None:
264 self
.references
[name
] = d
266 if name
== debugsym
and not quiet
:
267 print("New ref: %s" % (d
))
271 def add(self
, name
, header
, module
, static
, type, lineno
, info
=None,
272 extra
=None, conditionals
=None):
273 if name
[0:2] == '__':
277 d
= self
.identifiers
[name
]
278 d
.update(header
, module
, type, lineno
, info
, extra
, conditionals
)
280 d
= identifier(name
, header
, module
, type, lineno
, info
, extra
,
282 self
.identifiers
[name
] = d
284 if d
is not None and static
== 1:
287 if d
is not None and name
is not None and type is not None:
289 "function": self
.functions
,
290 "functype": self
.functions
,
291 "variable": self
.variables
,
292 "include": self
.includes
,
293 "struct": self
.structs
,
294 "union": self
.unions
,
296 "typedef": self
.typedefs
,
300 type_map
[type][name
] = d
302 self
.warning("Unable to register type ", type)
304 if name
== debugsym
and not quiet
:
305 print("New symbol: %s" % (d
))
309 def merge(self
, idx
):
310 for id in idx
.functions
.keys():
312 # macro might be used to override functions or variables
315 if id in self
.macros
:
317 if id in self
.functions
:
318 self
.warning("function %s from %s redeclared in %s" % (
319 id, self
.functions
[id].header
, idx
.functions
[id].header
))
321 self
.functions
[id] = idx
.functions
[id]
322 self
.identifiers
[id] = idx
.functions
[id]
323 for id in idx
.variables
.keys():
325 # macro might be used to override functions or variables
328 if id in self
.macros
:
330 if id in self
.variables
:
331 self
.warning("variable %s from %s redeclared in %s" % (
332 id, self
.variables
[id].header
, idx
.variables
[id].header
))
334 self
.variables
[id] = idx
.variables
[id]
335 self
.identifiers
[id] = idx
.variables
[id]
336 for id in idx
.structs
.keys():
337 if id in self
.structs
:
338 self
.warning("struct %s from %s redeclared in %s" % (
339 id, self
.structs
[id].header
, idx
.structs
[id].header
))
341 self
.structs
[id] = idx
.structs
[id]
342 self
.identifiers
[id] = idx
.structs
[id]
343 for id in idx
.unions
.keys():
344 if id in self
.unions
:
345 print("union %s from %s redeclared in %s" % (
346 id, self
.unions
[id].header
, idx
.unions
[id].header
))
348 self
.unions
[id] = idx
.unions
[id]
349 self
.identifiers
[id] = idx
.unions
[id]
350 for id in idx
.typedefs
.keys():
351 if id in self
.typedefs
:
352 self
.warning("typedef %s from %s redeclared in %s" % (
353 id, self
.typedefs
[id].header
, idx
.typedefs
[id].header
))
355 self
.typedefs
[id] = idx
.typedefs
[id]
356 self
.identifiers
[id] = idx
.typedefs
[id]
357 for id in idx
.macros
.keys():
359 # macro might be used to override functions or variables
362 if id in self
.variables
:
364 if id in self
.functions
:
368 if id in self
.macros
:
369 self
.warning("macro %s from %s redeclared in %s" % (
370 id, self
.macros
[id].header
, idx
.macros
[id].header
))
372 self
.macros
[id] = idx
.macros
[id]
373 self
.identifiers
[id] = idx
.macros
[id]
374 for id in idx
.enums
.keys():
376 self
.warning("enum %s from %s redeclared in %s" % (
377 id, self
.enums
[id].header
, idx
.enums
[id].header
))
379 self
.enums
[id] = idx
.enums
[id]
380 self
.identifiers
[id] = idx
.enums
[id]
382 def merge_public(self
, idx
):
383 for id in idx
.functions
.keys():
384 if id in self
.functions
:
385 up
= idx
.functions
[id]
386 # check that function condition agrees with header
387 if up
.conditionals
!= self
.functions
[id].conditionals
:
388 self
.warning("Header condition differs from Function"
390 self
.warning(" H: %s" % self
.functions
[id].conditionals
)
391 self
.warning(" C: %s" % up
.conditionals
)
392 self
.functions
[id].update(None, up
.module
, up
.type, up
.info
,
395 # print("Function %s from %s is not declared in headers" % (
396 # id, idx.functions[id].module))
397 # TODO: do the same for variables.
399 def analyze_dict(self
, type, dict):
402 for name
in dict.keys():
408 print(" %d %s , %d public" % (count
, type, public
))
410 print(" %d public %s" % (count
, type))
415 self
.analyze_dict("functions", self
.functions
)
416 self
.analyze_dict("variables", self
.variables
)
417 self
.analyze_dict("structs", self
.structs
)
418 self
.analyze_dict("unions", self
.unions
)
419 self
.analyze_dict("typedefs", self
.typedefs
)
420 self
.analyze_dict("macros", self
.macros
)
423 """A lexer for the C language, tokenize the input by reading and
424 analyzing it line by line"""
425 def __init__(self
, input):
434 line
= self
.input.readline()
441 while line
[-1] == '\\':
443 n
= self
.input.readline().strip()
453 def push(self
, token
):
454 self
.tokens
.insert(0, token
)
457 print("Last token: ", self
.last
)
458 print("Token queue: ", self
.tokens
)
459 print("Line %d end: " % self
.lineno
, self
.line
)
462 while self
.tokens
== []:
464 line
= self
.getline()
472 self
.tokens
= [('preproc', word
) for word
in line
.split()]
474 # We might have whitespace between the '#' and preproc
475 # macro name, so instead of having a single token element
476 # of '#define' we might end up with '#' and 'define'. This
477 # merges them back together
478 if self
.tokens
[0][1] == "#":
479 self
.tokens
[0] = ('preproc', "#" + self
.tokens
[1][1])
483 if line
[0] == '"' or line
[0] == "'":
486 while quote
not in line
[i
:]:
488 nextline
= self
.getline()
493 tok
, self
.line
= line
[1:].split(quote
, 1)
494 self
.last
= ('string', tok
)
497 if line
.startswith("/*"):
505 if line
[i
] == '*' and i
+1 < l
and line
[i
+1] == '/':
506 self
.line
= line
[i
+2:]
516 line
= self
.getline()
519 self
.last
= ('comment', tok
)
521 if line
.startswith("//"):
523 self
.last
= ('comment', line
)
527 if line
[i
] == '/' and i
+1 < l
and line
[i
+1] == '/':
531 if line
[i
] == '/' and i
+1 < l
and line
[i
+1] == '*':
535 if line
[i
] == '"' or line
[i
] == "'":
543 if line
[i
] == ' ' or line
[i
] == '\t':
546 if line
[i
].isalnum():
549 if line
[i
] not in " \t(){}:;,+-*/%&!|[]=><":
553 self
.tokens
.append(('name', line
[s
:i
]))
555 if line
[i
] in "(){}:;,[]":
556 # if line[i] == '(' or line[i] == ')' or line[i] == '{' or \
557 # line[i] == '}' or line[i] == ':' or line[i] == ';' or \
558 # line[i] == ',' or line[i] == '[' or line[i] == ']':
559 self
.tokens
.append(('sep', line
[i
]))
562 if line
[i
] in "+-*><=/%&!|.":
563 # if line[i] == '+' or line[i] == '-' or line[i] == '*' or \
564 # line[i] == '>' or line[i] == '<' or line[i] == '=' or \
565 # line[i] == '/' or line[i] == '%' or line[i] == '&' or \
566 # line[i] == '!' or line[i] == '|' or line[i] == '.':
567 if line
[i
] == '.' and i
+ 2 < l
and \
568 line
[i
+1] == '.' and line
[i
+2] == '.':
569 self
.tokens
.append(('name', '...'))
574 if j
< l
and line
[j
] in "+-*><=/%&!|":
575 # line[j] == '+' or line[j] == '-' or line[j] == '*' or \
576 # line[j] == '>' or line[j] == '<' or line[j] == '=' or \
577 # line[j] == '/' or line[j] == '%' or line[j] == '&' or \
578 # line[j] == '!' or line[j] == '|'):
579 self
.tokens
.append(('op', line
[i
:j
+1]))
582 self
.tokens
.append(('op', line
[i
]))
587 if line
[i
] not in " \t(){}:;,+-*/%&!|[]=><":
588 # line[i] != ' ' and line[i] != '\t' and
589 # line[i] != '(' and line[i] != ')' and
590 # line[i] != '{' and line[i] != '}' and
591 # line[i] != ':' and line[i] != ';' and
592 # line[i] != ',' and line[i] != '+' and
593 # line[i] != '-' and line[i] != '*' and
594 # line[i] != '/' and line[i] != '%' and
595 # line[i] != '&' and line[i] != '!' and
596 # line[i] != '|' and line[i] != '[' and
597 # line[i] != ']' and line[i] != '=' and
598 # line[i] != '*' and line[i] != '>' and
603 self
.tokens
.append(('name', line
[s
:i
]))
606 self
.tokens
= self
.tokens
[1:]
611 """The C module parser"""
612 def __init__(self
, filename
, idx
=None):
613 self
.filename
= filename
614 if len(filename
) > 2 and filename
[-2:] == '.h':
618 self
.input = open(filename
)
619 self
.lexer
= CLexer(self
.input)
624 self
.top_comment
= ""
625 self
.last_comment
= ""
629 self
.conditionals
= []
632 def collect_references(self
):
635 def stop_error(self
):
638 def start_error(self
):
642 return self
.lexer
.getlineno()
644 def index_add(self
, name
, module
, static
, type, info
=None, extra
=None):
645 if self
.is_header
== 1:
646 self
.index
.add(name
, module
, module
, static
, type, self
.lineno(),
647 info
, extra
, self
.conditionals
)
649 self
.index
.add(name
, None, module
, static
, type, self
.lineno(),
650 info
, extra
, self
.conditionals
)
652 def index_add_ref(self
, name
, module
, static
, type, info
=None,
654 if self
.is_header
== 1:
655 self
.index
.add_ref(name
, module
, module
, static
, type,
656 self
.lineno(), info
, extra
, self
.conditionals
)
658 self
.index
.add_ref(name
, None, module
, static
, type, self
.lineno(),
659 info
, extra
, self
.conditionals
)
661 def warning(self
, msg
):
663 warnings
= warnings
+ 1
668 def error(self
, msg
, token
=-1):
672 print("Parse Error: " + msg
)
674 print("Got token ", token
)
678 def debug(self
, msg
, token
=-1):
679 print("Debug: " + msg
)
681 print("Got token ", token
)
684 def parseTopComment(self
, comment
):
686 lines
= comment
.split("\n")
689 line
= line
.lstrip().lstrip('*').lstrip()
691 m
= re
.match('([_.a-zA-Z0-9]+):(.*)', line
)
694 line
= m
.group(2).lstrip()
698 res
[item
] = res
[item
] + " " + line
701 self
.index
.info
= res
703 def strip_lead_star(self
, line
):
704 if line
.lstrip().startswith('*'):
705 line
= line
.replace('*', '', 1)
708 def cleanupComment(self
):
709 if not isinstance(self
.comment
, str):
711 # remove the leading * on multi-line comments
712 lines
= self
.comment
.splitlines(True)
715 com
= com
+ self
.strip_lead_star(line
)
716 self
.comment
= com
.strip()
718 def parseComment(self
, token
):
720 if self
.top_comment
== "":
721 self
.top_comment
= com
722 if self
.comment
is None or com
[0] == '*':
725 self
.comment
= self
.comment
+ com
726 token
= self
.lexer
.token()
728 if self
.comment
.find("DOC_DISABLE") != -1:
731 if self
.comment
.find("DOC_ENABLE") != -1:
737 # Parse a comment block associate to a typedef
739 def parseTypeComment(self
, name
, quiet
=False):
740 if name
[0:2] == '__':
743 if self
.comment
is None:
745 self
.warning("Missing comment for type %s" % name
)
747 if not self
.comment
.startswith('*'):
749 self
.warning("Missing * in type comment for %s" % name
)
752 lines
= self
.comment
.split('\n')
753 # Remove lines that contain only single asterisk
754 lines
[:] = [line
for line
in lines
if line
.strip() != '*']
756 if lines
[0] != "* %s:" % name
:
758 self
.warning("Misformatted type comment for %s" % name
)
759 self
.warning(" Expecting '* %s:' got '%s'" % (name
, lines
[0]))
763 # Concatenate all remaining lines by striping leading asterisks
764 desc
= " ".join([line
.lstrip("*").strip() for line
in lines
]).strip()
766 if not (quiet
or desc
):
767 self
.warning("Type comment for %s lack description of the macro"
772 # Parse a comment block associate to a macro
774 def parseMacroComment(self
, name
, quiet
=0):
775 global ignored_macros
777 if name
[0:2] == '__':
779 if name
in ignored_macros
:
785 if self
.comment
is None:
787 self
.warning("Missing comment for macro %s" % name
)
789 if self
.comment
[0] != '*':
791 self
.warning("Missing * in macro comment for %s" % name
)
793 lines
= self
.comment
.split('\n')
796 if lines
[0] != "* %s:" % name
:
798 self
.warning("Misformatted macro comment for %s" % name
)
799 self
.warning(" Expecting '* %s:' got '%s'" % (name
, lines
[0]))
802 while lines
[0] == '*':
804 while len(lines
) > 0 and lines
[0][0:3] == '* @':
807 arg
, desc
= l
.split(':', 1)
812 self
.warning("Misformatted macro comment for %s" % name
)
813 self
.warning(" problem with '%s'" % lines
[0])
818 while len(l
) > 2 and l
[0:3] != '* @':
821 desc
= desc
+ ' ' + l
.strip()
826 args
.append((arg
, desc
))
827 while len(lines
) > 0 and lines
[0] == '*':
830 while len(lines
) > 0:
832 while len(l
) > 0 and l
[0] == '*':
835 desc
= desc
+ " " + l
842 self
.warning("Macro comment for %s lack description of the macro" % name
)
847 # Parse a comment block and merge the information found in the
848 # parameters descriptions, finally returns a block as complete
851 def mergeFunctionComment(self
, name
, description
, quiet
=0):
852 global ignored_functions
856 if name
[0:2] == '__':
858 if name
in ignored_functions
:
861 ret
, args
= description
865 if self
.comment
is None:
867 self
.warning("Missing comment for function %s" % name
)
868 return (ret
[0], retdesc
), args
, desc
869 if self
.comment
[0] != '*':
871 self
.warning("Missing * in function comment for %s" % name
)
872 return (ret
[0], retdesc
), args
, desc
873 lines
= self
.comment
.split('\n')
876 if lines
[0] != "* %s:" % name
:
878 self
.warning("Misformatted function comment for %s" % name
)
879 self
.warning(" Expecting '* %s:' got '%s'" % (name
, lines
[0]))
880 return (ret
[0], retdesc
), args
, desc
882 while lines
[0] == '*':
885 while len(lines
) > 0 and lines
[0][0:3] == '* @':
888 arg
, desc
= l
.split(':', 1)
893 self
.warning("Misformatted function comment for %s" % name
)
894 self
.warning(" problem with '%s'" % lines
[0])
899 while len(l
) > 2 and l
[0:3] != '* @':
902 desc
= desc
+ ' ' + l
.strip()
909 if args
[i
][1] == arg
:
910 args
[i
] = (args
[i
][0], arg
, desc
)
915 self
.warning("Unable to find arg %s from function comment for %s" % (
917 while len(lines
) > 0 and lines
[0] == '*':
920 while len(lines
) > 0:
923 # Remove all leading '*', followed by at most one ' ' character
924 # since we need to preserve correct indentation of code examples
925 while i
< len(l
) and l
[i
] == '*':
928 if i
< len(l
) and l
[i
] == ' ':
931 if len(l
) >= 6 and l
[0:7] == "Returns":
933 l
= l
.split(' ', 1)[1]
938 while len(lines
) > 0:
940 while len(l
) > 0 and l
[0] == '*':
943 retdesc
= retdesc
+ " " + l
947 desc
= desc
+ "\n" + l
954 retdesc
= retdesc
.strip()
959 # report missing comments
963 if args
[i
][2] is None and args
[i
][0] != "void" and args
[i
][1] is not None:
964 self
.warning("Function comment for %s lacks description of arg %s" % (name
, args
[i
][1]))
966 if retdesc
== "" and ret
[0] != "void":
967 self
.warning("Function comment for %s lacks description of return value" % name
)
969 self
.warning("Function comment for %s lacks description of the function" % name
)
972 return (ret
[0], retdesc
), args
, desc
974 def parsePreproc(self
, token
):
976 print("=> preproc ", token
, self
.lexer
.tokens
)
978 if name
== "#include":
979 token
= self
.lexer
.token()
982 if token
[0] == 'preproc':
983 self
.index_add(token
[1], self
.filename
, not self
.is_header
,
985 return self
.lexer
.token()
987 if name
== "#define":
988 token
= self
.lexer
.token()
991 if token
[0] == 'preproc':
992 # TODO macros with arguments
995 token
= self
.lexer
.token()
996 while token
is not None and token
[0] == 'preproc' and \
999 token
= self
.lexer
.token()
1001 name
= name
.split('(') [0]
1005 # skip hidden macros
1006 if name
in hidden_macros
:
1008 if name
[-2:] == "_H" or name
[-8:] == "_H_ALLOW":
1012 if len(lst
) == 1 and lst
[0][0] == '"' and lst
[0][-1] == '"':
1013 strValue
= lst
[0][1:-1]
1014 (args
, desc
) = self
.parseMacroComment(name
, not self
.is_header
)
1015 self
.index_add(name
, self
.filename
, not self
.is_header
,
1016 "macro", (args
, desc
, strValue
))
1020 # Processing of conditionals modified by Bill 1/1/05
1022 # We process conditionals (i.e. tokens from #ifdef, #ifndef,
1023 # #if, #else and #endif) for headers and mainline code,
1024 # store the ones from the header in libxml2-api.xml, and later
1025 # (in the routine merge_public) verify that the two (header and
1026 # mainline code) agree.
1028 # There is a small problem with processing the headers. Some of
1029 # the variables are not concerned with enabling / disabling of
1030 # library functions (e.g. '__XML_PARSER_H__'), and we don't want
1031 # them to be included in libxml2-api.xml, or involved in
1032 # the check between the header and the mainline code. To
1033 # accomplish this, we ignore any conditional which doesn't include
1034 # the string 'ENABLED'
1036 if name
== "#ifdef":
1037 apstr
= self
.lexer
.tokens
[0][1]
1039 self
.defines
.append(apstr
)
1040 if apstr
.find('ENABLED') != -1:
1041 self
.conditionals
.append("defined(%s)" % apstr
)
1044 elif name
== "#ifndef":
1045 apstr
= self
.lexer
.tokens
[0][1]
1047 self
.defines
.append(apstr
)
1048 if apstr
.find('ENABLED') != -1:
1049 self
.conditionals
.append("!defined(%s)" % apstr
)
1054 for tok
in self
.lexer
.tokens
:
1057 apstr
= apstr
+ tok
[1]
1059 self
.defines
.append(apstr
)
1060 if apstr
.find('ENABLED') != -1:
1061 self
.conditionals
.append(apstr
)
1064 elif name
== "#else":
1065 if self
.conditionals
!= [] and \
1066 self
.defines
[-1].find('ENABLED') != -1:
1067 self
.conditionals
[-1] = "!(%s)" % self
.conditionals
[-1]
1068 elif name
== "#endif":
1069 if self
.conditionals
!= [] and \
1070 self
.defines
[-1].find('ENABLED') != -1:
1071 self
.conditionals
= self
.conditionals
[:-1]
1072 self
.defines
= self
.defines
[:-1]
1073 token
= self
.lexer
.token()
1074 while token
is not None and token
[0] == 'preproc' and \
1076 token
= self
.lexer
.token()
1080 # token acquisition on top of the lexer, it handle internally
1081 # preprocessor and comments since they are logically not part of
1082 # the program structure.
1084 def push(self
, tok
):
1085 self
.lexer
.push(tok
)
1088 global ignored_words
1090 token
= self
.lexer
.token()
1091 while token
is not None:
1092 if token
[0] == 'comment':
1093 token
= self
.parseComment(token
)
1095 elif token
[0] == 'preproc':
1096 token
= self
.parsePreproc(token
)
1098 elif token
[0] == "name" and token
[1] == "__const":
1099 token
= ("name", "const")
1101 elif token
[0] == "name" and token
[1] == "__attribute":
1102 token
= self
.lexer
.token()
1103 while token
is not None and token
[1] != ";":
1104 token
= self
.lexer
.token()
1106 elif token
[0] == "name" and token
[1] in ignored_words
:
1107 (n
, info
) = ignored_words
[token
[1]]
1110 token
= self
.lexer
.token()
1112 token
= self
.lexer
.token()
1121 # Parse a typedef, it records the type and its name.
1123 def parseTypedef(self
, token
):
1126 token
= self
.parseType(token
)
1128 self
.error("parsing typedef")
1130 base_type
= self
.type
1132 # self.debug("end typedef type", token)
1133 while token
is not None:
1134 if token
[0] == "name":
1136 signature
= self
.signature
1137 if signature
is not None:
1138 type = type.split('(')[0]
1139 d
= self
.mergeFunctionComment(name
,
1140 ((type, None), signature
), 1)
1141 self
.index_add(name
, self
.filename
, not self
.is_header
,
1144 if base_type
== "struct":
1145 self
.index_add(name
, self
.filename
, not self
.is_header
,
1147 base_type
= "struct " + name
1149 # TODO report missing or misformatted comments
1150 info
= self
.parseTypeComment(name
, 1)
1151 self
.index_add(name
, self
.filename
, not self
.is_header
,
1152 "typedef", type, info
)
1153 token
= self
.token()
1155 self
.error("parsing typedef: expecting a name")
1157 # self.debug("end typedef", token)
1158 if token
is not None and token
[0] == 'sep' and token
[1] == ',':
1160 token
= self
.token()
1161 while token
is not None and token
[0] == "op":
1162 type = type + token
[1]
1163 token
= self
.token()
1164 elif token
is not None and token
[0] == 'sep' and token
[1] == ';':
1166 elif token
is not None and token
[0] == 'name':
1170 self
.error("parsing typedef: expecting ';'", token
)
1172 token
= self
.token()
1176 # Parse a C code block, used for functions it parse till
1177 # the balancing } included
1179 def parseBlock(self
, token
):
1180 while token
is not None:
1181 if token
[0] == "sep" and token
[1] == "{":
1182 token
= self
.token()
1183 token
= self
.parseBlock(token
)
1184 elif token
[0] == "sep" and token
[1] == "}":
1186 token
= self
.token()
1189 if self
.collect_ref
== 1:
1191 token
= self
.token()
1192 if oldtok
[0] == "name" and oldtok
[1][0:3] == "vir":
1193 if token
[0] == "sep" and token
[1] == "(":
1194 self
.index_add_ref(oldtok
[1], self
.filename
,
1196 token
= self
.token()
1197 elif token
[0] == "name":
1198 token
= self
.token()
1199 if token
[0] == "sep" and (token
[1] == ";" or
1200 token
[1] == "," or token
[1] == "="):
1201 self
.index_add_ref(oldtok
[1], self
.filename
,
1203 elif oldtok
[0] == "name" and oldtok
[1][0:4] == "XEN_":
1204 self
.index_add_ref(oldtok
[1], self
.filename
,
1206 elif oldtok
[0] == "name" and oldtok
[1][0:7] == "LIBXEN_":
1207 self
.index_add_ref(oldtok
[1], self
.filename
,
1211 token
= self
.token()
1215 # Parse a C struct definition till the balancing }
1217 def parseStruct(self
, token
):
1219 # self.debug("start parseStruct", token)
1220 while token
is not None:
1221 if token
[0] == "sep" and token
[1] == "{":
1222 token
= self
.token()
1223 token
= self
.parseTypeBlock(token
)
1224 elif token
[0] == "sep" and token
[1] == "}":
1225 self
.struct_fields
= fields
1226 # self.debug("end parseStruct", token)
1228 token
= self
.token()
1231 base_type
= self
.type
1232 # self.debug("before parseType", token)
1233 token
= self
.parseType(token
)
1234 # self.debug("after parseType", token)
1235 if token
is not None and token
[0] == "name":
1237 token
= self
.token()
1238 if token
[0] == "sep" and token
[1] == ";":
1240 token
= self
.token()
1241 self
.cleanupComment()
1242 if self
.type == "union":
1243 fields
.append((self
.type, fname
, self
.comment
,
1245 self
.union_fields
= []
1247 fields
.append((self
.type, fname
, self
.comment
))
1250 self
.error("parseStruct: expecting ;", token
)
1251 elif token
is not None and token
[0] == "sep" and token
[1] == "{":
1252 token
= self
.token()
1253 token
= self
.parseTypeBlock(token
)
1254 if token
is not None and token
[0] == "name":
1255 token
= self
.token()
1256 if token
is not None and token
[0] == "sep" and token
[1] == ";":
1257 token
= self
.token()
1259 self
.error("parseStruct: expecting ;", token
)
1261 self
.error("parseStruct: name", token
)
1262 token
= self
.token()
1263 self
.type = base_type
1264 self
.struct_fields
= fields
1265 # self.debug("end parseStruct", token)
1270 # Parse a C union definition till the balancing }
1272 def parseUnion(self
, token
):
1274 # self.debug("start parseUnion", token)
1275 while token
is not None:
1276 if token
[0] == "sep" and token
[1] == "{":
1277 token
= self
.token()
1278 token
= self
.parseTypeBlock(token
)
1279 elif token
[0] == "sep" and token
[1] == "}":
1280 self
.union_fields
= fields
1281 # self.debug("end parseUnion", token)
1283 token
= self
.token()
1286 base_type
= self
.type
1287 # self.debug("before parseType", token)
1288 token
= self
.parseType(token
)
1289 # self.debug("after parseType", token)
1290 if token
is not None and token
[0] == "name":
1292 token
= self
.token()
1293 if token
[0] == "sep" and token
[1] == ";":
1295 token
= self
.token()
1296 self
.cleanupComment()
1297 fields
.append((self
.type, fname
, self
.comment
))
1300 self
.error("parseUnion: expecting ;", token
)
1301 elif token
is not None and token
[0] == "sep" and token
[1] == "{":
1302 token
= self
.token()
1303 token
= self
.parseTypeBlock(token
)
1304 if token
is not None and token
[0] == "name":
1305 token
= self
.token()
1306 if token
is not None and token
[0] == "sep" and token
[1] == ";":
1307 token
= self
.token()
1309 self
.error("parseUnion: expecting ;", token
)
1311 self
.error("parseUnion: name", token
)
1312 token
= self
.token()
1313 self
.type = base_type
1314 self
.union_fields
= fields
1315 # self.debug("end parseUnion", token)
1320 # Parse a C enum block, parse till the balancing }
1322 def parseEnumBlock(self
, token
):
1327 commentsBeforeVal
= self
.comment
is not None
1328 while token
is not None:
1329 if token
[0] == "sep" and token
[1] == "{":
1330 token
= self
.token()
1331 token
= self
.parseTypeBlock(token
)
1332 elif token
[0] == "sep" and token
[1] == "}":
1333 if name
is not None:
1334 self
.cleanupComment()
1335 if self
.comment
is not None:
1336 comment
= self
.comment
1338 self
.enums
.append((name
, value
, comment
))
1339 token
= self
.token()
1341 elif token
[0] == "name":
1342 self
.cleanupComment()
1343 if name
is not None:
1344 if self
.comment
is not None:
1345 comment
= self
.comment
.strip()
1347 self
.enums
.append((name
, value
, comment
))
1350 token
= self
.token()
1351 if token
[0] == "op" and token
[1][0] == "=":
1353 if len(token
[1]) > 1:
1354 value
= token
[1][1:]
1355 token
= self
.token()
1356 while token
[0] != "sep" or (token
[1] != ',' and
1358 # We might be dealing with '1U << 12' here
1359 value
= value
+ re
.sub("^(\d+)U$", "\\1", token
[1])
1360 token
= self
.token()
1363 value
= "%d" % (int(value
) + 1)
1365 self
.warning("Failed to compute value of enum %s" % name
)
1367 if token
[0] == "sep" and token
[1] == ",":
1368 if commentsBeforeVal
:
1369 self
.cleanupComment()
1370 self
.enums
.append((name
, value
, self
.comment
))
1371 name
= comment
= self
.comment
= None
1372 token
= self
.token()
1374 token
= self
.token()
1377 def parseVirEnumDecl(self
, token
):
1378 if token
[0] != "name":
1379 self
.error("parsing VIR_ENUM_DECL: expecting name", token
)
1381 token
= self
.token()
1383 if token
[0] != "sep":
1384 self
.error("parsing VIR_ENUM_DECL: expecting ')'", token
)
1387 self
.error("parsing VIR_ENUM_DECL: expecting ')'", token
)
1389 token
= self
.token()
1390 if token
[0] == "sep" and token
[1] == ';':
1391 token
= self
.token()
1395 def parseVirEnumImpl(self
, token
):
1396 # First the type name
1397 if token
[0] != "name":
1398 self
.error("parsing VIR_ENUM_IMPL: expecting name", token
)
1400 token
= self
.token()
1402 if token
[0] != "sep":
1403 self
.error("parsing VIR_ENUM_IMPL: expecting ','", token
)
1406 self
.error("parsing VIR_ENUM_IMPL: expecting ','", token
)
1407 token
= self
.token()
1409 # Now the sentinel name
1410 if token
[0] != "name":
1411 self
.error("parsing VIR_ENUM_IMPL: expecting name", token
)
1413 token
= self
.token()
1415 if token
[0] != "sep":
1416 self
.error("parsing VIR_ENUM_IMPL: expecting ','", token
)
1419 self
.error("parsing VIR_ENUM_IMPL: expecting ','", token
)
1421 token
= self
.token()
1423 # Now a list of strings (optional comments)
1424 while token
is not None:
1426 # First a string, optionally with N_(...)
1427 if token
[0] == 'name':
1428 if token
[1] != 'N_':
1429 self
.error("parsing VIR_ENUM_IMPL: expecting 'N_'", token
)
1430 token
= self
.token()
1431 if token
[0] != "sep" or token
[1] != '(':
1432 self
.error("parsing VIR_ENUM_IMPL: expecting '('", token
)
1433 token
= self
.token()
1436 if token
[0] != "string":
1437 self
.error("parsing VIR_ENUM_IMPL: expecting a string", token
)
1438 token
= self
.token()
1439 elif token
[0] == "string":
1440 token
= self
.token()
1442 self
.error("parsing VIR_ENUM_IMPL: expecting a string", token
)
1445 if token
[0] == "sep":
1446 if isGettext
and token
[1] == ')':
1447 token
= self
.token()
1450 token
= self
.token()
1453 token
= self
.token()
1456 # Then an optional comment
1457 if token
[0] == "comment":
1458 token
= self
.token()
1461 if token
[0] == "sep" and token
[1] == ';':
1462 token
= self
.token()
1466 def parseVirLogInit(self
, token
):
1467 if token
[0] != "string":
1468 self
.error("parsing VIR_LOG_INIT: expecting string", token
)
1470 token
= self
.token()
1472 if token
[0] != "sep":
1473 self
.error("parsing VIR_LOG_INIT: expecting ')'", token
)
1476 self
.error("parsing VIR_LOG_INIT: expecting ')'", token
)
1478 token
= self
.token()
1479 if token
[0] == "sep" and token
[1] == ';':
1480 token
= self
.token()
1485 # Parse a C definition block, used for structs or unions it parse till
1488 def parseTypeBlock(self
, token
):
1489 while token
is not None:
1490 if token
[0] == "sep" and token
[1] == "{":
1491 token
= self
.token()
1492 token
= self
.parseTypeBlock(token
)
1493 elif token
[0] == "sep" and token
[1] == "}":
1494 token
= self
.token()
1497 token
= self
.token()
1501 # Parse a type: the fact that the type name can either occur after
1502 # the definition or within the definition makes it a little harder
1503 # if inside, the name token is pushed back before returning
1505 def parseType(self
, token
):
1507 self
.struct_fields
= []
1508 self
.union_fields
= []
1509 self
.signature
= None
1513 while (token
[0] == "name" and
1514 token
[1] in ["const", "unsigned", "signed"]):
1516 self
.type = token
[1]
1518 self
.type = self
.type + " " + token
[1]
1519 token
= self
.token()
1521 if token
[0] == "name" and token
[1] == "long":
1523 self
.type = token
[1]
1525 self
.type = self
.type + " " + token
[1]
1527 # some read ahead for long long
1529 token
= self
.token()
1530 if token
[0] == "name" and token
[1] == "long":
1531 self
.type = self
.type + " " + token
[1]
1537 token
= self
.token()
1538 if token
[0] == "name" and token
[1] == "int":
1539 self
.type = self
.type + " " + token
[1]
1544 elif token
[0] == "name" and token
[1] == "short":
1546 self
.type = token
[1]
1548 self
.type = self
.type + " " + token
[1]
1550 elif token
[0] == "name" and token
[1] == "struct":
1552 self
.type = token
[1]
1554 self
.type = self
.type + " " + token
[1]
1555 token
= self
.token()
1557 if token
[0] == "name":
1559 token
= self
.token()
1560 if token
is not None and token
[0] == "sep" and token
[1] == "{":
1561 token
= self
.token()
1562 token
= self
.parseStruct(token
)
1563 elif token
is not None and token
[0] == "op" and token
[1] == "*":
1564 self
.type = self
.type + " " + nametok
[1] + " *"
1565 token
= self
.token()
1566 while token
is not None and token
[0] == "op" and token
[1] == "*":
1567 self
.type = self
.type + " *"
1568 token
= self
.token()
1569 if token
[0] == "name":
1571 token
= self
.token()
1573 self
.error("struct : expecting name", token
)
1575 elif token
is not None and token
[0] == "name" and nametok
is not None:
1576 self
.type = self
.type + " " + nametok
[1]
1579 if nametok
is not None:
1580 self
.lexer
.push(token
)
1584 elif token
[0] == "name" and token
[1] == "union":
1586 self
.type = token
[1]
1588 self
.type = self
.type + " " + token
[1]
1589 token
= self
.token()
1591 if token
[0] == "name":
1593 token
= self
.token()
1594 if token
is not None and token
[0] == "sep" and token
[1] == "{":
1595 token
= self
.token()
1596 token
= self
.parseUnion(token
)
1597 elif token
is not None and token
[0] == "name" and nametok
is not None:
1598 self
.type = self
.type + " " + nametok
[1]
1601 if nametok
is not None:
1602 self
.lexer
.push(token
)
1606 elif token
[0] == "name" and token
[1] == "enum":
1608 self
.type = token
[1]
1610 self
.type = self
.type + " " + token
[1]
1612 token
= self
.token()
1613 if token
is not None and token
[0] == "sep" and token
[1] == "{":
1614 # drop comments before the enum block
1616 token
= self
.token()
1617 token
= self
.parseEnumBlock(token
)
1619 self
.error("parsing enum: expecting '{'", token
)
1621 if token
is not None and token
[0] != "name":
1622 self
.lexer
.push(token
)
1623 token
= ("name", "enum")
1625 enum_type
= token
[1]
1626 for enum
in self
.enums
:
1627 self
.index_add(enum
[0], self
.filename
,
1628 not self
.is_header
, "enum",
1629 (enum
[1], enum
[2], enum_type
))
1631 elif token
[0] == "name" and token
[1] == "VIR_ENUM_DECL":
1632 token
= self
.token()
1633 if token
is not None and token
[0] == "sep" and token
[1] == "(":
1634 token
= self
.token()
1635 token
= self
.parseVirEnumDecl(token
)
1637 self
.error("parsing VIR_ENUM_DECL: expecting '('", token
)
1638 if token
is not None:
1639 self
.lexer
.push(token
)
1640 token
= ("name", "virenumdecl")
1643 elif token
[0] == "name" and token
[1] == "VIR_ENUM_IMPL":
1644 token
= self
.token()
1645 if token
is not None and token
[0] == "sep" and token
[1] == "(":
1646 token
= self
.token()
1647 token
= self
.parseVirEnumImpl(token
)
1649 self
.error("parsing VIR_ENUM_IMPL: expecting '('", token
)
1650 if token
is not None:
1651 self
.lexer
.push(token
)
1652 token
= ("name", "virenumimpl")
1655 elif token
[0] == "name" and token
[1] == "VIR_LOG_INIT":
1656 token
= self
.token()
1657 if token
is not None and token
[0] == "sep" and token
[1] == "(":
1658 token
= self
.token()
1659 token
= self
.parseVirLogInit(token
)
1661 self
.error("parsing VIR_LOG_INIT: expecting '('", token
)
1662 if token
is not None:
1663 self
.lexer
.push(token
)
1664 token
= ("name", "virloginit")
1667 elif token
[0] == "name":
1669 self
.type = token
[1]
1671 self
.type = self
.type + " " + token
[1]
1673 self
.error("parsing type %s: expecting a name" % (self
.type),
1676 token
= self
.token()
1677 while token
is not None and (token
[0] == "op" or
1678 token
[0] == "name" and token
[1] == "const"):
1679 self
.type = self
.type + " " + token
[1]
1680 token
= self
.token()
1683 # if there is a parenthesis here, this means a function type
1685 if token
is not None and token
[0] == "sep" and token
[1] == '(':
1686 self
.type = self
.type + token
[1]
1687 token
= self
.token()
1688 while token
is not None and token
[0] == "op" and token
[1] == '*':
1689 self
.type = self
.type + token
[1]
1690 token
= self
.token()
1691 if token
is None or token
[0] != "name":
1692 self
.error("parsing function type, name expected", token
)
1694 self
.type = self
.type + token
[1]
1696 token
= self
.token()
1697 if token
is not None and token
[0] == "sep" and token
[1] == ')':
1698 self
.type = self
.type + token
[1]
1699 token
= self
.token()
1700 if token
is not None and token
[0] == "sep" and token
[1] == '(':
1701 token
= self
.token()
1703 token
= self
.parseSignature(token
)
1706 self
.error("parsing function type, '(' expected", token
)
1709 self
.error("parsing function type, ')' expected", token
)
1711 self
.lexer
.push(token
)
1716 # do some lookahead for arrays
1718 if token
is not None and token
[0] == "name":
1720 token
= self
.token()
1721 if token
is not None and token
[0] == "sep" and token
[1] == '[':
1722 self
.type = self
.type + " " + nametok
[1]
1723 while token
is not None and token
[0] == "sep" and token
[1] == '[':
1724 self
.type = self
.type + token
[1]
1725 token
= self
.token()
1726 while token
is not None and token
[0] != 'sep' and \
1727 token
[1] != ']' and token
[1] != ';':
1728 self
.type = self
.type + token
[1]
1729 token
= self
.token()
1730 if token
is not None and token
[0] == 'sep' and token
[1] == ']':
1731 self
.type = self
.type + token
[1]
1732 token
= self
.token()
1734 self
.error("parsing array type, ']' expected", token
)
1736 elif token
is not None and token
[0] == "sep" and token
[1] == ':':
1737 # remove :12 in case it's a limited int size
1738 token
= self
.token()
1739 token
= self
.token()
1740 self
.lexer
.push(token
)
1746 # Parse a signature: '(' has been parsed and we scan the type definition
1747 # up to the ')' included
1748 def parseSignature(self
, token
):
1750 if token
is not None and token
[0] == "sep" and token
[1] == ')':
1752 token
= self
.token()
1754 while token
is not None:
1755 token
= self
.parseType(token
)
1756 if token
is not None and token
[0] == "name":
1757 signature
.append((self
.type, token
[1], None))
1758 token
= self
.token()
1759 elif token
is not None and token
[0] == "sep" and token
[1] == ',':
1760 token
= self
.token()
1762 elif token
is not None and token
[0] == "sep" and token
[1] == ')':
1763 # only the type was provided
1764 if self
.type == "...":
1765 signature
.append((self
.type, "...", None))
1767 signature
.append((self
.type, None, None))
1768 if token
is not None and token
[0] == "sep":
1770 token
= self
.token()
1772 elif token
[1] == ')':
1773 token
= self
.token()
1775 self
.signature
= signature
1778 # this dict contains the functions that are allowed to use [unsigned]
1779 # long for legacy reasons in their signature and return type. this list is
1780 # fixed. new procedures and public APIs have to use [unsigned] long long
1781 long_legacy_functions
= {
1782 "virGetVersion": (False, ("libVer", "typeVer")),
1783 "virConnectGetLibVersion": (False, ("libVer")),
1784 "virConnectGetVersion": (False, ("hvVer")),
1785 "virDomainGetMaxMemory": (True, ()),
1786 "virDomainMigrate": (False, ("flags", "bandwidth")),
1787 "virDomainMigrate2": (False, ("flags", "bandwidth")),
1788 "virDomainMigrateBegin3": (False, ("flags", "bandwidth")),
1789 "virDomainMigrateConfirm3": (False, ("flags", "bandwidth")),
1790 "virDomainMigrateDirect": (False, ("flags", "bandwidth")),
1791 "virDomainMigrateFinish": (False, ("flags")),
1792 "virDomainMigrateFinish2": (False, ("flags")),
1793 "virDomainMigrateFinish3": (False, ("flags")),
1794 "virDomainMigratePeer2Peer": (False, ("flags", "bandwidth")),
1795 "virDomainMigratePerform": (False, ("flags", "bandwidth")),
1796 "virDomainMigratePerform3": (False, ("flags", "bandwidth")),
1797 "virDomainMigratePrepare": (False, ("flags", "bandwidth")),
1798 "virDomainMigratePrepare2": (False, ("flags", "bandwidth")),
1799 "virDomainMigratePrepare3": (False, ("flags", "bandwidth")),
1800 "virDomainMigratePrepareTunnel": (False, ("flags", "bandwidth")),
1801 "virDomainMigratePrepareTunnel3": (False, ("flags", "bandwidth")),
1802 "virDomainMigrateToURI": (False, ("flags", "bandwidth")),
1803 "virDomainMigrateToURI2": (False, ("flags", "bandwidth")),
1804 "virDomainMigrateVersion1": (False, ("flags", "bandwidth")),
1805 "virDomainMigrateVersion2": (False, ("flags", "bandwidth")),
1806 "virDomainMigrateVersion3": (False, ("flags", "bandwidth")),
1807 "virDomainMigrateSetMaxSpeed": (False, ("bandwidth")),
1808 "virDomainSetMaxMemory": (False, ("memory")),
1809 "virDomainSetMemory": (False, ("memory")),
1810 "virDomainSetMemoryFlags": (False, ("memory")),
1811 "virDomainBlockCommit": (False, ("bandwidth")),
1812 "virDomainBlockJobSetSpeed": (False, ("bandwidth")),
1813 "virDomainBlockPull": (False, ("bandwidth")),
1814 "virDomainBlockRebase": (False, ("bandwidth")),
1815 "virDomainMigrateGetMaxSpeed": (False, ("bandwidth"))
1818 def checkLongLegacyFunction(self
, name
, return_type
, signature
):
1819 if "long" in return_type
and "long long" not in return_type
:
1821 if not CParser
.long_legacy_functions
[name
][0]:
1824 self
.error(("function '%s' is not allowed to return long, "
1825 "use long long instead") % name
)
1827 for param
in signature
:
1828 if "long" in param
[0] and "long long" not in param
[0]:
1830 if param
[1] not in CParser
.long_legacy_functions
[name
][1]:
1833 self
.error(("function '%s' is not allowed to take long "
1834 "parameter '%s', use long long instead")
1837 # this dict contains the structs that are allowed to use [unsigned]
1838 # long for legacy reasons. this list is fixed. new structs have to use
1839 # [unsigned] long long
1840 long_legacy_struct_fields
= {
1841 "_virDomainInfo": ("maxMem", "memory"),
1842 "_virNodeInfo": ("memory"),
1843 "_virDomainBlockJobInfo": ("bandwidth")
1846 def checkLongLegacyStruct(self
, name
, fields
):
1847 for field
in fields
:
1848 if "long" in field
[0] and "long long" not in field
[0]:
1850 if field
[1] not in CParser
.long_legacy_struct_fields
[name
]:
1853 self
.error(("struct '%s' is not allowed to contain long "
1854 "field '%s', use long long instead")
1858 # Parse a global definition, be it a type, variable or function
1859 # the extern "C" blocks are a bit nasty and require it to recurse.
1861 def parseGlobal(self
, token
):
1863 if token
[1] == 'extern':
1864 token
= self
.token()
1867 if token
[0] == 'string':
1869 token
= self
.token()
1872 if token
[0] == 'sep' and token
[1] == "{":
1873 token
= self
.token()
1874 # print('Entering extern "C line ', self.lineno())
1875 while token
is not None and (token
[0] != 'sep' or
1877 if token
[0] == 'name':
1878 token
= self
.parseGlobal(token
)
1881 "token %s %s unexpected at the top level" % (
1882 token
[0], token
[1]))
1883 token
= self
.parseGlobal(token
)
1884 # print('Exiting extern "C" line', self.lineno())
1885 token
= self
.token()
1889 elif token
[1] == 'static':
1891 token
= self
.token()
1892 if token
is None or token
[0] != 'name':
1895 if token
[1] == 'typedef':
1896 token
= self
.token()
1897 return self
.parseTypedef(token
)
1899 token
= self
.parseType(token
)
1900 type_orig
= self
.type
1901 if token
is None or token
[0] != "name":
1904 self
.name
= token
[1]
1905 token
= self
.token()
1906 while token
is not None and (token
[0] == "sep" or token
[0] == "op"):
1907 if token
[0] == "sep":
1909 type = type + token
[1]
1910 token
= self
.token()
1911 while token
is not None and (token
[0] != "sep" or
1913 type = type + token
[1]
1914 token
= self
.token()
1916 if token
is not None and token
[0] == "op" and token
[1] == "=":
1918 # Skip the initialization of the variable
1920 token
= self
.token()
1921 if token
[0] == 'sep' and token
[1] == '{':
1922 token
= self
.token()
1923 token
= self
.parseBlock(token
)
1926 while token
is not None and (token
[0] != "sep" or
1927 token
[1] not in ',;'):
1928 token
= self
.token()
1930 if token
is None or token
[0] != "sep" or (token
[1] != ';' and
1932 self
.error("missing ';' or ',' after value")
1934 if token
is not None and token
[0] == "sep":
1937 token
= self
.token()
1938 if type == "struct":
1939 self
.checkLongLegacyStruct(self
.name
, self
.struct_fields
)
1940 self
.index_add(self
.name
, self
.filename
,
1941 not self
.is_header
, "struct", self
.struct_fields
)
1943 self
.index_add(self
.name
, self
.filename
,
1944 not self
.is_header
, "variable", type)
1946 elif token
[1] == "(":
1947 token
= self
.token()
1948 token
= self
.parseSignature(token
)
1951 if token
[0] == "sep" and token
[1] == ";":
1952 self
.checkLongLegacyFunction(self
.name
, type, self
.signature
)
1953 d
= self
.mergeFunctionComment(self
.name
,
1954 ((type, None), self
.signature
), 1)
1955 self
.index_add(self
.name
, self
.filename
, static
,
1957 token
= self
.token()
1958 elif token
[0] == "sep" and token
[1] == "{":
1959 self
.checkLongLegacyFunction(self
.name
, type, self
.signature
)
1960 d
= self
.mergeFunctionComment(self
.name
,
1961 ((type, None), self
.signature
), static
)
1962 self
.index_add(self
.name
, self
.filename
, static
,
1964 token
= self
.token()
1965 token
= self
.parseBlock(token
)
1966 elif token
[1] == ',':
1968 self
.index_add(self
.name
, self
.filename
, static
,
1971 token
= self
.token()
1972 while token
is not None and token
[0] == "sep":
1973 type = type + token
[1]
1974 token
= self
.token()
1975 if token
is not None and token
[0] == "name":
1976 self
.name
= token
[1]
1977 token
= self
.token()
1985 print("Parsing %s" % (self
.filename
))
1986 token
= self
.token()
1987 while token
is not None:
1988 if token
[0] == 'name':
1989 token
= self
.parseGlobal(token
)
1991 self
.error("token %s %s unexpected at the top level" % (
1992 token
[0], token
[1]))
1993 token
= self
.parseGlobal(token
)
1995 self
.parseTopComment(self
.top_comment
)
2000 """A documentation builder"""
2001 def __init__(self
, name
, path
='.', directories
=['.'], includes
=[]):
2004 self
.directories
= directories
2005 if name
== "libvirt":
2006 self
.includes
= includes
+ list(included_files
.keys())
2007 elif name
== "libvirt-qemu":
2008 self
.includes
= includes
+ list(qemu_included_files
.keys())
2009 elif name
== "libvirt-lxc":
2010 self
.includes
= includes
+ list(lxc_included_files
.keys())
2011 elif name
== "libvirt-admin":
2012 self
.includes
= includes
+ list(admin_included_files
.keys())
2018 self
.basename
= name
2021 def warning(self
, msg
):
2023 warnings
= warnings
+ 1
2026 def error(self
, msg
):
2028 print("Error:", msg
, file=sys
.stderr
)
2030 def indexString(self
, id, str):
2033 str = str.replace("'", ' ')
2034 str = str.replace('"', ' ')
2035 str = str.replace("/", ' ')
2036 str = str.replace('*', ' ')
2037 str = str.replace("[", ' ')
2038 str = str.replace("]", ' ')
2039 str = str.replace("(", ' ')
2040 str = str.replace(")", ' ')
2041 str = str.replace("<", ' ')
2042 str = str.replace('>', ' ')
2043 str = str.replace("&", ' ')
2044 str = str.replace('#', ' ')
2045 str = str.replace(",", ' ')
2046 str = str.replace('.', ' ')
2047 str = str.replace(';', ' ')
2048 tokens
= str.split()
2049 for token
in tokens
:
2051 if not re
.match(r
"[a-zA-Z]", c
):
2053 elif len(token
) < 3:
2056 lower
= token
.lower()
2057 # TODO: generalize this a bit
2058 if lower
== 'and' or lower
== 'the':
2060 elif token
in self
.xref
:
2061 self
.xref
[token
].append(id)
2063 self
.xref
[token
] = [id]
2067 print("Project %s : %d headers, %d modules" % (self
.name
, len(self
.headers
.keys()), len(self
.modules
.keys())))
2070 def scanHeaders(self
):
2071 for header
in self
.headers
.keys():
2072 parser
= CParser(header
)
2073 idx
= parser
.parse()
2074 self
.headers
[header
] = idx
2077 def scanModules(self
):
2078 for module
in self
.modules
.keys():
2079 parser
= CParser(module
)
2080 idx
= parser
.parse()
2082 self
.modules
[module
] = idx
2083 self
.idx
.merge_public(idx
)
2086 for directory
in self
.directories
:
2087 files
= glob
.glob(directory
+ "/*.c")
2090 for incl
in self
.includes
:
2091 if file.find(incl
) != -1:
2095 self
.modules
[file] = None
2096 files
= glob
.glob(directory
+ "/*.h")
2099 for incl
in self
.includes
:
2100 if file.find(incl
) != -1:
2104 self
.headers
[file] = None
2108 def modulename_file(self
, file):
2109 module
= os
.path
.basename(file)
2110 if module
[-2:] == '.h':
2111 module
= module
[:-2]
2112 elif module
[-2:] == '.c':
2113 module
= module
[:-2]
2116 def serialize_enum(self
, output
, name
):
2117 id = self
.idx
.enums
[name
]
2118 output
.write(" <enum name='%s' file='%s'" % (name
,
2119 self
.modulename_file(id.header
)))
2120 if id.info
is not None:
2123 if info
[0] is not None and info
[0] != '':
2129 output
.write(" value='%s'" % (val
))
2132 output
.write(" value_hex='%s'" % (valhex
))
2134 m
= re
.match("\(?1<<(\d+)\)?", info
[0])
2136 output
.write(" value_bitshift='%s'" % (m
.group(1)))
2138 if info
[2] is not None and info
[2] != '':
2139 output
.write(" type='%s'" % info
[2])
2140 if info
[1] is not None and info
[1] != '':
2141 output
.write(" info='%s'" % escape(info
[1]))
2142 output
.write("/>\n")
2144 def serialize_macro(self
, output
, name
):
2145 id = self
.idx
.macros
[name
]
2146 output
.write(" <macro name='%s' file='%s'" % (name
,
2147 self
.modulename_file(id.header
)))
2153 (args
, desc
, strValue
) = id.info
2155 if strValue
is not None:
2156 output
.write(" string='%s'" % strValue
)
2159 if desc
is not None and desc
!= "":
2160 output
.write(" <info><![CDATA[%s]]></info>\n" % (desc
))
2161 self
.indexString(name
, desc
)
2164 if desc
is not None and desc
!= "":
2165 output
.write(" <arg name='%s' info='%s'/>\n" % (
2166 name
, escape(desc
)))
2167 self
.indexString(name
, desc
)
2169 output
.write(" <arg name='%s'/>\n" % name
)
2170 output
.write(" </macro>\n")
2172 def serialize_union(self
, output
, field
, desc
):
2173 output
.write(" <field name='%s' type='union' info='%s'>\n" % (field
[1], desc
))
2174 output
.write(" <union>\n")
2181 output
.write(" <field name='%s' type='%s' info='%s'/>\n" % (f
[1], f
[0], desc
))
2183 output
.write(" </union>\n")
2184 output
.write(" </field>\n")
2186 def serialize_typedef(self
, output
, name
):
2187 id = self
.idx
.typedefs
[name
]
2188 if id.info
[0:7] == 'struct ':
2189 output
.write(" <struct name='%s' file='%s' type='%s'" % (
2190 name
, self
.modulename_file(id.header
), id.info
))
2192 if (name
in self
.idx
.structs
and
2193 isinstance(self
.idx
.structs
[name
].info
, (list, tuple))):
2196 for field
in self
.idx
.structs
[name
].info
:
2198 self
.indexString(name
, desc
)
2203 if field
[0] == "union":
2204 self
.serialize_union(output
, field
, desc
)
2206 output
.write(" <field name='%s' type='%s' info='%s'/>\n" % (field
[1], field
[0], desc
))
2208 self
.warning("Failed to serialize struct %s" % name
)
2209 output
.write(" </struct>\n")
2211 output
.write("/>\n")
2213 output
.write(" <typedef name='%s' file='%s' type='%s'" % (
2214 name
, self
.modulename_file(id.header
), id.info
))
2217 if desc
is not None and desc
!= "":
2218 output
.write(">\n <info><![CDATA[%s]]></info>\n" % (desc
))
2219 output
.write(" </typedef>\n")
2221 output
.write("/>\n")
2223 output
.write("/>\n")
2225 def serialize_variable(self
, output
, name
):
2226 id = self
.idx
.variables
[name
]
2227 if id.info
is not None:
2228 output
.write(" <variable name='%s' file='%s' type='%s'/>\n" % (
2229 name
, self
.modulename_file(id.header
), id.info
))
2231 output
.write(" <variable name='%s' file='%s'/>\n" % (
2232 name
, self
.modulename_file(id.header
)))
2234 def serialize_function(self
, output
, name
):
2235 id = self
.idx
.functions
[name
]
2236 if name
== debugsym
and not quiet
:
2239 # NB: this is consumed by a regex in 'getAPIFilenames' in hvsupport.pl
2240 output
.write(" <%s name='%s' file='%s' module='%s'>\n" % (id.type,
2241 name
, self
.modulename_file(id.header
),
2242 self
.modulename_file(id.module
)))
2244 # Processing of conditionals modified by Bill 1/1/05
2246 if id.conditionals
is not None:
2248 for cond
in id.conditionals
:
2250 apstr
= apstr
+ " && "
2251 apstr
= apstr
+ cond
2252 output
.write(" <cond>%s</cond>\n" % (apstr
))
2254 (ret
, params
, desc
) = id.info
2255 output
.write(" <info><![CDATA[%s]]></info>\n" % (desc
))
2256 self
.indexString(name
, desc
)
2257 if ret
[0] is not None:
2258 if ret
[0] == "void":
2259 output
.write(" <return type='void'/>\n")
2260 elif (ret
[1] is None or ret
[1] == '') and name
not in ignored_functions
:
2261 self
.error("Missing documentation for return of function `%s'" % name
)
2263 output
.write(" <return type='%s' info='%s'/>\n" % (
2264 ret
[0], escape(ret
[1])))
2265 self
.indexString(name
, ret
[1])
2266 for param
in params
:
2267 if param
[0] == 'void':
2269 if (param
[2] is None or param
[2] == ''):
2270 if name
in ignored_functions
:
2271 output
.write(" <arg name='%s' type='%s' info=''/>\n" % (param
[1], param
[0]))
2273 self
.error("Missing documentation for arg `%s' of function `%s'" % (param
[1], name
))
2275 output
.write(" <arg name='%s' type='%s' info='%s'/>\n" % (param
[1], param
[0], escape(param
[2])))
2276 self
.indexString(name
, param
[2])
2278 print("Exception:", sys
.exc_info()[1], file=sys
.stderr
)
2279 self
.warning("Failed to save function %s info: %s" % (name
, repr(id.info
)))
2280 output
.write(" </%s>\n" % (id.type))
2282 def serialize_exports(self
, output
, file):
2283 module
= self
.modulename_file(file)
2284 output
.write(" <file name='%s'>\n" % (module
))
2285 dict = self
.headers
[file]
2286 if dict.info
is not None:
2287 for data
in ('Summary', 'Description'):
2289 output
.write(" <%s>%s</%s>\n" % (
2291 escape(dict.info
[data
]),
2294 self
.warning("Header %s lacks a %s description" % (module
, data
))
2295 if 'Description' in dict.info
:
2296 desc
= dict.info
['Description']
2297 if desc
.find("DEPRECATED") != -1:
2298 output
.write(" <deprecated/>\n")
2300 for id in uniq(dict.macros
.keys()):
2301 # Macros are sometime used to masquerade other types.
2302 if id in dict.functions
:
2304 if id in dict.variables
:
2306 if id in dict.typedefs
:
2308 if id in dict.structs
:
2310 if id in dict.unions
:
2312 if id in dict.enums
:
2314 output
.write(" <exports symbol='%s' type='macro'/>\n" % (id))
2315 for id in uniq(dict.enums
.keys()):
2316 output
.write(" <exports symbol='%s' type='enum'/>\n" % (id))
2317 for id in uniq(dict.typedefs
.keys()):
2318 output
.write(" <exports symbol='%s' type='typedef'/>\n" % (id))
2319 for id in uniq(dict.structs
.keys()):
2320 output
.write(" <exports symbol='%s' type='struct'/>\n" % (id))
2321 for id in uniq(dict.variables
.keys()):
2322 output
.write(" <exports symbol='%s' type='variable'/>\n" % (id))
2323 for id in uniq(dict.functions
.keys()):
2324 output
.write(" <exports symbol='%s' type='function'/>\n" % (id))
2325 output
.write(" </file>\n")
2327 def serialize_xrefs_files(self
, output
):
2328 headers
= sorted(self
.headers
.keys())
2329 for file in headers
:
2330 module
= self
.modulename_file(file)
2331 output
.write(" <file name='%s'>\n" % (module
))
2332 dict = self
.headers
[file]
2333 ids
= uniq(list(dict.functions
.keys()) +
2334 list(dict.variables
.keys()) +
2335 list(dict.macros
.keys()) +
2336 list(dict.typedefs
.keys()) +
2337 list(dict.structs
.keys()) +
2338 list(dict.enums
.keys()))
2340 output
.write(" <ref name='%s'/>\n" % (id))
2341 output
.write(" </file>\n")
2344 def serialize_xrefs_functions(self
, output
):
2346 for name
in self
.idx
.functions
.keys():
2347 id = self
.idx
.functions
[name
]
2349 (ret
, params
, desc
) = id.info
2350 for param
in params
:
2351 if param
[0] == 'void':
2353 if param
[0] in funcs
:
2354 funcs
[param
[0]].append(name
)
2356 funcs
[param
[0]] = [name
]
2359 typ
= sorted(funcs
.keys())
2361 if type in ['', "void", "int", "char *", "const char *"]:
2363 output
.write(" <type name='%s'>\n" % (type))
2366 pid
= '' # not sure why we have dups, but get rid of them!
2369 output
.write(" <ref name='%s'/>\n" % (id))
2371 output
.write(" </type>\n")
2373 def serialize_xrefs_constructors(self
, output
):
2375 for name
in self
.idx
.functions
.keys():
2376 id = self
.idx
.functions
[name
]
2378 (ret
, params
, desc
) = id.info
2379 if ret
[0] == "void":
2382 funcs
[ret
[0]].append(name
)
2384 funcs
[ret
[0]] = [name
]
2387 typ
= sorted(funcs
.keys())
2389 if type in ['', "void", "int", "char *", "const char *"]:
2391 output
.write(" <type name='%s'>\n" % (type))
2392 ids
= sorted(funcs
[type])
2394 output
.write(" <ref name='%s'/>\n" % (id))
2395 output
.write(" </type>\n")
2397 def serialize_xrefs_alpha(self
, output
):
2399 ids
= sorted(self
.idx
.identifiers
.keys())
2402 if letter
is not None:
2403 output
.write(" </letter>\n")
2405 output
.write(" <letter name='%s'>\n" % (letter
))
2406 output
.write(" <ref name='%s'/>\n" % (id))
2407 if letter
is not None:
2408 output
.write(" </letter>\n")
2410 def serialize_xrefs_references(self
, output
):
2411 typ
= sorted(self
.idx
.identifiers
.keys())
2413 idf
= self
.idx
.identifiers
[id]
2415 output
.write(" <reference name='%s' href='%s'/>\n" % (id,
2416 'html/' + self
.basename
+ '-' +
2417 self
.modulename_file(module
) + '.html#' +
2420 def serialize_xrefs_index(self
, output
):
2422 typ
= sorted(index
.keys())
2428 if len(index
[id]) > 30:
2431 if letter
is None or count
> 200:
2432 if letter
is not None:
2433 output
.write(" </letter>\n")
2434 output
.write(" </chunk>\n")
2436 chunks
.append(["chunk%s" % (chunk
- 1), first_letter
, letter
])
2437 output
.write(" <chunk name='chunk%s'>\n" % (chunk
))
2438 first_letter
= id[0]
2440 elif letter
is not None:
2441 output
.write(" </letter>\n")
2443 output
.write(" <letter name='%s'>\n" % (letter
))
2444 output
.write(" <word name='%s'>\n" % (id))
2448 for token
in tokens
:
2452 output
.write(" <ref name='%s'/>\n" % (token
))
2454 output
.write(" </word>\n")
2455 if letter
is not None:
2456 output
.write(" </letter>\n")
2457 output
.write(" </chunk>\n")
2459 chunks
.append(["chunk%s" % (chunk
- 1), first_letter
, letter
])
2460 output
.write(" <chunks>\n")
2462 output
.write(" <chunk name='%s' start='%s' end='%s'/>\n" % (
2463 ch
[0], ch
[1], ch
[2]))
2464 output
.write(" </chunks>\n")
2466 def serialize_xrefs(self
, output
):
2467 output
.write(" <references>\n")
2468 self
.serialize_xrefs_references(output
)
2469 output
.write(" </references>\n")
2470 output
.write(" <alpha>\n")
2471 self
.serialize_xrefs_alpha(output
)
2472 output
.write(" </alpha>\n")
2473 output
.write(" <constructors>\n")
2474 self
.serialize_xrefs_constructors(output
)
2475 output
.write(" </constructors>\n")
2476 output
.write(" <functions>\n")
2477 self
.serialize_xrefs_functions(output
)
2478 output
.write(" </functions>\n")
2479 output
.write(" <files>\n")
2480 self
.serialize_xrefs_files(output
)
2481 output
.write(" </files>\n")
2482 output
.write(" <index>\n")
2483 self
.serialize_xrefs_index(output
)
2484 output
.write(" </index>\n")
2486 def serialize(self
):
2487 filename
= "%s/%s-api.xml" % (self
.path
, self
.name
)
2489 print("Saving XML description %s" % (filename
))
2490 output
= open(filename
, "w")
2491 output
.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
2492 output
.write("<api name='%s'>\n" % self
.name
)
2493 output
.write(" <files>\n")
2494 headers
= sorted(self
.headers
.keys())
2495 for file in headers
:
2496 self
.serialize_exports(output
, file)
2497 output
.write(" </files>\n")
2498 output
.write(" <symbols>\n")
2499 macros
= sorted(self
.idx
.macros
.keys())
2500 for macro
in macros
:
2501 self
.serialize_macro(output
, macro
)
2502 enums
= sorted(self
.idx
.enums
.keys())
2504 self
.serialize_enum(output
, enum
)
2505 typedefs
= sorted(self
.idx
.typedefs
.keys())
2506 for typedef
in typedefs
:
2507 self
.serialize_typedef(output
, typedef
)
2508 variables
= sorted(self
.idx
.variables
.keys())
2509 for variable
in variables
:
2510 self
.serialize_variable(output
, variable
)
2511 functions
= sorted(self
.idx
.functions
.keys())
2512 for function
in functions
:
2513 self
.serialize_function(output
, function
)
2514 output
.write(" </symbols>\n")
2515 output
.write("</api>\n")
2519 print("apibuild.py: %d error(s) encountered during generation" % self
.errors
, file=sys
.stderr
)
2522 filename
= "%s/%s-refs.xml" % (self
.path
, self
.name
)
2524 print("Saving XML Cross References %s" % (filename
))
2525 output
= open(filename
, "w")
2526 output
.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n')
2527 output
.write("<apirefs name='%s'>\n" % self
.name
)
2528 self
.serialize_xrefs(output
)
2529 output
.write("</apirefs>\n")
2534 def warning(self
, msg
):
2536 warnings
= warnings
+ 1
2539 def rebuild(self
, name
):
2540 if name
not in ["libvirt", "libvirt-qemu", "libvirt-lxc", "libvirt-admin"]:
2541 self
.warning("rebuild() failed, unknown module %s" % name
)
2544 srcdir
= os
.path
.abspath((os
.environ
["srcdir"]))
2545 builddir
= os
.path
.abspath((os
.environ
["builddir"]))
2546 if srcdir
== builddir
:
2548 if glob
.glob(srcdir
+ "/../src/libvirt.c") != []:
2550 print("Rebuilding API description for %s" % name
)
2551 dirs
= [srcdir
+ "/../src",
2552 srcdir
+ "/../src/util",
2553 srcdir
+ "/../include/libvirt"]
2555 not os
.path
.exists(srcdir
+ "/../include/libvirt/libvirt-common.h")):
2556 dirs
.append(builddir
+ "/../include/libvirt")
2557 builder
= docBuilder(name
, srcdir
, dirs
, [])
2558 elif glob
.glob("src/libvirt.c") != []:
2560 print("Rebuilding API description for %s" % name
)
2561 builder
= docBuilder(name
, srcdir
,
2562 ["src", "src/util", "include/libvirt"],
2565 self
.warning("rebuild() failed, unable to guess the module")
2573 # for debugging the parser
2575 def parse(self
, filename
):
2576 parser
= CParser(filename
)
2577 idx
= parser
.parse()
2581 if __name__
== "__main__":
2583 if len(sys
.argv
) > 1:
2585 app
.parse(sys
.argv
[1])
2587 app
.rebuild("libvirt")
2588 app
.rebuild("libvirt-qemu")
2589 app
.rebuild("libvirt-lxc")
2590 app
.rebuild("libvirt-admin")