4 # Copyright IBM, Corp. 2011
5 # Copyright (c) 2013-2015 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',
69 # Parsing the schema into expressions
73 def error_path(parent
):
76 res
= ("In file included from %s:%d:\n" % (parent
['file'],
77 parent
['line'])) + res
78 parent
= parent
['parent']
82 class QAPISchemaError(Exception):
83 def __init__(self
, schema
, msg
):
84 Exception.__init
__(self
)
85 self
.fname
= schema
.fname
88 self
.line
= schema
.line
89 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
91 self
.col
= (self
.col
+ 7) % 8 + 1
94 self
.info
= schema
.incl_info
97 return error_path(self
.info
) + \
98 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
101 class QAPIExprError(Exception):
102 def __init__(self
, expr_info
, msg
):
103 Exception.__init
__(self
)
105 self
.info
= expr_info
109 return error_path(self
.info
['parent']) + \
110 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
113 class QAPISchemaParser(object):
115 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
116 abs_fname
= os
.path
.abspath(fp
.name
)
119 previously_included
.append(abs_fname
)
120 self
.incl_info
= incl_info
122 if self
.src
== '' or self
.src
[-1] != '\n':
130 while self
.tok
is not None:
131 expr_info
= {'file': fname
, 'line': self
.line
,
132 'parent': self
.incl_info
}
133 expr
= self
.get_expr(False)
134 if isinstance(expr
, dict) and "include" in expr
:
136 raise QAPIExprError(expr_info
,
137 "Invalid 'include' directive")
138 include
= expr
["include"]
139 if not isinstance(include
, str):
140 raise QAPIExprError(expr_info
,
141 "Value of 'include' must be a string")
142 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
144 # catch inclusion cycle
147 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
148 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
151 # skip multiple include of the same file
152 if incl_abs_fname
in previously_included
:
155 fobj
= open(incl_abs_fname
, 'r')
157 raise QAPIExprError(expr_info
,
158 '%s: %s' % (e
.strerror
, include
))
159 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
161 self
.exprs
.extend(exprs_include
.exprs
)
163 expr_elem
= {'expr': expr
,
165 self
.exprs
.append(expr_elem
)
169 self
.tok
= self
.src
[self
.cursor
]
170 self
.pos
= self
.cursor
175 self
.cursor
= self
.src
.find('\n', self
.cursor
)
176 elif self
.tok
in "{}:,[]":
178 elif self
.tok
== "'":
182 ch
= self
.src
[self
.cursor
]
185 raise QAPISchemaError(self
,
186 'Missing terminating "\'"')
200 for _
in range(0, 4):
201 ch
= self
.src
[self
.cursor
]
203 if ch
not in "0123456789abcdefABCDEF":
204 raise QAPISchemaError(self
,
205 '\\u escape needs 4 '
207 value
= (value
<< 4) + int(ch
, 16)
208 # If Python 2 and 3 didn't disagree so much on
209 # how to handle Unicode, then we could allow
210 # Unicode string defaults. But most of QAPI is
211 # ASCII-only, so we aren't losing much for now.
212 if not value
or value
> 0x7f:
213 raise QAPISchemaError(self
,
214 'For now, \\u escape '
215 'only supports non-zero '
216 'values up to \\u007f')
221 raise QAPISchemaError(self
,
222 "Unknown escape \\%s" % ch
)
231 elif self
.src
.startswith("true", self
.pos
):
235 elif self
.src
.startswith("false", self
.pos
):
239 elif self
.src
.startswith("null", self
.pos
):
243 elif self
.tok
== '\n':
244 if self
.cursor
== len(self
.src
):
248 self
.line_pos
= self
.cursor
249 elif not self
.tok
.isspace():
250 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
252 def get_members(self
):
258 raise QAPISchemaError(self
, 'Expected string or "}"')
263 raise QAPISchemaError(self
, 'Expected ":"')
266 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
267 expr
[key
] = self
.get_expr(True)
272 raise QAPISchemaError(self
, 'Expected "," or "}"')
275 raise QAPISchemaError(self
, 'Expected string')
277 def get_values(self
):
282 if self
.tok
not in "{['tfn":
283 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
286 expr
.append(self
.get_expr(True))
291 raise QAPISchemaError(self
, 'Expected "," or "]"')
294 def get_expr(self
, nested
):
295 if self
.tok
!= '{' and not nested
:
296 raise QAPISchemaError(self
, 'Expected "{"')
299 expr
= self
.get_members()
300 elif self
.tok
== '[':
302 expr
= self
.get_values()
303 elif self
.tok
in "'tfn":
307 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
311 # Semantic analysis of schema expressions
312 # TODO fold into QAPISchema
313 # TODO catching name collisions in generated code would be nice
317 def find_base_fields(base
):
318 base_struct_define
= find_struct(base
)
319 if not base_struct_define
:
321 return base_struct_define
['data']
324 # Return the qtype of an alternate branch, or None on error.
325 def find_alternate_member_qtype(qapi_type
):
326 if qapi_type
in builtin_types
:
327 return builtin_types
[qapi_type
]
328 elif find_struct(qapi_type
):
330 elif find_enum(qapi_type
):
331 return "QTYPE_QSTRING"
332 elif find_union(qapi_type
):
337 # Return the discriminator enum define if discriminator is specified as an
338 # enum type, otherwise return None.
339 def discriminator_find_enum_define(expr
):
340 base
= expr
.get('base')
341 discriminator
= expr
.get('discriminator')
343 if not (discriminator
and base
):
346 base_fields
= find_base_fields(base
)
350 discriminator_type
= base_fields
.get(discriminator
)
351 if not discriminator_type
:
354 return find_enum(discriminator_type
)
357 # Names must be letters, numbers, -, and _. They must start with letter,
358 # except for downstream extensions which must start with __RFQDN_.
359 # Dots are only valid in the downstream extension prefix.
360 valid_name
= re
.compile('^(__[a-zA-Z0-9.-]+_)?'
361 '[a-zA-Z][a-zA-Z0-9_-]*$')
364 def check_name(expr_info
, source
, name
, allow_optional
=False,
369 if not isinstance(name
, str):
370 raise QAPIExprError(expr_info
,
371 "%s requires a string name" % source
)
372 if name
.startswith('*'):
373 membername
= name
[1:]
374 if not allow_optional
:
375 raise QAPIExprError(expr_info
,
376 "%s does not allow optional name '%s'"
378 # Enum members can start with a digit, because the generated C
379 # code always prefixes it with the enum name
380 if enum_member
and membername
[0].isdigit():
381 membername
= 'D' + membername
382 # Reserve the entire 'q_' namespace for c_name()
383 if not valid_name
.match(membername
) or \
384 c_name(membername
, False).startswith('q_'):
385 raise QAPIExprError(expr_info
,
386 "%s uses invalid name '%s'" % (source
, name
))
389 def add_name(name
, info
, meta
, implicit
=False):
391 check_name(info
, "'%s'" % meta
, name
)
392 # FIXME should reject names that differ only in '_' vs. '.'
393 # vs. '-', because they're liable to clash in generated C.
394 if name
in all_names
:
395 raise QAPIExprError(info
,
396 "%s '%s' is already defined"
397 % (all_names
[name
], name
))
398 if not implicit
and (name
.endswith('Kind') or name
.endswith('List')):
399 raise QAPIExprError(info
,
400 "%s '%s' should not end in '%s'"
401 % (meta
, name
, name
[-4:]))
402 all_names
[name
] = meta
405 def add_struct(definition
, info
):
407 name
= definition
['struct']
408 add_name(name
, info
, 'struct')
409 struct_types
.append(definition
)
412 def find_struct(name
):
414 for struct
in struct_types
:
415 if struct
['struct'] == name
:
420 def add_union(definition
, info
):
422 name
= definition
['union']
423 add_name(name
, info
, 'union')
424 union_types
.append(definition
)
427 def find_union(name
):
429 for union
in union_types
:
430 if union
['union'] == name
:
435 def add_enum(name
, info
, enum_values
=None, implicit
=False):
437 add_name(name
, info
, 'enum', implicit
)
438 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
443 for enum
in enum_types
:
444 if enum
['enum_name'] == name
:
450 return find_enum(name
) is not None
453 def check_type(expr_info
, source
, value
, allow_array
=False,
454 allow_dict
=False, allow_optional
=False,
461 # Check if array type for value is okay
462 if isinstance(value
, list):
464 raise QAPIExprError(expr_info
,
465 "%s cannot be an array" % source
)
466 if len(value
) != 1 or not isinstance(value
[0], str):
467 raise QAPIExprError(expr_info
,
468 "%s: array type must contain single type name"
472 # Check if type name for value is okay
473 if isinstance(value
, str):
474 if value
not in all_names
:
475 raise QAPIExprError(expr_info
,
476 "%s uses unknown type '%s'"
478 if not all_names
[value
] in allow_metas
:
479 raise QAPIExprError(expr_info
,
480 "%s cannot use %s type '%s'"
481 % (source
, all_names
[value
], value
))
485 raise QAPIExprError(expr_info
,
486 "%s should be a type name" % source
)
488 if not isinstance(value
, OrderedDict
):
489 raise QAPIExprError(expr_info
,
490 "%s should be a dictionary or type name" % source
)
492 # value is a dictionary, check that each member is okay
493 for (key
, arg
) in value
.items():
494 check_name(expr_info
, "Member of %s" % source
, key
,
495 allow_optional
=allow_optional
)
496 if c_name(key
, False) == 'u' or c_name(key
, False).startswith('has_'):
497 raise QAPIExprError(expr_info
,
498 "Member of %s uses reserved name '%s'"
500 # Todo: allow dictionaries to represent default values of
501 # an optional argument.
502 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
504 allow_metas
=['built-in', 'union', 'alternate', 'struct',
508 def check_member_clash(expr_info
, base_name
, data
, source
=""):
509 base
= find_struct(base_name
)
511 base_members
= base
['data']
512 for key
in data
.keys():
513 if key
.startswith('*'):
515 if key
in base_members
or "*" + key
in base_members
:
516 raise QAPIExprError(expr_info
,
517 "Member name '%s'%s clashes with base '%s'"
518 % (key
, source
, base_name
))
520 check_member_clash(expr_info
, base
['base'], data
, source
)
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']
554 # Two types of unions, determined by discriminator.
556 # With no discriminator it is a simple union.
557 if discriminator
is None:
559 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
561 raise QAPIExprError(expr_info
,
562 "Simple union '%s' must not have a base"
565 # Else, it's a flat union.
567 # The object must have a string member 'base'.
568 check_type(expr_info
, "'base' for union '%s'" % name
,
569 base
, allow_metas
=['struct'])
571 raise QAPIExprError(expr_info
,
572 "Flat union '%s' must have a base"
574 base_fields
= find_base_fields(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_fields
.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
)
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; furthermore, in flat unions,
600 # branches must be a struct with no overlapping member names
601 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
602 value
, allow_array
=not base
, allow_metas
=allow_metas
)
604 branch_struct
= find_struct(value
)
606 check_member_clash(expr_info
, base
, branch_struct
['data'],
607 " of branch '%s'" % key
)
609 # If the discriminator names an enum type, then all members
610 # of 'data' must also be members of the enum type.
612 if key
not in enum_define
['enum_values']:
613 raise QAPIExprError(expr_info
,
614 "Discriminator value '%s' is not found in "
616 (key
, enum_define
["enum_name"]))
618 # Otherwise, check for conflicts in the generated enum
620 c_key
= camel_to_upper(key
)
622 raise QAPIExprError(expr_info
,
623 "Union '%s' member '%s' clashes with '%s'"
624 % (name
, key
, values
[c_key
]))
628 def check_alternate(expr
, expr_info
):
629 name
= expr
['alternate']
630 members
= expr
['data']
635 for (key
, value
) in members
.items():
636 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
638 # Check for conflicts in the generated enum
639 c_key
= camel_to_upper(key
)
641 raise QAPIExprError(expr_info
,
642 "Alternate '%s' member '%s' clashes with '%s'"
643 % (name
, key
, values
[c_key
]))
646 # Ensure alternates have no type conflicts.
647 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
649 allow_metas
=['built-in', 'union', 'struct', 'enum'])
650 qtype
= find_alternate_member_qtype(value
)
652 if qtype
in types_seen
:
653 raise QAPIExprError(expr_info
,
654 "Alternate '%s' member '%s' can't "
655 "be distinguished from member '%s'"
656 % (name
, key
, types_seen
[qtype
]))
657 types_seen
[qtype
] = key
660 def check_enum(expr
, expr_info
):
662 members
= expr
.get('data')
663 prefix
= expr
.get('prefix')
666 if not isinstance(members
, list):
667 raise QAPIExprError(expr_info
,
668 "Enum '%s' requires an array for 'data'" % name
)
669 if prefix
is not None and not isinstance(prefix
, str):
670 raise QAPIExprError(expr_info
,
671 "Enum '%s' requires a string for 'prefix'" % name
)
672 for member
in members
:
673 check_name(expr_info
, "Member of enum '%s'" % name
, member
,
675 key
= camel_to_upper(member
)
677 raise QAPIExprError(expr_info
,
678 "Enum '%s' member '%s' clashes with '%s'"
679 % (name
, member
, values
[key
]))
683 def check_struct(expr
, expr_info
):
684 name
= expr
['struct']
685 members
= expr
['data']
687 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
688 allow_dict
=True, allow_optional
=True)
689 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
690 allow_metas
=['struct'])
692 check_member_clash(expr_info
, expr
['base'], expr
['data'])
695 def check_keys(expr_elem
, meta
, required
, optional
=[]):
696 expr
= expr_elem
['expr']
697 info
= expr_elem
['info']
699 if not isinstance(name
, str):
700 raise QAPIExprError(info
,
701 "'%s' key must have a string value" % meta
)
702 required
= required
+ [meta
]
703 for (key
, value
) in expr
.items():
704 if key
not in required
and key
not in optional
:
705 raise QAPIExprError(info
,
706 "Unknown key '%s' in %s '%s'"
708 if (key
== 'gen' or key
== 'success-response') and value
is not False:
709 raise QAPIExprError(info
,
710 "'%s' of %s '%s' should only use false value"
714 raise QAPIExprError(info
,
715 "Key '%s' is missing from %s '%s'"
719 def check_exprs(exprs
):
722 # Learn the types and check for valid expression keys
723 for builtin
in builtin_types
.keys():
724 all_names
[builtin
] = 'built-in'
725 for expr_elem
in exprs
:
726 expr
= expr_elem
['expr']
727 info
= expr_elem
['info']
729 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
730 add_enum(expr
['enum'], info
, expr
['data'])
731 elif 'union' in expr
:
732 check_keys(expr_elem
, 'union', ['data'],
733 ['base', 'discriminator'])
734 add_union(expr
, info
)
735 elif 'alternate' in expr
:
736 check_keys(expr_elem
, 'alternate', ['data'])
737 add_name(expr
['alternate'], info
, 'alternate')
738 elif 'struct' in expr
:
739 check_keys(expr_elem
, 'struct', ['data'], ['base'])
740 add_struct(expr
, info
)
741 elif 'command' in expr
:
742 check_keys(expr_elem
, 'command', [],
743 ['data', 'returns', 'gen', 'success-response'])
744 add_name(expr
['command'], info
, 'command')
745 elif 'event' in expr
:
746 check_keys(expr_elem
, 'event', [], ['data'])
747 add_name(expr
['event'], info
, 'event')
749 raise QAPIExprError(expr_elem
['info'],
750 "Expression is missing metatype")
752 # Try again for hidden UnionKind enum
753 for expr_elem
in exprs
:
754 expr
= expr_elem
['expr']
756 if not discriminator_find_enum_define(expr
):
757 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
759 elif 'alternate' in expr
:
760 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
763 # Validate that exprs make sense
764 for expr_elem
in exprs
:
765 expr
= expr_elem
['expr']
766 info
= expr_elem
['info']
769 check_enum(expr
, info
)
770 elif 'union' in expr
:
771 check_union(expr
, info
)
772 elif 'alternate' in expr
:
773 check_alternate(expr
, info
)
774 elif 'struct' in expr
:
775 check_struct(expr
, info
)
776 elif 'command' in expr
:
777 check_command(expr
, info
)
778 elif 'event' in expr
:
779 check_event(expr
, info
)
781 assert False, 'unexpected meta type'
787 # Schema compiler frontend
790 class QAPISchemaEntity(object):
791 def __init__(self
, name
, info
):
792 assert isinstance(name
, str)
794 # For explicitly defined entities, info points to the (explicit)
795 # definition. For builtins (and their arrays), info is None.
796 # For implicitly defined entities, info points to a place that
797 # triggered the implicit definition (there may be more than one
802 return c_name(self
.name
)
804 def check(self
, schema
):
807 def is_implicit(self
):
810 def visit(self
, visitor
):
814 class QAPISchemaVisitor(object):
815 def visit_begin(self
, schema
):
821 def visit_needed(self
, entity
):
822 # Default to visiting everything
825 def visit_builtin_type(self
, name
, info
, json_type
):
828 def visit_enum_type(self
, name
, info
, values
, prefix
):
831 def visit_array_type(self
, name
, info
, element_type
):
834 def visit_object_type(self
, name
, info
, base
, members
, variants
):
837 def visit_object_type_flat(self
, name
, info
, members
, variants
):
840 def visit_alternate_type(self
, name
, info
, variants
):
843 def visit_command(self
, name
, info
, arg_type
, ret_type
,
844 gen
, success_response
):
847 def visit_event(self
, name
, info
, arg_type
):
851 class QAPISchemaType(QAPISchemaEntity
):
852 def c_type(self
, is_param
=False):
853 return c_name(self
.name
) + pointer_suffix
861 def alternate_qtype(self
):
863 'string': 'QTYPE_QSTRING',
864 'number': 'QTYPE_QFLOAT',
866 'boolean': 'QTYPE_QBOOL',
867 'object': 'QTYPE_QDICT'
869 return json2qtype
.get(self
.json_type())
872 class QAPISchemaBuiltinType(QAPISchemaType
):
873 def __init__(self
, name
, json_type
, c_type
, c_null
):
874 QAPISchemaType
.__init
__(self
, name
, None)
875 assert not c_type
or isinstance(c_type
, str)
876 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
878 self
._json
_type
_name
= json_type
879 self
._c
_type
_name
= c_type
880 self
._c
_null
_val
= c_null
885 def c_type(self
, is_param
=False):
886 if is_param
and self
.name
== 'str':
887 return 'const ' + self
._c
_type
_name
888 return self
._c
_type
_name
891 return self
._c
_null
_val
894 return self
._json
_type
_name
896 def visit(self
, visitor
):
897 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
900 class QAPISchemaEnumType(QAPISchemaType
):
901 def __init__(self
, name
, info
, values
, prefix
):
902 QAPISchemaType
.__init
__(self
, name
, info
)
904 assert isinstance(v
, str)
905 assert prefix
is None or isinstance(prefix
, str)
909 def check(self
, schema
):
910 assert len(set(self
.values
)) == len(self
.values
)
912 def is_implicit(self
):
913 # See QAPISchema._make_implicit_enum_type()
914 return self
.name
.endswith('Kind')
916 def c_type(self
, is_param
=False):
917 return c_name(self
.name
)
920 return c_enum_const(self
.name
, (self
.values
+ ['_MAX'])[0],
926 def visit(self
, visitor
):
927 visitor
.visit_enum_type(self
.name
, self
.info
,
928 self
.values
, self
.prefix
)
931 class QAPISchemaArrayType(QAPISchemaType
):
932 def __init__(self
, name
, info
, element_type
):
933 QAPISchemaType
.__init
__(self
, name
, info
)
934 assert isinstance(element_type
, str)
935 self
._element
_type
_name
= element_type
936 self
.element_type
= None
938 def check(self
, schema
):
939 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
940 assert self
.element_type
942 def is_implicit(self
):
948 def visit(self
, visitor
):
949 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
952 class QAPISchemaObjectType(QAPISchemaType
):
953 def __init__(self
, name
, info
, base
, local_members
, variants
):
954 # struct has local_members, optional base, and no variants
955 # flat union has base, variants, and no local_members
956 # simple union has local_members, variants, and no base
957 QAPISchemaType
.__init
__(self
, name
, info
)
958 assert base
is None or isinstance(base
, str)
959 for m
in local_members
:
960 assert isinstance(m
, QAPISchemaObjectTypeMember
)
962 if variants
is not None:
963 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
964 variants
.set_owner(name
)
965 self
._base
_name
= base
967 self
.local_members
= local_members
968 self
.variants
= variants
971 def check(self
, schema
):
972 assert self
.members
is not False # not running in cycles
975 self
.members
= False # mark as being checked
978 self
.base
= schema
.lookup_type(self
._base
_name
)
979 assert isinstance(self
.base
, QAPISchemaObjectType
)
980 self
.base
.check(schema
)
981 self
.base
.check_clash(schema
, self
.info
, seen
)
982 for m
in self
.local_members
:
984 m
.check_clash(self
.info
, seen
)
985 self
.members
= seen
.values()
987 self
.variants
.check(schema
, seen
)
988 assert self
.variants
.tag_member
in self
.members
989 self
.variants
.check_clash(schema
, self
.info
, seen
)
991 # Check that the members of this type do not cause duplicate JSON fields,
992 # and update seen to track the members seen so far. Report any errors
993 # on behalf of info, which is not necessarily self.info
994 def check_clash(self
, schema
, info
, seen
):
995 assert not self
.variants
# not implemented
996 for m
in self
.members
:
997 m
.check_clash(info
, seen
)
999 def is_implicit(self
):
1000 # See QAPISchema._make_implicit_object_type()
1001 return self
.name
[0] == ':'
1004 assert not self
.is_implicit()
1005 return QAPISchemaType
.c_name(self
)
1007 def c_type(self
, is_param
=False):
1008 assert not self
.is_implicit()
1009 return QAPISchemaType
.c_type(self
)
1011 def json_type(self
):
1014 def visit(self
, visitor
):
1015 visitor
.visit_object_type(self
.name
, self
.info
,
1016 self
.base
, self
.local_members
, self
.variants
)
1017 visitor
.visit_object_type_flat(self
.name
, self
.info
,
1018 self
.members
, self
.variants
)
1021 class QAPISchemaObjectTypeMember(object):
1024 def __init__(self
, name
, typ
, optional
):
1025 assert isinstance(name
, str)
1026 assert isinstance(typ
, str)
1027 assert isinstance(optional
, bool)
1029 self
._type
_name
= typ
1031 self
.optional
= optional
1034 def set_owner(self
, name
):
1035 assert not self
.owner
1038 def check(self
, schema
):
1040 self
.type = schema
.lookup_type(self
._type
_name
)
1043 def check_clash(self
, info
, seen
):
1044 cname
= c_name(self
.name
)
1046 raise QAPIExprError(info
,
1047 "%s collides with %s"
1048 % (self
.describe(), seen
[cname
].describe()))
1051 def _pretty_owner(self
):
1053 if owner
.startswith(':obj-'):
1054 # See QAPISchema._make_implicit_object_type() - reverse the
1055 # mapping there to create a nice human-readable description
1057 if owner
.endswith('-arg'):
1058 return '(parameter of %s)' % owner
[:-4]
1060 assert owner
.endswith('-wrapper')
1061 # Unreachable and not implemented
1063 return '(%s of %s)' % (self
.role
, owner
)
1066 return "'%s' %s" % (self
.name
, self
._pretty
_owner
())
1069 class QAPISchemaObjectTypeVariants(object):
1070 def __init__(self
, tag_name
, tag_member
, variants
):
1071 # Flat unions pass tag_name but not tag_member.
1072 # Simple unions and alternates pass tag_member but not tag_name.
1073 # After check(), tag_member is always set, and tag_name remains
1074 # a reliable witness of being used by a flat union.
1075 assert bool(tag_member
) != bool(tag_name
)
1076 assert (isinstance(tag_name
, str) or
1077 isinstance(tag_member
, QAPISchemaObjectTypeMember
))
1079 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1080 self
.tag_name
= tag_name
1081 self
.tag_member
= tag_member
1082 self
.variants
= variants
1084 def set_owner(self
, name
):
1085 for v
in self
.variants
:
1088 def check(self
, schema
, seen
):
1089 if not self
.tag_member
: # flat union
1090 self
.tag_member
= seen
[c_name(self
.tag_name
)]
1091 assert self
.tag_name
== self
.tag_member
.name
1092 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1093 for v
in self
.variants
:
1095 assert v
.name
in self
.tag_member
.type.values
1096 if isinstance(v
.type, QAPISchemaObjectType
):
1097 v
.type.check(schema
)
1099 def check_clash(self
, schema
, info
, seen
):
1100 for v
in self
.variants
:
1101 # Reset seen map for each variant, since qapi names from one
1102 # branch do not affect another branch
1103 assert isinstance(v
.type, QAPISchemaObjectType
)
1104 v
.type.check_clash(schema
, info
, dict(seen
))
1107 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1110 def __init__(self
, name
, typ
):
1111 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1113 # This function exists to support ugly simple union special cases
1114 # TODO get rid of them, and drop the function
1115 def simple_union_type(self
):
1116 if (self
.type.is_implicit() and
1117 isinstance(self
.type, QAPISchemaObjectType
)):
1118 assert len(self
.type.members
) == 1
1119 assert not self
.type.variants
1120 return self
.type.members
[0].type
1124 class QAPISchemaAlternateType(QAPISchemaType
):
1125 def __init__(self
, name
, info
, variants
):
1126 QAPISchemaType
.__init
__(self
, name
, info
)
1127 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1128 assert not variants
.tag_name
1129 variants
.set_owner(name
)
1130 variants
.tag_member
.set_owner(self
.name
)
1131 self
.variants
= variants
1133 def check(self
, schema
):
1134 self
.variants
.tag_member
.check(schema
)
1135 # Not calling self.variants.check_clash(), because there's nothing
1137 self
.variants
.check(schema
, {})
1139 def json_type(self
):
1142 def visit(self
, visitor
):
1143 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1146 class QAPISchemaCommand(QAPISchemaEntity
):
1147 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1148 QAPISchemaEntity
.__init
__(self
, name
, info
)
1149 assert not arg_type
or isinstance(arg_type
, str)
1150 assert not ret_type
or isinstance(ret_type
, str)
1151 self
._arg
_type
_name
= arg_type
1152 self
.arg_type
= None
1153 self
._ret
_type
_name
= ret_type
1154 self
.ret_type
= None
1156 self
.success_response
= success_response
1158 def check(self
, schema
):
1159 if self
._arg
_type
_name
:
1160 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1161 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1162 assert not self
.arg_type
.variants
# not implemented
1163 if self
._ret
_type
_name
:
1164 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1165 assert isinstance(self
.ret_type
, QAPISchemaType
)
1167 def visit(self
, visitor
):
1168 visitor
.visit_command(self
.name
, self
.info
,
1169 self
.arg_type
, self
.ret_type
,
1170 self
.gen
, self
.success_response
)
1173 class QAPISchemaEvent(QAPISchemaEntity
):
1174 def __init__(self
, name
, info
, arg_type
):
1175 QAPISchemaEntity
.__init
__(self
, name
, info
)
1176 assert not arg_type
or isinstance(arg_type
, str)
1177 self
._arg
_type
_name
= arg_type
1178 self
.arg_type
= None
1180 def check(self
, schema
):
1181 if self
._arg
_type
_name
:
1182 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1183 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1184 assert not self
.arg_type
.variants
# not implemented
1186 def visit(self
, visitor
):
1187 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1190 class QAPISchema(object):
1191 def __init__(self
, fname
):
1193 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1194 self
._entity
_dict
= {}
1195 self
._predefining
= True
1196 self
._def
_predefineds
()
1197 self
._predefining
= False
1200 except (QAPISchemaError
, QAPIExprError
), err
:
1201 print >>sys
.stderr
, err
1204 def _def_entity(self
, ent
):
1205 # Only the predefined types are allowed to not have info
1206 assert ent
.info
or self
._predefining
1207 assert ent
.name
not in self
._entity
_dict
1208 self
._entity
_dict
[ent
.name
] = ent
1210 def lookup_entity(self
, name
, typ
=None):
1211 ent
= self
._entity
_dict
.get(name
)
1212 if typ
and not isinstance(ent
, typ
):
1216 def lookup_type(self
, name
):
1217 return self
.lookup_entity(name
, QAPISchemaType
)
1219 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1220 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
1222 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1223 # qapi-types.h from a single .c, all arrays of builtins must be
1224 # declared in the first file whether or not they are used. Nicer
1225 # would be to use lazy instantiation, while figuring out how to
1226 # avoid compilation issues with multiple qapi-types.h.
1227 self
._make
_array
_type
(name
, None)
1229 def _def_predefineds(self
):
1230 for t
in [('str', 'string', 'char' + pointer_suffix
, 'NULL'),
1231 ('number', 'number', 'double', '0'),
1232 ('int', 'int', 'int64_t', '0'),
1233 ('int8', 'int', 'int8_t', '0'),
1234 ('int16', 'int', 'int16_t', '0'),
1235 ('int32', 'int', 'int32_t', '0'),
1236 ('int64', 'int', 'int64_t', '0'),
1237 ('uint8', 'int', 'uint8_t', '0'),
1238 ('uint16', 'int', 'uint16_t', '0'),
1239 ('uint32', 'int', 'uint32_t', '0'),
1240 ('uint64', 'int', 'uint64_t', '0'),
1241 ('size', 'int', 'uint64_t', '0'),
1242 ('bool', 'boolean', 'bool', 'false'),
1243 ('any', 'value', 'QObject' + pointer_suffix
, 'NULL')]:
1244 self
._def
_builtin
_type
(*t
)
1245 self
.the_empty_object_type
= QAPISchemaObjectType(':empty', None, None,
1247 self
._def
_entity
(self
.the_empty_object_type
)
1248 self
._def
_entity
(QAPISchemaEnumType('QType', None,
1249 ['none', 'qnull', 'qint',
1250 'qstring', 'qdict', 'qlist',
1254 def _make_implicit_enum_type(self
, name
, info
, values
):
1255 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1256 self
._def
_entity
(QAPISchemaEnumType(name
, info
, values
, None))
1259 def _make_array_type(self
, element_type
, info
):
1260 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1261 if not self
.lookup_type(name
):
1262 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1265 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1268 # See also QAPISchemaObjectTypeMember._pretty_owner()
1269 name
= ':obj-%s-%s' % (name
, role
)
1270 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1271 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1275 def _def_enum_type(self
, expr
, info
):
1278 prefix
= expr
.get('prefix')
1279 self
._def
_entity
(QAPISchemaEnumType(name
, info
, data
, prefix
))
1281 def _make_member(self
, name
, typ
, info
):
1283 if name
.startswith('*'):
1286 if isinstance(typ
, list):
1287 assert len(typ
) == 1
1288 typ
= self
._make
_array
_type
(typ
[0], info
)
1289 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1291 def _make_members(self
, data
, info
):
1292 return [self
._make
_member
(key
, value
, info
)
1293 for (key
, value
) in data
.iteritems()]
1295 def _def_struct_type(self
, expr
, info
):
1296 name
= expr
['struct']
1297 base
= expr
.get('base')
1299 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1300 self
._make
_members
(data
, info
),
1303 def _make_variant(self
, case
, typ
):
1304 return QAPISchemaObjectTypeVariant(case
, typ
)
1306 def _make_simple_variant(self
, case
, typ
, info
):
1307 if isinstance(typ
, list):
1308 assert len(typ
) == 1
1309 typ
= self
._make
_array
_type
(typ
[0], info
)
1310 typ
= self
._make
_implicit
_object
_type
(
1311 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1312 return QAPISchemaObjectTypeVariant(case
, typ
)
1314 def _make_implicit_tag(self
, type_name
, info
, variants
):
1315 typ
= self
._make
_implicit
_enum
_type
(type_name
, info
,
1316 [v
.name
for v
in variants
])
1317 return QAPISchemaObjectTypeMember('type', typ
, False)
1319 def _def_union_type(self
, expr
, info
):
1320 name
= expr
['union']
1322 base
= expr
.get('base')
1323 tag_name
= expr
.get('discriminator')
1326 variants
= [self
._make
_variant
(key
, value
)
1327 for (key
, value
) in data
.iteritems()]
1330 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1331 for (key
, value
) in data
.iteritems()]
1332 tag_member
= self
._make
_implicit
_tag
(name
, info
, variants
)
1333 members
= [tag_member
]
1335 QAPISchemaObjectType(name
, info
, base
, members
,
1336 QAPISchemaObjectTypeVariants(tag_name
,
1340 def _def_alternate_type(self
, expr
, info
):
1341 name
= expr
['alternate']
1343 variants
= [self
._make
_variant
(key
, value
)
1344 for (key
, value
) in data
.iteritems()]
1345 tag_member
= self
._make
_implicit
_tag
(name
, info
, variants
)
1347 QAPISchemaAlternateType(name
, info
,
1348 QAPISchemaObjectTypeVariants(None,
1352 def _def_command(self
, expr
, info
):
1353 name
= expr
['command']
1354 data
= expr
.get('data')
1355 rets
= expr
.get('returns')
1356 gen
= expr
.get('gen', True)
1357 success_response
= expr
.get('success-response', True)
1358 if isinstance(data
, OrderedDict
):
1359 data
= self
._make
_implicit
_object
_type
(
1360 name
, info
, 'arg', self
._make
_members
(data
, info
))
1361 if isinstance(rets
, list):
1362 assert len(rets
) == 1
1363 rets
= self
._make
_array
_type
(rets
[0], info
)
1364 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1367 def _def_event(self
, expr
, info
):
1368 name
= expr
['event']
1369 data
= expr
.get('data')
1370 if isinstance(data
, OrderedDict
):
1371 data
= self
._make
_implicit
_object
_type
(
1372 name
, info
, 'arg', self
._make
_members
(data
, info
))
1373 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1375 def _def_exprs(self
):
1376 for expr_elem
in self
.exprs
:
1377 expr
= expr_elem
['expr']
1378 info
= expr_elem
['info']
1380 self
._def
_enum
_type
(expr
, info
)
1381 elif 'struct' in expr
:
1382 self
._def
_struct
_type
(expr
, info
)
1383 elif 'union' in expr
:
1384 self
._def
_union
_type
(expr
, info
)
1385 elif 'alternate' in expr
:
1386 self
._def
_alternate
_type
(expr
, info
)
1387 elif 'command' in expr
:
1388 self
._def
_command
(expr
, info
)
1389 elif 'event' in expr
:
1390 self
._def
_event
(expr
, info
)
1395 for ent
in self
._entity
_dict
.values():
1398 def visit(self
, visitor
):
1399 visitor
.visit_begin(self
)
1400 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1401 if visitor
.visit_needed(entity
):
1402 entity
.visit(visitor
)
1407 # Code generation helpers
1410 def camel_case(name
):
1414 if ch
in ['_', '-']:
1417 new_name
+= ch
.upper()
1420 new_name
+= ch
.lower()
1424 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1425 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1426 # ENUM24_Name -> ENUM24_NAME
1427 def camel_to_upper(value
):
1428 c_fun_str
= c_name(value
, False)
1436 # When c is upper and no "_" appears before, do more checks
1437 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1438 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1440 elif c_fun_str
[i
- 1].isdigit():
1443 return new_name
.lstrip('_').upper()
1446 def c_enum_const(type_name
, const_name
, prefix
=None):
1447 if prefix
is not None:
1449 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1451 c_name_trans
= string
.maketrans('.-', '__')
1454 # Map @name to a valid C identifier.
1455 # If @protect, avoid returning certain ticklish identifiers (like
1456 # C keywords) by prepending "q_".
1458 # Used for converting 'name' from a 'name':'type' qapi definition
1459 # into a generated struct member, as well as converting type names
1460 # into substrings of a generated C function name.
1461 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1462 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1463 def c_name(name
, protect
=True):
1464 # ANSI X3J11/88-090, 3.1.1
1465 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1466 'default', 'do', 'double', 'else', 'enum', 'extern',
1467 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1468 'return', 'short', 'signed', 'sizeof', 'static',
1469 'struct', 'switch', 'typedef', 'union', 'unsigned',
1470 'void', 'volatile', 'while'])
1471 # ISO/IEC 9899:1999, 6.4.1
1472 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1473 # ISO/IEC 9899:2011, 6.4.1
1474 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1475 '_Noreturn', '_Static_assert', '_Thread_local'])
1476 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1478 gcc_words
= set(['asm', 'typeof'])
1479 # C++ ISO/IEC 14882:2003 2.11
1480 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1481 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1482 'namespace', 'new', 'operator', 'private', 'protected',
1483 'public', 'reinterpret_cast', 'static_cast', 'template',
1484 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1485 'using', 'virtual', 'wchar_t',
1486 # alternative representations
1487 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1488 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1489 # namespace pollution:
1490 polluted_words
= set(['unix', 'errno'])
1491 name
= name
.translate(c_name_trans
)
1492 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1493 | cpp_words | polluted_words
):
1497 eatspace
= '\033EATSPACE.'
1498 pointer_suffix
= ' *' + eatspace
1501 def genindent(count
):
1503 for _
in range(count
):
1510 def push_indent(indent_amount
=4):
1512 indent_level
+= indent_amount
1515 def pop_indent(indent_amount
=4):
1517 indent_level
-= indent_amount
1520 # Generate @code with @kwds interpolated.
1521 # Obey indent_level, and strip eatspace.
1522 def cgen(code
, **kwds
):
1525 indent
= genindent(indent_level
)
1526 # re.subn() lacks flags support before Python 2.7, use re.compile()
1527 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1528 indent
+ r
'\g<0>', raw
)
1530 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1533 def mcgen(code
, **kwds
):
1536 return cgen(code
, **kwds
)
1539 def guardname(filename
):
1540 return c_name(filename
, protect
=False).upper()
1543 def guardstart(name
):
1550 name
=guardname(name
))
1556 #endif /* %(name)s */
1559 name
=guardname(name
))
1562 def gen_enum_lookup(name
, values
, prefix
=None):
1565 const char *const %(c_name)s_lookup[] = {
1567 c_name
=c_name(name
))
1568 for value
in values
:
1569 index
= c_enum_const(name
, value
, prefix
)
1571 [%(index)s] = "%(value)s",
1573 index
=index
, value
=value
)
1575 max_index
= c_enum_const(name
, '_MAX', prefix
)
1577 [%(max_index)s] = NULL,
1580 max_index
=max_index
)
1584 def gen_enum(name
, values
, prefix
=None):
1585 # append automatically generated _MAX value
1586 enum_values
= values
+ ['_MAX']
1590 typedef enum %(c_name)s {
1592 c_name
=c_name(name
))
1595 for value
in enum_values
:
1599 c_enum
=c_enum_const(name
, value
, prefix
),
1606 c_name
=c_name(name
))
1610 extern const char *const %(c_name)s_lookup[];
1612 c_name
=c_name(name
))
1616 def gen_params(arg_type
, extra
):
1619 assert not arg_type
.variants
1622 for memb
in arg_type
.members
:
1626 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1627 ret
+= '%s %s' % (memb
.type.c_type(is_param
=True), c_name(memb
.name
))
1633 def gen_err_check(label
='out', skiperr
=False):
1644 def gen_visit_fields(members
, prefix
='', need_cast
=False, skiperr
=False):
1651 for memb
in members
:
1654 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1656 prefix
=prefix
, c_name
=c_name(memb
.name
),
1657 name
=memb
.name
, errp
=errparg
)
1658 ret
+= gen_err_check(skiperr
=skiperr
)
1660 if (%(prefix)shas_%(c_name)s) {
1662 prefix
=prefix
, c_name
=c_name(memb
.name
))
1665 # Ugly: sometimes we need to cast away const
1666 if need_cast
and memb
.type.name
== 'str':
1672 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1674 c_type
=memb
.type.c_name(), prefix
=prefix
, cast
=cast
,
1675 c_name
=c_name(memb
.name
), name
=memb
.name
,
1677 ret
+= gen_err_check(skiperr
=skiperr
)
1688 # Common command line parsing
1692 def parse_command_line(extra_options
="", extra_long_options
=[]):
1695 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1696 "chp:o:" + extra_options
,
1697 ["source", "header", "prefix=",
1698 "output-dir="] + extra_long_options
)
1699 except getopt
.GetoptError
, err
:
1700 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1711 if o
in ("-p", "--prefix"):
1712 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1713 if match
.end() != len(a
):
1714 print >>sys
.stderr
, \
1715 "%s: 'funny character '%s' in argument of --prefix" \
1716 % (sys
.argv
[0], a
[match
.end()])
1719 elif o
in ("-o", "--output-dir"):
1720 output_dir
= a
+ "/"
1721 elif o
in ("-c", "--source"):
1723 elif o
in ("-h", "--header"):
1726 extra_opts
.append(oa
)
1728 if not do_c
and not do_h
:
1733 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1737 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1740 # Generate output files with boilerplate
1744 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1745 c_comment
, h_comment
):
1746 guard
= guardname(prefix
+ h_file
)
1747 c_file
= output_dir
+ prefix
+ c_file
1748 h_file
= output_dir
+ prefix
+ h_file
1752 os
.makedirs(output_dir
)
1754 if e
.errno
!= errno
.EEXIST
:
1757 def maybe_open(really
, name
, opt
):
1759 return open(name
, opt
)
1762 return StringIO
.StringIO()
1764 fdef
= maybe_open(do_c
, c_file
, 'w')
1765 fdecl
= maybe_open(do_h
, h_file
, 'w')
1767 fdef
.write(mcgen('''
1768 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1773 fdecl
.write(mcgen('''
1774 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1780 comment
=h_comment
, guard
=guard
))
1782 return (fdef
, fdecl
)
1785 def close_output(fdef
, fdecl
):