hw/arm/virt: smbios: inform guest of kvm
[qemu/ar7.git] / scripts / qapi.py
blob26cff3f05c78d8537dfe68e03efee88be8215f02
2 # QAPI helper library
4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2015 Red Hat Inc.
7 # Authors:
8 # Anthony Liguori <aliguori@us.ibm.com>
9 # Markus Armbruster <armbru@redhat.com>
11 # This work is licensed under the terms of the GNU GPL, version 2.
12 # See the COPYING file in the top-level directory.
14 import re
15 from ordereddict import OrderedDict
16 import errno
17 import getopt
18 import os
19 import sys
20 import string
22 builtin_types = {
23 'str': 'QTYPE_QSTRING',
24 'int': 'QTYPE_QINT',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
27 'int8': 'QTYPE_QINT',
28 'int16': 'QTYPE_QINT',
29 'int32': 'QTYPE_QINT',
30 'int64': 'QTYPE_QINT',
31 'uint8': 'QTYPE_QINT',
32 'uint16': 'QTYPE_QINT',
33 'uint32': 'QTYPE_QINT',
34 'uint64': 'QTYPE_QINT',
35 'size': 'QTYPE_QINT',
36 'any': None, # any qtype_code possible, actually
39 # Whitelist of commands allowed to return a non-dictionary
40 returns_whitelist = [
41 # From QMP:
42 'human-monitor-command',
43 'qom-get',
44 'query-migrate-cache-size',
45 'query-tpm-models',
46 'query-tpm-types',
47 'ringbuf-read',
49 # From QGA:
50 'guest-file-open',
51 'guest-fsfreeze-freeze',
52 'guest-fsfreeze-freeze-list',
53 'guest-fsfreeze-status',
54 'guest-fsfreeze-thaw',
55 'guest-get-time',
56 'guest-set-vcpus',
57 'guest-sync',
58 'guest-sync-delimited',
60 # From qapi-schema-test:
61 'user_def_cmd3',
64 enum_types = []
65 struct_types = []
66 union_types = []
67 events = []
68 all_names = {}
71 # Parsing the schema into expressions
75 def error_path(parent):
76 res = ""
77 while parent:
78 res = ("In file included from %s:%d:\n" % (parent['file'],
79 parent['line'])) + res
80 parent = parent['parent']
81 return res
84 class QAPISchemaError(Exception):
85 def __init__(self, schema, msg):
86 Exception.__init__(self)
87 self.fname = schema.fname
88 self.msg = msg
89 self.col = 1
90 self.line = schema.line
91 for ch in schema.src[schema.line_pos:schema.pos]:
92 if ch == '\t':
93 self.col = (self.col + 7) % 8 + 1
94 else:
95 self.col += 1
96 self.info = schema.incl_info
98 def __str__(self):
99 return error_path(self.info) + \
100 "%s:%d:%d: %s" % (self.fname, self.line, self.col, self.msg)
103 class QAPIExprError(Exception):
104 def __init__(self, expr_info, msg):
105 Exception.__init__(self)
106 self.info = expr_info
107 self.msg = msg
109 def __str__(self):
110 return error_path(self.info['parent']) + \
111 "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
114 class QAPISchemaParser(object):
116 def __init__(self, fp, previously_included=[], incl_info=None):
117 abs_fname = os.path.abspath(fp.name)
118 fname = fp.name
119 self.fname = fname
120 previously_included.append(abs_fname)
121 self.incl_info = incl_info
122 self.src = fp.read()
123 if self.src == '' or self.src[-1] != '\n':
124 self.src += '\n'
125 self.cursor = 0
126 self.line = 1
127 self.line_pos = 0
128 self.exprs = []
129 self.accept()
131 while self.tok is not None:
132 expr_info = {'file': fname, 'line': self.line,
133 'parent': self.incl_info}
134 expr = self.get_expr(False)
135 if isinstance(expr, dict) and "include" in expr:
136 if len(expr) != 1:
137 raise QAPIExprError(expr_info,
138 "Invalid 'include' directive")
139 include = expr["include"]
140 if not isinstance(include, str):
141 raise QAPIExprError(expr_info,
142 "Value of 'include' must be a string")
143 incl_abs_fname = os.path.join(os.path.dirname(abs_fname),
144 include)
145 # catch inclusion cycle
146 inf = expr_info
147 while inf:
148 if incl_abs_fname == os.path.abspath(inf['file']):
149 raise QAPIExprError(expr_info, "Inclusion loop for %s"
150 % include)
151 inf = inf['parent']
152 # skip multiple include of the same file
153 if incl_abs_fname in previously_included:
154 continue
155 try:
156 fobj = open(incl_abs_fname, 'r')
157 except IOError, e:
158 raise QAPIExprError(expr_info,
159 '%s: %s' % (e.strerror, include))
160 exprs_include = QAPISchemaParser(fobj, previously_included,
161 expr_info)
162 self.exprs.extend(exprs_include.exprs)
163 else:
164 expr_elem = {'expr': expr,
165 'info': expr_info}
166 self.exprs.append(expr_elem)
168 def accept(self):
169 while True:
170 self.tok = self.src[self.cursor]
171 self.pos = self.cursor
172 self.cursor += 1
173 self.val = None
175 if self.tok == '#':
176 self.cursor = self.src.find('\n', self.cursor)
177 elif self.tok in ['{', '}', ':', ',', '[', ']']:
178 return
179 elif self.tok == "'":
180 string = ''
181 esc = False
182 while True:
183 ch = self.src[self.cursor]
184 self.cursor += 1
185 if ch == '\n':
186 raise QAPISchemaError(self,
187 'Missing terminating "\'"')
188 if esc:
189 if ch == 'b':
190 string += '\b'
191 elif ch == 'f':
192 string += '\f'
193 elif ch == 'n':
194 string += '\n'
195 elif ch == 'r':
196 string += '\r'
197 elif ch == 't':
198 string += '\t'
199 elif ch == 'u':
200 value = 0
201 for _ in range(0, 4):
202 ch = self.src[self.cursor]
203 self.cursor += 1
204 if ch not in "0123456789abcdefABCDEF":
205 raise QAPISchemaError(self,
206 '\\u escape needs 4 '
207 'hex digits')
208 value = (value << 4) + int(ch, 16)
209 # If Python 2 and 3 didn't disagree so much on
210 # how to handle Unicode, then we could allow
211 # Unicode string defaults. But most of QAPI is
212 # ASCII-only, so we aren't losing much for now.
213 if not value or value > 0x7f:
214 raise QAPISchemaError(self,
215 'For now, \\u escape '
216 'only supports non-zero '
217 'values up to \\u007f')
218 string += chr(value)
219 elif ch in "\\/'\"":
220 string += ch
221 else:
222 raise QAPISchemaError(self,
223 "Unknown escape \\%s" % ch)
224 esc = False
225 elif ch == "\\":
226 esc = True
227 elif ch == "'":
228 self.val = string
229 return
230 else:
231 string += ch
232 elif self.src.startswith("true", self.pos):
233 self.val = True
234 self.cursor += 3
235 return
236 elif self.src.startswith("false", self.pos):
237 self.val = False
238 self.cursor += 4
239 return
240 elif self.src.startswith("null", self.pos):
241 self.val = None
242 self.cursor += 3
243 return
244 elif self.tok == '\n':
245 if self.cursor == len(self.src):
246 self.tok = None
247 return
248 self.line += 1
249 self.line_pos = self.cursor
250 elif not self.tok.isspace():
251 raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
253 def get_members(self):
254 expr = OrderedDict()
255 if self.tok == '}':
256 self.accept()
257 return expr
258 if self.tok != "'":
259 raise QAPISchemaError(self, 'Expected string or "}"')
260 while True:
261 key = self.val
262 self.accept()
263 if self.tok != ':':
264 raise QAPISchemaError(self, 'Expected ":"')
265 self.accept()
266 if key in expr:
267 raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
268 expr[key] = self.get_expr(True)
269 if self.tok == '}':
270 self.accept()
271 return expr
272 if self.tok != ',':
273 raise QAPISchemaError(self, 'Expected "," or "}"')
274 self.accept()
275 if self.tok != "'":
276 raise QAPISchemaError(self, 'Expected string')
278 def get_values(self):
279 expr = []
280 if self.tok == ']':
281 self.accept()
282 return expr
283 if self.tok not in "{['tfn":
284 raise QAPISchemaError(self, 'Expected "{", "[", "]", string, '
285 'boolean or "null"')
286 while True:
287 expr.append(self.get_expr(True))
288 if self.tok == ']':
289 self.accept()
290 return expr
291 if self.tok != ',':
292 raise QAPISchemaError(self, 'Expected "," or "]"')
293 self.accept()
295 def get_expr(self, nested):
296 if self.tok != '{' and not nested:
297 raise QAPISchemaError(self, 'Expected "{"')
298 if self.tok == '{':
299 self.accept()
300 expr = self.get_members()
301 elif self.tok == '[':
302 self.accept()
303 expr = self.get_values()
304 elif self.tok in "'tfn":
305 expr = self.val
306 self.accept()
307 else:
308 raise QAPISchemaError(self, 'Expected "{", "[" or string')
309 return expr
312 # Semantic analysis of schema expressions
313 # TODO fold into QAPISchema
314 # TODO catching name collisions in generated code would be nice
318 def find_base_fields(base):
319 base_struct_define = find_struct(base)
320 if not base_struct_define:
321 return None
322 return base_struct_define['data']
325 # Return the qtype of an alternate branch, or None on error.
326 def find_alternate_member_qtype(qapi_type):
327 if qapi_type in builtin_types:
328 return builtin_types[qapi_type]
329 elif find_struct(qapi_type):
330 return "QTYPE_QDICT"
331 elif find_enum(qapi_type):
332 return "QTYPE_QSTRING"
333 elif find_union(qapi_type):
334 return "QTYPE_QDICT"
335 return None
338 # Return the discriminator enum define if discriminator is specified as an
339 # enum type, otherwise return None.
340 def discriminator_find_enum_define(expr):
341 base = expr.get('base')
342 discriminator = expr.get('discriminator')
344 if not (discriminator and base):
345 return None
347 base_fields = find_base_fields(base)
348 if not base_fields:
349 return None
351 discriminator_type = base_fields.get(discriminator)
352 if not discriminator_type:
353 return None
355 return find_enum(discriminator_type)
358 # FIXME should enforce "other than downstream extensions [...], all
359 # names should begin with a letter".
360 valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
363 def check_name(expr_info, source, name, allow_optional=False,
364 enum_member=False):
365 global valid_name
366 membername = name
368 if not isinstance(name, str):
369 raise QAPIExprError(expr_info,
370 "%s requires a string name" % source)
371 if name.startswith('*'):
372 membername = name[1:]
373 if not allow_optional:
374 raise QAPIExprError(expr_info,
375 "%s does not allow optional name '%s'"
376 % (source, name))
377 # Enum members can start with a digit, because the generated C
378 # code always prefixes it with the enum name
379 if enum_member:
380 membername = '_' + membername
381 if not valid_name.match(membername):
382 raise QAPIExprError(expr_info,
383 "%s uses invalid name '%s'" % (source, name))
386 def add_name(name, info, meta, implicit=False):
387 global all_names
388 check_name(info, "'%s'" % meta, name)
389 # FIXME should reject names that differ only in '_' vs. '.'
390 # vs. '-', because they're liable to clash in generated C.
391 if name in all_names:
392 raise QAPIExprError(info,
393 "%s '%s' is already defined"
394 % (all_names[name], name))
395 if not implicit and name[-4:] == 'Kind':
396 raise QAPIExprError(info,
397 "%s '%s' should not end in 'Kind'"
398 % (meta, name))
399 all_names[name] = meta
402 def add_struct(definition, info):
403 global struct_types
404 name = definition['struct']
405 add_name(name, info, 'struct')
406 struct_types.append(definition)
409 def find_struct(name):
410 global struct_types
411 for struct in struct_types:
412 if struct['struct'] == name:
413 return struct
414 return None
417 def add_union(definition, info):
418 global union_types
419 name = definition['union']
420 add_name(name, info, 'union')
421 union_types.append(definition)
424 def find_union(name):
425 global union_types
426 for union in union_types:
427 if union['union'] == name:
428 return union
429 return None
432 def add_enum(name, info, enum_values=None, implicit=False):
433 global enum_types
434 add_name(name, info, 'enum', implicit)
435 enum_types.append({"enum_name": name, "enum_values": enum_values})
438 def find_enum(name):
439 global enum_types
440 for enum in enum_types:
441 if enum['enum_name'] == name:
442 return enum
443 return None
446 def is_enum(name):
447 return find_enum(name) is not None
450 def check_type(expr_info, source, value, allow_array=False,
451 allow_dict=False, allow_optional=False,
452 allow_metas=[]):
453 global all_names
455 if value is None:
456 return
458 # Check if array type for value is okay
459 if isinstance(value, list):
460 if not allow_array:
461 raise QAPIExprError(expr_info,
462 "%s cannot be an array" % source)
463 if len(value) != 1 or not isinstance(value[0], str):
464 raise QAPIExprError(expr_info,
465 "%s: array type must contain single type name"
466 % source)
467 value = value[0]
469 # Check if type name for value is okay
470 if isinstance(value, str):
471 if value not in all_names:
472 raise QAPIExprError(expr_info,
473 "%s uses unknown type '%s'"
474 % (source, value))
475 if not all_names[value] in allow_metas:
476 raise QAPIExprError(expr_info,
477 "%s cannot use %s type '%s'"
478 % (source, all_names[value], value))
479 return
481 if not allow_dict:
482 raise QAPIExprError(expr_info,
483 "%s should be a type name" % source)
485 if not isinstance(value, OrderedDict):
486 raise QAPIExprError(expr_info,
487 "%s should be a dictionary or type name" % source)
489 # value is a dictionary, check that each member is okay
490 for (key, arg) in value.items():
491 check_name(expr_info, "Member of %s" % source, key,
492 allow_optional=allow_optional)
493 # Todo: allow dictionaries to represent default values of
494 # an optional argument.
495 check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
496 allow_array=True,
497 allow_metas=['built-in', 'union', 'alternate', 'struct',
498 'enum'])
501 def check_member_clash(expr_info, base_name, data, source=""):
502 base = find_struct(base_name)
503 assert base
504 base_members = base['data']
505 for key in data.keys():
506 if key.startswith('*'):
507 key = key[1:]
508 if key in base_members or "*" + key in base_members:
509 raise QAPIExprError(expr_info,
510 "Member name '%s'%s clashes with base '%s'"
511 % (key, source, base_name))
512 if base.get('base'):
513 check_member_clash(expr_info, base['base'], data, source)
516 def check_command(expr, expr_info):
517 name = expr['command']
519 check_type(expr_info, "'data' for command '%s'" % name,
520 expr.get('data'), allow_dict=True, allow_optional=True,
521 allow_metas=['struct'])
522 returns_meta = ['union', 'struct']
523 if name in returns_whitelist:
524 returns_meta += ['built-in', 'alternate', 'enum']
525 check_type(expr_info, "'returns' for command '%s'" % name,
526 expr.get('returns'), allow_array=True,
527 allow_optional=True, allow_metas=returns_meta)
530 def check_event(expr, expr_info):
531 global events
532 name = expr['event']
534 if name.upper() == 'MAX':
535 raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
536 events.append(name)
537 check_type(expr_info, "'data' for event '%s'" % name,
538 expr.get('data'), allow_dict=True, allow_optional=True,
539 allow_metas=['struct'])
542 def check_union(expr, expr_info):
543 name = expr['union']
544 base = expr.get('base')
545 discriminator = expr.get('discriminator')
546 members = expr['data']
547 values = {'MAX': '(automatic)', 'KIND': '(automatic)'}
549 # Two types of unions, determined by discriminator.
551 # With no discriminator it is a simple union.
552 if discriminator is None:
553 enum_define = None
554 allow_metas = ['built-in', 'union', 'alternate', 'struct', 'enum']
555 if base is not None:
556 raise QAPIExprError(expr_info,
557 "Simple union '%s' must not have a base"
558 % name)
560 # Else, it's a flat union.
561 else:
562 # The object must have a string member 'base'.
563 check_type(expr_info, "'base' for union '%s'" % name,
564 base, allow_metas=['struct'])
565 if not base:
566 raise QAPIExprError(expr_info,
567 "Flat union '%s' must have a base"
568 % name)
569 base_fields = find_base_fields(base)
570 assert base_fields
572 # The value of member 'discriminator' must name a non-optional
573 # member of the base struct.
574 check_name(expr_info, "Discriminator of flat union '%s'" % name,
575 discriminator)
576 discriminator_type = base_fields.get(discriminator)
577 if not discriminator_type:
578 raise QAPIExprError(expr_info,
579 "Discriminator '%s' is not a member of base "
580 "struct '%s'"
581 % (discriminator, base))
582 enum_define = find_enum(discriminator_type)
583 allow_metas = ['struct']
584 # Do not allow string discriminator
585 if not enum_define:
586 raise QAPIExprError(expr_info,
587 "Discriminator '%s' must be of enumeration "
588 "type" % discriminator)
590 # Check every branch
591 for (key, value) in members.items():
592 check_name(expr_info, "Member of union '%s'" % name, key)
594 # Each value must name a known type; furthermore, in flat unions,
595 # branches must be a struct with no overlapping member names
596 check_type(expr_info, "Member '%s' of union '%s'" % (key, name),
597 value, allow_array=not base, allow_metas=allow_metas)
598 if base:
599 branch_struct = find_struct(value)
600 assert branch_struct
601 check_member_clash(expr_info, base, branch_struct['data'],
602 " of branch '%s'" % key)
604 # If the discriminator names an enum type, then all members
605 # of 'data' must also be members of the enum type, which in turn
606 # must not collide with the discriminator name.
607 if enum_define:
608 if key not in enum_define['enum_values']:
609 raise QAPIExprError(expr_info,
610 "Discriminator value '%s' is not found in "
611 "enum '%s'" %
612 (key, enum_define["enum_name"]))
613 if discriminator in enum_define['enum_values']:
614 raise QAPIExprError(expr_info,
615 "Discriminator name '%s' collides with "
616 "enum value in '%s'" %
617 (discriminator, enum_define["enum_name"]))
619 # Otherwise, check for conflicts in the generated enum
620 else:
621 c_key = camel_to_upper(key)
622 if c_key in values:
623 raise QAPIExprError(expr_info,
624 "Union '%s' member '%s' clashes with '%s'"
625 % (name, key, values[c_key]))
626 values[c_key] = key
629 def check_alternate(expr, expr_info):
630 name = expr['alternate']
631 members = expr['data']
632 values = {'MAX': '(automatic)'}
633 types_seen = {}
635 # Check every branch
636 for (key, value) in members.items():
637 check_name(expr_info, "Member of alternate '%s'" % name, key)
639 # Check for conflicts in the generated enum
640 c_key = camel_to_upper(key)
641 if c_key in values:
642 raise QAPIExprError(expr_info,
643 "Alternate '%s' member '%s' clashes with '%s'"
644 % (name, key, values[c_key]))
645 values[c_key] = key
647 # Ensure alternates have no type conflicts.
648 check_type(expr_info, "Member '%s' of alternate '%s'" % (key, name),
649 value,
650 allow_metas=['built-in', 'union', 'struct', 'enum'])
651 qtype = find_alternate_member_qtype(value)
652 assert qtype
653 if qtype in types_seen:
654 raise QAPIExprError(expr_info,
655 "Alternate '%s' member '%s' can't "
656 "be distinguished from member '%s'"
657 % (name, key, types_seen[qtype]))
658 types_seen[qtype] = key
661 def check_enum(expr, expr_info):
662 name = expr['enum']
663 members = expr.get('data')
664 prefix = expr.get('prefix')
665 values = {'MAX': '(automatic)'}
667 if not isinstance(members, list):
668 raise QAPIExprError(expr_info,
669 "Enum '%s' requires an array for 'data'" % name)
670 if prefix is not None and not isinstance(prefix, str):
671 raise QAPIExprError(expr_info,
672 "Enum '%s' requires a string for 'prefix'" % name)
673 for member in members:
674 check_name(expr_info, "Member of enum '%s'" % name, member,
675 enum_member=True)
676 key = camel_to_upper(member)
677 if key in values:
678 raise QAPIExprError(expr_info,
679 "Enum '%s' member '%s' clashes with '%s'"
680 % (name, member, values[key]))
681 values[key] = member
684 def check_struct(expr, expr_info):
685 name = expr['struct']
686 members = expr['data']
688 check_type(expr_info, "'data' for struct '%s'" % name, members,
689 allow_dict=True, allow_optional=True)
690 check_type(expr_info, "'base' for struct '%s'" % name, expr.get('base'),
691 allow_metas=['struct'])
692 if expr.get('base'):
693 check_member_clash(expr_info, expr['base'], expr['data'])
696 def check_keys(expr_elem, meta, required, optional=[]):
697 expr = expr_elem['expr']
698 info = expr_elem['info']
699 name = expr[meta]
700 if not isinstance(name, str):
701 raise QAPIExprError(info,
702 "'%s' key must have a string value" % meta)
703 required = required + [meta]
704 for (key, value) in expr.items():
705 if key not in required and key not in optional:
706 raise QAPIExprError(info,
707 "Unknown key '%s' in %s '%s'"
708 % (key, meta, name))
709 if (key == 'gen' or key == 'success-response') and value is not False:
710 raise QAPIExprError(info,
711 "'%s' of %s '%s' should only use false value"
712 % (key, meta, name))
713 for key in required:
714 if key not in expr:
715 raise QAPIExprError(info,
716 "Key '%s' is missing from %s '%s'"
717 % (key, meta, name))
720 def check_exprs(exprs):
721 global all_names
723 # Learn the types and check for valid expression keys
724 for builtin in builtin_types.keys():
725 all_names[builtin] = 'built-in'
726 for expr_elem in exprs:
727 expr = expr_elem['expr']
728 info = expr_elem['info']
729 if 'enum' in expr:
730 check_keys(expr_elem, 'enum', ['data'], ['prefix'])
731 add_enum(expr['enum'], info, expr['data'])
732 elif 'union' in expr:
733 check_keys(expr_elem, 'union', ['data'],
734 ['base', 'discriminator'])
735 add_union(expr, info)
736 elif 'alternate' in expr:
737 check_keys(expr_elem, 'alternate', ['data'])
738 add_name(expr['alternate'], info, 'alternate')
739 elif 'struct' in expr:
740 check_keys(expr_elem, 'struct', ['data'], ['base'])
741 add_struct(expr, info)
742 elif 'command' in expr:
743 check_keys(expr_elem, 'command', [],
744 ['data', 'returns', 'gen', 'success-response'])
745 add_name(expr['command'], info, 'command')
746 elif 'event' in expr:
747 check_keys(expr_elem, 'event', [], ['data'])
748 add_name(expr['event'], info, 'event')
749 else:
750 raise QAPIExprError(expr_elem['info'],
751 "Expression is missing metatype")
753 # Try again for hidden UnionKind enum
754 for expr_elem in exprs:
755 expr = expr_elem['expr']
756 if 'union' in expr:
757 if not discriminator_find_enum_define(expr):
758 add_enum('%sKind' % expr['union'], expr_elem['info'],
759 implicit=True)
760 elif 'alternate' in expr:
761 add_enum('%sKind' % expr['alternate'], expr_elem['info'],
762 implicit=True)
764 # Validate that exprs make sense
765 for expr_elem in exprs:
766 expr = expr_elem['expr']
767 info = expr_elem['info']
769 if 'enum' in expr:
770 check_enum(expr, info)
771 elif 'union' in expr:
772 check_union(expr, info)
773 elif 'alternate' in expr:
774 check_alternate(expr, info)
775 elif 'struct' in expr:
776 check_struct(expr, info)
777 elif 'command' in expr:
778 check_command(expr, info)
779 elif 'event' in expr:
780 check_event(expr, info)
781 else:
782 assert False, 'unexpected meta type'
784 return exprs
788 # Schema compiler frontend
791 class QAPISchemaEntity(object):
792 def __init__(self, name, info):
793 assert isinstance(name, str)
794 self.name = name
795 self.info = info
797 def c_name(self):
798 return c_name(self.name)
800 def check(self, schema):
801 pass
803 def visit(self, visitor):
804 pass
807 class QAPISchemaVisitor(object):
808 def visit_begin(self, schema):
809 pass
811 def visit_end(self):
812 pass
814 def visit_builtin_type(self, name, info, json_type):
815 pass
817 def visit_enum_type(self, name, info, values, prefix):
818 pass
820 def visit_array_type(self, name, info, element_type):
821 pass
823 def visit_object_type(self, name, info, base, members, variants):
824 pass
826 def visit_object_type_flat(self, name, info, members, variants):
827 pass
829 def visit_alternate_type(self, name, info, variants):
830 pass
832 def visit_command(self, name, info, arg_type, ret_type,
833 gen, success_response):
834 pass
836 def visit_event(self, name, info, arg_type):
837 pass
840 class QAPISchemaType(QAPISchemaEntity):
841 def c_type(self, is_param=False):
842 return c_name(self.name) + pointer_suffix
844 def c_null(self):
845 return 'NULL'
847 def json_type(self):
848 pass
850 def alternate_qtype(self):
851 json2qtype = {
852 'string': 'QTYPE_QSTRING',
853 'number': 'QTYPE_QFLOAT',
854 'int': 'QTYPE_QINT',
855 'boolean': 'QTYPE_QBOOL',
856 'object': 'QTYPE_QDICT'
858 return json2qtype.get(self.json_type())
861 class QAPISchemaBuiltinType(QAPISchemaType):
862 def __init__(self, name, json_type, c_type, c_null):
863 QAPISchemaType.__init__(self, name, None)
864 assert not c_type or isinstance(c_type, str)
865 assert json_type in ('string', 'number', 'int', 'boolean', 'null',
866 'value')
867 self._json_type_name = json_type
868 self._c_type_name = c_type
869 self._c_null_val = c_null
871 def c_name(self):
872 return self.name
874 def c_type(self, is_param=False):
875 if is_param and self.name == 'str':
876 return 'const ' + self._c_type_name
877 return self._c_type_name
879 def c_null(self):
880 return self._c_null_val
882 def json_type(self):
883 return self._json_type_name
885 def visit(self, visitor):
886 visitor.visit_builtin_type(self.name, self.info, self.json_type())
889 class QAPISchemaEnumType(QAPISchemaType):
890 def __init__(self, name, info, values, prefix):
891 QAPISchemaType.__init__(self, name, info)
892 for v in values:
893 assert isinstance(v, str)
894 assert prefix is None or isinstance(prefix, str)
895 self.values = values
896 self.prefix = prefix
898 def check(self, schema):
899 assert len(set(self.values)) == len(self.values)
901 def c_type(self, is_param=False):
902 return c_name(self.name)
904 def c_null(self):
905 return c_enum_const(self.name, (self.values + ['MAX'])[0],
906 self.prefix)
908 def json_type(self):
909 return 'string'
911 def visit(self, visitor):
912 visitor.visit_enum_type(self.name, self.info,
913 self.values, self.prefix)
916 class QAPISchemaArrayType(QAPISchemaType):
917 def __init__(self, name, info, element_type):
918 QAPISchemaType.__init__(self, name, info)
919 assert isinstance(element_type, str)
920 self._element_type_name = element_type
921 self.element_type = None
923 def check(self, schema):
924 self.element_type = schema.lookup_type(self._element_type_name)
925 assert self.element_type
927 def json_type(self):
928 return 'array'
930 def visit(self, visitor):
931 visitor.visit_array_type(self.name, self.info, self.element_type)
934 class QAPISchemaObjectType(QAPISchemaType):
935 def __init__(self, name, info, base, local_members, variants):
936 QAPISchemaType.__init__(self, name, info)
937 assert base is None or isinstance(base, str)
938 for m in local_members:
939 assert isinstance(m, QAPISchemaObjectTypeMember)
940 assert (variants is None or
941 isinstance(variants, QAPISchemaObjectTypeVariants))
942 self._base_name = base
943 self.base = None
944 self.local_members = local_members
945 self.variants = variants
946 self.members = None
948 def check(self, schema):
949 assert self.members is not False # not running in cycles
950 if self.members:
951 return
952 self.members = False # mark as being checked
953 if self._base_name:
954 self.base = schema.lookup_type(self._base_name)
955 assert isinstance(self.base, QAPISchemaObjectType)
956 assert not self.base.variants # not implemented
957 self.base.check(schema)
958 members = list(self.base.members)
959 else:
960 members = []
961 seen = {}
962 for m in members:
963 seen[m.name] = m
964 for m in self.local_members:
965 m.check(schema, members, seen)
966 if self.variants:
967 self.variants.check(schema, members, seen)
968 self.members = members
970 def c_name(self):
971 assert self.info
972 return QAPISchemaType.c_name(self)
974 def c_type(self, is_param=False):
975 assert self.info
976 return QAPISchemaType.c_type(self)
978 def json_type(self):
979 return 'object'
981 def visit(self, visitor):
982 visitor.visit_object_type(self.name, self.info,
983 self.base, self.local_members, self.variants)
984 visitor.visit_object_type_flat(self.name, self.info,
985 self.members, self.variants)
988 class QAPISchemaObjectTypeMember(object):
989 def __init__(self, name, typ, optional):
990 assert isinstance(name, str)
991 assert isinstance(typ, str)
992 assert isinstance(optional, bool)
993 self.name = name
994 self._type_name = typ
995 self.type = None
996 self.optional = optional
998 def check(self, schema, all_members, seen):
999 assert self.name not in seen
1000 self.type = schema.lookup_type(self._type_name)
1001 assert self.type
1002 all_members.append(self)
1003 seen[self.name] = self
1006 class QAPISchemaObjectTypeVariants(object):
1007 def __init__(self, tag_name, tag_enum, variants):
1008 assert tag_name is None or isinstance(tag_name, str)
1009 assert tag_enum is None or isinstance(tag_enum, str)
1010 for v in variants:
1011 assert isinstance(v, QAPISchemaObjectTypeVariant)
1012 self.tag_name = tag_name
1013 if tag_name:
1014 assert not tag_enum
1015 self.tag_member = None
1016 else:
1017 self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
1018 False)
1019 self.variants = variants
1021 def check(self, schema, members, seen):
1022 if self.tag_name:
1023 self.tag_member = seen[self.tag_name]
1024 else:
1025 self.tag_member.check(schema, members, seen)
1026 assert isinstance(self.tag_member.type, QAPISchemaEnumType)
1027 for v in self.variants:
1028 vseen = dict(seen)
1029 v.check(schema, self.tag_member.type, vseen)
1032 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
1033 def __init__(self, name, typ):
1034 QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
1036 def check(self, schema, tag_type, seen):
1037 QAPISchemaObjectTypeMember.check(self, schema, [], seen)
1038 assert self.name in tag_type.values
1040 # This function exists to support ugly simple union special cases
1041 # TODO get rid of them, and drop the function
1042 def simple_union_type(self):
1043 if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
1044 assert len(self.type.members) == 1
1045 assert not self.type.variants
1046 return self.type.members[0].type
1047 return None
1050 class QAPISchemaAlternateType(QAPISchemaType):
1051 def __init__(self, name, info, variants):
1052 QAPISchemaType.__init__(self, name, info)
1053 assert isinstance(variants, QAPISchemaObjectTypeVariants)
1054 assert not variants.tag_name
1055 self.variants = variants
1057 def check(self, schema):
1058 self.variants.check(schema, [], {})
1060 def json_type(self):
1061 return 'value'
1063 def visit(self, visitor):
1064 visitor.visit_alternate_type(self.name, self.info, self.variants)
1067 class QAPISchemaCommand(QAPISchemaEntity):
1068 def __init__(self, name, info, arg_type, ret_type, gen, success_response):
1069 QAPISchemaEntity.__init__(self, name, info)
1070 assert not arg_type or isinstance(arg_type, str)
1071 assert not ret_type or isinstance(ret_type, str)
1072 self._arg_type_name = arg_type
1073 self.arg_type = None
1074 self._ret_type_name = ret_type
1075 self.ret_type = None
1076 self.gen = gen
1077 self.success_response = success_response
1079 def check(self, schema):
1080 if self._arg_type_name:
1081 self.arg_type = schema.lookup_type(self._arg_type_name)
1082 assert isinstance(self.arg_type, QAPISchemaObjectType)
1083 assert not self.arg_type.variants # not implemented
1084 if self._ret_type_name:
1085 self.ret_type = schema.lookup_type(self._ret_type_name)
1086 assert isinstance(self.ret_type, QAPISchemaType)
1088 def visit(self, visitor):
1089 visitor.visit_command(self.name, self.info,
1090 self.arg_type, self.ret_type,
1091 self.gen, self.success_response)
1094 class QAPISchemaEvent(QAPISchemaEntity):
1095 def __init__(self, name, info, arg_type):
1096 QAPISchemaEntity.__init__(self, name, info)
1097 assert not arg_type or isinstance(arg_type, str)
1098 self._arg_type_name = arg_type
1099 self.arg_type = None
1101 def check(self, schema):
1102 if self._arg_type_name:
1103 self.arg_type = schema.lookup_type(self._arg_type_name)
1104 assert isinstance(self.arg_type, QAPISchemaObjectType)
1105 assert not self.arg_type.variants # not implemented
1107 def visit(self, visitor):
1108 visitor.visit_event(self.name, self.info, self.arg_type)
1111 class QAPISchema(object):
1112 def __init__(self, fname):
1113 try:
1114 self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
1115 except (QAPISchemaError, QAPIExprError), err:
1116 print >>sys.stderr, err
1117 exit(1)
1118 self._entity_dict = {}
1119 self._def_predefineds()
1120 self._def_exprs()
1121 self.check()
1123 def _def_entity(self, ent):
1124 assert ent.name not in self._entity_dict
1125 self._entity_dict[ent.name] = ent
1127 def lookup_entity(self, name, typ=None):
1128 ent = self._entity_dict.get(name)
1129 if typ and not isinstance(ent, typ):
1130 return None
1131 return ent
1133 def lookup_type(self, name):
1134 return self.lookup_entity(name, QAPISchemaType)
1136 def _def_builtin_type(self, name, json_type, c_type, c_null):
1137 self._def_entity(QAPISchemaBuiltinType(name, json_type,
1138 c_type, c_null))
1139 self._make_array_type(name) # TODO really needed?
1141 def _def_predefineds(self):
1142 for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'),
1143 ('number', 'number', 'double', '0'),
1144 ('int', 'int', 'int64_t', '0'),
1145 ('int8', 'int', 'int8_t', '0'),
1146 ('int16', 'int', 'int16_t', '0'),
1147 ('int32', 'int', 'int32_t', '0'),
1148 ('int64', 'int', 'int64_t', '0'),
1149 ('uint8', 'int', 'uint8_t', '0'),
1150 ('uint16', 'int', 'uint16_t', '0'),
1151 ('uint32', 'int', 'uint32_t', '0'),
1152 ('uint64', 'int', 'uint64_t', '0'),
1153 ('size', 'int', 'uint64_t', '0'),
1154 ('bool', 'boolean', 'bool', 'false'),
1155 ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]:
1156 self._def_builtin_type(*t)
1157 self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
1158 [], None)
1159 self._def_entity(self.the_empty_object_type)
1161 def _make_implicit_enum_type(self, name, values):
1162 name = name + 'Kind'
1163 self._def_entity(QAPISchemaEnumType(name, None, values, None))
1164 return name
1166 def _make_array_type(self, element_type):
1167 name = element_type + 'List'
1168 if not self.lookup_type(name):
1169 self._def_entity(QAPISchemaArrayType(name, None, element_type))
1170 return name
1172 def _make_implicit_object_type(self, name, role, members):
1173 if not members:
1174 return None
1175 name = ':obj-%s-%s' % (name, role)
1176 if not self.lookup_entity(name, QAPISchemaObjectType):
1177 self._def_entity(QAPISchemaObjectType(name, None, None,
1178 members, None))
1179 return name
1181 def _def_enum_type(self, expr, info):
1182 name = expr['enum']
1183 data = expr['data']
1184 prefix = expr.get('prefix')
1185 self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
1186 self._make_array_type(name) # TODO really needed?
1188 def _make_member(self, name, typ):
1189 optional = False
1190 if name.startswith('*'):
1191 name = name[1:]
1192 optional = True
1193 if isinstance(typ, list):
1194 assert len(typ) == 1
1195 typ = self._make_array_type(typ[0])
1196 return QAPISchemaObjectTypeMember(name, typ, optional)
1198 def _make_members(self, data):
1199 return [self._make_member(key, value)
1200 for (key, value) in data.iteritems()]
1202 def _def_struct_type(self, expr, info):
1203 name = expr['struct']
1204 base = expr.get('base')
1205 data = expr['data']
1206 self._def_entity(QAPISchemaObjectType(name, info, base,
1207 self._make_members(data),
1208 None))
1209 self._make_array_type(name) # TODO really needed?
1211 def _make_variant(self, case, typ):
1212 return QAPISchemaObjectTypeVariant(case, typ)
1214 def _make_simple_variant(self, case, typ):
1215 if isinstance(typ, list):
1216 assert len(typ) == 1
1217 typ = self._make_array_type(typ[0])
1218 typ = self._make_implicit_object_type(typ, 'wrapper',
1219 [self._make_member('data', typ)])
1220 return QAPISchemaObjectTypeVariant(case, typ)
1222 def _make_tag_enum(self, type_name, variants):
1223 return self._make_implicit_enum_type(type_name,
1224 [v.name for v in variants])
1226 def _def_union_type(self, expr, info):
1227 name = expr['union']
1228 data = expr['data']
1229 base = expr.get('base')
1230 tag_name = expr.get('discriminator')
1231 tag_enum = None
1232 if tag_name:
1233 variants = [self._make_variant(key, value)
1234 for (key, value) in data.iteritems()]
1235 else:
1236 variants = [self._make_simple_variant(key, value)
1237 for (key, value) in data.iteritems()]
1238 tag_enum = self._make_tag_enum(name, variants)
1239 self._def_entity(
1240 QAPISchemaObjectType(name, info, base,
1241 self._make_members(OrderedDict()),
1242 QAPISchemaObjectTypeVariants(tag_name,
1243 tag_enum,
1244 variants)))
1245 self._make_array_type(name) # TODO really needed?
1247 def _def_alternate_type(self, expr, info):
1248 name = expr['alternate']
1249 data = expr['data']
1250 variants = [self._make_variant(key, value)
1251 for (key, value) in data.iteritems()]
1252 tag_enum = self._make_tag_enum(name, variants)
1253 self._def_entity(
1254 QAPISchemaAlternateType(name, info,
1255 QAPISchemaObjectTypeVariants(None,
1256 tag_enum,
1257 variants)))
1258 self._make_array_type(name) # TODO really needed?
1260 def _def_command(self, expr, info):
1261 name = expr['command']
1262 data = expr.get('data')
1263 rets = expr.get('returns')
1264 gen = expr.get('gen', True)
1265 success_response = expr.get('success-response', True)
1266 if isinstance(data, OrderedDict):
1267 data = self._make_implicit_object_type(name, 'arg',
1268 self._make_members(data))
1269 if isinstance(rets, list):
1270 assert len(rets) == 1
1271 rets = self._make_array_type(rets[0])
1272 self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
1273 success_response))
1275 def _def_event(self, expr, info):
1276 name = expr['event']
1277 data = expr.get('data')
1278 if isinstance(data, OrderedDict):
1279 data = self._make_implicit_object_type(name, 'arg',
1280 self._make_members(data))
1281 self._def_entity(QAPISchemaEvent(name, info, data))
1283 def _def_exprs(self):
1284 for expr_elem in self.exprs:
1285 expr = expr_elem['expr']
1286 info = expr_elem['info']
1287 if 'enum' in expr:
1288 self._def_enum_type(expr, info)
1289 elif 'struct' in expr:
1290 self._def_struct_type(expr, info)
1291 elif 'union' in expr:
1292 self._def_union_type(expr, info)
1293 elif 'alternate' in expr:
1294 self._def_alternate_type(expr, info)
1295 elif 'command' in expr:
1296 self._def_command(expr, info)
1297 elif 'event' in expr:
1298 self._def_event(expr, info)
1299 else:
1300 assert False
1302 def check(self):
1303 for ent in self._entity_dict.values():
1304 ent.check(self)
1306 def visit(self, visitor):
1307 ignore = visitor.visit_begin(self)
1308 for name in sorted(self._entity_dict.keys()):
1309 if not ignore or not isinstance(self._entity_dict[name], ignore):
1310 self._entity_dict[name].visit(visitor)
1311 visitor.visit_end()
1315 # Code generation helpers
1318 def camel_case(name):
1319 new_name = ''
1320 first = True
1321 for ch in name:
1322 if ch in ['_', '-']:
1323 first = True
1324 elif first:
1325 new_name += ch.upper()
1326 first = False
1327 else:
1328 new_name += ch.lower()
1329 return new_name
1332 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1333 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1334 # ENUM24_Name -> ENUM24_NAME
1335 def camel_to_upper(value):
1336 c_fun_str = c_name(value, False)
1337 if value.isupper():
1338 return c_fun_str
1340 new_name = ''
1341 l = len(c_fun_str)
1342 for i in range(l):
1343 c = c_fun_str[i]
1344 # When c is upper and no "_" appears before, do more checks
1345 if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
1346 if i < l - 1 and c_fun_str[i + 1].islower():
1347 new_name += '_'
1348 elif c_fun_str[i - 1].isdigit():
1349 new_name += '_'
1350 new_name += c
1351 return new_name.lstrip('_').upper()
1354 def c_enum_const(type_name, const_name, prefix=None):
1355 if prefix is not None:
1356 type_name = prefix
1357 return camel_to_upper(type_name + '_' + const_name)
1359 c_name_trans = string.maketrans('.-', '__')
1362 # Map @name to a valid C identifier.
1363 # If @protect, avoid returning certain ticklish identifiers (like
1364 # C keywords) by prepending "q_".
1366 # Used for converting 'name' from a 'name':'type' qapi definition
1367 # into a generated struct member, as well as converting type names
1368 # into substrings of a generated C function name.
1369 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1370 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1371 def c_name(name, protect=True):
1372 # ANSI X3J11/88-090, 3.1.1
1373 c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
1374 'default', 'do', 'double', 'else', 'enum', 'extern',
1375 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1376 'return', 'short', 'signed', 'sizeof', 'static',
1377 'struct', 'switch', 'typedef', 'union', 'unsigned',
1378 'void', 'volatile', 'while'])
1379 # ISO/IEC 9899:1999, 6.4.1
1380 c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1381 # ISO/IEC 9899:2011, 6.4.1
1382 c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1383 '_Noreturn', '_Static_assert', '_Thread_local'])
1384 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1385 # excluding _.*
1386 gcc_words = set(['asm', 'typeof'])
1387 # C++ ISO/IEC 14882:2003 2.11
1388 cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
1389 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1390 'namespace', 'new', 'operator', 'private', 'protected',
1391 'public', 'reinterpret_cast', 'static_cast', 'template',
1392 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1393 'using', 'virtual', 'wchar_t',
1394 # alternative representations
1395 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1396 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1397 # namespace pollution:
1398 polluted_words = set(['unix', 'errno'])
1399 if protect and (name in c89_words | c99_words | c11_words | gcc_words
1400 | cpp_words | polluted_words):
1401 return "q_" + name
1402 return name.translate(c_name_trans)
1404 eatspace = '\033EATSPACE.'
1405 pointer_suffix = ' *' + eatspace
1408 def genindent(count):
1409 ret = ""
1410 for _ in range(count):
1411 ret += " "
1412 return ret
1414 indent_level = 0
1417 def push_indent(indent_amount=4):
1418 global indent_level
1419 indent_level += indent_amount
1422 def pop_indent(indent_amount=4):
1423 global indent_level
1424 indent_level -= indent_amount
1427 # Generate @code with @kwds interpolated.
1428 # Obey indent_level, and strip eatspace.
1429 def cgen(code, **kwds):
1430 raw = code % kwds
1431 if indent_level:
1432 indent = genindent(indent_level)
1433 # re.subn() lacks flags support before Python 2.7, use re.compile()
1434 raw = re.subn(re.compile("^.", re.MULTILINE),
1435 indent + r'\g<0>', raw)
1436 raw = raw[0]
1437 return re.sub(re.escape(eatspace) + ' *', '', raw)
1440 def mcgen(code, **kwds):
1441 if code[0] == '\n':
1442 code = code[1:]
1443 return cgen(code, **kwds)
1446 def guardname(filename):
1447 return c_name(filename, protect=False).upper()
1450 def guardstart(name):
1451 return mcgen('''
1453 #ifndef %(name)s
1454 #define %(name)s
1456 ''',
1457 name=guardname(name))
1460 def guardend(name):
1461 return mcgen('''
1463 #endif /* %(name)s */
1465 ''',
1466 name=guardname(name))
1469 def gen_enum_lookup(name, values, prefix=None):
1470 ret = mcgen('''
1472 const char *const %(c_name)s_lookup[] = {
1473 ''',
1474 c_name=c_name(name))
1475 for value in values:
1476 index = c_enum_const(name, value, prefix)
1477 ret += mcgen('''
1478 [%(index)s] = "%(value)s",
1479 ''',
1480 index=index, value=value)
1482 max_index = c_enum_const(name, 'MAX', prefix)
1483 ret += mcgen('''
1484 [%(max_index)s] = NULL,
1486 ''',
1487 max_index=max_index)
1488 return ret
1491 def gen_enum(name, values, prefix=None):
1492 # append automatically generated _MAX value
1493 enum_values = values + ['MAX']
1495 ret = mcgen('''
1497 typedef enum %(c_name)s {
1498 ''',
1499 c_name=c_name(name))
1501 i = 0
1502 for value in enum_values:
1503 ret += mcgen('''
1504 %(c_enum)s = %(i)d,
1505 ''',
1506 c_enum=c_enum_const(name, value, prefix),
1507 i=i)
1508 i += 1
1510 ret += mcgen('''
1511 } %(c_name)s;
1512 ''',
1513 c_name=c_name(name))
1515 ret += mcgen('''
1517 extern const char *const %(c_name)s_lookup[];
1518 ''',
1519 c_name=c_name(name))
1520 return ret
1523 def gen_params(arg_type, extra):
1524 if not arg_type:
1525 return extra
1526 assert not arg_type.variants
1527 ret = ''
1528 sep = ''
1529 for memb in arg_type.members:
1530 ret += sep
1531 sep = ', '
1532 if memb.optional:
1533 ret += 'bool has_%s, ' % c_name(memb.name)
1534 ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
1535 if extra:
1536 ret += sep + extra
1537 return ret
1540 def gen_err_check(label='out', skiperr=False):
1541 if skiperr:
1542 return ''
1543 return mcgen('''
1544 if (err) {
1545 goto %(label)s;
1547 ''',
1548 label=label)
1551 def gen_visit_fields(members, prefix='', need_cast=False, skiperr=False):
1552 ret = ''
1553 if skiperr:
1554 errparg = 'NULL'
1555 else:
1556 errparg = '&err'
1558 for memb in members:
1559 if memb.optional:
1560 ret += mcgen('''
1561 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1562 ''',
1563 prefix=prefix, c_name=c_name(memb.name),
1564 name=memb.name, errp=errparg)
1565 ret += gen_err_check(skiperr=skiperr)
1566 ret += mcgen('''
1567 if (%(prefix)shas_%(c_name)s) {
1568 ''',
1569 prefix=prefix, c_name=c_name(memb.name))
1570 push_indent()
1572 # Ugly: sometimes we need to cast away const
1573 if need_cast and memb.type.name == 'str':
1574 cast = '(char **)'
1575 else:
1576 cast = ''
1578 ret += mcgen('''
1579 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1580 ''',
1581 c_type=memb.type.c_name(), prefix=prefix, cast=cast,
1582 c_name=c_name(memb.name), name=memb.name,
1583 errp=errparg)
1584 ret += gen_err_check(skiperr=skiperr)
1586 if memb.optional:
1587 pop_indent()
1588 ret += mcgen('''
1590 ''')
1591 return ret
1595 # Common command line parsing
1599 def parse_command_line(extra_options="", extra_long_options=[]):
1601 try:
1602 opts, args = getopt.gnu_getopt(sys.argv[1:],
1603 "chp:o:" + extra_options,
1604 ["source", "header", "prefix=",
1605 "output-dir="] + extra_long_options)
1606 except getopt.GetoptError, err:
1607 print >>sys.stderr, "%s: %s" % (sys.argv[0], str(err))
1608 sys.exit(1)
1610 output_dir = ""
1611 prefix = ""
1612 do_c = False
1613 do_h = False
1614 extra_opts = []
1616 for oa in opts:
1617 o, a = oa
1618 if o in ("-p", "--prefix"):
1619 match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
1620 if match.end() != len(a):
1621 print >>sys.stderr, \
1622 "%s: 'funny character '%s' in argument of --prefix" \
1623 % (sys.argv[0], a[match.end()])
1624 sys.exit(1)
1625 prefix = a
1626 elif o in ("-o", "--output-dir"):
1627 output_dir = a + "/"
1628 elif o in ("-c", "--source"):
1629 do_c = True
1630 elif o in ("-h", "--header"):
1631 do_h = True
1632 else:
1633 extra_opts.append(oa)
1635 if not do_c and not do_h:
1636 do_c = True
1637 do_h = True
1639 if len(args) != 1:
1640 print >>sys.stderr, "%s: need exactly one argument" % sys.argv[0]
1641 sys.exit(1)
1642 fname = args[0]
1644 return (fname, output_dir, do_c, do_h, prefix, extra_opts)
1647 # Generate output files with boilerplate
1651 def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
1652 c_comment, h_comment):
1653 guard = guardname(prefix + h_file)
1654 c_file = output_dir + prefix + c_file
1655 h_file = output_dir + prefix + h_file
1657 if output_dir:
1658 try:
1659 os.makedirs(output_dir)
1660 except os.error, e:
1661 if e.errno != errno.EEXIST:
1662 raise
1664 def maybe_open(really, name, opt):
1665 if really:
1666 return open(name, opt)
1667 else:
1668 import StringIO
1669 return StringIO.StringIO()
1671 fdef = maybe_open(do_c, c_file, 'w')
1672 fdecl = maybe_open(do_h, h_file, 'w')
1674 fdef.write(mcgen('''
1675 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1676 %(comment)s
1677 ''',
1678 comment=c_comment))
1680 fdecl.write(mcgen('''
1681 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1682 %(comment)s
1683 #ifndef %(guard)s
1684 #define %(guard)s
1686 ''',
1687 comment=h_comment, guard=guard))
1689 return (fdef, fdecl)
1692 def close_output(fdef, fdecl):
1693 fdecl.write('''
1694 #endif
1695 ''')
1696 fdecl.close()
1697 fdef.close()