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 'QapiErrorClass', # all members, visible through errors
70 'UuidInfo', # UUID, visible through query-uuid
71 'X86CPURegister32', # all members, visible indirectly through qom-get
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 base_struct_define
= find_struct(base
)
331 if not base_struct_define
:
333 return base_struct_define
['data']
336 # Return the qtype of an alternate branch, or None on error.
337 def find_alternate_member_qtype(qapi_type
):
338 if qapi_type
in builtin_types
:
339 return builtin_types
[qapi_type
]
340 elif find_struct(qapi_type
):
342 elif find_enum(qapi_type
):
343 return "QTYPE_QSTRING"
344 elif find_union(qapi_type
):
349 # Return the discriminator enum define if discriminator is specified as an
350 # enum type, otherwise return None.
351 def discriminator_find_enum_define(expr
):
352 base
= expr
.get('base')
353 discriminator
= expr
.get('discriminator')
355 if not (discriminator
and base
):
358 base_members
= find_base_members(base
)
362 discriminator_type
= base_members
.get(discriminator
)
363 if not discriminator_type
:
366 return find_enum(discriminator_type
)
369 # Names must be letters, numbers, -, and _. They must start with letter,
370 # except for downstream extensions which must start with __RFQDN_.
371 # Dots are only valid in the downstream extension prefix.
372 valid_name
= re
.compile('^(__[a-zA-Z0-9.-]+_)?'
373 '[a-zA-Z][a-zA-Z0-9_-]*$')
376 def check_name(expr_info
, source
, name
, allow_optional
=False,
381 if not isinstance(name
, str):
382 raise QAPIExprError(expr_info
,
383 "%s requires a string name" % source
)
384 if name
.startswith('*'):
385 membername
= name
[1:]
386 if not allow_optional
:
387 raise QAPIExprError(expr_info
,
388 "%s does not allow optional name '%s'"
390 # Enum members can start with a digit, because the generated C
391 # code always prefixes it with the enum name
392 if enum_member
and membername
[0].isdigit():
393 membername
= 'D' + membername
394 # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty'
395 # and 'q_obj_*' implicit type names.
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_members
= find_base_members(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_members
.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 # Return the C type for common use.
827 # For the types we commonly box, this is a pointer type.
831 # Return the C type to be used in a parameter list.
832 def c_param_type(self
):
835 # Return the C type to be used where we suppress boxing.
836 def c_unboxed_type(self
):
842 def alternate_qtype(self
):
844 'string': 'QTYPE_QSTRING',
845 'number': 'QTYPE_QFLOAT',
847 'boolean': 'QTYPE_QBOOL',
848 'object': 'QTYPE_QDICT'
850 return json2qtype
.get(self
.json_type())
853 class QAPISchemaBuiltinType(QAPISchemaType
):
854 def __init__(self
, name
, json_type
, c_type
):
855 QAPISchemaType
.__init
__(self
, name
, None)
856 assert not c_type
or isinstance(c_type
, str)
857 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
859 self
._json
_type
_name
= json_type
860 self
._c
_type
_name
= c_type
866 return self
._c
_type
_name
868 def c_param_type(self
):
869 if self
.name
== 'str':
870 return 'const ' + self
._c
_type
_name
871 return self
._c
_type
_name
874 return self
._json
_type
_name
876 def visit(self
, visitor
):
877 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
880 class QAPISchemaEnumType(QAPISchemaType
):
881 def __init__(self
, name
, info
, values
, prefix
):
882 QAPISchemaType
.__init
__(self
, name
, info
)
884 assert isinstance(v
, QAPISchemaMember
)
886 assert prefix
is None or isinstance(prefix
, str)
890 def check(self
, schema
):
892 for v
in self
.values
:
893 v
.check_clash(self
.info
, seen
)
895 def is_implicit(self
):
896 # See QAPISchema._make_implicit_enum_type()
897 return self
.name
.endswith('Kind')
900 return c_name(self
.name
)
902 def member_names(self
):
903 return [v
.name
for v
in self
.values
]
908 def visit(self
, visitor
):
909 visitor
.visit_enum_type(self
.name
, self
.info
,
910 self
.member_names(), self
.prefix
)
913 class QAPISchemaArrayType(QAPISchemaType
):
914 def __init__(self
, name
, info
, element_type
):
915 QAPISchemaType
.__init
__(self
, name
, info
)
916 assert isinstance(element_type
, str)
917 self
._element
_type
_name
= element_type
918 self
.element_type
= None
920 def check(self
, schema
):
921 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
922 assert self
.element_type
924 def is_implicit(self
):
928 return c_name(self
.name
) + pointer_suffix
933 def visit(self
, visitor
):
934 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
937 class QAPISchemaObjectType(QAPISchemaType
):
938 def __init__(self
, name
, info
, base
, local_members
, variants
):
939 # struct has local_members, optional base, and no variants
940 # flat union has base, variants, and no local_members
941 # simple union has local_members, variants, and no base
942 QAPISchemaType
.__init
__(self
, name
, info
)
943 assert base
is None or isinstance(base
, str)
944 for m
in local_members
:
945 assert isinstance(m
, QAPISchemaObjectTypeMember
)
947 if variants
is not None:
948 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
949 variants
.set_owner(name
)
950 self
._base
_name
= base
952 self
.local_members
= local_members
953 self
.variants
= variants
956 def check(self
, schema
):
957 if self
.members
is False: # check for cycles
958 raise QAPIExprError(self
.info
,
959 "Object %s contains itself" % self
.name
)
962 self
.members
= False # mark as being checked
965 self
.base
= schema
.lookup_type(self
._base
_name
)
966 assert isinstance(self
.base
, QAPISchemaObjectType
)
967 self
.base
.check(schema
)
968 self
.base
.check_clash(schema
, self
.info
, seen
)
969 for m
in self
.local_members
:
971 m
.check_clash(self
.info
, seen
)
972 self
.members
= seen
.values()
974 self
.variants
.check(schema
, seen
)
975 assert self
.variants
.tag_member
in self
.members
976 self
.variants
.check_clash(schema
, self
.info
, seen
)
978 # Check that the members of this type do not cause duplicate JSON members,
979 # and update seen to track the members seen so far. Report any errors
980 # on behalf of info, which is not necessarily self.info
981 def check_clash(self
, schema
, info
, seen
):
982 assert not self
.variants
# not implemented
983 for m
in self
.members
:
984 m
.check_clash(info
, seen
)
986 def is_implicit(self
):
987 # See QAPISchema._make_implicit_object_type(), as well as
989 return self
.name
.startswith('q_')
992 return QAPISchemaType
.c_name(self
)
995 assert not self
.is_implicit()
996 return c_name(self
.name
) + pointer_suffix
998 def c_unboxed_type(self
):
999 return c_name(self
.name
)
1001 def json_type(self
):
1004 def visit(self
, visitor
):
1005 visitor
.visit_object_type(self
.name
, self
.info
,
1006 self
.base
, self
.local_members
, self
.variants
)
1007 visitor
.visit_object_type_flat(self
.name
, self
.info
,
1008 self
.members
, self
.variants
)
1011 class QAPISchemaMember(object):
1014 def __init__(self
, name
):
1015 assert isinstance(name
, str)
1019 def set_owner(self
, name
):
1020 assert not self
.owner
1023 def check_clash(self
, info
, seen
):
1024 cname
= c_name(self
.name
)
1025 if cname
.lower() != cname
and self
.owner
not in case_whitelist
:
1026 raise QAPIExprError(info
,
1027 "%s should not use uppercase" % self
.describe())
1029 raise QAPIExprError(info
,
1030 "%s collides with %s"
1031 % (self
.describe(), seen
[cname
].describe()))
1034 def _pretty_owner(self
):
1036 if owner
.startswith('q_obj_'):
1037 # See QAPISchema._make_implicit_object_type() - reverse the
1038 # mapping there to create a nice human-readable description
1040 if owner
.endswith('-arg'):
1041 return '(parameter of %s)' % owner
[:-4]
1043 assert owner
.endswith('-wrapper')
1044 # Unreachable and not implemented
1046 if owner
.endswith('Kind'):
1047 # See QAPISchema._make_implicit_enum_type()
1048 return '(branch of %s)' % owner
[:-4]
1049 return '(%s of %s)' % (self
.role
, owner
)
1052 return "'%s' %s" % (self
.name
, self
._pretty
_owner
())
1055 class QAPISchemaObjectTypeMember(QAPISchemaMember
):
1056 def __init__(self
, name
, typ
, optional
):
1057 QAPISchemaMember
.__init
__(self
, name
)
1058 assert isinstance(typ
, str)
1059 assert isinstance(optional
, bool)
1060 self
._type
_name
= typ
1062 self
.optional
= optional
1064 def check(self
, schema
):
1066 self
.type = schema
.lookup_type(self
._type
_name
)
1070 class QAPISchemaObjectTypeVariants(object):
1071 def __init__(self
, tag_name
, tag_member
, variants
):
1072 # Flat unions pass tag_name but not tag_member.
1073 # Simple unions and alternates pass tag_member but not tag_name.
1074 # After check(), tag_member is always set, and tag_name remains
1075 # a reliable witness of being used by a flat union.
1076 assert bool(tag_member
) != bool(tag_name
)
1077 assert (isinstance(tag_name
, str) or
1078 isinstance(tag_member
, QAPISchemaObjectTypeMember
))
1079 assert len(variants
) > 0
1081 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1082 self
.tag_name
= tag_name
1083 self
.tag_member
= tag_member
1084 self
.variants
= variants
1086 def set_owner(self
, name
):
1087 for v
in self
.variants
:
1090 def check(self
, schema
, seen
):
1091 if not self
.tag_member
: # flat union
1092 self
.tag_member
= seen
[c_name(self
.tag_name
)]
1093 assert self
.tag_name
== self
.tag_member
.name
1094 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1095 for v
in self
.variants
:
1097 # Union names must match enum values; alternate names are
1098 # checked separately. Use 'seen' to tell the two apart.
1100 assert v
.name
in self
.tag_member
.type.member_names()
1101 assert isinstance(v
.type, QAPISchemaObjectType
)
1102 v
.type.check(schema
)
1104 def check_clash(self
, schema
, info
, seen
):
1105 for v
in self
.variants
:
1106 # Reset seen map for each variant, since qapi names from one
1107 # branch do not affect another branch
1108 assert isinstance(v
.type, QAPISchemaObjectType
)
1109 v
.type.check_clash(schema
, info
, dict(seen
))
1112 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1115 def __init__(self
, name
, typ
):
1116 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1118 # This function exists to support ugly simple union special cases
1119 # TODO get rid of them, and drop the function
1120 def simple_union_type(self
):
1121 if (self
.type.is_implicit() and
1122 isinstance(self
.type, QAPISchemaObjectType
)):
1123 assert len(self
.type.members
) == 1
1124 assert not self
.type.variants
1125 return self
.type.members
[0].type
1129 class QAPISchemaAlternateType(QAPISchemaType
):
1130 def __init__(self
, name
, info
, variants
):
1131 QAPISchemaType
.__init
__(self
, name
, info
)
1132 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1133 assert not variants
.tag_name
1134 variants
.set_owner(name
)
1135 variants
.tag_member
.set_owner(self
.name
)
1136 self
.variants
= variants
1138 def check(self
, schema
):
1139 self
.variants
.tag_member
.check(schema
)
1140 # Not calling self.variants.check_clash(), because there's nothing
1142 self
.variants
.check(schema
, {})
1143 # Alternate branch names have no relation to the tag enum values;
1144 # so we have to check for potential name collisions ourselves.
1146 for v
in self
.variants
.variants
:
1147 v
.check_clash(self
.info
, seen
)
1150 return c_name(self
.name
) + pointer_suffix
1152 def json_type(self
):
1155 def visit(self
, visitor
):
1156 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1159 class QAPISchemaCommand(QAPISchemaEntity
):
1160 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1161 QAPISchemaEntity
.__init
__(self
, name
, info
)
1162 assert not arg_type
or isinstance(arg_type
, str)
1163 assert not ret_type
or isinstance(ret_type
, str)
1164 self
._arg
_type
_name
= arg_type
1165 self
.arg_type
= None
1166 self
._ret
_type
_name
= ret_type
1167 self
.ret_type
= None
1169 self
.success_response
= success_response
1171 def check(self
, schema
):
1172 if self
._arg
_type
_name
:
1173 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1174 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1175 assert not self
.arg_type
.variants
# not implemented
1176 if self
._ret
_type
_name
:
1177 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1178 assert isinstance(self
.ret_type
, QAPISchemaType
)
1180 def visit(self
, visitor
):
1181 visitor
.visit_command(self
.name
, self
.info
,
1182 self
.arg_type
, self
.ret_type
,
1183 self
.gen
, self
.success_response
)
1186 class QAPISchemaEvent(QAPISchemaEntity
):
1187 def __init__(self
, name
, info
, arg_type
):
1188 QAPISchemaEntity
.__init
__(self
, name
, info
)
1189 assert not arg_type
or isinstance(arg_type
, str)
1190 self
._arg
_type
_name
= arg_type
1191 self
.arg_type
= None
1193 def check(self
, schema
):
1194 if self
._arg
_type
_name
:
1195 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1196 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1197 assert not self
.arg_type
.variants
# not implemented
1199 def visit(self
, visitor
):
1200 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1203 class QAPISchema(object):
1204 def __init__(self
, fname
):
1206 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1207 self
._entity
_dict
= {}
1208 self
._predefining
= True
1209 self
._def
_predefineds
()
1210 self
._predefining
= False
1213 except (QAPISchemaError
, QAPIExprError
) as err
:
1214 print >>sys
.stderr
, err
1217 def _def_entity(self
, ent
):
1218 # Only the predefined types are allowed to not have info
1219 assert ent
.info
or self
._predefining
1220 assert ent
.name
not in self
._entity
_dict
1221 self
._entity
_dict
[ent
.name
] = ent
1223 def lookup_entity(self
, name
, typ
=None):
1224 ent
= self
._entity
_dict
.get(name
)
1225 if typ
and not isinstance(ent
, typ
):
1229 def lookup_type(self
, name
):
1230 return self
.lookup_entity(name
, QAPISchemaType
)
1232 def _def_builtin_type(self
, name
, json_type
, c_type
):
1233 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
, c_type
))
1234 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1235 # qapi-types.h from a single .c, all arrays of builtins must be
1236 # declared in the first file whether or not they are used. Nicer
1237 # would be to use lazy instantiation, while figuring out how to
1238 # avoid compilation issues with multiple qapi-types.h.
1239 self
._make
_array
_type
(name
, None)
1241 def _def_predefineds(self
):
1242 for t
in [('str', 'string', 'char' + pointer_suffix
),
1243 ('number', 'number', 'double'),
1244 ('int', 'int', 'int64_t'),
1245 ('int8', 'int', 'int8_t'),
1246 ('int16', 'int', 'int16_t'),
1247 ('int32', 'int', 'int32_t'),
1248 ('int64', 'int', 'int64_t'),
1249 ('uint8', 'int', 'uint8_t'),
1250 ('uint16', 'int', 'uint16_t'),
1251 ('uint32', 'int', 'uint32_t'),
1252 ('uint64', 'int', 'uint64_t'),
1253 ('size', 'int', 'uint64_t'),
1254 ('bool', 'boolean', 'bool'),
1255 ('any', 'value', 'QObject' + pointer_suffix
)]:
1256 self
._def
_builtin
_type
(*t
)
1257 self
.the_empty_object_type
= QAPISchemaObjectType('q_empty', None,
1259 self
._def
_entity
(self
.the_empty_object_type
)
1260 qtype_values
= self
._make
_enum
_members
(['none', 'qnull', 'qint',
1261 'qstring', 'qdict', 'qlist',
1263 self
._def
_entity
(QAPISchemaEnumType('QType', None, qtype_values
,
1266 def _make_enum_members(self
, values
):
1267 return [QAPISchemaMember(v
) for v
in values
]
1269 def _make_implicit_enum_type(self
, name
, info
, values
):
1270 # See also QAPISchemaObjectTypeMember._pretty_owner()
1271 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1272 self
._def
_entity
(QAPISchemaEnumType(
1273 name
, info
, self
._make
_enum
_members
(values
), None))
1276 def _make_array_type(self
, element_type
, info
):
1277 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1278 if not self
.lookup_type(name
):
1279 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1282 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1285 # See also QAPISchemaObjectTypeMember._pretty_owner()
1286 name
= 'q_obj_%s-%s' % (name
, role
)
1287 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1288 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1292 def _def_enum_type(self
, expr
, info
):
1295 prefix
= expr
.get('prefix')
1296 self
._def
_entity
(QAPISchemaEnumType(
1297 name
, info
, self
._make
_enum
_members
(data
), prefix
))
1299 def _make_member(self
, name
, typ
, info
):
1301 if name
.startswith('*'):
1304 if isinstance(typ
, list):
1305 assert len(typ
) == 1
1306 typ
= self
._make
_array
_type
(typ
[0], info
)
1307 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1309 def _make_members(self
, data
, info
):
1310 return [self
._make
_member
(key
, value
, info
)
1311 for (key
, value
) in data
.iteritems()]
1313 def _def_struct_type(self
, expr
, info
):
1314 name
= expr
['struct']
1315 base
= expr
.get('base')
1317 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1318 self
._make
_members
(data
, info
),
1321 def _make_variant(self
, case
, typ
):
1322 return QAPISchemaObjectTypeVariant(case
, typ
)
1324 def _make_simple_variant(self
, case
, typ
, info
):
1325 if isinstance(typ
, list):
1326 assert len(typ
) == 1
1327 typ
= self
._make
_array
_type
(typ
[0], info
)
1328 typ
= self
._make
_implicit
_object
_type
(
1329 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1330 return QAPISchemaObjectTypeVariant(case
, typ
)
1332 def _def_union_type(self
, expr
, info
):
1333 name
= expr
['union']
1335 base
= expr
.get('base')
1336 tag_name
= expr
.get('discriminator')
1339 variants
= [self
._make
_variant
(key
, value
)
1340 for (key
, value
) in data
.iteritems()]
1343 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1344 for (key
, value
) in data
.iteritems()]
1345 typ
= self
._make
_implicit
_enum
_type
(name
, info
,
1346 [v
.name
for v
in variants
])
1347 tag_member
= QAPISchemaObjectTypeMember('type', typ
, False)
1348 members
= [tag_member
]
1350 QAPISchemaObjectType(name
, info
, base
, members
,
1351 QAPISchemaObjectTypeVariants(tag_name
,
1355 def _def_alternate_type(self
, expr
, info
):
1356 name
= expr
['alternate']
1358 variants
= [self
._make
_variant
(key
, value
)
1359 for (key
, value
) in data
.iteritems()]
1360 tag_member
= QAPISchemaObjectTypeMember('type', 'QType', False)
1362 QAPISchemaAlternateType(name
, info
,
1363 QAPISchemaObjectTypeVariants(None,
1367 def _def_command(self
, expr
, info
):
1368 name
= expr
['command']
1369 data
= expr
.get('data')
1370 rets
= expr
.get('returns')
1371 gen
= expr
.get('gen', True)
1372 success_response
= expr
.get('success-response', True)
1373 if isinstance(data
, OrderedDict
):
1374 data
= self
._make
_implicit
_object
_type
(
1375 name
, info
, 'arg', self
._make
_members
(data
, info
))
1376 if isinstance(rets
, list):
1377 assert len(rets
) == 1
1378 rets
= self
._make
_array
_type
(rets
[0], info
)
1379 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1382 def _def_event(self
, expr
, info
):
1383 name
= expr
['event']
1384 data
= expr
.get('data')
1385 if isinstance(data
, OrderedDict
):
1386 data
= self
._make
_implicit
_object
_type
(
1387 name
, info
, 'arg', self
._make
_members
(data
, info
))
1388 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1390 def _def_exprs(self
):
1391 for expr_elem
in self
.exprs
:
1392 expr
= expr_elem
['expr']
1393 info
= expr_elem
['info']
1395 self
._def
_enum
_type
(expr
, info
)
1396 elif 'struct' in expr
:
1397 self
._def
_struct
_type
(expr
, info
)
1398 elif 'union' in expr
:
1399 self
._def
_union
_type
(expr
, info
)
1400 elif 'alternate' in expr
:
1401 self
._def
_alternate
_type
(expr
, info
)
1402 elif 'command' in expr
:
1403 self
._def
_command
(expr
, info
)
1404 elif 'event' in expr
:
1405 self
._def
_event
(expr
, info
)
1410 for ent
in self
._entity
_dict
.values():
1413 def visit(self
, visitor
):
1414 visitor
.visit_begin(self
)
1415 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1416 if visitor
.visit_needed(entity
):
1417 entity
.visit(visitor
)
1422 # Code generation helpers
1425 def camel_case(name
):
1429 if ch
in ['_', '-']:
1432 new_name
+= ch
.upper()
1435 new_name
+= ch
.lower()
1439 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1440 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1441 # ENUM24_Name -> ENUM24_NAME
1442 def camel_to_upper(value
):
1443 c_fun_str
= c_name(value
, False)
1451 # When c is upper and no "_" appears before, do more checks
1452 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1453 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1455 elif c_fun_str
[i
- 1].isdigit():
1458 return new_name
.lstrip('_').upper()
1461 def c_enum_const(type_name
, const_name
, prefix
=None):
1462 if prefix
is not None:
1464 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1466 c_name_trans
= string
.maketrans('.-', '__')
1469 # Map @name to a valid C identifier.
1470 # If @protect, avoid returning certain ticklish identifiers (like
1471 # C keywords) by prepending "q_".
1473 # Used for converting 'name' from a 'name':'type' qapi definition
1474 # into a generated struct member, as well as converting type names
1475 # into substrings of a generated C function name.
1476 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1477 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1478 def c_name(name
, protect
=True):
1479 # ANSI X3J11/88-090, 3.1.1
1480 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1481 'default', 'do', 'double', 'else', 'enum', 'extern',
1482 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1483 'return', 'short', 'signed', 'sizeof', 'static',
1484 'struct', 'switch', 'typedef', 'union', 'unsigned',
1485 'void', 'volatile', 'while'])
1486 # ISO/IEC 9899:1999, 6.4.1
1487 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1488 # ISO/IEC 9899:2011, 6.4.1
1489 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1490 '_Noreturn', '_Static_assert', '_Thread_local'])
1491 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1493 gcc_words
= set(['asm', 'typeof'])
1494 # C++ ISO/IEC 14882:2003 2.11
1495 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1496 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1497 'namespace', 'new', 'operator', 'private', 'protected',
1498 'public', 'reinterpret_cast', 'static_cast', 'template',
1499 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1500 'using', 'virtual', 'wchar_t',
1501 # alternative representations
1502 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1503 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1504 # namespace pollution:
1505 polluted_words
= set(['unix', 'errno', 'mips', 'sparc'])
1506 name
= name
.translate(c_name_trans
)
1507 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1508 | cpp_words | polluted_words
):
1512 eatspace
= '\033EATSPACE.'
1513 pointer_suffix
= ' *' + eatspace
1516 def genindent(count
):
1518 for _
in range(count
):
1525 def push_indent(indent_amount
=4):
1527 indent_level
+= indent_amount
1530 def pop_indent(indent_amount
=4):
1532 indent_level
-= indent_amount
1535 # Generate @code with @kwds interpolated.
1536 # Obey indent_level, and strip eatspace.
1537 def cgen(code
, **kwds
):
1540 indent
= genindent(indent_level
)
1541 # re.subn() lacks flags support before Python 2.7, use re.compile()
1542 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1543 indent
+ r
'\g<0>', raw
)
1545 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1548 def mcgen(code
, **kwds
):
1551 return cgen(code
, **kwds
)
1554 def guardname(filename
):
1555 return c_name(filename
, protect
=False).upper()
1558 def guardstart(name
):
1565 name
=guardname(name
))
1571 #endif /* %(name)s */
1574 name
=guardname(name
))
1577 def gen_enum_lookup(name
, values
, prefix
=None):
1580 const char *const %(c_name)s_lookup[] = {
1582 c_name
=c_name(name
))
1583 for value
in values
:
1584 index
= c_enum_const(name
, value
, prefix
)
1586 [%(index)s] = "%(value)s",
1588 index
=index
, value
=value
)
1590 max_index
= c_enum_const(name
, '_MAX', prefix
)
1592 [%(max_index)s] = NULL,
1595 max_index
=max_index
)
1599 def gen_enum(name
, values
, prefix
=None):
1600 # append automatically generated _MAX value
1601 enum_values
= values
+ ['_MAX']
1605 typedef enum %(c_name)s {
1607 c_name
=c_name(name
))
1610 for value
in enum_values
:
1614 c_enum
=c_enum_const(name
, value
, prefix
),
1621 c_name
=c_name(name
))
1625 extern const char *const %(c_name)s_lookup[];
1627 c_name
=c_name(name
))
1631 def gen_params(arg_type
, extra
):
1634 assert not arg_type
.variants
1637 for memb
in arg_type
.members
:
1641 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1642 ret
+= '%s %s' % (memb
.type.c_param_type(), c_name(memb
.name
))
1648 def gen_err_check():
1657 # Common command line parsing
1661 def parse_command_line(extra_options
="", extra_long_options
=[]):
1664 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1665 "chp:o:" + extra_options
,
1666 ["source", "header", "prefix=",
1667 "output-dir="] + extra_long_options
)
1668 except getopt
.GetoptError
as err
:
1669 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1680 if o
in ("-p", "--prefix"):
1681 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1682 if match
.end() != len(a
):
1683 print >>sys
.stderr
, \
1684 "%s: 'funny character '%s' in argument of --prefix" \
1685 % (sys
.argv
[0], a
[match
.end()])
1688 elif o
in ("-o", "--output-dir"):
1689 output_dir
= a
+ "/"
1690 elif o
in ("-c", "--source"):
1692 elif o
in ("-h", "--header"):
1695 extra_opts
.append(oa
)
1697 if not do_c
and not do_h
:
1702 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1706 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1709 # Generate output files with boilerplate
1713 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1714 c_comment
, h_comment
):
1715 guard
= guardname(prefix
+ h_file
)
1716 c_file
= output_dir
+ prefix
+ c_file
1717 h_file
= output_dir
+ prefix
+ h_file
1721 os
.makedirs(output_dir
)
1722 except os
.error
as e
:
1723 if e
.errno
!= errno
.EEXIST
:
1726 def maybe_open(really
, name
, opt
):
1728 return open(name
, opt
)
1731 return StringIO
.StringIO()
1733 fdef
= maybe_open(do_c
, c_file
, 'w')
1734 fdecl
= maybe_open(do_h
, h_file
, 'w')
1736 fdef
.write(mcgen('''
1737 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1742 fdecl
.write(mcgen('''
1743 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1749 comment
=h_comment
, guard
=guard
))
1751 return (fdef
, fdecl
)
1754 def close_output(fdef
, fdecl
):