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 'QapiErrorClass', # all members, visible through errors
71 'UuidInfo', # UUID, visible through query-uuid
72 'X86CPURegister32', # all members, visible indirectly through qom-get
82 # Parsing the schema into expressions
86 def error_path(parent
):
89 res
= ("In file included from %s:%d:\n" % (parent
['file'],
90 parent
['line'])) + res
91 parent
= parent
['parent']
95 class QAPISchemaError(Exception):
96 def __init__(self
, schema
, msg
):
97 Exception.__init
__(self
)
98 self
.fname
= schema
.fname
101 self
.line
= schema
.line
102 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
104 self
.col
= (self
.col
+ 7) % 8 + 1
107 self
.info
= schema
.incl_info
110 return error_path(self
.info
) + \
111 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
114 class QAPIExprError(Exception):
115 def __init__(self
, expr_info
, msg
):
116 Exception.__init
__(self
)
118 self
.info
= expr_info
122 return error_path(self
.info
['parent']) + \
123 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
126 class QAPISchemaParser(object):
128 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
129 abs_fname
= os
.path
.abspath(fp
.name
)
132 previously_included
.append(abs_fname
)
133 self
.incl_info
= incl_info
135 if self
.src
== '' or self
.src
[-1] != '\n':
143 while self
.tok
is not None:
144 expr_info
= {'file': fname
, 'line': self
.line
,
145 'parent': self
.incl_info
}
146 expr
= self
.get_expr(False)
147 if isinstance(expr
, dict) and "include" in expr
:
149 raise QAPIExprError(expr_info
,
150 "Invalid 'include' directive")
151 include
= expr
["include"]
152 if not isinstance(include
, str):
153 raise QAPIExprError(expr_info
,
154 "Value of 'include' must be a string")
155 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
157 # catch inclusion cycle
160 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
161 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
164 # skip multiple include of the same file
165 if incl_abs_fname
in previously_included
:
168 fobj
= open(incl_abs_fname
, 'r')
170 raise QAPIExprError(expr_info
,
171 '%s: %s' % (e
.strerror
, include
))
172 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
174 self
.exprs
.extend(exprs_include
.exprs
)
176 expr_elem
= {'expr': expr
,
178 self
.exprs
.append(expr_elem
)
182 self
.tok
= self
.src
[self
.cursor
]
183 self
.pos
= self
.cursor
188 self
.cursor
= self
.src
.find('\n', self
.cursor
)
189 elif self
.tok
in "{}:,[]":
191 elif self
.tok
== "'":
195 ch
= self
.src
[self
.cursor
]
198 raise QAPISchemaError(self
,
199 'Missing terminating "\'"')
213 for _
in range(0, 4):
214 ch
= self
.src
[self
.cursor
]
216 if ch
not in "0123456789abcdefABCDEF":
217 raise QAPISchemaError(self
,
218 '\\u escape needs 4 '
220 value
= (value
<< 4) + int(ch
, 16)
221 # If Python 2 and 3 didn't disagree so much on
222 # how to handle Unicode, then we could allow
223 # Unicode string defaults. But most of QAPI is
224 # ASCII-only, so we aren't losing much for now.
225 if not value
or value
> 0x7f:
226 raise QAPISchemaError(self
,
227 'For now, \\u escape '
228 'only supports non-zero '
229 'values up to \\u007f')
234 raise QAPISchemaError(self
,
235 "Unknown escape \\%s" % ch
)
244 elif self
.src
.startswith("true", self
.pos
):
248 elif self
.src
.startswith("false", self
.pos
):
252 elif self
.src
.startswith("null", self
.pos
):
256 elif self
.tok
== '\n':
257 if self
.cursor
== len(self
.src
):
261 self
.line_pos
= self
.cursor
262 elif not self
.tok
.isspace():
263 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
265 def get_members(self
):
271 raise QAPISchemaError(self
, 'Expected string or "}"')
276 raise QAPISchemaError(self
, 'Expected ":"')
279 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
280 expr
[key
] = self
.get_expr(True)
285 raise QAPISchemaError(self
, 'Expected "," or "}"')
288 raise QAPISchemaError(self
, 'Expected string')
290 def get_values(self
):
295 if self
.tok
not in "{['tfn":
296 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
299 expr
.append(self
.get_expr(True))
304 raise QAPISchemaError(self
, 'Expected "," or "]"')
307 def get_expr(self
, nested
):
308 if self
.tok
!= '{' and not nested
:
309 raise QAPISchemaError(self
, 'Expected "{"')
312 expr
= self
.get_members()
313 elif self
.tok
== '[':
315 expr
= self
.get_values()
316 elif self
.tok
in "'tfn":
320 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
324 # Semantic analysis of schema expressions
325 # TODO fold into QAPISchema
326 # TODO catching name collisions in generated code would be nice
330 def find_base_fields(base
):
331 base_struct_define
= find_struct(base
)
332 if not base_struct_define
:
334 return base_struct_define
['data']
337 # Return the qtype of an alternate branch, or None on error.
338 def find_alternate_member_qtype(qapi_type
):
339 if qapi_type
in builtin_types
:
340 return builtin_types
[qapi_type
]
341 elif find_struct(qapi_type
):
343 elif find_enum(qapi_type
):
344 return "QTYPE_QSTRING"
345 elif find_union(qapi_type
):
350 # Return the discriminator enum define if discriminator is specified as an
351 # enum type, otherwise return None.
352 def discriminator_find_enum_define(expr
):
353 base
= expr
.get('base')
354 discriminator
= expr
.get('discriminator')
356 if not (discriminator
and base
):
359 base_fields
= find_base_fields(base
)
363 discriminator_type
= base_fields
.get(discriminator
)
364 if not discriminator_type
:
367 return find_enum(discriminator_type
)
370 # Names must be letters, numbers, -, and _. They must start with letter,
371 # except for downstream extensions which must start with __RFQDN_.
372 # Dots are only valid in the downstream extension prefix.
373 valid_name
= re
.compile('^(__[a-zA-Z0-9.-]+_)?'
374 '[a-zA-Z][a-zA-Z0-9_-]*$')
377 def check_name(expr_info
, source
, name
, allow_optional
=False,
382 if not isinstance(name
, str):
383 raise QAPIExprError(expr_info
,
384 "%s requires a string name" % source
)
385 if name
.startswith('*'):
386 membername
= name
[1:]
387 if not allow_optional
:
388 raise QAPIExprError(expr_info
,
389 "%s does not allow optional name '%s'"
391 # Enum members can start with a digit, because the generated C
392 # code always prefixes it with the enum name
393 if enum_member
and membername
[0].isdigit():
394 membername
= 'D' + membername
395 # Reserve the entire 'q_' namespace for c_name()
396 if not valid_name
.match(membername
) or \
397 c_name(membername
, False).startswith('q_'):
398 raise QAPIExprError(expr_info
,
399 "%s uses invalid name '%s'" % (source
, name
))
402 def add_name(name
, info
, meta
, implicit
=False):
404 check_name(info
, "'%s'" % meta
, name
)
405 # FIXME should reject names that differ only in '_' vs. '.'
406 # vs. '-', because they're liable to clash in generated C.
407 if name
in all_names
:
408 raise QAPIExprError(info
,
409 "%s '%s' is already defined"
410 % (all_names
[name
], name
))
411 if not implicit
and (name
.endswith('Kind') or name
.endswith('List')):
412 raise QAPIExprError(info
,
413 "%s '%s' should not end in '%s'"
414 % (meta
, name
, name
[-4:]))
415 all_names
[name
] = meta
418 def add_struct(definition
, info
):
420 name
= definition
['struct']
421 add_name(name
, info
, 'struct')
422 struct_types
.append(definition
)
425 def find_struct(name
):
427 for struct
in struct_types
:
428 if struct
['struct'] == name
:
433 def add_union(definition
, info
):
435 name
= definition
['union']
436 add_name(name
, info
, 'union')
437 union_types
.append(definition
)
440 def find_union(name
):
442 for union
in union_types
:
443 if union
['union'] == name
:
448 def add_enum(name
, info
, enum_values
=None, implicit
=False):
450 add_name(name
, info
, 'enum', implicit
)
451 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
456 for enum
in enum_types
:
457 if enum
['enum_name'] == name
:
463 return find_enum(name
) is not None
466 def check_type(expr_info
, source
, value
, allow_array
=False,
467 allow_dict
=False, allow_optional
=False,
474 # Check if array type for value is okay
475 if isinstance(value
, list):
477 raise QAPIExprError(expr_info
,
478 "%s cannot be an array" % source
)
479 if len(value
) != 1 or not isinstance(value
[0], str):
480 raise QAPIExprError(expr_info
,
481 "%s: array type must contain single type name"
485 # Check if type name for value is okay
486 if isinstance(value
, str):
487 if value
not in all_names
:
488 raise QAPIExprError(expr_info
,
489 "%s uses unknown type '%s'"
491 if not all_names
[value
] in allow_metas
:
492 raise QAPIExprError(expr_info
,
493 "%s cannot use %s type '%s'"
494 % (source
, all_names
[value
], value
))
498 raise QAPIExprError(expr_info
,
499 "%s should be a type name" % source
)
501 if not isinstance(value
, OrderedDict
):
502 raise QAPIExprError(expr_info
,
503 "%s should be a dictionary or type name" % source
)
505 # value is a dictionary, check that each member is okay
506 for (key
, arg
) in value
.items():
507 check_name(expr_info
, "Member of %s" % source
, key
,
508 allow_optional
=allow_optional
)
509 if c_name(key
, False) == 'u' or c_name(key
, False).startswith('has_'):
510 raise QAPIExprError(expr_info
,
511 "Member of %s uses reserved name '%s'"
513 # Todo: allow dictionaries to represent default values of
514 # an optional argument.
515 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
517 allow_metas
=['built-in', 'union', 'alternate', 'struct',
521 def check_command(expr
, expr_info
):
522 name
= expr
['command']
524 check_type(expr_info
, "'data' for command '%s'" % name
,
525 expr
.get('data'), allow_dict
=True, allow_optional
=True,
526 allow_metas
=['struct'])
527 returns_meta
= ['union', 'struct']
528 if name
in returns_whitelist
:
529 returns_meta
+= ['built-in', 'alternate', 'enum']
530 check_type(expr_info
, "'returns' for command '%s'" % name
,
531 expr
.get('returns'), allow_array
=True,
532 allow_optional
=True, allow_metas
=returns_meta
)
535 def check_event(expr
, expr_info
):
540 check_type(expr_info
, "'data' for event '%s'" % name
,
541 expr
.get('data'), allow_dict
=True, allow_optional
=True,
542 allow_metas
=['struct'])
545 def check_union(expr
, expr_info
):
547 base
= expr
.get('base')
548 discriminator
= expr
.get('discriminator')
549 members
= expr
['data']
551 # Two types of unions, determined by discriminator.
553 # With no discriminator it is a simple union.
554 if discriminator
is None:
556 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
558 raise QAPIExprError(expr_info
,
559 "Simple union '%s' must not have a base"
562 # Else, it's a flat union.
564 # The object must have a string member 'base'.
565 check_type(expr_info
, "'base' for union '%s'" % name
,
566 base
, allow_metas
=['struct'])
568 raise QAPIExprError(expr_info
,
569 "Flat union '%s' must have a base"
571 base_fields
= find_base_fields(base
)
574 # The value of member 'discriminator' must name a non-optional
575 # member of the base struct.
576 check_name(expr_info
, "Discriminator of flat union '%s'" % name
,
578 discriminator_type
= base_fields
.get(discriminator
)
579 if not discriminator_type
:
580 raise QAPIExprError(expr_info
,
581 "Discriminator '%s' is not a member of base "
583 % (discriminator
, base
))
584 enum_define
= find_enum(discriminator_type
)
585 allow_metas
= ['struct']
586 # Do not allow string discriminator
588 raise QAPIExprError(expr_info
,
589 "Discriminator '%s' must be of enumeration "
590 "type" % discriminator
)
592 # Check every branch; don't allow an empty union
593 if len(members
) == 0:
594 raise QAPIExprError(expr_info
,
595 "Union '%s' cannot have empty 'data'" % name
)
596 for (key
, value
) in members
.items():
597 check_name(expr_info
, "Member of union '%s'" % name
, key
)
599 # Each value must name a known type
600 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
601 value
, allow_array
=not base
, allow_metas
=allow_metas
)
603 # If the discriminator names an enum type, then all members
604 # of 'data' must also be members of the enum type.
606 if key
not in enum_define
['enum_values']:
607 raise QAPIExprError(expr_info
,
608 "Discriminator value '%s' is not found in "
610 (key
, enum_define
["enum_name"]))
613 def check_alternate(expr
, expr_info
):
614 name
= expr
['alternate']
615 members
= expr
['data']
618 # Check every branch; require at least two branches
620 raise QAPIExprError(expr_info
,
621 "Alternate '%s' should have at least two branches "
623 for (key
, value
) in members
.items():
624 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
626 # Ensure alternates have no type conflicts.
627 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
629 allow_metas
=['built-in', 'union', 'struct', 'enum'])
630 qtype
= find_alternate_member_qtype(value
)
632 raise QAPIExprError(expr_info
,
633 "Alternate '%s' member '%s' cannot use "
634 "type '%s'" % (name
, key
, value
))
635 if qtype
in types_seen
:
636 raise QAPIExprError(expr_info
,
637 "Alternate '%s' member '%s' can't "
638 "be distinguished from member '%s'"
639 % (name
, key
, types_seen
[qtype
]))
640 types_seen
[qtype
] = key
643 def check_enum(expr
, expr_info
):
645 members
= expr
.get('data')
646 prefix
= expr
.get('prefix')
648 if not isinstance(members
, list):
649 raise QAPIExprError(expr_info
,
650 "Enum '%s' requires an array for 'data'" % name
)
651 if prefix
is not None and not isinstance(prefix
, str):
652 raise QAPIExprError(expr_info
,
653 "Enum '%s' requires a string for 'prefix'" % name
)
654 for member
in members
:
655 check_name(expr_info
, "Member of enum '%s'" % name
, member
,
659 def check_struct(expr
, expr_info
):
660 name
= expr
['struct']
661 members
= expr
['data']
663 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
664 allow_dict
=True, allow_optional
=True)
665 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
666 allow_metas
=['struct'])
669 def check_keys(expr_elem
, meta
, required
, optional
=[]):
670 expr
= expr_elem
['expr']
671 info
= expr_elem
['info']
673 if not isinstance(name
, str):
674 raise QAPIExprError(info
,
675 "'%s' key must have a string value" % meta
)
676 required
= required
+ [meta
]
677 for (key
, value
) in expr
.items():
678 if key
not in required
and key
not in optional
:
679 raise QAPIExprError(info
,
680 "Unknown key '%s' in %s '%s'"
682 if (key
== 'gen' or key
== 'success-response') and value
is not False:
683 raise QAPIExprError(info
,
684 "'%s' of %s '%s' should only use false value"
688 raise QAPIExprError(info
,
689 "Key '%s' is missing from %s '%s'"
693 def check_exprs(exprs
):
696 # Learn the types and check for valid expression keys
697 for builtin
in builtin_types
.keys():
698 all_names
[builtin
] = 'built-in'
699 for expr_elem
in exprs
:
700 expr
= expr_elem
['expr']
701 info
= expr_elem
['info']
703 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
704 add_enum(expr
['enum'], info
, expr
['data'])
705 elif 'union' in expr
:
706 check_keys(expr_elem
, 'union', ['data'],
707 ['base', 'discriminator'])
708 add_union(expr
, info
)
709 elif 'alternate' in expr
:
710 check_keys(expr_elem
, 'alternate', ['data'])
711 add_name(expr
['alternate'], info
, 'alternate')
712 elif 'struct' in expr
:
713 check_keys(expr_elem
, 'struct', ['data'], ['base'])
714 add_struct(expr
, info
)
715 elif 'command' in expr
:
716 check_keys(expr_elem
, 'command', [],
717 ['data', 'returns', 'gen', 'success-response'])
718 add_name(expr
['command'], info
, 'command')
719 elif 'event' in expr
:
720 check_keys(expr_elem
, 'event', [], ['data'])
721 add_name(expr
['event'], info
, 'event')
723 raise QAPIExprError(expr_elem
['info'],
724 "Expression is missing metatype")
726 # Try again for hidden UnionKind enum
727 for expr_elem
in exprs
:
728 expr
= expr_elem
['expr']
730 if not discriminator_find_enum_define(expr
):
731 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
733 elif 'alternate' in expr
:
734 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
737 # Validate that exprs make sense
738 for expr_elem
in exprs
:
739 expr
= expr_elem
['expr']
740 info
= expr_elem
['info']
743 check_enum(expr
, info
)
744 elif 'union' in expr
:
745 check_union(expr
, info
)
746 elif 'alternate' in expr
:
747 check_alternate(expr
, info
)
748 elif 'struct' in expr
:
749 check_struct(expr
, info
)
750 elif 'command' in expr
:
751 check_command(expr
, info
)
752 elif 'event' in expr
:
753 check_event(expr
, info
)
755 assert False, 'unexpected meta type'
761 # Schema compiler frontend
764 class QAPISchemaEntity(object):
765 def __init__(self
, name
, info
):
766 assert isinstance(name
, str)
768 # For explicitly defined entities, info points to the (explicit)
769 # definition. For builtins (and their arrays), info is None.
770 # For implicitly defined entities, info points to a place that
771 # triggered the implicit definition (there may be more than one
776 return c_name(self
.name
)
778 def check(self
, schema
):
781 def is_implicit(self
):
784 def visit(self
, visitor
):
788 class QAPISchemaVisitor(object):
789 def visit_begin(self
, schema
):
795 def visit_needed(self
, entity
):
796 # Default to visiting everything
799 def visit_builtin_type(self
, name
, info
, json_type
):
802 def visit_enum_type(self
, name
, info
, values
, prefix
):
805 def visit_array_type(self
, name
, info
, element_type
):
808 def visit_object_type(self
, name
, info
, base
, members
, variants
):
811 def visit_object_type_flat(self
, name
, info
, members
, variants
):
814 def visit_alternate_type(self
, name
, info
, variants
):
817 def visit_command(self
, name
, info
, arg_type
, ret_type
,
818 gen
, success_response
):
821 def visit_event(self
, name
, info
, arg_type
):
825 class QAPISchemaType(QAPISchemaEntity
):
826 def c_type(self
, is_param
=False, is_unboxed
=False):
827 return c_name(self
.name
) + pointer_suffix
835 def alternate_qtype(self
):
837 'string': 'QTYPE_QSTRING',
838 'number': 'QTYPE_QFLOAT',
840 'boolean': 'QTYPE_QBOOL',
841 'object': 'QTYPE_QDICT'
843 return json2qtype
.get(self
.json_type())
846 class QAPISchemaBuiltinType(QAPISchemaType
):
847 def __init__(self
, name
, json_type
, c_type
, c_null
):
848 QAPISchemaType
.__init
__(self
, name
, None)
849 assert not c_type
or isinstance(c_type
, str)
850 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
852 self
._json
_type
_name
= json_type
853 self
._c
_type
_name
= c_type
854 self
._c
_null
_val
= c_null
859 def c_type(self
, is_param
=False, is_unboxed
=False):
860 if is_param
and self
.name
== 'str':
861 return 'const ' + self
._c
_type
_name
862 return self
._c
_type
_name
865 return self
._c
_null
_val
868 return self
._json
_type
_name
870 def visit(self
, visitor
):
871 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
874 class QAPISchemaEnumType(QAPISchemaType
):
875 def __init__(self
, name
, info
, values
, prefix
):
876 QAPISchemaType
.__init
__(self
, name
, info
)
878 assert isinstance(v
, QAPISchemaMember
)
880 assert prefix
is None or isinstance(prefix
, str)
884 def check(self
, schema
):
886 for v
in self
.values
:
887 v
.check_clash(self
.info
, seen
)
889 def is_implicit(self
):
890 # See QAPISchema._make_implicit_enum_type()
891 return self
.name
.endswith('Kind')
893 def c_type(self
, is_param
=False, is_unboxed
=False):
894 return c_name(self
.name
)
896 def member_names(self
):
897 return [v
.name
for v
in self
.values
]
900 return c_enum_const(self
.name
, (self
.member_names() + ['_MAX'])[0],
906 def visit(self
, visitor
):
907 visitor
.visit_enum_type(self
.name
, self
.info
,
908 self
.member_names(), self
.prefix
)
911 class QAPISchemaArrayType(QAPISchemaType
):
912 def __init__(self
, name
, info
, element_type
):
913 QAPISchemaType
.__init
__(self
, name
, info
)
914 assert isinstance(element_type
, str)
915 self
._element
_type
_name
= element_type
916 self
.element_type
= None
918 def check(self
, schema
):
919 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
920 assert self
.element_type
922 def is_implicit(self
):
928 def visit(self
, visitor
):
929 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
932 class QAPISchemaObjectType(QAPISchemaType
):
933 def __init__(self
, name
, info
, base
, local_members
, variants
):
934 # struct has local_members, optional base, and no variants
935 # flat union has base, variants, and no local_members
936 # simple union has local_members, variants, and no base
937 QAPISchemaType
.__init
__(self
, name
, info
)
938 assert base
is None or isinstance(base
, str)
939 for m
in local_members
:
940 assert isinstance(m
, QAPISchemaObjectTypeMember
)
942 if variants
is not None:
943 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
944 variants
.set_owner(name
)
945 self
._base
_name
= base
947 self
.local_members
= local_members
948 self
.variants
= variants
951 def check(self
, schema
):
952 if self
.members
is False: # check for cycles
953 raise QAPIExprError(self
.info
,
954 "Object %s contains itself" % self
.name
)
957 self
.members
= False # mark as being checked
960 self
.base
= schema
.lookup_type(self
._base
_name
)
961 assert isinstance(self
.base
, QAPISchemaObjectType
)
962 self
.base
.check(schema
)
963 self
.base
.check_clash(schema
, self
.info
, seen
)
964 for m
in self
.local_members
:
966 m
.check_clash(self
.info
, seen
)
967 self
.members
= seen
.values()
969 self
.variants
.check(schema
, seen
)
970 assert self
.variants
.tag_member
in self
.members
971 self
.variants
.check_clash(schema
, self
.info
, seen
)
973 # Check that the members of this type do not cause duplicate JSON fields,
974 # and update seen to track the members seen so far. Report any errors
975 # on behalf of info, which is not necessarily self.info
976 def check_clash(self
, schema
, info
, seen
):
977 assert not self
.variants
# not implemented
978 for m
in self
.members
:
979 m
.check_clash(info
, seen
)
981 def is_implicit(self
):
982 # See QAPISchema._make_implicit_object_type()
983 return self
.name
[0] == ':'
986 assert not self
.is_implicit()
987 return QAPISchemaType
.c_name(self
)
989 def c_type(self
, is_param
=False, is_unboxed
=False):
990 assert not self
.is_implicit()
992 return c_name(self
.name
)
993 return c_name(self
.name
) + pointer_suffix
998 def visit(self
, visitor
):
999 visitor
.visit_object_type(self
.name
, self
.info
,
1000 self
.base
, self
.local_members
, self
.variants
)
1001 visitor
.visit_object_type_flat(self
.name
, self
.info
,
1002 self
.members
, self
.variants
)
1005 class QAPISchemaMember(object):
1008 def __init__(self
, name
):
1009 assert isinstance(name
, str)
1013 def set_owner(self
, name
):
1014 assert not self
.owner
1017 def check_clash(self
, info
, seen
):
1018 cname
= c_name(self
.name
)
1019 if cname
.lower() != cname
and self
.owner
not in case_whitelist
:
1020 raise QAPIExprError(info
,
1021 "%s should not use uppercase" % self
.describe())
1023 raise QAPIExprError(info
,
1024 "%s collides with %s"
1025 % (self
.describe(), seen
[cname
].describe()))
1028 def _pretty_owner(self
):
1030 if owner
.startswith(':obj-'):
1031 # See QAPISchema._make_implicit_object_type() - reverse the
1032 # mapping there to create a nice human-readable description
1034 if owner
.endswith('-arg'):
1035 return '(parameter of %s)' % owner
[:-4]
1037 assert owner
.endswith('-wrapper')
1038 # Unreachable and not implemented
1040 if owner
.endswith('Kind'):
1041 # See QAPISchema._make_implicit_enum_type()
1042 return '(branch of %s)' % owner
[:-4]
1043 return '(%s of %s)' % (self
.role
, owner
)
1046 return "'%s' %s" % (self
.name
, self
._pretty
_owner
())
1049 class QAPISchemaObjectTypeMember(QAPISchemaMember
):
1050 def __init__(self
, name
, typ
, optional
):
1051 QAPISchemaMember
.__init
__(self
, name
)
1052 assert isinstance(typ
, str)
1053 assert isinstance(optional
, bool)
1054 self
._type
_name
= typ
1056 self
.optional
= optional
1058 def check(self
, schema
):
1060 self
.type = schema
.lookup_type(self
._type
_name
)
1064 class QAPISchemaObjectTypeVariants(object):
1065 def __init__(self
, tag_name
, tag_member
, variants
):
1066 # Flat unions pass tag_name but not tag_member.
1067 # Simple unions and alternates pass tag_member but not tag_name.
1068 # After check(), tag_member is always set, and tag_name remains
1069 # a reliable witness of being used by a flat union.
1070 assert bool(tag_member
) != bool(tag_name
)
1071 assert (isinstance(tag_name
, str) or
1072 isinstance(tag_member
, QAPISchemaObjectTypeMember
))
1073 assert len(variants
) > 0
1075 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1076 self
.tag_name
= tag_name
1077 self
.tag_member
= tag_member
1078 self
.variants
= variants
1080 def set_owner(self
, name
):
1081 for v
in self
.variants
:
1084 def check(self
, schema
, seen
):
1085 if not self
.tag_member
: # flat union
1086 self
.tag_member
= seen
[c_name(self
.tag_name
)]
1087 assert self
.tag_name
== self
.tag_member
.name
1088 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1089 for v
in self
.variants
:
1091 # Union names must match enum values; alternate names are
1092 # checked separately. Use 'seen' to tell the two apart.
1094 assert v
.name
in self
.tag_member
.type.member_names()
1095 assert isinstance(v
.type, QAPISchemaObjectType
)
1096 v
.type.check(schema
)
1098 def check_clash(self
, schema
, info
, seen
):
1099 for v
in self
.variants
:
1100 # Reset seen map for each variant, since qapi names from one
1101 # branch do not affect another branch
1102 assert isinstance(v
.type, QAPISchemaObjectType
)
1103 v
.type.check_clash(schema
, info
, dict(seen
))
1106 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1109 def __init__(self
, name
, typ
):
1110 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1112 # This function exists to support ugly simple union special cases
1113 # TODO get rid of them, and drop the function
1114 def simple_union_type(self
):
1115 if (self
.type.is_implicit() and
1116 isinstance(self
.type, QAPISchemaObjectType
)):
1117 assert len(self
.type.members
) == 1
1118 assert not self
.type.variants
1119 return self
.type.members
[0].type
1123 class QAPISchemaAlternateType(QAPISchemaType
):
1124 def __init__(self
, name
, info
, variants
):
1125 QAPISchemaType
.__init
__(self
, name
, info
)
1126 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1127 assert not variants
.tag_name
1128 variants
.set_owner(name
)
1129 variants
.tag_member
.set_owner(self
.name
)
1130 self
.variants
= variants
1132 def check(self
, schema
):
1133 self
.variants
.tag_member
.check(schema
)
1134 # Not calling self.variants.check_clash(), because there's nothing
1136 self
.variants
.check(schema
, {})
1137 # Alternate branch names have no relation to the tag enum values;
1138 # so we have to check for potential name collisions ourselves.
1140 for v
in self
.variants
.variants
:
1141 v
.check_clash(self
.info
, seen
)
1143 def json_type(self
):
1146 def visit(self
, visitor
):
1147 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1150 class QAPISchemaCommand(QAPISchemaEntity
):
1151 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1152 QAPISchemaEntity
.__init
__(self
, name
, info
)
1153 assert not arg_type
or isinstance(arg_type
, str)
1154 assert not ret_type
or isinstance(ret_type
, str)
1155 self
._arg
_type
_name
= arg_type
1156 self
.arg_type
= None
1157 self
._ret
_type
_name
= ret_type
1158 self
.ret_type
= None
1160 self
.success_response
= success_response
1162 def check(self
, schema
):
1163 if self
._arg
_type
_name
:
1164 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1165 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1166 assert not self
.arg_type
.variants
# not implemented
1167 if self
._ret
_type
_name
:
1168 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1169 assert isinstance(self
.ret_type
, QAPISchemaType
)
1171 def visit(self
, visitor
):
1172 visitor
.visit_command(self
.name
, self
.info
,
1173 self
.arg_type
, self
.ret_type
,
1174 self
.gen
, self
.success_response
)
1177 class QAPISchemaEvent(QAPISchemaEntity
):
1178 def __init__(self
, name
, info
, arg_type
):
1179 QAPISchemaEntity
.__init
__(self
, name
, info
)
1180 assert not arg_type
or isinstance(arg_type
, str)
1181 self
._arg
_type
_name
= arg_type
1182 self
.arg_type
= None
1184 def check(self
, schema
):
1185 if self
._arg
_type
_name
:
1186 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1187 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1188 assert not self
.arg_type
.variants
# not implemented
1190 def visit(self
, visitor
):
1191 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1194 class QAPISchema(object):
1195 def __init__(self
, fname
):
1197 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1198 self
._entity
_dict
= {}
1199 self
._predefining
= True
1200 self
._def
_predefineds
()
1201 self
._predefining
= False
1204 except (QAPISchemaError
, QAPIExprError
) as err
:
1205 print >>sys
.stderr
, err
1208 def _def_entity(self
, ent
):
1209 # Only the predefined types are allowed to not have info
1210 assert ent
.info
or self
._predefining
1211 assert ent
.name
not in self
._entity
_dict
1212 self
._entity
_dict
[ent
.name
] = ent
1214 def lookup_entity(self
, name
, typ
=None):
1215 ent
= self
._entity
_dict
.get(name
)
1216 if typ
and not isinstance(ent
, typ
):
1220 def lookup_type(self
, name
):
1221 return self
.lookup_entity(name
, QAPISchemaType
)
1223 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1224 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
1226 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1227 # qapi-types.h from a single .c, all arrays of builtins must be
1228 # declared in the first file whether or not they are used. Nicer
1229 # would be to use lazy instantiation, while figuring out how to
1230 # avoid compilation issues with multiple qapi-types.h.
1231 self
._make
_array
_type
(name
, None)
1233 def _def_predefineds(self
):
1234 for t
in [('str', 'string', 'char' + pointer_suffix
, 'NULL'),
1235 ('number', 'number', 'double', '0'),
1236 ('int', 'int', 'int64_t', '0'),
1237 ('int8', 'int', 'int8_t', '0'),
1238 ('int16', 'int', 'int16_t', '0'),
1239 ('int32', 'int', 'int32_t', '0'),
1240 ('int64', 'int', 'int64_t', '0'),
1241 ('uint8', 'int', 'uint8_t', '0'),
1242 ('uint16', 'int', 'uint16_t', '0'),
1243 ('uint32', 'int', 'uint32_t', '0'),
1244 ('uint64', 'int', 'uint64_t', '0'),
1245 ('size', 'int', 'uint64_t', '0'),
1246 ('bool', 'boolean', 'bool', 'false'),
1247 ('any', 'value', 'QObject' + pointer_suffix
, 'NULL')]:
1248 self
._def
_builtin
_type
(*t
)
1249 self
.the_empty_object_type
= QAPISchemaObjectType(':empty', None, None,
1251 self
._def
_entity
(self
.the_empty_object_type
)
1252 qtype_values
= self
._make
_enum
_members
(['none', 'qnull', 'qint',
1253 'qstring', 'qdict', 'qlist',
1255 self
._def
_entity
(QAPISchemaEnumType('QType', None, qtype_values
,
1258 def _make_enum_members(self
, values
):
1259 return [QAPISchemaMember(v
) for v
in values
]
1261 def _make_implicit_enum_type(self
, name
, info
, values
):
1262 # See also QAPISchemaObjectTypeMember._pretty_owner()
1263 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1264 self
._def
_entity
(QAPISchemaEnumType(
1265 name
, info
, self
._make
_enum
_members
(values
), None))
1268 def _make_array_type(self
, element_type
, info
):
1269 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1270 if not self
.lookup_type(name
):
1271 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1274 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1277 # See also QAPISchemaObjectTypeMember._pretty_owner()
1278 name
= ':obj-%s-%s' % (name
, role
)
1279 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1280 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1284 def _def_enum_type(self
, expr
, info
):
1287 prefix
= expr
.get('prefix')
1288 self
._def
_entity
(QAPISchemaEnumType(
1289 name
, info
, self
._make
_enum
_members
(data
), prefix
))
1291 def _make_member(self
, name
, typ
, info
):
1293 if name
.startswith('*'):
1296 if isinstance(typ
, list):
1297 assert len(typ
) == 1
1298 typ
= self
._make
_array
_type
(typ
[0], info
)
1299 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1301 def _make_members(self
, data
, info
):
1302 return [self
._make
_member
(key
, value
, info
)
1303 for (key
, value
) in data
.iteritems()]
1305 def _def_struct_type(self
, expr
, info
):
1306 name
= expr
['struct']
1307 base
= expr
.get('base')
1309 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1310 self
._make
_members
(data
, info
),
1313 def _make_variant(self
, case
, typ
):
1314 return QAPISchemaObjectTypeVariant(case
, typ
)
1316 def _make_simple_variant(self
, case
, typ
, info
):
1317 if isinstance(typ
, list):
1318 assert len(typ
) == 1
1319 typ
= self
._make
_array
_type
(typ
[0], info
)
1320 typ
= self
._make
_implicit
_object
_type
(
1321 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1322 return QAPISchemaObjectTypeVariant(case
, typ
)
1324 def _def_union_type(self
, expr
, info
):
1325 name
= expr
['union']
1327 base
= expr
.get('base')
1328 tag_name
= expr
.get('discriminator')
1331 variants
= [self
._make
_variant
(key
, value
)
1332 for (key
, value
) in data
.iteritems()]
1335 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1336 for (key
, value
) in data
.iteritems()]
1337 typ
= self
._make
_implicit
_enum
_type
(name
, info
,
1338 [v
.name
for v
in variants
])
1339 tag_member
= QAPISchemaObjectTypeMember('type', typ
, False)
1340 members
= [tag_member
]
1342 QAPISchemaObjectType(name
, info
, base
, members
,
1343 QAPISchemaObjectTypeVariants(tag_name
,
1347 def _def_alternate_type(self
, expr
, info
):
1348 name
= expr
['alternate']
1350 variants
= [self
._make
_variant
(key
, value
)
1351 for (key
, value
) in data
.iteritems()]
1352 tag_member
= QAPISchemaObjectTypeMember('type', 'QType', False)
1354 QAPISchemaAlternateType(name
, info
,
1355 QAPISchemaObjectTypeVariants(None,
1359 def _def_command(self
, expr
, info
):
1360 name
= expr
['command']
1361 data
= expr
.get('data')
1362 rets
= expr
.get('returns')
1363 gen
= expr
.get('gen', True)
1364 success_response
= expr
.get('success-response', True)
1365 if isinstance(data
, OrderedDict
):
1366 data
= self
._make
_implicit
_object
_type
(
1367 name
, info
, 'arg', self
._make
_members
(data
, info
))
1368 if isinstance(rets
, list):
1369 assert len(rets
) == 1
1370 rets
= self
._make
_array
_type
(rets
[0], info
)
1371 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1374 def _def_event(self
, expr
, info
):
1375 name
= expr
['event']
1376 data
= expr
.get('data')
1377 if isinstance(data
, OrderedDict
):
1378 data
= self
._make
_implicit
_object
_type
(
1379 name
, info
, 'arg', self
._make
_members
(data
, info
))
1380 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1382 def _def_exprs(self
):
1383 for expr_elem
in self
.exprs
:
1384 expr
= expr_elem
['expr']
1385 info
= expr_elem
['info']
1387 self
._def
_enum
_type
(expr
, info
)
1388 elif 'struct' in expr
:
1389 self
._def
_struct
_type
(expr
, info
)
1390 elif 'union' in expr
:
1391 self
._def
_union
_type
(expr
, info
)
1392 elif 'alternate' in expr
:
1393 self
._def
_alternate
_type
(expr
, info
)
1394 elif 'command' in expr
:
1395 self
._def
_command
(expr
, info
)
1396 elif 'event' in expr
:
1397 self
._def
_event
(expr
, info
)
1402 for ent
in self
._entity
_dict
.values():
1405 def visit(self
, visitor
):
1406 visitor
.visit_begin(self
)
1407 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1408 if visitor
.visit_needed(entity
):
1409 entity
.visit(visitor
)
1414 # Code generation helpers
1417 def camel_case(name
):
1421 if ch
in ['_', '-']:
1424 new_name
+= ch
.upper()
1427 new_name
+= ch
.lower()
1431 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1432 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1433 # ENUM24_Name -> ENUM24_NAME
1434 def camel_to_upper(value
):
1435 c_fun_str
= c_name(value
, False)
1443 # When c is upper and no "_" appears before, do more checks
1444 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1445 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1447 elif c_fun_str
[i
- 1].isdigit():
1450 return new_name
.lstrip('_').upper()
1453 def c_enum_const(type_name
, const_name
, prefix
=None):
1454 if prefix
is not None:
1456 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1458 c_name_trans
= string
.maketrans('.-', '__')
1461 # Map @name to a valid C identifier.
1462 # If @protect, avoid returning certain ticklish identifiers (like
1463 # C keywords) by prepending "q_".
1465 # Used for converting 'name' from a 'name':'type' qapi definition
1466 # into a generated struct member, as well as converting type names
1467 # into substrings of a generated C function name.
1468 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1469 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1470 def c_name(name
, protect
=True):
1471 # ANSI X3J11/88-090, 3.1.1
1472 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1473 'default', 'do', 'double', 'else', 'enum', 'extern',
1474 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1475 'return', 'short', 'signed', 'sizeof', 'static',
1476 'struct', 'switch', 'typedef', 'union', 'unsigned',
1477 'void', 'volatile', 'while'])
1478 # ISO/IEC 9899:1999, 6.4.1
1479 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1480 # ISO/IEC 9899:2011, 6.4.1
1481 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1482 '_Noreturn', '_Static_assert', '_Thread_local'])
1483 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1485 gcc_words
= set(['asm', 'typeof'])
1486 # C++ ISO/IEC 14882:2003 2.11
1487 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1488 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1489 'namespace', 'new', 'operator', 'private', 'protected',
1490 'public', 'reinterpret_cast', 'static_cast', 'template',
1491 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1492 'using', 'virtual', 'wchar_t',
1493 # alternative representations
1494 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1495 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1496 # namespace pollution:
1497 polluted_words
= set(['unix', 'errno', 'mips', 'sparc'])
1498 name
= name
.translate(c_name_trans
)
1499 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1500 | cpp_words | polluted_words
):
1504 eatspace
= '\033EATSPACE.'
1505 pointer_suffix
= ' *' + eatspace
1508 def genindent(count
):
1510 for _
in range(count
):
1517 def push_indent(indent_amount
=4):
1519 indent_level
+= indent_amount
1522 def pop_indent(indent_amount
=4):
1524 indent_level
-= indent_amount
1527 # Generate @code with @kwds interpolated.
1528 # Obey indent_level, and strip eatspace.
1529 def cgen(code
, **kwds
):
1532 indent
= genindent(indent_level
)
1533 # re.subn() lacks flags support before Python 2.7, use re.compile()
1534 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1535 indent
+ r
'\g<0>', raw
)
1537 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1540 def mcgen(code
, **kwds
):
1543 return cgen(code
, **kwds
)
1546 def guardname(filename
):
1547 return c_name(filename
, protect
=False).upper()
1550 def guardstart(name
):
1557 name
=guardname(name
))
1563 #endif /* %(name)s */
1566 name
=guardname(name
))
1569 def gen_enum_lookup(name
, values
, prefix
=None):
1572 const char *const %(c_name)s_lookup[] = {
1574 c_name
=c_name(name
))
1575 for value
in values
:
1576 index
= c_enum_const(name
, value
, prefix
)
1578 [%(index)s] = "%(value)s",
1580 index
=index
, value
=value
)
1582 max_index
= c_enum_const(name
, '_MAX', prefix
)
1584 [%(max_index)s] = NULL,
1587 max_index
=max_index
)
1591 def gen_enum(name
, values
, prefix
=None):
1592 # append automatically generated _MAX value
1593 enum_values
= values
+ ['_MAX']
1597 typedef enum %(c_name)s {
1599 c_name
=c_name(name
))
1602 for value
in enum_values
:
1606 c_enum
=c_enum_const(name
, value
, prefix
),
1613 c_name
=c_name(name
))
1617 extern const char *const %(c_name)s_lookup[];
1619 c_name
=c_name(name
))
1623 def gen_params(arg_type
, extra
):
1626 assert not arg_type
.variants
1629 for memb
in arg_type
.members
:
1633 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1634 ret
+= '%s %s' % (memb
.type.c_type(is_param
=True), c_name(memb
.name
))
1640 def gen_err_check(label
='out', skiperr
=False):
1651 def gen_visit_fields(members
, prefix
='', need_cast
=False, skiperr
=False,
1659 for memb
in members
:
1662 if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) {
1664 prefix
=prefix
, c_name
=c_name(memb
.name
),
1668 # Ugly: sometimes we need to cast away const
1669 if need_cast
and memb
.type.name
== 'str':
1675 visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s);
1677 c_type
=memb
.type.c_name(), prefix
=prefix
, cast
=cast
,
1678 c_name
=c_name(memb
.name
), name
=memb
.name
,
1680 ret
+= gen_err_check(skiperr
=skiperr
, label
=label
)
1691 # Common command line parsing
1695 def parse_command_line(extra_options
="", extra_long_options
=[]):
1698 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1699 "chp:o:" + extra_options
,
1700 ["source", "header", "prefix=",
1701 "output-dir="] + extra_long_options
)
1702 except getopt
.GetoptError
as err
:
1703 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1714 if o
in ("-p", "--prefix"):
1715 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1716 if match
.end() != len(a
):
1717 print >>sys
.stderr
, \
1718 "%s: 'funny character '%s' in argument of --prefix" \
1719 % (sys
.argv
[0], a
[match
.end()])
1722 elif o
in ("-o", "--output-dir"):
1723 output_dir
= a
+ "/"
1724 elif o
in ("-c", "--source"):
1726 elif o
in ("-h", "--header"):
1729 extra_opts
.append(oa
)
1731 if not do_c
and not do_h
:
1736 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1740 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1743 # Generate output files with boilerplate
1747 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1748 c_comment
, h_comment
):
1749 guard
= guardname(prefix
+ h_file
)
1750 c_file
= output_dir
+ prefix
+ c_file
1751 h_file
= output_dir
+ prefix
+ h_file
1755 os
.makedirs(output_dir
)
1756 except os
.error
as e
:
1757 if e
.errno
!= errno
.EEXIST
:
1760 def maybe_open(really
, name
, opt
):
1762 return open(name
, opt
)
1765 return StringIO
.StringIO()
1767 fdef
= maybe_open(do_c
, c_file
, 'w')
1768 fdecl
= maybe_open(do_h
, h_file
, 'w')
1770 fdef
.write(mcgen('''
1771 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1776 fdecl
.write(mcgen('''
1777 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1783 comment
=h_comment
, guard
=guard
))
1785 return (fdef
, fdecl
)
1788 def close_output(fdef
, fdecl
):