4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2016 Red Hat Inc.
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.
15 from ordereddict
import OrderedDict
23 'str': 'QTYPE_QSTRING',
25 'number': 'QTYPE_QFLOAT',
26 'bool': 'QTYPE_QBOOL',
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',
36 'any': None, # any QType possible, actually
37 'QType': 'QTYPE_QSTRING',
40 # Whitelist of commands allowed to return a non-dictionary
43 'human-monitor-command',
45 'query-migrate-cache-size',
52 'guest-fsfreeze-freeze',
53 'guest-fsfreeze-freeze-list',
54 'guest-fsfreeze-status',
55 'guest-fsfreeze-thaw',
59 'guest-sync-delimited',
62 # Whitelist of entities allowed to violate case conventions
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoBase', # CPU, visible through query-cpu
67 'CpuInfoMIPS', # PC, visible through query-cpu
68 'CpuInfoTricore', # PC, visible through query-cpu
69 'InputAxis', # TODO: drop when x-input-send-event is fixed
70 'InputButton', # TODO: drop when x-input-send-event is fixed
71 'QapiErrorClass', # all members, visible through errors
72 'UuidInfo', # UUID, visible through query-uuid
73 'X86CPURegister32', # all members, visible indirectly through qom-get
83 # Parsing the schema into expressions
87 def error_path(parent
):
90 res
= ("In file included from %s:%d:\n" % (parent
['file'],
91 parent
['line'])) + res
92 parent
= parent
['parent']
96 class QAPISchemaError(Exception):
97 def __init__(self
, schema
, msg
):
98 Exception.__init
__(self
)
99 self
.fname
= schema
.fname
102 self
.line
= schema
.line
103 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
105 self
.col
= (self
.col
+ 7) % 8 + 1
108 self
.info
= schema
.incl_info
111 return error_path(self
.info
) + \
112 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
115 class QAPIExprError(Exception):
116 def __init__(self
, expr_info
, msg
):
117 Exception.__init
__(self
)
119 self
.info
= expr_info
123 return error_path(self
.info
['parent']) + \
124 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
127 class QAPISchemaParser(object):
129 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
130 abs_fname
= os
.path
.abspath(fp
.name
)
133 previously_included
.append(abs_fname
)
134 self
.incl_info
= incl_info
136 if self
.src
== '' or self
.src
[-1] != '\n':
144 while self
.tok
is not None:
145 expr_info
= {'file': fname
, 'line': self
.line
,
146 'parent': self
.incl_info
}
147 expr
= self
.get_expr(False)
148 if isinstance(expr
, dict) and "include" in expr
:
150 raise QAPIExprError(expr_info
,
151 "Invalid 'include' directive")
152 include
= expr
["include"]
153 if not isinstance(include
, str):
154 raise QAPIExprError(expr_info
,
155 "Value of 'include' must be a string")
156 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
158 # catch inclusion cycle
161 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
162 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
165 # skip multiple include of the same file
166 if incl_abs_fname
in previously_included
:
169 fobj
= open(incl_abs_fname
, 'r')
171 raise QAPIExprError(expr_info
,
172 '%s: %s' % (e
.strerror
, include
))
173 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
175 self
.exprs
.extend(exprs_include
.exprs
)
177 expr_elem
= {'expr': expr
,
179 self
.exprs
.append(expr_elem
)
183 self
.tok
= self
.src
[self
.cursor
]
184 self
.pos
= self
.cursor
189 self
.cursor
= self
.src
.find('\n', self
.cursor
)
190 elif self
.tok
in "{}:,[]":
192 elif self
.tok
== "'":
196 ch
= self
.src
[self
.cursor
]
199 raise QAPISchemaError(self
,
200 'Missing terminating "\'"')
214 for _
in range(0, 4):
215 ch
= self
.src
[self
.cursor
]
217 if ch
not in "0123456789abcdefABCDEF":
218 raise QAPISchemaError(self
,
219 '\\u escape needs 4 '
221 value
= (value
<< 4) + int(ch
, 16)
222 # If Python 2 and 3 didn't disagree so much on
223 # how to handle Unicode, then we could allow
224 # Unicode string defaults. But most of QAPI is
225 # ASCII-only, so we aren't losing much for now.
226 if not value
or value
> 0x7f:
227 raise QAPISchemaError(self
,
228 'For now, \\u escape '
229 'only supports non-zero '
230 'values up to \\u007f')
235 raise QAPISchemaError(self
,
236 "Unknown escape \\%s" % ch
)
245 elif self
.src
.startswith("true", self
.pos
):
249 elif self
.src
.startswith("false", self
.pos
):
253 elif self
.src
.startswith("null", self
.pos
):
257 elif self
.tok
== '\n':
258 if self
.cursor
== len(self
.src
):
262 self
.line_pos
= self
.cursor
263 elif not self
.tok
.isspace():
264 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
266 def get_members(self
):
272 raise QAPISchemaError(self
, 'Expected string or "}"')
277 raise QAPISchemaError(self
, 'Expected ":"')
280 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
281 expr
[key
] = self
.get_expr(True)
286 raise QAPISchemaError(self
, 'Expected "," or "}"')
289 raise QAPISchemaError(self
, 'Expected string')
291 def get_values(self
):
296 if self
.tok
not in "{['tfn":
297 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
300 expr
.append(self
.get_expr(True))
305 raise QAPISchemaError(self
, 'Expected "," or "]"')
308 def get_expr(self
, nested
):
309 if self
.tok
!= '{' and not nested
:
310 raise QAPISchemaError(self
, 'Expected "{"')
313 expr
= self
.get_members()
314 elif self
.tok
== '[':
316 expr
= self
.get_values()
317 elif self
.tok
in "'tfn":
321 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
325 # Semantic analysis of schema expressions
326 # TODO fold into QAPISchema
327 # TODO catching name collisions in generated code would be nice
331 def find_base_fields(base
):
332 base_struct_define
= find_struct(base
)
333 if not base_struct_define
:
335 return base_struct_define
['data']
338 # Return the qtype of an alternate branch, or None on error.
339 def find_alternate_member_qtype(qapi_type
):
340 if qapi_type
in builtin_types
:
341 return builtin_types
[qapi_type
]
342 elif find_struct(qapi_type
):
344 elif find_enum(qapi_type
):
345 return "QTYPE_QSTRING"
346 elif find_union(qapi_type
):
351 # Return the discriminator enum define if discriminator is specified as an
352 # enum type, otherwise return None.
353 def discriminator_find_enum_define(expr
):
354 base
= expr
.get('base')
355 discriminator
= expr
.get('discriminator')
357 if not (discriminator
and base
):
360 base_fields
= find_base_fields(base
)
364 discriminator_type
= base_fields
.get(discriminator
)
365 if not discriminator_type
:
368 return find_enum(discriminator_type
)
371 # Names must be letters, numbers, -, and _. They must start with letter,
372 # except for downstream extensions which must start with __RFQDN_.
373 # Dots are only valid in the downstream extension prefix.
374 valid_name
= re
.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
378 def check_name(expr_info
, source
, name
, allow_optional
=False,
383 if not isinstance(name
, str):
384 raise QAPIExprError(expr_info
,
385 "%s requires a string name" % source
)
386 if name
.startswith('*'):
387 membername
= name
[1:]
388 if not allow_optional
:
389 raise QAPIExprError(expr_info
,
390 "%s does not allow optional name '%s'"
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
394 if enum_member
and membername
[0].isdigit():
395 membername
= 'D' + membername
396 # Reserve the entire 'q_' namespace for c_name()
397 if not valid_name
.match(membername
) or \
398 c_name(membername
, False).startswith('q_'):
399 raise QAPIExprError(expr_info
,
400 "%s uses invalid name '%s'" % (source
, name
))
403 def add_name(name
, info
, meta
, implicit
=False):
405 check_name(info
, "'%s'" % meta
, name
)
406 # FIXME should reject names that differ only in '_' vs. '.'
407 # vs. '-', because they're liable to clash in generated C.
408 if name
in all_names
:
409 raise QAPIExprError(info
,
410 "%s '%s' is already defined"
411 % (all_names
[name
], name
))
412 if not implicit
and (name
.endswith('Kind') or name
.endswith('List')):
413 raise QAPIExprError(info
,
414 "%s '%s' should not end in '%s'"
415 % (meta
, name
, name
[-4:]))
416 all_names
[name
] = meta
419 def add_struct(definition
, info
):
421 name
= definition
['struct']
422 add_name(name
, info
, 'struct')
423 struct_types
.append(definition
)
426 def find_struct(name
):
428 for struct
in struct_types
:
429 if struct
['struct'] == name
:
434 def add_union(definition
, info
):
436 name
= definition
['union']
437 add_name(name
, info
, 'union')
438 union_types
.append(definition
)
441 def find_union(name
):
443 for union
in union_types
:
444 if union
['union'] == name
:
449 def add_enum(name
, info
, enum_values
=None, implicit
=False):
451 add_name(name
, info
, 'enum', implicit
)
452 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
457 for enum
in enum_types
:
458 if enum
['enum_name'] == name
:
464 return find_enum(name
) is not None
467 def check_type(expr_info
, source
, value
, allow_array
=False,
468 allow_dict
=False, allow_optional
=False,
475 # Check if array type for value is okay
476 if isinstance(value
, list):
478 raise QAPIExprError(expr_info
,
479 "%s cannot be an array" % source
)
480 if len(value
) != 1 or not isinstance(value
[0], str):
481 raise QAPIExprError(expr_info
,
482 "%s: array type must contain single type name"
486 # Check if type name for value is okay
487 if isinstance(value
, str):
488 if value
not in all_names
:
489 raise QAPIExprError(expr_info
,
490 "%s uses unknown type '%s'"
492 if not all_names
[value
] in allow_metas
:
493 raise QAPIExprError(expr_info
,
494 "%s cannot use %s type '%s'"
495 % (source
, all_names
[value
], value
))
499 raise QAPIExprError(expr_info
,
500 "%s should be a type name" % source
)
502 if not isinstance(value
, OrderedDict
):
503 raise QAPIExprError(expr_info
,
504 "%s should be a dictionary or type name" % source
)
506 # value is a dictionary, check that each member is okay
507 for (key
, arg
) in value
.items():
508 check_name(expr_info
, "Member of %s" % source
, key
,
509 allow_optional
=allow_optional
)
510 if c_name(key
, False) == 'u' or c_name(key
, False).startswith('has_'):
511 raise QAPIExprError(expr_info
,
512 "Member of %s uses reserved name '%s'"
514 # Todo: allow dictionaries to represent default values of
515 # an optional argument.
516 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
518 allow_metas
=['built-in', 'union', 'alternate', 'struct',
522 def check_command(expr
, expr_info
):
523 name
= expr
['command']
525 check_type(expr_info
, "'data' for command '%s'" % name
,
526 expr
.get('data'), allow_dict
=True, allow_optional
=True,
527 allow_metas
=['struct'])
528 returns_meta
= ['union', 'struct']
529 if name
in returns_whitelist
:
530 returns_meta
+= ['built-in', 'alternate', 'enum']
531 check_type(expr_info
, "'returns' for command '%s'" % name
,
532 expr
.get('returns'), allow_array
=True,
533 allow_optional
=True, allow_metas
=returns_meta
)
536 def check_event(expr
, expr_info
):
541 check_type(expr_info
, "'data' for event '%s'" % name
,
542 expr
.get('data'), allow_dict
=True, allow_optional
=True,
543 allow_metas
=['struct'])
546 def check_union(expr
, expr_info
):
548 base
= expr
.get('base')
549 discriminator
= expr
.get('discriminator')
550 members
= expr
['data']
552 # Two types of unions, determined by discriminator.
554 # With no discriminator it is a simple union.
555 if discriminator
is None:
557 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
559 raise QAPIExprError(expr_info
,
560 "Simple union '%s' must not have a base"
563 # Else, it's a flat union.
565 # The object must have a string member 'base'.
566 check_type(expr_info
, "'base' for union '%s'" % name
,
567 base
, allow_metas
=['struct'])
569 raise QAPIExprError(expr_info
,
570 "Flat union '%s' must have a base"
572 base_fields
= find_base_fields(base
)
575 # The value of member 'discriminator' must name a non-optional
576 # member of the base struct.
577 check_name(expr_info
, "Discriminator of flat union '%s'" % name
,
579 discriminator_type
= base_fields
.get(discriminator
)
580 if not discriminator_type
:
581 raise QAPIExprError(expr_info
,
582 "Discriminator '%s' is not a member of base "
584 % (discriminator
, base
))
585 enum_define
= find_enum(discriminator_type
)
586 allow_metas
= ['struct']
587 # Do not allow string discriminator
589 raise QAPIExprError(expr_info
,
590 "Discriminator '%s' must be of enumeration "
591 "type" % discriminator
)
593 # Check every branch; don't allow an empty union
594 if len(members
) == 0:
595 raise QAPIExprError(expr_info
,
596 "Union '%s' cannot have empty 'data'" % name
)
597 for (key
, value
) in members
.items():
598 check_name(expr_info
, "Member of union '%s'" % name
, key
)
600 # Each value must name a known type
601 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
602 value
, allow_array
=not base
, allow_metas
=allow_metas
)
604 # If the discriminator names an enum type, then all members
605 # of 'data' must also be members of the enum type.
607 if key
not in enum_define
['enum_values']:
608 raise QAPIExprError(expr_info
,
609 "Discriminator value '%s' is not found in "
611 (key
, enum_define
["enum_name"]))
614 def check_alternate(expr
, expr_info
):
615 name
= expr
['alternate']
616 members
= expr
['data']
619 # Check every branch; require at least two branches
621 raise QAPIExprError(expr_info
,
622 "Alternate '%s' should have at least two branches "
624 for (key
, value
) in members
.items():
625 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
627 # Ensure alternates have no type conflicts.
628 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
630 allow_metas
=['built-in', 'union', 'struct', 'enum'])
631 qtype
= find_alternate_member_qtype(value
)
633 raise QAPIExprError(expr_info
,
634 "Alternate '%s' member '%s' cannot use "
635 "type '%s'" % (name
, key
, value
))
636 if qtype
in types_seen
:
637 raise QAPIExprError(expr_info
,
638 "Alternate '%s' member '%s' can't "
639 "be distinguished from member '%s'"
640 % (name
, key
, types_seen
[qtype
]))
641 types_seen
[qtype
] = key
644 def check_enum(expr
, expr_info
):
646 members
= expr
.get('data')
647 prefix
= expr
.get('prefix')
649 if not isinstance(members
, list):
650 raise QAPIExprError(expr_info
,
651 "Enum '%s' requires an array for 'data'" % name
)
652 if prefix
is not None and not isinstance(prefix
, str):
653 raise QAPIExprError(expr_info
,
654 "Enum '%s' requires a string for 'prefix'" % name
)
655 for member
in members
:
656 check_name(expr_info
, "Member of enum '%s'" % name
, member
,
660 def check_struct(expr
, expr_info
):
661 name
= expr
['struct']
662 members
= expr
['data']
664 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
665 allow_dict
=True, allow_optional
=True)
666 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
667 allow_metas
=['struct'])
670 def check_keys(expr_elem
, meta
, required
, optional
=[]):
671 expr
= expr_elem
['expr']
672 info
= expr_elem
['info']
674 if not isinstance(name
, str):
675 raise QAPIExprError(info
,
676 "'%s' key must have a string value" % meta
)
677 required
= required
+ [meta
]
678 for (key
, value
) in expr
.items():
679 if key
not in required
and key
not in optional
:
680 raise QAPIExprError(info
,
681 "Unknown key '%s' in %s '%s'"
683 if (key
== 'gen' or key
== 'success-response') and value
is not False:
684 raise QAPIExprError(info
,
685 "'%s' of %s '%s' should only use false value"
689 raise QAPIExprError(info
,
690 "Key '%s' is missing from %s '%s'"
694 def check_exprs(exprs
):
697 # Learn the types and check for valid expression keys
698 for builtin
in builtin_types
.keys():
699 all_names
[builtin
] = 'built-in'
700 for expr_elem
in exprs
:
701 expr
= expr_elem
['expr']
702 info
= expr_elem
['info']
704 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
705 add_enum(expr
['enum'], info
, expr
['data'])
706 elif 'union' in expr
:
707 check_keys(expr_elem
, 'union', ['data'],
708 ['base', 'discriminator'])
709 add_union(expr
, info
)
710 elif 'alternate' in expr
:
711 check_keys(expr_elem
, 'alternate', ['data'])
712 add_name(expr
['alternate'], info
, 'alternate')
713 elif 'struct' in expr
:
714 check_keys(expr_elem
, 'struct', ['data'], ['base'])
715 add_struct(expr
, info
)
716 elif 'command' in expr
:
717 check_keys(expr_elem
, 'command', [],
718 ['data', 'returns', 'gen', 'success-response'])
719 add_name(expr
['command'], info
, 'command')
720 elif 'event' in expr
:
721 check_keys(expr_elem
, 'event', [], ['data'])
722 add_name(expr
['event'], info
, 'event')
724 raise QAPIExprError(expr_elem
['info'],
725 "Expression is missing metatype")
727 # Try again for hidden UnionKind enum
728 for expr_elem
in exprs
:
729 expr
= expr_elem
['expr']
731 if not discriminator_find_enum_define(expr
):
732 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
734 elif 'alternate' in expr
:
735 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
738 # Validate that exprs make sense
739 for expr_elem
in exprs
:
740 expr
= expr_elem
['expr']
741 info
= expr_elem
['info']
744 check_enum(expr
, info
)
745 elif 'union' in expr
:
746 check_union(expr
, info
)
747 elif 'alternate' in expr
:
748 check_alternate(expr
, info
)
749 elif 'struct' in expr
:
750 check_struct(expr
, info
)
751 elif 'command' in expr
:
752 check_command(expr
, info
)
753 elif 'event' in expr
:
754 check_event(expr
, info
)
756 assert False, 'unexpected meta type'
762 # Schema compiler frontend
765 class QAPISchemaEntity(object):
766 def __init__(self
, name
, info
):
767 assert isinstance(name
, str)
769 # For explicitly defined entities, info points to the (explicit)
770 # definition. For builtins (and their arrays), info is None.
771 # For implicitly defined entities, info points to a place that
772 # triggered the implicit definition (there may be more than one
777 return c_name(self
.name
)
779 def check(self
, schema
):
782 def is_implicit(self
):
785 def visit(self
, visitor
):
789 class QAPISchemaVisitor(object):
790 def visit_begin(self
, schema
):
796 def visit_needed(self
, entity
):
797 # Default to visiting everything
800 def visit_builtin_type(self
, name
, info
, json_type
):
803 def visit_enum_type(self
, name
, info
, values
, prefix
):
806 def visit_array_type(self
, name
, info
, element_type
):
809 def visit_object_type(self
, name
, info
, base
, members
, variants
):
812 def visit_object_type_flat(self
, name
, info
, members
, variants
):
815 def visit_alternate_type(self
, name
, info
, variants
):
818 def visit_command(self
, name
, info
, arg_type
, ret_type
,
819 gen
, success_response
):
822 def visit_event(self
, name
, info
, arg_type
):
826 class QAPISchemaType(QAPISchemaEntity
):
827 def c_type(self
, is_param
=False, is_unboxed
=False):
828 return c_name(self
.name
) + pointer_suffix
836 def alternate_qtype(self
):
838 'string': 'QTYPE_QSTRING',
839 'number': 'QTYPE_QFLOAT',
841 'boolean': 'QTYPE_QBOOL',
842 'object': 'QTYPE_QDICT'
844 return json2qtype
.get(self
.json_type())
847 class QAPISchemaBuiltinType(QAPISchemaType
):
848 def __init__(self
, name
, json_type
, c_type
, c_null
):
849 QAPISchemaType
.__init
__(self
, name
, None)
850 assert not c_type
or isinstance(c_type
, str)
851 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
853 self
._json
_type
_name
= json_type
854 self
._c
_type
_name
= c_type
855 self
._c
_null
_val
= c_null
860 def c_type(self
, is_param
=False, is_unboxed
=False):
861 if is_param
and self
.name
== 'str':
862 return 'const ' + self
._c
_type
_name
863 return self
._c
_type
_name
866 return self
._c
_null
_val
869 return self
._json
_type
_name
871 def visit(self
, visitor
):
872 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
875 class QAPISchemaEnumType(QAPISchemaType
):
876 def __init__(self
, name
, info
, values
, prefix
):
877 QAPISchemaType
.__init
__(self
, name
, info
)
879 assert isinstance(v
, QAPISchemaMember
)
881 assert prefix
is None or isinstance(prefix
, str)
885 def check(self
, schema
):
887 for v
in self
.values
:
888 v
.check_clash(self
.info
, seen
)
890 def is_implicit(self
):
891 # See QAPISchema._make_implicit_enum_type()
892 return self
.name
.endswith('Kind')
894 def c_type(self
, is_param
=False, is_unboxed
=False):
895 return c_name(self
.name
)
897 def member_names(self
):
898 return [v
.name
for v
in self
.values
]
901 return c_enum_const(self
.name
, (self
.member_names() + ['_MAX'])[0],
907 def visit(self
, visitor
):
908 visitor
.visit_enum_type(self
.name
, self
.info
,
909 self
.member_names(), self
.prefix
)
912 class QAPISchemaArrayType(QAPISchemaType
):
913 def __init__(self
, name
, info
, element_type
):
914 QAPISchemaType
.__init
__(self
, name
, info
)
915 assert isinstance(element_type
, str)
916 self
._element
_type
_name
= element_type
917 self
.element_type
= None
919 def check(self
, schema
):
920 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
921 assert self
.element_type
923 def is_implicit(self
):
929 def visit(self
, visitor
):
930 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
933 class QAPISchemaObjectType(QAPISchemaType
):
934 def __init__(self
, name
, info
, base
, local_members
, variants
):
935 # struct has local_members, optional base, and no variants
936 # flat union has base, variants, and no local_members
937 # simple union has local_members, variants, and no base
938 QAPISchemaType
.__init
__(self
, name
, info
)
939 assert base
is None or isinstance(base
, str)
940 for m
in local_members
:
941 assert isinstance(m
, QAPISchemaObjectTypeMember
)
943 if variants
is not None:
944 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
945 variants
.set_owner(name
)
946 self
._base
_name
= base
948 self
.local_members
= local_members
949 self
.variants
= variants
952 def check(self
, schema
):
953 if self
.members
is False: # check for cycles
954 raise QAPIExprError(self
.info
,
955 "Object %s contains itself" % self
.name
)
958 self
.members
= False # mark as being checked
961 self
.base
= schema
.lookup_type(self
._base
_name
)
962 assert isinstance(self
.base
, QAPISchemaObjectType
)
963 self
.base
.check(schema
)
964 self
.base
.check_clash(schema
, self
.info
, seen
)
965 for m
in self
.local_members
:
967 m
.check_clash(self
.info
, seen
)
968 self
.members
= seen
.values()
970 self
.variants
.check(schema
, seen
)
971 assert self
.variants
.tag_member
in self
.members
972 self
.variants
.check_clash(schema
, self
.info
, seen
)
974 # Check that the members of this type do not cause duplicate JSON fields,
975 # and update seen to track the members seen so far. Report any errors
976 # on behalf of info, which is not necessarily self.info
977 def check_clash(self
, schema
, info
, seen
):
978 assert not self
.variants
# not implemented
979 for m
in self
.members
:
980 m
.check_clash(info
, seen
)
982 def is_implicit(self
):
983 # See QAPISchema._make_implicit_object_type()
984 return self
.name
[0] == ':'
987 assert not self
.is_implicit()
988 return QAPISchemaType
.c_name(self
)
990 def c_type(self
, is_param
=False, is_unboxed
=False):
991 assert not self
.is_implicit()
993 return c_name(self
.name
)
994 return c_name(self
.name
) + pointer_suffix
999 def visit(self
, visitor
):
1000 visitor
.visit_object_type(self
.name
, self
.info
,
1001 self
.base
, self
.local_members
, self
.variants
)
1002 visitor
.visit_object_type_flat(self
.name
, self
.info
,
1003 self
.members
, self
.variants
)
1006 class QAPISchemaMember(object):
1009 def __init__(self
, name
):
1010 assert isinstance(name
, str)
1014 def set_owner(self
, name
):
1015 assert not self
.owner
1018 def check_clash(self
, info
, seen
):
1019 cname
= c_name(self
.name
)
1020 if cname
.lower() != cname
and self
.owner
not in case_whitelist
:
1021 raise QAPIExprError(info
,
1022 "%s should not use uppercase" % self
.describe())
1024 raise QAPIExprError(info
,
1025 "%s collides with %s"
1026 % (self
.describe(), seen
[cname
].describe()))
1029 def _pretty_owner(self
):
1031 if owner
.startswith(':obj-'):
1032 # See QAPISchema._make_implicit_object_type() - reverse the
1033 # mapping there to create a nice human-readable description
1035 if owner
.endswith('-arg'):
1036 return '(parameter of %s)' % owner
[:-4]
1038 assert owner
.endswith('-wrapper')
1039 # Unreachable and not implemented
1041 if owner
.endswith('Kind'):
1042 # See QAPISchema._make_implicit_enum_type()
1043 return '(branch of %s)' % owner
[:-4]
1044 return '(%s of %s)' % (self
.role
, owner
)
1047 return "'%s' %s" % (self
.name
, self
._pretty
_owner
())
1050 class QAPISchemaObjectTypeMember(QAPISchemaMember
):
1051 def __init__(self
, name
, typ
, optional
):
1052 QAPISchemaMember
.__init
__(self
, name
)
1053 assert isinstance(typ
, str)
1054 assert isinstance(optional
, bool)
1055 self
._type
_name
= typ
1057 self
.optional
= optional
1059 def check(self
, schema
):
1061 self
.type = schema
.lookup_type(self
._type
_name
)
1065 class QAPISchemaObjectTypeVariants(object):
1066 def __init__(self
, tag_name
, tag_member
, variants
):
1067 # Flat unions pass tag_name but not tag_member.
1068 # Simple unions and alternates pass tag_member but not tag_name.
1069 # After check(), tag_member is always set, and tag_name remains
1070 # a reliable witness of being used by a flat union.
1071 assert bool(tag_member
) != bool(tag_name
)
1072 assert (isinstance(tag_name
, str) or
1073 isinstance(tag_member
, QAPISchemaObjectTypeMember
))
1074 assert len(variants
) > 0
1076 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1077 self
.tag_name
= tag_name
1078 self
.tag_member
= tag_member
1079 self
.variants
= variants
1081 def set_owner(self
, name
):
1082 for v
in self
.variants
:
1085 def check(self
, schema
, seen
):
1086 if not self
.tag_member
: # flat union
1087 self
.tag_member
= seen
[c_name(self
.tag_name
)]
1088 assert self
.tag_name
== self
.tag_member
.name
1089 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1090 for v
in self
.variants
:
1092 # Union names must match enum values; alternate names are
1093 # checked separately. Use 'seen' to tell the two apart.
1095 assert v
.name
in self
.tag_member
.type.member_names()
1096 assert isinstance(v
.type, QAPISchemaObjectType
)
1097 v
.type.check(schema
)
1099 def check_clash(self
, schema
, info
, seen
):
1100 for v
in self
.variants
:
1101 # Reset seen map for each variant, since qapi names from one
1102 # branch do not affect another branch
1103 assert isinstance(v
.type, QAPISchemaObjectType
)
1104 v
.type.check_clash(schema
, info
, dict(seen
))
1107 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1110 def __init__(self
, name
, typ
):
1111 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1113 # This function exists to support ugly simple union special cases
1114 # TODO get rid of them, and drop the function
1115 def simple_union_type(self
):
1116 if (self
.type.is_implicit() and
1117 isinstance(self
.type, QAPISchemaObjectType
)):
1118 assert len(self
.type.members
) == 1
1119 assert not self
.type.variants
1120 return self
.type.members
[0].type
1124 class QAPISchemaAlternateType(QAPISchemaType
):
1125 def __init__(self
, name
, info
, variants
):
1126 QAPISchemaType
.__init
__(self
, name
, info
)
1127 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1128 assert not variants
.tag_name
1129 variants
.set_owner(name
)
1130 variants
.tag_member
.set_owner(self
.name
)
1131 self
.variants
= variants
1133 def check(self
, schema
):
1134 self
.variants
.tag_member
.check(schema
)
1135 # Not calling self.variants.check_clash(), because there's nothing
1137 self
.variants
.check(schema
, {})
1138 # Alternate branch names have no relation to the tag enum values;
1139 # so we have to check for potential name collisions ourselves.
1141 for v
in self
.variants
.variants
:
1142 v
.check_clash(self
.info
, seen
)
1144 def json_type(self
):
1147 def visit(self
, visitor
):
1148 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1151 class QAPISchemaCommand(QAPISchemaEntity
):
1152 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1153 QAPISchemaEntity
.__init
__(self
, name
, info
)
1154 assert not arg_type
or isinstance(arg_type
, str)
1155 assert not ret_type
or isinstance(ret_type
, str)
1156 self
._arg
_type
_name
= arg_type
1157 self
.arg_type
= None
1158 self
._ret
_type
_name
= ret_type
1159 self
.ret_type
= None
1161 self
.success_response
= success_response
1163 def check(self
, schema
):
1164 if self
._arg
_type
_name
:
1165 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1166 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1167 assert not self
.arg_type
.variants
# not implemented
1168 if self
._ret
_type
_name
:
1169 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1170 assert isinstance(self
.ret_type
, QAPISchemaType
)
1172 def visit(self
, visitor
):
1173 visitor
.visit_command(self
.name
, self
.info
,
1174 self
.arg_type
, self
.ret_type
,
1175 self
.gen
, self
.success_response
)
1178 class QAPISchemaEvent(QAPISchemaEntity
):
1179 def __init__(self
, name
, info
, arg_type
):
1180 QAPISchemaEntity
.__init
__(self
, name
, info
)
1181 assert not arg_type
or isinstance(arg_type
, str)
1182 self
._arg
_type
_name
= arg_type
1183 self
.arg_type
= None
1185 def check(self
, schema
):
1186 if self
._arg
_type
_name
:
1187 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1188 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1189 assert not self
.arg_type
.variants
# not implemented
1191 def visit(self
, visitor
):
1192 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1195 class QAPISchema(object):
1196 def __init__(self
, fname
):
1198 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1199 self
._entity
_dict
= {}
1200 self
._predefining
= True
1201 self
._def
_predefineds
()
1202 self
._predefining
= False
1205 except (QAPISchemaError
, QAPIExprError
) as err
:
1206 print >>sys
.stderr
, err
1209 def _def_entity(self
, ent
):
1210 # Only the predefined types are allowed to not have info
1211 assert ent
.info
or self
._predefining
1212 assert ent
.name
not in self
._entity
_dict
1213 self
._entity
_dict
[ent
.name
] = ent
1215 def lookup_entity(self
, name
, typ
=None):
1216 ent
= self
._entity
_dict
.get(name
)
1217 if typ
and not isinstance(ent
, typ
):
1221 def lookup_type(self
, name
):
1222 return self
.lookup_entity(name
, QAPISchemaType
)
1224 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1225 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
1227 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1228 # qapi-types.h from a single .c, all arrays of builtins must be
1229 # declared in the first file whether or not they are used. Nicer
1230 # would be to use lazy instantiation, while figuring out how to
1231 # avoid compilation issues with multiple qapi-types.h.
1232 self
._make
_array
_type
(name
, None)
1234 def _def_predefineds(self
):
1235 for t
in [('str', 'string', 'char' + pointer_suffix
, 'NULL'),
1236 ('number', 'number', 'double', '0'),
1237 ('int', 'int', 'int64_t', '0'),
1238 ('int8', 'int', 'int8_t', '0'),
1239 ('int16', 'int', 'int16_t', '0'),
1240 ('int32', 'int', 'int32_t', '0'),
1241 ('int64', 'int', 'int64_t', '0'),
1242 ('uint8', 'int', 'uint8_t', '0'),
1243 ('uint16', 'int', 'uint16_t', '0'),
1244 ('uint32', 'int', 'uint32_t', '0'),
1245 ('uint64', 'int', 'uint64_t', '0'),
1246 ('size', 'int', 'uint64_t', '0'),
1247 ('bool', 'boolean', 'bool', 'false'),
1248 ('any', 'value', 'QObject' + pointer_suffix
, 'NULL')]:
1249 self
._def
_builtin
_type
(*t
)
1250 self
.the_empty_object_type
= QAPISchemaObjectType(':empty', None, None,
1252 self
._def
_entity
(self
.the_empty_object_type
)
1253 qtype_values
= self
._make
_enum
_members
(['none', 'qnull', 'qint',
1254 'qstring', 'qdict', 'qlist',
1256 self
._def
_entity
(QAPISchemaEnumType('QType', None, qtype_values
,
1259 def _make_enum_members(self
, values
):
1260 return [QAPISchemaMember(v
) for v
in values
]
1262 def _make_implicit_enum_type(self
, name
, info
, values
):
1263 # See also QAPISchemaObjectTypeMember._pretty_owner()
1264 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1265 self
._def
_entity
(QAPISchemaEnumType(
1266 name
, info
, self
._make
_enum
_members
(values
), None))
1269 def _make_array_type(self
, element_type
, info
):
1270 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1271 if not self
.lookup_type(name
):
1272 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1275 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1278 # See also QAPISchemaObjectTypeMember._pretty_owner()
1279 name
= ':obj-%s-%s' % (name
, role
)
1280 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1281 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1285 def _def_enum_type(self
, expr
, info
):
1288 prefix
= expr
.get('prefix')
1289 self
._def
_entity
(QAPISchemaEnumType(
1290 name
, info
, self
._make
_enum
_members
(data
), prefix
))
1292 def _make_member(self
, name
, typ
, info
):
1294 if name
.startswith('*'):
1297 if isinstance(typ
, list):
1298 assert len(typ
) == 1
1299 typ
= self
._make
_array
_type
(typ
[0], info
)
1300 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1302 def _make_members(self
, data
, info
):
1303 return [self
._make
_member
(key
, value
, info
)
1304 for (key
, value
) in data
.iteritems()]
1306 def _def_struct_type(self
, expr
, info
):
1307 name
= expr
['struct']
1308 base
= expr
.get('base')
1310 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1311 self
._make
_members
(data
, info
),
1314 def _make_variant(self
, case
, typ
):
1315 return QAPISchemaObjectTypeVariant(case
, typ
)
1317 def _make_simple_variant(self
, case
, typ
, info
):
1318 if isinstance(typ
, list):
1319 assert len(typ
) == 1
1320 typ
= self
._make
_array
_type
(typ
[0], info
)
1321 typ
= self
._make
_implicit
_object
_type
(
1322 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1323 return QAPISchemaObjectTypeVariant(case
, typ
)
1325 def _def_union_type(self
, expr
, info
):
1326 name
= expr
['union']
1328 base
= expr
.get('base')
1329 tag_name
= expr
.get('discriminator')
1332 variants
= [self
._make
_variant
(key
, value
)
1333 for (key
, value
) in data
.iteritems()]
1336 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1337 for (key
, value
) in data
.iteritems()]
1338 typ
= self
._make
_implicit
_enum
_type
(name
, info
,
1339 [v
.name
for v
in variants
])
1340 tag_member
= QAPISchemaObjectTypeMember('type', typ
, False)
1341 members
= [tag_member
]
1343 QAPISchemaObjectType(name
, info
, base
, members
,
1344 QAPISchemaObjectTypeVariants(tag_name
,
1348 def _def_alternate_type(self
, expr
, info
):
1349 name
= expr
['alternate']
1351 variants
= [self
._make
_variant
(key
, value
)
1352 for (key
, value
) in data
.iteritems()]
1353 tag_member
= QAPISchemaObjectTypeMember('type', 'QType', False)
1355 QAPISchemaAlternateType(name
, info
,
1356 QAPISchemaObjectTypeVariants(None,
1360 def _def_command(self
, expr
, info
):
1361 name
= expr
['command']
1362 data
= expr
.get('data')
1363 rets
= expr
.get('returns')
1364 gen
= expr
.get('gen', True)
1365 success_response
= expr
.get('success-response', True)
1366 if isinstance(data
, OrderedDict
):
1367 data
= self
._make
_implicit
_object
_type
(
1368 name
, info
, 'arg', self
._make
_members
(data
, info
))
1369 if isinstance(rets
, list):
1370 assert len(rets
) == 1
1371 rets
= self
._make
_array
_type
(rets
[0], info
)
1372 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1375 def _def_event(self
, expr
, info
):
1376 name
= expr
['event']
1377 data
= expr
.get('data')
1378 if isinstance(data
, OrderedDict
):
1379 data
= self
._make
_implicit
_object
_type
(
1380 name
, info
, 'arg', self
._make
_members
(data
, info
))
1381 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1383 def _def_exprs(self
):
1384 for expr_elem
in self
.exprs
:
1385 expr
= expr_elem
['expr']
1386 info
= expr_elem
['info']
1388 self
._def
_enum
_type
(expr
, info
)
1389 elif 'struct' in expr
:
1390 self
._def
_struct
_type
(expr
, info
)
1391 elif 'union' in expr
:
1392 self
._def
_union
_type
(expr
, info
)
1393 elif 'alternate' in expr
:
1394 self
._def
_alternate
_type
(expr
, info
)
1395 elif 'command' in expr
:
1396 self
._def
_command
(expr
, info
)
1397 elif 'event' in expr
:
1398 self
._def
_event
(expr
, info
)
1403 for ent
in self
._entity
_dict
.values():
1406 def visit(self
, visitor
):
1407 visitor
.visit_begin(self
)
1408 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1409 if visitor
.visit_needed(entity
):
1410 entity
.visit(visitor
)
1415 # Code generation helpers
1418 def camel_case(name
):
1422 if ch
in ['_', '-']:
1425 new_name
+= ch
.upper()
1428 new_name
+= ch
.lower()
1432 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1433 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1434 # ENUM24_Name -> ENUM24_NAME
1435 def camel_to_upper(value
):
1436 c_fun_str
= c_name(value
, False)
1444 # When c is upper and no "_" appears before, do more checks
1445 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1446 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1448 elif c_fun_str
[i
- 1].isdigit():
1451 return new_name
.lstrip('_').upper()
1454 def c_enum_const(type_name
, const_name
, prefix
=None):
1455 if prefix
is not None:
1457 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1459 c_name_trans
= string
.maketrans('.-', '__')
1462 # Map @name to a valid C identifier.
1463 # If @protect, avoid returning certain ticklish identifiers (like
1464 # C keywords) by prepending "q_".
1466 # Used for converting 'name' from a 'name':'type' qapi definition
1467 # into a generated struct member, as well as converting type names
1468 # into substrings of a generated C function name.
1469 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1470 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1471 def c_name(name
, protect
=True):
1472 # ANSI X3J11/88-090, 3.1.1
1473 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1474 'default', 'do', 'double', 'else', 'enum', 'extern',
1475 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1476 'return', 'short', 'signed', 'sizeof', 'static',
1477 'struct', 'switch', 'typedef', 'union', 'unsigned',
1478 'void', 'volatile', 'while'])
1479 # ISO/IEC 9899:1999, 6.4.1
1480 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1481 # ISO/IEC 9899:2011, 6.4.1
1482 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1483 '_Noreturn', '_Static_assert', '_Thread_local'])
1484 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1486 gcc_words
= set(['asm', 'typeof'])
1487 # C++ ISO/IEC 14882:2003 2.11
1488 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1489 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1490 'namespace', 'new', 'operator', 'private', 'protected',
1491 'public', 'reinterpret_cast', 'static_cast', 'template',
1492 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1493 'using', 'virtual', 'wchar_t',
1494 # alternative representations
1495 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1496 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1497 # namespace pollution:
1498 polluted_words
= set(['unix', 'errno', 'mips', 'sparc'])
1499 name
= name
.translate(c_name_trans
)
1500 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1501 | cpp_words | polluted_words
):
1505 eatspace
= '\033EATSPACE.'
1506 pointer_suffix
= ' *' + eatspace
1509 def genindent(count
):
1511 for _
in range(count
):
1518 def push_indent(indent_amount
=4):
1520 indent_level
+= indent_amount
1523 def pop_indent(indent_amount
=4):
1525 indent_level
-= indent_amount
1528 # Generate @code with @kwds interpolated.
1529 # Obey indent_level, and strip eatspace.
1530 def cgen(code
, **kwds
):
1533 indent
= genindent(indent_level
)
1534 # re.subn() lacks flags support before Python 2.7, use re.compile()
1535 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1536 indent
+ r
'\g<0>', raw
)
1538 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1541 def mcgen(code
, **kwds
):
1544 return cgen(code
, **kwds
)
1547 def guardname(filename
):
1548 return c_name(filename
, protect
=False).upper()
1551 def guardstart(name
):
1558 name
=guardname(name
))
1564 #endif /* %(name)s */
1567 name
=guardname(name
))
1570 def gen_enum_lookup(name
, values
, prefix
=None):
1573 const char *const %(c_name)s_lookup[] = {
1575 c_name
=c_name(name
))
1576 for value
in values
:
1577 index
= c_enum_const(name
, value
, prefix
)
1579 [%(index)s] = "%(value)s",
1581 index
=index
, value
=value
)
1583 max_index
= c_enum_const(name
, '_MAX', prefix
)
1585 [%(max_index)s] = NULL,
1588 max_index
=max_index
)
1592 def gen_enum(name
, values
, prefix
=None):
1593 # append automatically generated _MAX value
1594 enum_values
= values
+ ['_MAX']
1598 typedef enum %(c_name)s {
1600 c_name
=c_name(name
))
1603 for value
in enum_values
:
1607 c_enum
=c_enum_const(name
, value
, prefix
),
1614 c_name
=c_name(name
))
1618 extern const char *const %(c_name)s_lookup[];
1620 c_name
=c_name(name
))
1624 def gen_params(arg_type
, extra
):
1627 assert not arg_type
.variants
1630 for memb
in arg_type
.members
:
1634 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1635 ret
+= '%s %s' % (memb
.type.c_type(is_param
=True), c_name(memb
.name
))
1641 def gen_err_check(label
='out', skiperr
=False):
1652 def gen_visit_fields(members
, prefix
='', need_cast
=False, skiperr
=False,
1660 for memb
in members
:
1663 if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
1665 prefix
=prefix
, c_name
=c_name(memb
.name
),
1669 # Ugly: sometimes we need to cast away const
1670 if need_cast
and memb
.type.name
== 'str':
1676 visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
1678 c_type
=memb
.type.c_name(), prefix
=prefix
, cast
=cast
,
1679 c_name
=c_name(memb
.name
), name
=memb
.name
,
1681 ret
+= gen_err_check(skiperr
=skiperr
, label
=label
)
1692 # Common command line parsing
1696 def parse_command_line(extra_options
="", extra_long_options
=[]):
1699 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1700 "chp:o:" + extra_options
,
1701 ["source", "header", "prefix=",
1702 "output-dir="] + extra_long_options
)
1703 except getopt
.GetoptError
as err
:
1704 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1715 if o
in ("-p", "--prefix"):
1716 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1717 if match
.end() != len(a
):
1718 print >>sys
.stderr
, \
1719 "%s: 'funny character '%s' in argument of --prefix" \
1720 % (sys
.argv
[0], a
[match
.end()])
1723 elif o
in ("-o", "--output-dir"):
1724 output_dir
= a
+ "/"
1725 elif o
in ("-c", "--source"):
1727 elif o
in ("-h", "--header"):
1730 extra_opts
.append(oa
)
1732 if not do_c
and not do_h
:
1737 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1741 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1744 # Generate output files with boilerplate
1748 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1749 c_comment
, h_comment
):
1750 guard
= guardname(prefix
+ h_file
)
1751 c_file
= output_dir
+ prefix
+ c_file
1752 h_file
= output_dir
+ prefix
+ h_file
1756 os
.makedirs(output_dir
)
1757 except os
.error
as e
:
1758 if e
.errno
!= errno
.EEXIST
:
1761 def maybe_open(really
, name
, opt
):
1763 return open(name
, opt
)
1766 return StringIO
.StringIO()
1768 fdef
= maybe_open(do_c
, c_file
, 'w')
1769 fdecl
= maybe_open(do_h
, h_file
, 'w')
1771 fdef
.write(mcgen('''
1772 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1777 fdecl
.write(mcgen('''
1778 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1784 comment
=h_comment
, guard
=guard
))
1786 return (fdef
, fdecl
)
1789 def close_output(fdef
, fdecl
):