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 'CpuInfoMIPS', # PC, visible through query-cpu
67 'CpuInfoTricore', # PC, visible through query-cpu
68 'QapiErrorClass', # all members, visible through errors
69 'UuidInfo', # UUID, visible through query-uuid
70 'X86CPURegister32', # all members, visible indirectly through qom-get
71 'q_obj_CpuInfo-base', # CPU, visible through query-cpu
81 # Parsing the schema into expressions
85 def error_path(parent
):
88 res
= ("In file included from %s:%d:\n" % (parent
['file'],
89 parent
['line'])) + res
90 parent
= parent
['parent']
94 class QAPISchemaError(Exception):
95 def __init__(self
, schema
, msg
):
96 Exception.__init
__(self
)
97 self
.fname
= schema
.fname
100 self
.line
= schema
.line
101 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
103 self
.col
= (self
.col
+ 7) % 8 + 1
106 self
.info
= schema
.incl_info
109 return error_path(self
.info
) + \
110 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
113 class QAPIExprError(Exception):
114 def __init__(self
, expr_info
, msg
):
115 Exception.__init
__(self
)
117 self
.info
= expr_info
121 return error_path(self
.info
['parent']) + \
122 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
125 class QAPISchemaParser(object):
127 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
128 abs_fname
= os
.path
.abspath(fp
.name
)
131 previously_included
.append(abs_fname
)
132 self
.incl_info
= incl_info
134 if self
.src
== '' or self
.src
[-1] != '\n':
142 while self
.tok
is not None:
143 expr_info
= {'file': fname
, 'line': self
.line
,
144 'parent': self
.incl_info
}
145 expr
= self
.get_expr(False)
146 if isinstance(expr
, dict) and "include" in expr
:
148 raise QAPIExprError(expr_info
,
149 "Invalid 'include' directive")
150 include
= expr
["include"]
151 if not isinstance(include
, str):
152 raise QAPIExprError(expr_info
,
153 "Value of 'include' must be a string")
154 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
156 # catch inclusion cycle
159 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
160 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
163 # skip multiple include of the same file
164 if incl_abs_fname
in previously_included
:
167 fobj
= open(incl_abs_fname
, 'r')
169 raise QAPIExprError(expr_info
,
170 '%s: %s' % (e
.strerror
, include
))
171 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
173 self
.exprs
.extend(exprs_include
.exprs
)
175 expr_elem
= {'expr': expr
,
177 self
.exprs
.append(expr_elem
)
181 self
.tok
= self
.src
[self
.cursor
]
182 self
.pos
= self
.cursor
187 self
.cursor
= self
.src
.find('\n', self
.cursor
)
188 elif self
.tok
in "{}:,[]":
190 elif self
.tok
== "'":
194 ch
= self
.src
[self
.cursor
]
197 raise QAPISchemaError(self
,
198 'Missing terminating "\'"')
212 for _
in range(0, 4):
213 ch
= self
.src
[self
.cursor
]
215 if ch
not in "0123456789abcdefABCDEF":
216 raise QAPISchemaError(self
,
217 '\\u escape needs 4 '
219 value
= (value
<< 4) + int(ch
, 16)
220 # If Python 2 and 3 didn't disagree so much on
221 # how to handle Unicode, then we could allow
222 # Unicode string defaults. But most of QAPI is
223 # ASCII-only, so we aren't losing much for now.
224 if not value
or value
> 0x7f:
225 raise QAPISchemaError(self
,
226 'For now, \\u escape '
227 'only supports non-zero '
228 'values up to \\u007f')
233 raise QAPISchemaError(self
,
234 "Unknown escape \\%s" % ch
)
243 elif self
.src
.startswith("true", self
.pos
):
247 elif self
.src
.startswith("false", self
.pos
):
251 elif self
.src
.startswith("null", self
.pos
):
255 elif self
.tok
== '\n':
256 if self
.cursor
== len(self
.src
):
260 self
.line_pos
= self
.cursor
261 elif not self
.tok
.isspace():
262 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
264 def get_members(self
):
270 raise QAPISchemaError(self
, 'Expected string or "}"')
275 raise QAPISchemaError(self
, 'Expected ":"')
278 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
279 expr
[key
] = self
.get_expr(True)
284 raise QAPISchemaError(self
, 'Expected "," or "}"')
287 raise QAPISchemaError(self
, 'Expected string')
289 def get_values(self
):
294 if self
.tok
not in "{['tfn":
295 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
298 expr
.append(self
.get_expr(True))
303 raise QAPISchemaError(self
, 'Expected "," or "]"')
306 def get_expr(self
, nested
):
307 if self
.tok
!= '{' and not nested
:
308 raise QAPISchemaError(self
, 'Expected "{"')
311 expr
= self
.get_members()
312 elif self
.tok
== '[':
314 expr
= self
.get_values()
315 elif self
.tok
in "'tfn":
319 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
323 # Semantic analysis of schema expressions
324 # TODO fold into QAPISchema
325 # TODO catching name collisions in generated code would be nice
329 def find_base_members(base
):
330 if isinstance(base
, dict):
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_members
= find_base_members(base
)
364 discriminator_type
= base_members
.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(), and for 'q_empty'
397 # and 'q_obj_*' implicit type names.
398 if not valid_name
.match(membername
) or \
399 c_name(membername
, False).startswith('q_'):
400 raise QAPIExprError(expr_info
,
401 "%s uses invalid name '%s'" % (source
, name
))
404 def add_name(name
, info
, meta
, implicit
=False):
406 check_name(info
, "'%s'" % meta
, name
)
407 # FIXME should reject names that differ only in '_' vs. '.'
408 # vs. '-', because they're liable to clash in generated C.
409 if name
in all_names
:
410 raise QAPIExprError(info
,
411 "%s '%s' is already defined"
412 % (all_names
[name
], name
))
413 if not implicit
and (name
.endswith('Kind') or name
.endswith('List')):
414 raise QAPIExprError(info
,
415 "%s '%s' should not end in '%s'"
416 % (meta
, name
, name
[-4:]))
417 all_names
[name
] = meta
420 def add_struct(definition
, info
):
422 name
= definition
['struct']
423 add_name(name
, info
, 'struct')
424 struct_types
.append(definition
)
427 def find_struct(name
):
429 for struct
in struct_types
:
430 if struct
['struct'] == name
:
435 def add_union(definition
, info
):
437 name
= definition
['union']
438 add_name(name
, info
, 'union')
439 union_types
.append(definition
)
442 def find_union(name
):
444 for union
in union_types
:
445 if union
['union'] == name
:
450 def add_enum(name
, info
, enum_values
=None, implicit
=False):
452 add_name(name
, info
, 'enum', implicit
)
453 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
458 for enum
in enum_types
:
459 if enum
['enum_name'] == name
:
465 return find_enum(name
) is not None
468 def check_type(expr_info
, source
, value
, allow_array
=False,
469 allow_dict
=False, allow_optional
=False,
476 # Check if array type for value is okay
477 if isinstance(value
, list):
479 raise QAPIExprError(expr_info
,
480 "%s cannot be an array" % source
)
481 if len(value
) != 1 or not isinstance(value
[0], str):
482 raise QAPIExprError(expr_info
,
483 "%s: array type must contain single type name"
487 # Check if type name for value is okay
488 if isinstance(value
, str):
489 if value
not in all_names
:
490 raise QAPIExprError(expr_info
,
491 "%s uses unknown type '%s'"
493 if not all_names
[value
] in allow_metas
:
494 raise QAPIExprError(expr_info
,
495 "%s cannot use %s type '%s'"
496 % (source
, all_names
[value
], value
))
500 raise QAPIExprError(expr_info
,
501 "%s should be a type name" % source
)
503 if not isinstance(value
, OrderedDict
):
504 raise QAPIExprError(expr_info
,
505 "%s should be a dictionary or type name" % source
)
507 # value is a dictionary, check that each member is okay
508 for (key
, arg
) in value
.items():
509 check_name(expr_info
, "Member of %s" % source
, key
,
510 allow_optional
=allow_optional
)
511 if c_name(key
, False) == 'u' or c_name(key
, False).startswith('has_'):
512 raise QAPIExprError(expr_info
,
513 "Member of %s uses reserved name '%s'"
515 # Todo: allow dictionaries to represent default values of
516 # an optional argument.
517 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
519 allow_metas
=['built-in', 'union', 'alternate', 'struct',
523 def check_command(expr
, expr_info
):
524 name
= expr
['command']
526 check_type(expr_info
, "'data' for command '%s'" % name
,
527 expr
.get('data'), allow_dict
=True, allow_optional
=True,
528 allow_metas
=['struct'])
529 returns_meta
= ['union', 'struct']
530 if name
in returns_whitelist
:
531 returns_meta
+= ['built-in', 'alternate', 'enum']
532 check_type(expr_info
, "'returns' for command '%s'" % name
,
533 expr
.get('returns'), allow_array
=True,
534 allow_optional
=True, allow_metas
=returns_meta
)
537 def check_event(expr
, expr_info
):
542 check_type(expr_info
, "'data' for event '%s'" % name
,
543 expr
.get('data'), allow_dict
=True, allow_optional
=True,
544 allow_metas
=['struct'])
547 def check_union(expr
, expr_info
):
549 base
= expr
.get('base')
550 discriminator
= expr
.get('discriminator')
551 members
= expr
['data']
553 # Two types of unions, determined by discriminator.
555 # With no discriminator it is a simple union.
556 if discriminator
is None:
558 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
560 raise QAPIExprError(expr_info
,
561 "Simple union '%s' must not have a base"
564 # Else, it's a flat union.
566 # The object must have a string or dictionary 'base'.
567 check_type(expr_info
, "'base' for union '%s'" % name
,
568 base
, allow_dict
=True, allow_optional
=True,
569 allow_metas
=['struct'])
571 raise QAPIExprError(expr_info
,
572 "Flat union '%s' must have a base"
574 base_members
= find_base_members(base
)
577 # The value of member 'discriminator' must name a non-optional
578 # member of the base struct.
579 check_name(expr_info
, "Discriminator of flat union '%s'" % name
,
581 discriminator_type
= base_members
.get(discriminator
)
582 if not discriminator_type
:
583 raise QAPIExprError(expr_info
,
584 "Discriminator '%s' is not a member of base "
586 % (discriminator
, base
))
587 enum_define
= find_enum(discriminator_type
)
588 allow_metas
= ['struct']
589 # Do not allow string discriminator
591 raise QAPIExprError(expr_info
,
592 "Discriminator '%s' must be of enumeration "
593 "type" % discriminator
)
595 # Check every branch; don't allow an empty union
596 if len(members
) == 0:
597 raise QAPIExprError(expr_info
,
598 "Union '%s' cannot have empty 'data'" % name
)
599 for (key
, value
) in members
.items():
600 check_name(expr_info
, "Member of union '%s'" % name
, key
)
602 # Each value must name a known type
603 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
604 value
, allow_array
=not base
, allow_metas
=allow_metas
)
606 # If the discriminator names an enum type, then all members
607 # of 'data' must also be members of the enum type.
609 if key
not in enum_define
['enum_values']:
610 raise QAPIExprError(expr_info
,
611 "Discriminator value '%s' is not found in "
613 (key
, enum_define
["enum_name"]))
615 # If discriminator is user-defined, ensure all values are covered
617 for value
in enum_define
['enum_values']:
618 if value
not in members
.keys():
619 raise QAPIExprError(expr_info
,
620 "Union '%s' data missing '%s' branch"
624 def check_alternate(expr
, expr_info
):
625 name
= expr
['alternate']
626 members
= expr
['data']
629 # Check every branch; require at least two branches
631 raise QAPIExprError(expr_info
,
632 "Alternate '%s' should have at least two branches "
634 for (key
, value
) in members
.items():
635 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
637 # Ensure alternates have no type conflicts.
638 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
640 allow_metas
=['built-in', 'union', 'struct', 'enum'])
641 qtype
= find_alternate_member_qtype(value
)
643 raise QAPIExprError(expr_info
,
644 "Alternate '%s' member '%s' cannot use "
645 "type '%s'" % (name
, key
, value
))
646 if qtype
in types_seen
:
647 raise QAPIExprError(expr_info
,
648 "Alternate '%s' member '%s' can't "
649 "be distinguished from member '%s'"
650 % (name
, key
, types_seen
[qtype
]))
651 types_seen
[qtype
] = key
654 def check_enum(expr
, expr_info
):
656 members
= expr
.get('data')
657 prefix
= expr
.get('prefix')
659 if not isinstance(members
, list):
660 raise QAPIExprError(expr_info
,
661 "Enum '%s' requires an array for 'data'" % name
)
662 if prefix
is not None and not isinstance(prefix
, str):
663 raise QAPIExprError(expr_info
,
664 "Enum '%s' requires a string for 'prefix'" % name
)
665 for member
in members
:
666 check_name(expr_info
, "Member of enum '%s'" % name
, member
,
670 def check_struct(expr
, expr_info
):
671 name
= expr
['struct']
672 members
= expr
['data']
674 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
675 allow_dict
=True, allow_optional
=True)
676 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
677 allow_metas
=['struct'])
680 def check_keys(expr_elem
, meta
, required
, optional
=[]):
681 expr
= expr_elem
['expr']
682 info
= expr_elem
['info']
684 if not isinstance(name
, str):
685 raise QAPIExprError(info
,
686 "'%s' key must have a string value" % meta
)
687 required
= required
+ [meta
]
688 for (key
, value
) in expr
.items():
689 if key
not in required
and key
not in optional
:
690 raise QAPIExprError(info
,
691 "Unknown key '%s' in %s '%s'"
693 if (key
== 'gen' or key
== 'success-response') and value
is not False:
694 raise QAPIExprError(info
,
695 "'%s' of %s '%s' should only use false value"
699 raise QAPIExprError(info
,
700 "Key '%s' is missing from %s '%s'"
704 def check_exprs(exprs
):
707 # Learn the types and check for valid expression keys
708 for builtin
in builtin_types
.keys():
709 all_names
[builtin
] = 'built-in'
710 for expr_elem
in exprs
:
711 expr
= expr_elem
['expr']
712 info
= expr_elem
['info']
714 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
715 add_enum(expr
['enum'], info
, expr
['data'])
716 elif 'union' in expr
:
717 check_keys(expr_elem
, 'union', ['data'],
718 ['base', 'discriminator'])
719 add_union(expr
, info
)
720 elif 'alternate' in expr
:
721 check_keys(expr_elem
, 'alternate', ['data'])
722 add_name(expr
['alternate'], info
, 'alternate')
723 elif 'struct' in expr
:
724 check_keys(expr_elem
, 'struct', ['data'], ['base'])
725 add_struct(expr
, info
)
726 elif 'command' in expr
:
727 check_keys(expr_elem
, 'command', [],
728 ['data', 'returns', 'gen', 'success-response'])
729 add_name(expr
['command'], info
, 'command')
730 elif 'event' in expr
:
731 check_keys(expr_elem
, 'event', [], ['data'])
732 add_name(expr
['event'], info
, 'event')
734 raise QAPIExprError(expr_elem
['info'],
735 "Expression is missing metatype")
737 # Try again for hidden UnionKind enum
738 for expr_elem
in exprs
:
739 expr
= expr_elem
['expr']
741 if not discriminator_find_enum_define(expr
):
742 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
744 elif 'alternate' in expr
:
745 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
748 # Validate that exprs make sense
749 for expr_elem
in exprs
:
750 expr
= expr_elem
['expr']
751 info
= expr_elem
['info']
754 check_enum(expr
, info
)
755 elif 'union' in expr
:
756 check_union(expr
, info
)
757 elif 'alternate' in expr
:
758 check_alternate(expr
, info
)
759 elif 'struct' in expr
:
760 check_struct(expr
, info
)
761 elif 'command' in expr
:
762 check_command(expr
, info
)
763 elif 'event' in expr
:
764 check_event(expr
, info
)
766 assert False, 'unexpected meta type'
772 # Schema compiler frontend
775 class QAPISchemaEntity(object):
776 def __init__(self
, name
, info
):
777 assert isinstance(name
, str)
779 # For explicitly defined entities, info points to the (explicit)
780 # definition. For builtins (and their arrays), info is None.
781 # For implicitly defined entities, info points to a place that
782 # triggered the implicit definition (there may be more than one
787 return c_name(self
.name
)
789 def check(self
, schema
):
792 def is_implicit(self
):
795 def visit(self
, visitor
):
799 class QAPISchemaVisitor(object):
800 def visit_begin(self
, schema
):
806 def visit_needed(self
, entity
):
807 # Default to visiting everything
810 def visit_builtin_type(self
, name
, info
, json_type
):
813 def visit_enum_type(self
, name
, info
, values
, prefix
):
816 def visit_array_type(self
, name
, info
, element_type
):
819 def visit_object_type(self
, name
, info
, base
, members
, variants
):
822 def visit_object_type_flat(self
, name
, info
, members
, variants
):
825 def visit_alternate_type(self
, name
, info
, variants
):
828 def visit_command(self
, name
, info
, arg_type
, ret_type
,
829 gen
, success_response
, boxed
):
832 def visit_event(self
, name
, info
, arg_type
, boxed
):
836 class QAPISchemaType(QAPISchemaEntity
):
837 # Return the C type for common use.
838 # For the types we commonly box, this is a pointer type.
842 # Return the C type to be used in a parameter list.
843 def c_param_type(self
):
846 # Return the C type to be used where we suppress boxing.
847 def c_unboxed_type(self
):
853 def alternate_qtype(self
):
855 'string': 'QTYPE_QSTRING',
856 'number': 'QTYPE_QFLOAT',
858 'boolean': 'QTYPE_QBOOL',
859 'object': 'QTYPE_QDICT'
861 return json2qtype
.get(self
.json_type())
864 class QAPISchemaBuiltinType(QAPISchemaType
):
865 def __init__(self
, name
, json_type
, c_type
):
866 QAPISchemaType
.__init
__(self
, name
, None)
867 assert not c_type
or isinstance(c_type
, str)
868 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
870 self
._json
_type
_name
= json_type
871 self
._c
_type
_name
= c_type
877 return self
._c
_type
_name
879 def c_param_type(self
):
880 if self
.name
== 'str':
881 return 'const ' + self
._c
_type
_name
882 return self
._c
_type
_name
885 return self
._json
_type
_name
887 def visit(self
, visitor
):
888 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
891 class QAPISchemaEnumType(QAPISchemaType
):
892 def __init__(self
, name
, info
, values
, prefix
):
893 QAPISchemaType
.__init
__(self
, name
, info
)
895 assert isinstance(v
, QAPISchemaMember
)
897 assert prefix
is None or isinstance(prefix
, str)
901 def check(self
, schema
):
903 for v
in self
.values
:
904 v
.check_clash(self
.info
, seen
)
906 def is_implicit(self
):
907 # See QAPISchema._make_implicit_enum_type()
908 return self
.name
.endswith('Kind')
911 return c_name(self
.name
)
913 def member_names(self
):
914 return [v
.name
for v
in self
.values
]
919 def visit(self
, visitor
):
920 visitor
.visit_enum_type(self
.name
, self
.info
,
921 self
.member_names(), self
.prefix
)
924 class QAPISchemaArrayType(QAPISchemaType
):
925 def __init__(self
, name
, info
, element_type
):
926 QAPISchemaType
.__init
__(self
, name
, info
)
927 assert isinstance(element_type
, str)
928 self
._element
_type
_name
= element_type
929 self
.element_type
= None
931 def check(self
, schema
):
932 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
933 assert self
.element_type
935 def is_implicit(self
):
939 return c_name(self
.name
) + pointer_suffix
944 def visit(self
, visitor
):
945 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
948 class QAPISchemaObjectType(QAPISchemaType
):
949 def __init__(self
, name
, info
, base
, local_members
, variants
):
950 # struct has local_members, optional base, and no variants
951 # flat union has base, variants, and no local_members
952 # simple union has local_members, variants, and no base
953 QAPISchemaType
.__init
__(self
, name
, info
)
954 assert base
is None or isinstance(base
, str)
955 for m
in local_members
:
956 assert isinstance(m
, QAPISchemaObjectTypeMember
)
958 if variants
is not None:
959 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
960 variants
.set_owner(name
)
961 self
._base
_name
= base
963 self
.local_members
= local_members
964 self
.variants
= variants
967 def check(self
, schema
):
968 if self
.members
is False: # check for cycles
969 raise QAPIExprError(self
.info
,
970 "Object %s contains itself" % self
.name
)
973 self
.members
= False # mark as being checked
976 self
.base
= schema
.lookup_type(self
._base
_name
)
977 assert isinstance(self
.base
, QAPISchemaObjectType
)
978 self
.base
.check(schema
)
979 self
.base
.check_clash(schema
, self
.info
, seen
)
980 for m
in self
.local_members
:
982 m
.check_clash(self
.info
, seen
)
983 self
.members
= seen
.values()
985 self
.variants
.check(schema
, seen
)
986 assert self
.variants
.tag_member
in self
.members
987 self
.variants
.check_clash(schema
, self
.info
, seen
)
989 # Check that the members of this type do not cause duplicate JSON members,
990 # and update seen to track the members seen so far. Report any errors
991 # on behalf of info, which is not necessarily self.info
992 def check_clash(self
, schema
, info
, seen
):
993 assert not self
.variants
# not implemented
994 for m
in self
.members
:
995 m
.check_clash(info
, seen
)
997 def is_implicit(self
):
998 # See QAPISchema._make_implicit_object_type(), as well as
1000 return self
.name
.startswith('q_')
1003 assert self
.members
is not None
1004 return not self
.members
and not self
.variants
1007 assert self
.name
!= 'q_empty'
1008 return QAPISchemaType
.c_name(self
)
1011 assert not self
.is_implicit()
1012 return c_name(self
.name
) + pointer_suffix
1014 def c_unboxed_type(self
):
1015 return c_name(self
.name
)
1017 def json_type(self
):
1020 def visit(self
, visitor
):
1021 visitor
.visit_object_type(self
.name
, self
.info
,
1022 self
.base
, self
.local_members
, self
.variants
)
1023 visitor
.visit_object_type_flat(self
.name
, self
.info
,
1024 self
.members
, self
.variants
)
1027 class QAPISchemaMember(object):
1030 def __init__(self
, name
):
1031 assert isinstance(name
, str)
1035 def set_owner(self
, name
):
1036 assert not self
.owner
1039 def check_clash(self
, info
, seen
):
1040 cname
= c_name(self
.name
)
1041 if cname
.lower() != cname
and self
.owner
not in case_whitelist
:
1042 raise QAPIExprError(info
,
1043 "%s should not use uppercase" % self
.describe())
1045 raise QAPIExprError(info
,
1046 "%s collides with %s"
1047 % (self
.describe(), seen
[cname
].describe()))
1050 def _pretty_owner(self
):
1052 if owner
.startswith('q_obj_'):
1053 # See QAPISchema._make_implicit_object_type() - reverse the
1054 # mapping there to create a nice human-readable description
1056 if owner
.endswith('-arg'):
1057 return '(parameter of %s)' % owner
[:-4]
1058 elif owner
.endswith('-base'):
1059 return '(base of %s)' % owner
[:-5]
1061 assert owner
.endswith('-wrapper')
1062 # Unreachable and not implemented
1064 if owner
.endswith('Kind'):
1065 # See QAPISchema._make_implicit_enum_type()
1066 return '(branch of %s)' % owner
[:-4]
1067 return '(%s of %s)' % (self
.role
, owner
)
1070 return "'%s' %s" % (self
.name
, self
._pretty
_owner
())
1073 class QAPISchemaObjectTypeMember(QAPISchemaMember
):
1074 def __init__(self
, name
, typ
, optional
):
1075 QAPISchemaMember
.__init
__(self
, name
)
1076 assert isinstance(typ
, str)
1077 assert isinstance(optional
, bool)
1078 self
._type
_name
= typ
1080 self
.optional
= optional
1082 def check(self
, schema
):
1084 self
.type = schema
.lookup_type(self
._type
_name
)
1088 class QAPISchemaObjectTypeVariants(object):
1089 def __init__(self
, tag_name
, tag_member
, variants
):
1090 # Flat unions pass tag_name but not tag_member.
1091 # Simple unions and alternates pass tag_member but not tag_name.
1092 # After check(), tag_member is always set, and tag_name remains
1093 # a reliable witness of being used by a flat union.
1094 assert bool(tag_member
) != bool(tag_name
)
1095 assert (isinstance(tag_name
, str) or
1096 isinstance(tag_member
, QAPISchemaObjectTypeMember
))
1097 assert len(variants
) > 0
1099 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1100 self
._tag
_name
= tag_name
1101 self
.tag_member
= tag_member
1102 self
.variants
= variants
1104 def set_owner(self
, name
):
1105 for v
in self
.variants
:
1108 def check(self
, schema
, seen
):
1109 if not self
.tag_member
: # flat union
1110 self
.tag_member
= seen
[c_name(self
._tag
_name
)]
1111 assert self
._tag
_name
== self
.tag_member
.name
1112 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1113 for v
in self
.variants
:
1115 # Union names must match enum values; alternate names are
1116 # checked separately. Use 'seen' to tell the two apart.
1118 assert v
.name
in self
.tag_member
.type.member_names()
1119 assert isinstance(v
.type, QAPISchemaObjectType
)
1120 v
.type.check(schema
)
1122 def check_clash(self
, schema
, info
, seen
):
1123 for v
in self
.variants
:
1124 # Reset seen map for each variant, since qapi names from one
1125 # branch do not affect another branch
1126 assert isinstance(v
.type, QAPISchemaObjectType
)
1127 v
.type.check_clash(schema
, info
, dict(seen
))
1130 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1133 def __init__(self
, name
, typ
):
1134 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1137 class QAPISchemaAlternateType(QAPISchemaType
):
1138 def __init__(self
, name
, info
, variants
):
1139 QAPISchemaType
.__init
__(self
, name
, info
)
1140 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1141 assert variants
.tag_member
1142 variants
.set_owner(name
)
1143 variants
.tag_member
.set_owner(self
.name
)
1144 self
.variants
= variants
1146 def check(self
, schema
):
1147 self
.variants
.tag_member
.check(schema
)
1148 # Not calling self.variants.check_clash(), because there's nothing
1150 self
.variants
.check(schema
, {})
1151 # Alternate branch names have no relation to the tag enum values;
1152 # so we have to check for potential name collisions ourselves.
1154 for v
in self
.variants
.variants
:
1155 v
.check_clash(self
.info
, seen
)
1158 return c_name(self
.name
) + pointer_suffix
1160 def json_type(self
):
1163 def visit(self
, visitor
):
1164 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1167 class QAPISchemaCommand(QAPISchemaEntity
):
1168 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
,
1170 QAPISchemaEntity
.__init
__(self
, name
, info
)
1171 assert not arg_type
or isinstance(arg_type
, str)
1172 assert not ret_type
or isinstance(ret_type
, str)
1173 self
._arg
_type
_name
= arg_type
1174 self
.arg_type
= None
1175 self
._ret
_type
_name
= ret_type
1176 self
.ret_type
= None
1178 self
.success_response
= success_response
1181 def check(self
, schema
):
1182 if self
._arg
_type
_name
:
1183 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1184 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1185 assert not self
.arg_type
.variants
# not implemented
1186 assert not self
.boxed
# not implemented
1187 if self
._ret
_type
_name
:
1188 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1189 assert isinstance(self
.ret_type
, QAPISchemaType
)
1191 def visit(self
, visitor
):
1192 visitor
.visit_command(self
.name
, self
.info
,
1193 self
.arg_type
, self
.ret_type
,
1194 self
.gen
, self
.success_response
, self
.boxed
)
1197 class QAPISchemaEvent(QAPISchemaEntity
):
1198 def __init__(self
, name
, info
, arg_type
, boxed
):
1199 QAPISchemaEntity
.__init
__(self
, name
, info
)
1200 assert not arg_type
or isinstance(arg_type
, str)
1201 self
._arg
_type
_name
= arg_type
1202 self
.arg_type
= None
1205 def check(self
, schema
):
1206 if self
._arg
_type
_name
:
1207 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1208 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1209 assert not self
.arg_type
.variants
# not implemented
1210 assert not self
.boxed
# not implemented
1212 def visit(self
, visitor
):
1213 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
, self
.boxed
)
1216 class QAPISchema(object):
1217 def __init__(self
, fname
):
1219 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1220 self
._entity
_dict
= {}
1221 self
._predefining
= True
1222 self
._def
_predefineds
()
1223 self
._predefining
= False
1226 except (QAPISchemaError
, QAPIExprError
) as err
:
1227 print >>sys
.stderr
, err
1230 def _def_entity(self
, ent
):
1231 # Only the predefined types are allowed to not have info
1232 assert ent
.info
or self
._predefining
1233 assert ent
.name
not in self
._entity
_dict
1234 self
._entity
_dict
[ent
.name
] = ent
1236 def lookup_entity(self
, name
, typ
=None):
1237 ent
= self
._entity
_dict
.get(name
)
1238 if typ
and not isinstance(ent
, typ
):
1242 def lookup_type(self
, name
):
1243 return self
.lookup_entity(name
, QAPISchemaType
)
1245 def _def_builtin_type(self
, name
, json_type
, c_type
):
1246 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
, c_type
))
1247 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1248 # qapi-types.h from a single .c, all arrays of builtins must be
1249 # declared in the first file whether or not they are used. Nicer
1250 # would be to use lazy instantiation, while figuring out how to
1251 # avoid compilation issues with multiple qapi-types.h.
1252 self
._make
_array
_type
(name
, None)
1254 def _def_predefineds(self
):
1255 for t
in [('str', 'string', 'char' + pointer_suffix
),
1256 ('number', 'number', 'double'),
1257 ('int', 'int', 'int64_t'),
1258 ('int8', 'int', 'int8_t'),
1259 ('int16', 'int', 'int16_t'),
1260 ('int32', 'int', 'int32_t'),
1261 ('int64', 'int', 'int64_t'),
1262 ('uint8', 'int', 'uint8_t'),
1263 ('uint16', 'int', 'uint16_t'),
1264 ('uint32', 'int', 'uint32_t'),
1265 ('uint64', 'int', 'uint64_t'),
1266 ('size', 'int', 'uint64_t'),
1267 ('bool', 'boolean', 'bool'),
1268 ('any', 'value', 'QObject' + pointer_suffix
)]:
1269 self
._def
_builtin
_type
(*t
)
1270 self
.the_empty_object_type
= QAPISchemaObjectType('q_empty', None,
1272 self
._def
_entity
(self
.the_empty_object_type
)
1273 qtype_values
= self
._make
_enum
_members
(['none', 'qnull', 'qint',
1274 'qstring', 'qdict', 'qlist',
1276 self
._def
_entity
(QAPISchemaEnumType('QType', None, qtype_values
,
1279 def _make_enum_members(self
, values
):
1280 return [QAPISchemaMember(v
) for v
in values
]
1282 def _make_implicit_enum_type(self
, name
, info
, values
):
1283 # See also QAPISchemaObjectTypeMember._pretty_owner()
1284 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1285 self
._def
_entity
(QAPISchemaEnumType(
1286 name
, info
, self
._make
_enum
_members
(values
), None))
1289 def _make_array_type(self
, element_type
, info
):
1290 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1291 if not self
.lookup_type(name
):
1292 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1295 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1298 # See also QAPISchemaObjectTypeMember._pretty_owner()
1299 name
= 'q_obj_%s-%s' % (name
, role
)
1300 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1301 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1305 def _def_enum_type(self
, expr
, info
):
1308 prefix
= expr
.get('prefix')
1309 self
._def
_entity
(QAPISchemaEnumType(
1310 name
, info
, self
._make
_enum
_members
(data
), prefix
))
1312 def _make_member(self
, name
, typ
, info
):
1314 if name
.startswith('*'):
1317 if isinstance(typ
, list):
1318 assert len(typ
) == 1
1319 typ
= self
._make
_array
_type
(typ
[0], info
)
1320 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1322 def _make_members(self
, data
, info
):
1323 return [self
._make
_member
(key
, value
, info
)
1324 for (key
, value
) in data
.iteritems()]
1326 def _def_struct_type(self
, expr
, info
):
1327 name
= expr
['struct']
1328 base
= expr
.get('base')
1330 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1331 self
._make
_members
(data
, info
),
1334 def _make_variant(self
, case
, typ
):
1335 return QAPISchemaObjectTypeVariant(case
, typ
)
1337 def _make_simple_variant(self
, case
, typ
, info
):
1338 if isinstance(typ
, list):
1339 assert len(typ
) == 1
1340 typ
= self
._make
_array
_type
(typ
[0], info
)
1341 typ
= self
._make
_implicit
_object
_type
(
1342 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1343 return QAPISchemaObjectTypeVariant(case
, typ
)
1345 def _def_union_type(self
, expr
, info
):
1346 name
= expr
['union']
1348 base
= expr
.get('base')
1349 tag_name
= expr
.get('discriminator')
1351 if isinstance(base
, dict):
1352 base
= (self
._make
_implicit
_object
_type
(
1353 name
, info
, 'base', self
._make
_members
(base
, info
)))
1355 variants
= [self
._make
_variant
(key
, value
)
1356 for (key
, value
) in data
.iteritems()]
1359 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1360 for (key
, value
) in data
.iteritems()]
1361 typ
= self
._make
_implicit
_enum
_type
(name
, info
,
1362 [v
.name
for v
in variants
])
1363 tag_member
= QAPISchemaObjectTypeMember('type', typ
, False)
1364 members
= [tag_member
]
1366 QAPISchemaObjectType(name
, info
, base
, members
,
1367 QAPISchemaObjectTypeVariants(tag_name
,
1371 def _def_alternate_type(self
, expr
, info
):
1372 name
= expr
['alternate']
1374 variants
= [self
._make
_variant
(key
, value
)
1375 for (key
, value
) in data
.iteritems()]
1376 tag_member
= QAPISchemaObjectTypeMember('type', 'QType', False)
1378 QAPISchemaAlternateType(name
, info
,
1379 QAPISchemaObjectTypeVariants(None,
1383 def _def_command(self
, expr
, info
):
1384 name
= expr
['command']
1385 data
= expr
.get('data')
1386 rets
= expr
.get('returns')
1387 gen
= expr
.get('gen', True)
1388 success_response
= expr
.get('success-response', True)
1389 boxed
= expr
.get('boxed', False)
1390 if isinstance(data
, OrderedDict
):
1391 data
= self
._make
_implicit
_object
_type
(
1392 name
, info
, 'arg', self
._make
_members
(data
, info
))
1393 if isinstance(rets
, list):
1394 assert len(rets
) == 1
1395 rets
= self
._make
_array
_type
(rets
[0], info
)
1396 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1397 success_response
, boxed
))
1399 def _def_event(self
, expr
, info
):
1400 name
= expr
['event']
1401 data
= expr
.get('data')
1402 boxed
= expr
.get('boxed', False)
1403 if isinstance(data
, OrderedDict
):
1404 data
= self
._make
_implicit
_object
_type
(
1405 name
, info
, 'arg', self
._make
_members
(data
, info
))
1406 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
, boxed
))
1408 def _def_exprs(self
):
1409 for expr_elem
in self
.exprs
:
1410 expr
= expr_elem
['expr']
1411 info
= expr_elem
['info']
1413 self
._def
_enum
_type
(expr
, info
)
1414 elif 'struct' in expr
:
1415 self
._def
_struct
_type
(expr
, info
)
1416 elif 'union' in expr
:
1417 self
._def
_union
_type
(expr
, info
)
1418 elif 'alternate' in expr
:
1419 self
._def
_alternate
_type
(expr
, info
)
1420 elif 'command' in expr
:
1421 self
._def
_command
(expr
, info
)
1422 elif 'event' in expr
:
1423 self
._def
_event
(expr
, info
)
1428 for ent
in self
._entity
_dict
.values():
1431 def visit(self
, visitor
):
1432 visitor
.visit_begin(self
)
1433 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1434 if visitor
.visit_needed(entity
):
1435 entity
.visit(visitor
)
1440 # Code generation helpers
1443 def camel_case(name
):
1447 if ch
in ['_', '-']:
1450 new_name
+= ch
.upper()
1453 new_name
+= ch
.lower()
1457 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1458 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1459 # ENUM24_Name -> ENUM24_NAME
1460 def camel_to_upper(value
):
1461 c_fun_str
= c_name(value
, False)
1469 # When c is upper and no "_" appears before, do more checks
1470 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1471 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1473 elif c_fun_str
[i
- 1].isdigit():
1476 return new_name
.lstrip('_').upper()
1479 def c_enum_const(type_name
, const_name
, prefix
=None):
1480 if prefix
is not None:
1482 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1484 c_name_trans
= string
.maketrans('.-', '__')
1487 # Map @name to a valid C identifier.
1488 # If @protect, avoid returning certain ticklish identifiers (like
1489 # C keywords) by prepending "q_".
1491 # Used for converting 'name' from a 'name':'type' qapi definition
1492 # into a generated struct member, as well as converting type names
1493 # into substrings of a generated C function name.
1494 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1495 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1496 def c_name(name
, protect
=True):
1497 # ANSI X3J11/88-090, 3.1.1
1498 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1499 'default', 'do', 'double', 'else', 'enum', 'extern',
1500 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1501 'return', 'short', 'signed', 'sizeof', 'static',
1502 'struct', 'switch', 'typedef', 'union', 'unsigned',
1503 'void', 'volatile', 'while'])
1504 # ISO/IEC 9899:1999, 6.4.1
1505 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1506 # ISO/IEC 9899:2011, 6.4.1
1507 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1508 '_Noreturn', '_Static_assert', '_Thread_local'])
1509 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1511 gcc_words
= set(['asm', 'typeof'])
1512 # C++ ISO/IEC 14882:2003 2.11
1513 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1514 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1515 'namespace', 'new', 'operator', 'private', 'protected',
1516 'public', 'reinterpret_cast', 'static_cast', 'template',
1517 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1518 'using', 'virtual', 'wchar_t',
1519 # alternative representations
1520 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1521 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1522 # namespace pollution:
1523 polluted_words
= set(['unix', 'errno', 'mips', 'sparc'])
1524 name
= name
.translate(c_name_trans
)
1525 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1526 | cpp_words | polluted_words
):
1530 eatspace
= '\033EATSPACE.'
1531 pointer_suffix
= ' *' + eatspace
1534 def genindent(count
):
1536 for _
in range(count
):
1543 def push_indent(indent_amount
=4):
1545 indent_level
+= indent_amount
1548 def pop_indent(indent_amount
=4):
1550 indent_level
-= indent_amount
1553 # Generate @code with @kwds interpolated.
1554 # Obey indent_level, and strip eatspace.
1555 def cgen(code
, **kwds
):
1558 indent
= genindent(indent_level
)
1559 # re.subn() lacks flags support before Python 2.7, use re.compile()
1560 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1561 indent
+ r
'\g<0>', raw
)
1563 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1566 def mcgen(code
, **kwds
):
1569 return cgen(code
, **kwds
)
1572 def guardname(filename
):
1573 return c_name(filename
, protect
=False).upper()
1576 def guardstart(name
):
1583 name
=guardname(name
))
1589 #endif /* %(name)s */
1592 name
=guardname(name
))
1595 def gen_enum_lookup(name
, values
, prefix
=None):
1598 const char *const %(c_name)s_lookup[] = {
1600 c_name
=c_name(name
))
1601 for value
in values
:
1602 index
= c_enum_const(name
, value
, prefix
)
1604 [%(index)s] = "%(value)s",
1606 index
=index
, value
=value
)
1608 max_index
= c_enum_const(name
, '_MAX', prefix
)
1610 [%(max_index)s] = NULL,
1613 max_index
=max_index
)
1617 def gen_enum(name
, values
, prefix
=None):
1618 # append automatically generated _MAX value
1619 enum_values
= values
+ ['_MAX']
1623 typedef enum %(c_name)s {
1625 c_name
=c_name(name
))
1628 for value
in enum_values
:
1632 c_enum
=c_enum_const(name
, value
, prefix
),
1639 c_name
=c_name(name
))
1643 extern const char *const %(c_name)s_lookup[];
1645 c_name
=c_name(name
))
1649 def gen_params(arg_type
, boxed
, extra
):
1655 assert False # not implemented
1657 assert not arg_type
.variants
1658 for memb
in arg_type
.members
:
1662 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1663 ret
+= '%s %s' % (memb
.type.c_param_type(),
1671 # Common command line parsing
1675 def parse_command_line(extra_options
="", extra_long_options
=[]):
1678 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1679 "chp:o:" + extra_options
,
1680 ["source", "header", "prefix=",
1681 "output-dir="] + extra_long_options
)
1682 except getopt
.GetoptError
as err
:
1683 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1694 if o
in ("-p", "--prefix"):
1695 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1696 if match
.end() != len(a
):
1697 print >>sys
.stderr
, \
1698 "%s: 'funny character '%s' in argument of --prefix" \
1699 % (sys
.argv
[0], a
[match
.end()])
1702 elif o
in ("-o", "--output-dir"):
1703 output_dir
= a
+ "/"
1704 elif o
in ("-c", "--source"):
1706 elif o
in ("-h", "--header"):
1709 extra_opts
.append(oa
)
1711 if not do_c
and not do_h
:
1716 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1720 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1723 # Generate output files with boilerplate
1727 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1728 c_comment
, h_comment
):
1729 guard
= guardname(prefix
+ h_file
)
1730 c_file
= output_dir
+ prefix
+ c_file
1731 h_file
= output_dir
+ prefix
+ h_file
1735 os
.makedirs(output_dir
)
1736 except os
.error
as e
:
1737 if e
.errno
!= errno
.EEXIST
:
1740 def maybe_open(really
, name
, opt
):
1742 return open(name
, opt
)
1745 return StringIO
.StringIO()
1747 fdef
= maybe_open(do_c
, c_file
, 'w')
1748 fdecl
= maybe_open(do_h
, h_file
, 'w')
1750 fdef
.write(mcgen('''
1751 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1756 fdecl
.write(mcgen('''
1757 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1763 comment
=h_comment
, guard
=guard
))
1765 return (fdef
, fdecl
)
1768 def close_output(fdef
, fdecl
):