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 branch names
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 # Union names must match enum values; alternate names are
1096 # checked separately. Use 'seen' to tell the two apart.
1098 assert v
.name
in self
.tag_member
.type.values
1099 assert isinstance(v
.type, QAPISchemaObjectType
)
1100 v
.type.check(schema
)
1102 def check_clash(self
, schema
, info
, seen
):
1103 for v
in self
.variants
:
1104 # Reset seen map for each variant, since qapi names from one
1105 # branch do not affect another branch
1106 assert isinstance(v
.type, QAPISchemaObjectType
)
1107 v
.type.check_clash(schema
, info
, dict(seen
))
1110 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1113 def __init__(self
, name
, typ
):
1114 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1116 # This function exists to support ugly simple union special cases
1117 # TODO get rid of them, and drop the function
1118 def simple_union_type(self
):
1119 if (self
.type.is_implicit() and
1120 isinstance(self
.type, QAPISchemaObjectType
)):
1121 assert len(self
.type.members
) == 1
1122 assert not self
.type.variants
1123 return self
.type.members
[0].type
1127 class QAPISchemaAlternateType(QAPISchemaType
):
1128 def __init__(self
, name
, info
, variants
):
1129 QAPISchemaType
.__init
__(self
, name
, info
)
1130 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1131 assert not variants
.tag_name
1132 variants
.set_owner(name
)
1133 variants
.tag_member
.set_owner(self
.name
)
1134 self
.variants
= variants
1136 def check(self
, schema
):
1137 self
.variants
.tag_member
.check(schema
)
1138 # Not calling self.variants.check_clash(), because there's nothing
1140 self
.variants
.check(schema
, {})
1141 # Alternate branch names have no relation to the tag enum values;
1142 # so we have to check for potential name collisions ourselves.
1144 for v
in self
.variants
.variants
:
1145 v
.check_clash(self
.info
, seen
)
1147 def json_type(self
):
1150 def visit(self
, visitor
):
1151 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1154 class QAPISchemaCommand(QAPISchemaEntity
):
1155 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1156 QAPISchemaEntity
.__init
__(self
, name
, info
)
1157 assert not arg_type
or isinstance(arg_type
, str)
1158 assert not ret_type
or isinstance(ret_type
, str)
1159 self
._arg
_type
_name
= arg_type
1160 self
.arg_type
= None
1161 self
._ret
_type
_name
= ret_type
1162 self
.ret_type
= None
1164 self
.success_response
= success_response
1166 def check(self
, schema
):
1167 if self
._arg
_type
_name
:
1168 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1169 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1170 assert not self
.arg_type
.variants
# not implemented
1171 if self
._ret
_type
_name
:
1172 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1173 assert isinstance(self
.ret_type
, QAPISchemaType
)
1175 def visit(self
, visitor
):
1176 visitor
.visit_command(self
.name
, self
.info
,
1177 self
.arg_type
, self
.ret_type
,
1178 self
.gen
, self
.success_response
)
1181 class QAPISchemaEvent(QAPISchemaEntity
):
1182 def __init__(self
, name
, info
, arg_type
):
1183 QAPISchemaEntity
.__init
__(self
, name
, info
)
1184 assert not arg_type
or isinstance(arg_type
, str)
1185 self
._arg
_type
_name
= arg_type
1186 self
.arg_type
= None
1188 def check(self
, schema
):
1189 if self
._arg
_type
_name
:
1190 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1191 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1192 assert not self
.arg_type
.variants
# not implemented
1194 def visit(self
, visitor
):
1195 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1198 class QAPISchema(object):
1199 def __init__(self
, fname
):
1201 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1202 self
._entity
_dict
= {}
1203 self
._predefining
= True
1204 self
._def
_predefineds
()
1205 self
._predefining
= False
1208 except (QAPISchemaError
, QAPIExprError
), err
:
1209 print >>sys
.stderr
, err
1212 def _def_entity(self
, ent
):
1213 # Only the predefined types are allowed to not have info
1214 assert ent
.info
or self
._predefining
1215 assert ent
.name
not in self
._entity
_dict
1216 self
._entity
_dict
[ent
.name
] = ent
1218 def lookup_entity(self
, name
, typ
=None):
1219 ent
= self
._entity
_dict
.get(name
)
1220 if typ
and not isinstance(ent
, typ
):
1224 def lookup_type(self
, name
):
1225 return self
.lookup_entity(name
, QAPISchemaType
)
1227 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1228 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
1230 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1231 # qapi-types.h from a single .c, all arrays of builtins must be
1232 # declared in the first file whether or not they are used. Nicer
1233 # would be to use lazy instantiation, while figuring out how to
1234 # avoid compilation issues with multiple qapi-types.h.
1235 self
._make
_array
_type
(name
, None)
1237 def _def_predefineds(self
):
1238 for t
in [('str', 'string', 'char' + pointer_suffix
, 'NULL'),
1239 ('number', 'number', 'double', '0'),
1240 ('int', 'int', 'int64_t', '0'),
1241 ('int8', 'int', 'int8_t', '0'),
1242 ('int16', 'int', 'int16_t', '0'),
1243 ('int32', 'int', 'int32_t', '0'),
1244 ('int64', 'int', 'int64_t', '0'),
1245 ('uint8', 'int', 'uint8_t', '0'),
1246 ('uint16', 'int', 'uint16_t', '0'),
1247 ('uint32', 'int', 'uint32_t', '0'),
1248 ('uint64', 'int', 'uint64_t', '0'),
1249 ('size', 'int', 'uint64_t', '0'),
1250 ('bool', 'boolean', 'bool', 'false'),
1251 ('any', 'value', 'QObject' + pointer_suffix
, 'NULL')]:
1252 self
._def
_builtin
_type
(*t
)
1253 self
.the_empty_object_type
= QAPISchemaObjectType(':empty', None, None,
1255 self
._def
_entity
(self
.the_empty_object_type
)
1256 self
._def
_entity
(QAPISchemaEnumType('QType', None,
1257 ['none', 'qnull', 'qint',
1258 'qstring', 'qdict', 'qlist',
1262 def _make_implicit_enum_type(self
, name
, info
, values
):
1263 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1264 self
._def
_entity
(QAPISchemaEnumType(name
, info
, values
, None))
1267 def _make_array_type(self
, element_type
, info
):
1268 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1269 if not self
.lookup_type(name
):
1270 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1273 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1276 # See also QAPISchemaObjectTypeMember._pretty_owner()
1277 name
= ':obj-%s-%s' % (name
, role
)
1278 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1279 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1283 def _def_enum_type(self
, expr
, info
):
1286 prefix
= expr
.get('prefix')
1287 self
._def
_entity
(QAPISchemaEnumType(name
, info
, data
, prefix
))
1289 def _make_member(self
, name
, typ
, info
):
1291 if name
.startswith('*'):
1294 if isinstance(typ
, list):
1295 assert len(typ
) == 1
1296 typ
= self
._make
_array
_type
(typ
[0], info
)
1297 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1299 def _make_members(self
, data
, info
):
1300 return [self
._make
_member
(key
, value
, info
)
1301 for (key
, value
) in data
.iteritems()]
1303 def _def_struct_type(self
, expr
, info
):
1304 name
= expr
['struct']
1305 base
= expr
.get('base')
1307 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1308 self
._make
_members
(data
, info
),
1311 def _make_variant(self
, case
, typ
):
1312 return QAPISchemaObjectTypeVariant(case
, typ
)
1314 def _make_simple_variant(self
, case
, typ
, info
):
1315 if isinstance(typ
, list):
1316 assert len(typ
) == 1
1317 typ
= self
._make
_array
_type
(typ
[0], info
)
1318 typ
= self
._make
_implicit
_object
_type
(
1319 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1320 return QAPISchemaObjectTypeVariant(case
, typ
)
1322 def _def_union_type(self
, expr
, info
):
1323 name
= expr
['union']
1325 base
= expr
.get('base')
1326 tag_name
= expr
.get('discriminator')
1329 variants
= [self
._make
_variant
(key
, value
)
1330 for (key
, value
) in data
.iteritems()]
1333 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1334 for (key
, value
) in data
.iteritems()]
1335 typ
= self
._make
_implicit
_enum
_type
(name
, info
,
1336 [v
.name
for v
in variants
])
1337 tag_member
= QAPISchemaObjectTypeMember('type', typ
, False)
1338 members
= [tag_member
]
1340 QAPISchemaObjectType(name
, info
, base
, members
,
1341 QAPISchemaObjectTypeVariants(tag_name
,
1345 def _def_alternate_type(self
, expr
, info
):
1346 name
= expr
['alternate']
1348 variants
= [self
._make
_variant
(key
, value
)
1349 for (key
, value
) in data
.iteritems()]
1350 tag_member
= QAPISchemaObjectTypeMember('type', 'QType', False)
1352 QAPISchemaAlternateType(name
, info
,
1353 QAPISchemaObjectTypeVariants(None,
1357 def _def_command(self
, expr
, info
):
1358 name
= expr
['command']
1359 data
= expr
.get('data')
1360 rets
= expr
.get('returns')
1361 gen
= expr
.get('gen', True)
1362 success_response
= expr
.get('success-response', True)
1363 if isinstance(data
, OrderedDict
):
1364 data
= self
._make
_implicit
_object
_type
(
1365 name
, info
, 'arg', self
._make
_members
(data
, info
))
1366 if isinstance(rets
, list):
1367 assert len(rets
) == 1
1368 rets
= self
._make
_array
_type
(rets
[0], info
)
1369 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1372 def _def_event(self
, expr
, info
):
1373 name
= expr
['event']
1374 data
= expr
.get('data')
1375 if isinstance(data
, OrderedDict
):
1376 data
= self
._make
_implicit
_object
_type
(
1377 name
, info
, 'arg', self
._make
_members
(data
, info
))
1378 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1380 def _def_exprs(self
):
1381 for expr_elem
in self
.exprs
:
1382 expr
= expr_elem
['expr']
1383 info
= expr_elem
['info']
1385 self
._def
_enum
_type
(expr
, info
)
1386 elif 'struct' in expr
:
1387 self
._def
_struct
_type
(expr
, info
)
1388 elif 'union' in expr
:
1389 self
._def
_union
_type
(expr
, info
)
1390 elif 'alternate' in expr
:
1391 self
._def
_alternate
_type
(expr
, info
)
1392 elif 'command' in expr
:
1393 self
._def
_command
(expr
, info
)
1394 elif 'event' in expr
:
1395 self
._def
_event
(expr
, info
)
1400 for ent
in self
._entity
_dict
.values():
1403 def visit(self
, visitor
):
1404 visitor
.visit_begin(self
)
1405 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1406 if visitor
.visit_needed(entity
):
1407 entity
.visit(visitor
)
1412 # Code generation helpers
1415 def camel_case(name
):
1419 if ch
in ['_', '-']:
1422 new_name
+= ch
.upper()
1425 new_name
+= ch
.lower()
1429 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1430 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1431 # ENUM24_Name -> ENUM24_NAME
1432 def camel_to_upper(value
):
1433 c_fun_str
= c_name(value
, False)
1441 # When c is upper and no "_" appears before, do more checks
1442 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1443 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1445 elif c_fun_str
[i
- 1].isdigit():
1448 return new_name
.lstrip('_').upper()
1451 def c_enum_const(type_name
, const_name
, prefix
=None):
1452 if prefix
is not None:
1454 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1456 c_name_trans
= string
.maketrans('.-', '__')
1459 # Map @name to a valid C identifier.
1460 # If @protect, avoid returning certain ticklish identifiers (like
1461 # C keywords) by prepending "q_".
1463 # Used for converting 'name' from a 'name':'type' qapi definition
1464 # into a generated struct member, as well as converting type names
1465 # into substrings of a generated C function name.
1466 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1467 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1468 def c_name(name
, protect
=True):
1469 # ANSI X3J11/88-090, 3.1.1
1470 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1471 'default', 'do', 'double', 'else', 'enum', 'extern',
1472 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1473 'return', 'short', 'signed', 'sizeof', 'static',
1474 'struct', 'switch', 'typedef', 'union', 'unsigned',
1475 'void', 'volatile', 'while'])
1476 # ISO/IEC 9899:1999, 6.4.1
1477 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1478 # ISO/IEC 9899:2011, 6.4.1
1479 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1480 '_Noreturn', '_Static_assert', '_Thread_local'])
1481 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1483 gcc_words
= set(['asm', 'typeof'])
1484 # C++ ISO/IEC 14882:2003 2.11
1485 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1486 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1487 'namespace', 'new', 'operator', 'private', 'protected',
1488 'public', 'reinterpret_cast', 'static_cast', 'template',
1489 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1490 'using', 'virtual', 'wchar_t',
1491 # alternative representations
1492 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1493 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1494 # namespace pollution:
1495 polluted_words
= set(['unix', 'errno'])
1496 name
= name
.translate(c_name_trans
)
1497 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1498 | cpp_words | polluted_words
):
1502 eatspace
= '\033EATSPACE.'
1503 pointer_suffix
= ' *' + eatspace
1506 def genindent(count
):
1508 for _
in range(count
):
1515 def push_indent(indent_amount
=4):
1517 indent_level
+= indent_amount
1520 def pop_indent(indent_amount
=4):
1522 indent_level
-= indent_amount
1525 # Generate @code with @kwds interpolated.
1526 # Obey indent_level, and strip eatspace.
1527 def cgen(code
, **kwds
):
1530 indent
= genindent(indent_level
)
1531 # re.subn() lacks flags support before Python 2.7, use re.compile()
1532 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1533 indent
+ r
'\g<0>', raw
)
1535 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1538 def mcgen(code
, **kwds
):
1541 return cgen(code
, **kwds
)
1544 def guardname(filename
):
1545 return c_name(filename
, protect
=False).upper()
1548 def guardstart(name
):
1555 name
=guardname(name
))
1561 #endif /* %(name)s */
1564 name
=guardname(name
))
1567 def gen_enum_lookup(name
, values
, prefix
=None):
1570 const char *const %(c_name)s_lookup[] = {
1572 c_name
=c_name(name
))
1573 for value
in values
:
1574 index
= c_enum_const(name
, value
, prefix
)
1576 [%(index)s] = "%(value)s",
1578 index
=index
, value
=value
)
1580 max_index
= c_enum_const(name
, '_MAX', prefix
)
1582 [%(max_index)s] = NULL,
1585 max_index
=max_index
)
1589 def gen_enum(name
, values
, prefix
=None):
1590 # append automatically generated _MAX value
1591 enum_values
= values
+ ['_MAX']
1595 typedef enum %(c_name)s {
1597 c_name
=c_name(name
))
1600 for value
in enum_values
:
1604 c_enum
=c_enum_const(name
, value
, prefix
),
1611 c_name
=c_name(name
))
1615 extern const char *const %(c_name)s_lookup[];
1617 c_name
=c_name(name
))
1621 def gen_params(arg_type
, extra
):
1624 assert not arg_type
.variants
1627 for memb
in arg_type
.members
:
1631 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1632 ret
+= '%s %s' % (memb
.type.c_type(is_param
=True), c_name(memb
.name
))
1638 def gen_err_check(label
='out', skiperr
=False):
1649 def gen_visit_fields(members
, prefix
='', need_cast
=False, skiperr
=False):
1656 for memb
in members
:
1659 visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s", %(errp)s);
1661 prefix
=prefix
, c_name
=c_name(memb
.name
),
1662 name
=memb
.name
, errp
=errparg
)
1663 ret
+= gen_err_check(skiperr
=skiperr
)
1665 if (%(prefix)shas_%(c_name)s) {
1667 prefix
=prefix
, c_name
=c_name(memb
.name
))
1670 # Ugly: sometimes we need to cast away const
1671 if need_cast
and memb
.type.name
== 'str':
1677 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1679 c_type
=memb
.type.c_name(), prefix
=prefix
, cast
=cast
,
1680 c_name
=c_name(memb
.name
), name
=memb
.name
,
1682 ret
+= gen_err_check(skiperr
=skiperr
)
1693 # Common command line parsing
1697 def parse_command_line(extra_options
="", extra_long_options
=[]):
1700 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1701 "chp:o:" + extra_options
,
1702 ["source", "header", "prefix=",
1703 "output-dir="] + extra_long_options
)
1704 except getopt
.GetoptError
, err
:
1705 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1716 if o
in ("-p", "--prefix"):
1717 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1718 if match
.end() != len(a
):
1719 print >>sys
.stderr
, \
1720 "%s: 'funny character '%s' in argument of --prefix" \
1721 % (sys
.argv
[0], a
[match
.end()])
1724 elif o
in ("-o", "--output-dir"):
1725 output_dir
= a
+ "/"
1726 elif o
in ("-c", "--source"):
1728 elif o
in ("-h", "--header"):
1731 extra_opts
.append(oa
)
1733 if not do_c
and not do_h
:
1738 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1742 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1745 # Generate output files with boilerplate
1749 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1750 c_comment
, h_comment
):
1751 guard
= guardname(prefix
+ h_file
)
1752 c_file
= output_dir
+ prefix
+ c_file
1753 h_file
= output_dir
+ prefix
+ h_file
1757 os
.makedirs(output_dir
)
1759 if e
.errno
!= errno
.EEXIST
:
1762 def maybe_open(really
, name
, opt
):
1764 return open(name
, opt
)
1767 return StringIO
.StringIO()
1769 fdef
= maybe_open(do_c
, c_file
, 'w')
1770 fdecl
= maybe_open(do_h
, h_file
, 'w')
1772 fdef
.write(mcgen('''
1773 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1778 fdecl
.write(mcgen('''
1779 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1785 comment
=h_comment
, guard
=guard
))
1787 return (fdef
, fdecl
)
1790 def close_output(fdef
, fdecl
):