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',
62 # Whitelist of entities allowed to violate case conventions
65 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status
66 'CpuInfoBase', # CPU, visible through query-cpu
67 'CpuInfoMIPS', # PC, visible through query-cpu
68 'CpuInfoTricore', # PC, visible through query-cpu
69 'InputAxis', # TODO: drop when x-input-send-event is fixed
70 'InputButton', # TODO: drop when x-input-send-event is fixed
71 'QapiErrorClass', # all members, visible through errors
72 'UuidInfo', # UUID, visible through query-uuid
73 'X86CPURegister32', # all members, visible indirectly through qom-get
83 # Parsing the schema into expressions
87 def error_path(parent
):
90 res
= ("In file included from %s:%d:\n" % (parent
['file'],
91 parent
['line'])) + res
92 parent
= parent
['parent']
96 class QAPISchemaError(Exception):
97 def __init__(self
, schema
, msg
):
98 Exception.__init
__(self
)
99 self
.fname
= schema
.fname
102 self
.line
= schema
.line
103 for ch
in schema
.src
[schema
.line_pos
:schema
.pos
]:
105 self
.col
= (self
.col
+ 7) % 8 + 1
108 self
.info
= schema
.incl_info
111 return error_path(self
.info
) + \
112 "%s:%d:%d: %s" % (self
.fname
, self
.line
, self
.col
, self
.msg
)
115 class QAPIExprError(Exception):
116 def __init__(self
, expr_info
, msg
):
117 Exception.__init
__(self
)
119 self
.info
= expr_info
123 return error_path(self
.info
['parent']) + \
124 "%s:%d: %s" % (self
.info
['file'], self
.info
['line'], self
.msg
)
127 class QAPISchemaParser(object):
129 def __init__(self
, fp
, previously_included
=[], incl_info
=None):
130 abs_fname
= os
.path
.abspath(fp
.name
)
133 previously_included
.append(abs_fname
)
134 self
.incl_info
= incl_info
136 if self
.src
== '' or self
.src
[-1] != '\n':
144 while self
.tok
is not None:
145 expr_info
= {'file': fname
, 'line': self
.line
,
146 'parent': self
.incl_info
}
147 expr
= self
.get_expr(False)
148 if isinstance(expr
, dict) and "include" in expr
:
150 raise QAPIExprError(expr_info
,
151 "Invalid 'include' directive")
152 include
= expr
["include"]
153 if not isinstance(include
, str):
154 raise QAPIExprError(expr_info
,
155 "Value of 'include' must be a string")
156 incl_abs_fname
= os
.path
.join(os
.path
.dirname(abs_fname
),
158 # catch inclusion cycle
161 if incl_abs_fname
== os
.path
.abspath(inf
['file']):
162 raise QAPIExprError(expr_info
, "Inclusion loop for %s"
165 # skip multiple include of the same file
166 if incl_abs_fname
in previously_included
:
169 fobj
= open(incl_abs_fname
, 'r')
171 raise QAPIExprError(expr_info
,
172 '%s: %s' % (e
.strerror
, include
))
173 exprs_include
= QAPISchemaParser(fobj
, previously_included
,
175 self
.exprs
.extend(exprs_include
.exprs
)
177 expr_elem
= {'expr': expr
,
179 self
.exprs
.append(expr_elem
)
183 self
.tok
= self
.src
[self
.cursor
]
184 self
.pos
= self
.cursor
189 self
.cursor
= self
.src
.find('\n', self
.cursor
)
190 elif self
.tok
in "{}:,[]":
192 elif self
.tok
== "'":
196 ch
= self
.src
[self
.cursor
]
199 raise QAPISchemaError(self
,
200 'Missing terminating "\'"')
214 for _
in range(0, 4):
215 ch
= self
.src
[self
.cursor
]
217 if ch
not in "0123456789abcdefABCDEF":
218 raise QAPISchemaError(self
,
219 '\\u escape needs 4 '
221 value
= (value
<< 4) + int(ch
, 16)
222 # If Python 2 and 3 didn't disagree so much on
223 # how to handle Unicode, then we could allow
224 # Unicode string defaults. But most of QAPI is
225 # ASCII-only, so we aren't losing much for now.
226 if not value
or value
> 0x7f:
227 raise QAPISchemaError(self
,
228 'For now, \\u escape '
229 'only supports non-zero '
230 'values up to \\u007f')
235 raise QAPISchemaError(self
,
236 "Unknown escape \\%s" % ch
)
245 elif self
.src
.startswith("true", self
.pos
):
249 elif self
.src
.startswith("false", self
.pos
):
253 elif self
.src
.startswith("null", self
.pos
):
257 elif self
.tok
== '\n':
258 if self
.cursor
== len(self
.src
):
262 self
.line_pos
= self
.cursor
263 elif not self
.tok
.isspace():
264 raise QAPISchemaError(self
, 'Stray "%s"' % self
.tok
)
266 def get_members(self
):
272 raise QAPISchemaError(self
, 'Expected string or "}"')
277 raise QAPISchemaError(self
, 'Expected ":"')
280 raise QAPISchemaError(self
, 'Duplicate key "%s"' % key
)
281 expr
[key
] = self
.get_expr(True)
286 raise QAPISchemaError(self
, 'Expected "," or "}"')
289 raise QAPISchemaError(self
, 'Expected string')
291 def get_values(self
):
296 if self
.tok
not in "{['tfn":
297 raise QAPISchemaError(self
, 'Expected "{", "[", "]", string, '
300 expr
.append(self
.get_expr(True))
305 raise QAPISchemaError(self
, 'Expected "," or "]"')
308 def get_expr(self
, nested
):
309 if self
.tok
!= '{' and not nested
:
310 raise QAPISchemaError(self
, 'Expected "{"')
313 expr
= self
.get_members()
314 elif self
.tok
== '[':
316 expr
= self
.get_values()
317 elif self
.tok
in "'tfn":
321 raise QAPISchemaError(self
, 'Expected "{", "[" or string')
325 # Semantic analysis of schema expressions
326 # TODO fold into QAPISchema
327 # TODO catching name collisions in generated code would be nice
331 def find_base_fields(base
):
332 base_struct_define
= find_struct(base
)
333 if not base_struct_define
:
335 return base_struct_define
['data']
338 # Return the qtype of an alternate branch, or None on error.
339 def find_alternate_member_qtype(qapi_type
):
340 if qapi_type
in builtin_types
:
341 return builtin_types
[qapi_type
]
342 elif find_struct(qapi_type
):
344 elif find_enum(qapi_type
):
345 return "QTYPE_QSTRING"
346 elif find_union(qapi_type
):
351 # Return the discriminator enum define if discriminator is specified as an
352 # enum type, otherwise return None.
353 def discriminator_find_enum_define(expr
):
354 base
= expr
.get('base')
355 discriminator
= expr
.get('discriminator')
357 if not (discriminator
and base
):
360 base_fields
= find_base_fields(base
)
364 discriminator_type
= base_fields
.get(discriminator
)
365 if not discriminator_type
:
368 return find_enum(discriminator_type
)
371 # Names must be letters, numbers, -, and _. They must start with letter,
372 # except for downstream extensions which must start with __RFQDN_.
373 # Dots are only valid in the downstream extension prefix.
374 valid_name
= re
.compile('^(__[a-zA-Z0-9.-]+_)?'
375 '[a-zA-Z][a-zA-Z0-9_-]*$')
378 def check_name(expr_info
, source
, name
, allow_optional
=False,
383 if not isinstance(name
, str):
384 raise QAPIExprError(expr_info
,
385 "%s requires a string name" % source
)
386 if name
.startswith('*'):
387 membername
= name
[1:]
388 if not allow_optional
:
389 raise QAPIExprError(expr_info
,
390 "%s does not allow optional name '%s'"
392 # Enum members can start with a digit, because the generated C
393 # code always prefixes it with the enum name
394 if enum_member
and membername
[0].isdigit():
395 membername
= 'D' + membername
396 # Reserve the entire 'q_' namespace for c_name()
397 if not valid_name
.match(membername
) or \
398 c_name(membername
, False).startswith('q_'):
399 raise QAPIExprError(expr_info
,
400 "%s uses invalid name '%s'" % (source
, name
))
403 def add_name(name
, info
, meta
, implicit
=False):
405 check_name(info
, "'%s'" % meta
, name
)
406 # FIXME should reject names that differ only in '_' vs. '.'
407 # vs. '-', because they're liable to clash in generated C.
408 if name
in all_names
:
409 raise QAPIExprError(info
,
410 "%s '%s' is already defined"
411 % (all_names
[name
], name
))
412 if not implicit
and (name
.endswith('Kind') or name
.endswith('List')):
413 raise QAPIExprError(info
,
414 "%s '%s' should not end in '%s'"
415 % (meta
, name
, name
[-4:]))
416 all_names
[name
] = meta
419 def add_struct(definition
, info
):
421 name
= definition
['struct']
422 add_name(name
, info
, 'struct')
423 struct_types
.append(definition
)
426 def find_struct(name
):
428 for struct
in struct_types
:
429 if struct
['struct'] == name
:
434 def add_union(definition
, info
):
436 name
= definition
['union']
437 add_name(name
, info
, 'union')
438 union_types
.append(definition
)
441 def find_union(name
):
443 for union
in union_types
:
444 if union
['union'] == name
:
449 def add_enum(name
, info
, enum_values
=None, implicit
=False):
451 add_name(name
, info
, 'enum', implicit
)
452 enum_types
.append({"enum_name": name
, "enum_values": enum_values
})
457 for enum
in enum_types
:
458 if enum
['enum_name'] == name
:
464 return find_enum(name
) is not None
467 def check_type(expr_info
, source
, value
, allow_array
=False,
468 allow_dict
=False, allow_optional
=False,
475 # Check if array type for value is okay
476 if isinstance(value
, list):
478 raise QAPIExprError(expr_info
,
479 "%s cannot be an array" % source
)
480 if len(value
) != 1 or not isinstance(value
[0], str):
481 raise QAPIExprError(expr_info
,
482 "%s: array type must contain single type name"
486 # Check if type name for value is okay
487 if isinstance(value
, str):
488 if value
not in all_names
:
489 raise QAPIExprError(expr_info
,
490 "%s uses unknown type '%s'"
492 if not all_names
[value
] in allow_metas
:
493 raise QAPIExprError(expr_info
,
494 "%s cannot use %s type '%s'"
495 % (source
, all_names
[value
], value
))
499 raise QAPIExprError(expr_info
,
500 "%s should be a type name" % source
)
502 if not isinstance(value
, OrderedDict
):
503 raise QAPIExprError(expr_info
,
504 "%s should be a dictionary or type name" % source
)
506 # value is a dictionary, check that each member is okay
507 for (key
, arg
) in value
.items():
508 check_name(expr_info
, "Member of %s" % source
, key
,
509 allow_optional
=allow_optional
)
510 if c_name(key
, False) == 'u' or c_name(key
, False).startswith('has_'):
511 raise QAPIExprError(expr_info
,
512 "Member of %s uses reserved name '%s'"
514 # Todo: allow dictionaries to represent default values of
515 # an optional argument.
516 check_type(expr_info
, "Member '%s' of %s" % (key
, source
), arg
,
518 allow_metas
=['built-in', 'union', 'alternate', 'struct',
522 def check_command(expr
, expr_info
):
523 name
= expr
['command']
525 check_type(expr_info
, "'data' for command '%s'" % name
,
526 expr
.get('data'), allow_dict
=True, allow_optional
=True,
527 allow_metas
=['struct'])
528 returns_meta
= ['union', 'struct']
529 if name
in returns_whitelist
:
530 returns_meta
+= ['built-in', 'alternate', 'enum']
531 check_type(expr_info
, "'returns' for command '%s'" % name
,
532 expr
.get('returns'), allow_array
=True,
533 allow_optional
=True, allow_metas
=returns_meta
)
536 def check_event(expr
, expr_info
):
541 check_type(expr_info
, "'data' for event '%s'" % name
,
542 expr
.get('data'), allow_dict
=True, allow_optional
=True,
543 allow_metas
=['struct'])
546 def check_union(expr
, expr_info
):
548 base
= expr
.get('base')
549 discriminator
= expr
.get('discriminator')
550 members
= expr
['data']
552 # Two types of unions, determined by discriminator.
554 # With no discriminator it is a simple union.
555 if discriminator
is None:
557 allow_metas
= ['built-in', 'union', 'alternate', 'struct', 'enum']
559 raise QAPIExprError(expr_info
,
560 "Simple union '%s' must not have a base"
563 # Else, it's a flat union.
565 # The object must have a string member 'base'.
566 check_type(expr_info
, "'base' for union '%s'" % name
,
567 base
, allow_metas
=['struct'])
569 raise QAPIExprError(expr_info
,
570 "Flat union '%s' must have a base"
572 base_fields
= find_base_fields(base
)
575 # The value of member 'discriminator' must name a non-optional
576 # member of the base struct.
577 check_name(expr_info
, "Discriminator of flat union '%s'" % name
,
579 discriminator_type
= base_fields
.get(discriminator
)
580 if not discriminator_type
:
581 raise QAPIExprError(expr_info
,
582 "Discriminator '%s' is not a member of base "
584 % (discriminator
, base
))
585 enum_define
= find_enum(discriminator_type
)
586 allow_metas
= ['struct']
587 # Do not allow string discriminator
589 raise QAPIExprError(expr_info
,
590 "Discriminator '%s' must be of enumeration "
591 "type" % discriminator
)
594 for (key
, value
) in members
.items():
595 check_name(expr_info
, "Member of union '%s'" % name
, key
)
597 # Each value must name a known type
598 check_type(expr_info
, "Member '%s' of union '%s'" % (key
, name
),
599 value
, allow_array
=not base
, allow_metas
=allow_metas
)
601 # If the discriminator names an enum type, then all members
602 # of 'data' must also be members of the enum type.
604 if key
not in enum_define
['enum_values']:
605 raise QAPIExprError(expr_info
,
606 "Discriminator value '%s' is not found in "
608 (key
, enum_define
["enum_name"]))
611 def check_alternate(expr
, expr_info
):
612 name
= expr
['alternate']
613 members
= expr
['data']
617 for (key
, value
) in members
.items():
618 check_name(expr_info
, "Member of alternate '%s'" % name
, key
)
620 # Ensure alternates have no type conflicts.
621 check_type(expr_info
, "Member '%s' of alternate '%s'" % (key
, name
),
623 allow_metas
=['built-in', 'union', 'struct', 'enum'])
624 qtype
= find_alternate_member_qtype(value
)
626 if qtype
in types_seen
:
627 raise QAPIExprError(expr_info
,
628 "Alternate '%s' member '%s' can't "
629 "be distinguished from member '%s'"
630 % (name
, key
, types_seen
[qtype
]))
631 types_seen
[qtype
] = key
634 def check_enum(expr
, expr_info
):
636 members
= expr
.get('data')
637 prefix
= expr
.get('prefix')
639 if not isinstance(members
, list):
640 raise QAPIExprError(expr_info
,
641 "Enum '%s' requires an array for 'data'" % name
)
642 if prefix
is not None and not isinstance(prefix
, str):
643 raise QAPIExprError(expr_info
,
644 "Enum '%s' requires a string for 'prefix'" % name
)
645 for member
in members
:
646 check_name(expr_info
, "Member of enum '%s'" % name
, member
,
650 def check_struct(expr
, expr_info
):
651 name
= expr
['struct']
652 members
= expr
['data']
654 check_type(expr_info
, "'data' for struct '%s'" % name
, members
,
655 allow_dict
=True, allow_optional
=True)
656 check_type(expr_info
, "'base' for struct '%s'" % name
, expr
.get('base'),
657 allow_metas
=['struct'])
660 def check_keys(expr_elem
, meta
, required
, optional
=[]):
661 expr
= expr_elem
['expr']
662 info
= expr_elem
['info']
664 if not isinstance(name
, str):
665 raise QAPIExprError(info
,
666 "'%s' key must have a string value" % meta
)
667 required
= required
+ [meta
]
668 for (key
, value
) in expr
.items():
669 if key
not in required
and key
not in optional
:
670 raise QAPIExprError(info
,
671 "Unknown key '%s' in %s '%s'"
673 if (key
== 'gen' or key
== 'success-response') and value
is not False:
674 raise QAPIExprError(info
,
675 "'%s' of %s '%s' should only use false value"
679 raise QAPIExprError(info
,
680 "Key '%s' is missing from %s '%s'"
684 def check_exprs(exprs
):
687 # Learn the types and check for valid expression keys
688 for builtin
in builtin_types
.keys():
689 all_names
[builtin
] = 'built-in'
690 for expr_elem
in exprs
:
691 expr
= expr_elem
['expr']
692 info
= expr_elem
['info']
694 check_keys(expr_elem
, 'enum', ['data'], ['prefix'])
695 add_enum(expr
['enum'], info
, expr
['data'])
696 elif 'union' in expr
:
697 check_keys(expr_elem
, 'union', ['data'],
698 ['base', 'discriminator'])
699 add_union(expr
, info
)
700 elif 'alternate' in expr
:
701 check_keys(expr_elem
, 'alternate', ['data'])
702 add_name(expr
['alternate'], info
, 'alternate')
703 elif 'struct' in expr
:
704 check_keys(expr_elem
, 'struct', ['data'], ['base'])
705 add_struct(expr
, info
)
706 elif 'command' in expr
:
707 check_keys(expr_elem
, 'command', [],
708 ['data', 'returns', 'gen', 'success-response'])
709 add_name(expr
['command'], info
, 'command')
710 elif 'event' in expr
:
711 check_keys(expr_elem
, 'event', [], ['data'])
712 add_name(expr
['event'], info
, 'event')
714 raise QAPIExprError(expr_elem
['info'],
715 "Expression is missing metatype")
717 # Try again for hidden UnionKind enum
718 for expr_elem
in exprs
:
719 expr
= expr_elem
['expr']
721 if not discriminator_find_enum_define(expr
):
722 add_enum('%sKind' % expr
['union'], expr_elem
['info'],
724 elif 'alternate' in expr
:
725 add_enum('%sKind' % expr
['alternate'], expr_elem
['info'],
728 # Validate that exprs make sense
729 for expr_elem
in exprs
:
730 expr
= expr_elem
['expr']
731 info
= expr_elem
['info']
734 check_enum(expr
, info
)
735 elif 'union' in expr
:
736 check_union(expr
, info
)
737 elif 'alternate' in expr
:
738 check_alternate(expr
, info
)
739 elif 'struct' in expr
:
740 check_struct(expr
, info
)
741 elif 'command' in expr
:
742 check_command(expr
, info
)
743 elif 'event' in expr
:
744 check_event(expr
, info
)
746 assert False, 'unexpected meta type'
752 # Schema compiler frontend
755 class QAPISchemaEntity(object):
756 def __init__(self
, name
, info
):
757 assert isinstance(name
, str)
759 # For explicitly defined entities, info points to the (explicit)
760 # definition. For builtins (and their arrays), info is None.
761 # For implicitly defined entities, info points to a place that
762 # triggered the implicit definition (there may be more than one
767 return c_name(self
.name
)
769 def check(self
, schema
):
772 def is_implicit(self
):
775 def visit(self
, visitor
):
779 class QAPISchemaVisitor(object):
780 def visit_begin(self
, schema
):
786 def visit_needed(self
, entity
):
787 # Default to visiting everything
790 def visit_builtin_type(self
, name
, info
, json_type
):
793 def visit_enum_type(self
, name
, info
, values
, prefix
):
796 def visit_array_type(self
, name
, info
, element_type
):
799 def visit_object_type(self
, name
, info
, base
, members
, variants
):
802 def visit_object_type_flat(self
, name
, info
, members
, variants
):
805 def visit_alternate_type(self
, name
, info
, variants
):
808 def visit_command(self
, name
, info
, arg_type
, ret_type
,
809 gen
, success_response
):
812 def visit_event(self
, name
, info
, arg_type
):
816 class QAPISchemaType(QAPISchemaEntity
):
817 def c_type(self
, is_param
=False):
818 return c_name(self
.name
) + pointer_suffix
826 def alternate_qtype(self
):
828 'string': 'QTYPE_QSTRING',
829 'number': 'QTYPE_QFLOAT',
831 'boolean': 'QTYPE_QBOOL',
832 'object': 'QTYPE_QDICT'
834 return json2qtype
.get(self
.json_type())
837 class QAPISchemaBuiltinType(QAPISchemaType
):
838 def __init__(self
, name
, json_type
, c_type
, c_null
):
839 QAPISchemaType
.__init
__(self
, name
, None)
840 assert not c_type
or isinstance(c_type
, str)
841 assert json_type
in ('string', 'number', 'int', 'boolean', 'null',
843 self
._json
_type
_name
= json_type
844 self
._c
_type
_name
= c_type
845 self
._c
_null
_val
= c_null
850 def c_type(self
, is_param
=False):
851 if is_param
and self
.name
== 'str':
852 return 'const ' + self
._c
_type
_name
853 return self
._c
_type
_name
856 return self
._c
_null
_val
859 return self
._json
_type
_name
861 def visit(self
, visitor
):
862 visitor
.visit_builtin_type(self
.name
, self
.info
, self
.json_type())
865 class QAPISchemaEnumType(QAPISchemaType
):
866 def __init__(self
, name
, info
, values
, prefix
):
867 QAPISchemaType
.__init
__(self
, name
, info
)
869 assert isinstance(v
, QAPISchemaMember
)
871 assert prefix
is None or isinstance(prefix
, str)
875 def check(self
, schema
):
877 for v
in self
.values
:
878 v
.check_clash(self
.info
, seen
)
880 def is_implicit(self
):
881 # See QAPISchema._make_implicit_enum_type()
882 return self
.name
.endswith('Kind')
884 def c_type(self
, is_param
=False):
885 return c_name(self
.name
)
887 def member_names(self
):
888 return [v
.name
for v
in self
.values
]
891 return c_enum_const(self
.name
, (self
.member_names() + ['_MAX'])[0],
897 def visit(self
, visitor
):
898 visitor
.visit_enum_type(self
.name
, self
.info
,
899 self
.member_names(), self
.prefix
)
902 class QAPISchemaArrayType(QAPISchemaType
):
903 def __init__(self
, name
, info
, element_type
):
904 QAPISchemaType
.__init
__(self
, name
, info
)
905 assert isinstance(element_type
, str)
906 self
._element
_type
_name
= element_type
907 self
.element_type
= None
909 def check(self
, schema
):
910 self
.element_type
= schema
.lookup_type(self
._element
_type
_name
)
911 assert self
.element_type
913 def is_implicit(self
):
919 def visit(self
, visitor
):
920 visitor
.visit_array_type(self
.name
, self
.info
, self
.element_type
)
923 class QAPISchemaObjectType(QAPISchemaType
):
924 def __init__(self
, name
, info
, base
, local_members
, variants
):
925 # struct has local_members, optional base, and no variants
926 # flat union has base, variants, and no local_members
927 # simple union has local_members, variants, and no base
928 QAPISchemaType
.__init
__(self
, name
, info
)
929 assert base
is None or isinstance(base
, str)
930 for m
in local_members
:
931 assert isinstance(m
, QAPISchemaObjectTypeMember
)
933 if variants
is not None:
934 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
935 variants
.set_owner(name
)
936 self
._base
_name
= base
938 self
.local_members
= local_members
939 self
.variants
= variants
942 def check(self
, schema
):
943 if self
.members
is False: # check for cycles
944 raise QAPIExprError(self
.info
,
945 "Object %s contains itself" % self
.name
)
948 self
.members
= False # mark as being checked
951 self
.base
= schema
.lookup_type(self
._base
_name
)
952 assert isinstance(self
.base
, QAPISchemaObjectType
)
953 self
.base
.check(schema
)
954 self
.base
.check_clash(schema
, self
.info
, seen
)
955 for m
in self
.local_members
:
957 m
.check_clash(self
.info
, seen
)
958 self
.members
= seen
.values()
960 self
.variants
.check(schema
, seen
)
961 assert self
.variants
.tag_member
in self
.members
962 self
.variants
.check_clash(schema
, self
.info
, seen
)
964 # Check that the members of this type do not cause duplicate JSON fields,
965 # and update seen to track the members seen so far. Report any errors
966 # on behalf of info, which is not necessarily self.info
967 def check_clash(self
, schema
, info
, seen
):
968 assert not self
.variants
# not implemented
969 for m
in self
.members
:
970 m
.check_clash(info
, seen
)
972 def is_implicit(self
):
973 # See QAPISchema._make_implicit_object_type()
974 return self
.name
[0] == ':'
977 assert not self
.is_implicit()
978 return QAPISchemaType
.c_name(self
)
980 def c_type(self
, is_param
=False):
981 assert not self
.is_implicit()
982 return QAPISchemaType
.c_type(self
)
987 def visit(self
, visitor
):
988 visitor
.visit_object_type(self
.name
, self
.info
,
989 self
.base
, self
.local_members
, self
.variants
)
990 visitor
.visit_object_type_flat(self
.name
, self
.info
,
991 self
.members
, self
.variants
)
994 class QAPISchemaMember(object):
997 def __init__(self
, name
):
998 assert isinstance(name
, str)
1002 def set_owner(self
, name
):
1003 assert not self
.owner
1006 def check_clash(self
, info
, seen
):
1007 cname
= c_name(self
.name
)
1008 if cname
.lower() != cname
and self
.owner
not in case_whitelist
:
1009 raise QAPIExprError(info
,
1010 "%s should not use uppercase" % self
.describe())
1012 raise QAPIExprError(info
,
1013 "%s collides with %s"
1014 % (self
.describe(), seen
[cname
].describe()))
1017 def _pretty_owner(self
):
1019 if owner
.startswith(':obj-'):
1020 # See QAPISchema._make_implicit_object_type() - reverse the
1021 # mapping there to create a nice human-readable description
1023 if owner
.endswith('-arg'):
1024 return '(parameter of %s)' % owner
[:-4]
1026 assert owner
.endswith('-wrapper')
1027 # Unreachable and not implemented
1029 if owner
.endswith('Kind'):
1030 # See QAPISchema._make_implicit_enum_type()
1031 return '(branch of %s)' % owner
[:-4]
1032 return '(%s of %s)' % (self
.role
, owner
)
1035 return "'%s' %s" % (self
.name
, self
._pretty
_owner
())
1038 class QAPISchemaObjectTypeMember(QAPISchemaMember
):
1039 def __init__(self
, name
, typ
, optional
):
1040 QAPISchemaMember
.__init
__(self
, name
)
1041 assert isinstance(typ
, str)
1042 assert isinstance(optional
, bool)
1043 self
._type
_name
= typ
1045 self
.optional
= optional
1047 def check(self
, schema
):
1049 self
.type = schema
.lookup_type(self
._type
_name
)
1053 class QAPISchemaObjectTypeVariants(object):
1054 def __init__(self
, tag_name
, tag_member
, variants
):
1055 # Flat unions pass tag_name but not tag_member.
1056 # Simple unions and alternates pass tag_member but not tag_name.
1057 # After check(), tag_member is always set, and tag_name remains
1058 # a reliable witness of being used by a flat union.
1059 assert bool(tag_member
) != bool(tag_name
)
1060 assert (isinstance(tag_name
, str) or
1061 isinstance(tag_member
, QAPISchemaObjectTypeMember
))
1063 assert isinstance(v
, QAPISchemaObjectTypeVariant
)
1064 self
.tag_name
= tag_name
1065 self
.tag_member
= tag_member
1066 self
.variants
= variants
1068 def set_owner(self
, name
):
1069 for v
in self
.variants
:
1072 def check(self
, schema
, seen
):
1073 if not self
.tag_member
: # flat union
1074 self
.tag_member
= seen
[c_name(self
.tag_name
)]
1075 assert self
.tag_name
== self
.tag_member
.name
1076 assert isinstance(self
.tag_member
.type, QAPISchemaEnumType
)
1077 for v
in self
.variants
:
1079 # Union names must match enum values; alternate names are
1080 # checked separately. Use 'seen' to tell the two apart.
1082 assert v
.name
in self
.tag_member
.type.member_names()
1083 assert isinstance(v
.type, QAPISchemaObjectType
)
1084 v
.type.check(schema
)
1086 def check_clash(self
, schema
, info
, seen
):
1087 for v
in self
.variants
:
1088 # Reset seen map for each variant, since qapi names from one
1089 # branch do not affect another branch
1090 assert isinstance(v
.type, QAPISchemaObjectType
)
1091 v
.type.check_clash(schema
, info
, dict(seen
))
1094 class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember
):
1097 def __init__(self
, name
, typ
):
1098 QAPISchemaObjectTypeMember
.__init
__(self
, name
, typ
, False)
1100 # This function exists to support ugly simple union special cases
1101 # TODO get rid of them, and drop the function
1102 def simple_union_type(self
):
1103 if (self
.type.is_implicit() and
1104 isinstance(self
.type, QAPISchemaObjectType
)):
1105 assert len(self
.type.members
) == 1
1106 assert not self
.type.variants
1107 return self
.type.members
[0].type
1111 class QAPISchemaAlternateType(QAPISchemaType
):
1112 def __init__(self
, name
, info
, variants
):
1113 QAPISchemaType
.__init
__(self
, name
, info
)
1114 assert isinstance(variants
, QAPISchemaObjectTypeVariants
)
1115 assert not variants
.tag_name
1116 variants
.set_owner(name
)
1117 variants
.tag_member
.set_owner(self
.name
)
1118 self
.variants
= variants
1120 def check(self
, schema
):
1121 self
.variants
.tag_member
.check(schema
)
1122 # Not calling self.variants.check_clash(), because there's nothing
1124 self
.variants
.check(schema
, {})
1125 # Alternate branch names have no relation to the tag enum values;
1126 # so we have to check for potential name collisions ourselves.
1128 for v
in self
.variants
.variants
:
1129 v
.check_clash(self
.info
, seen
)
1131 def json_type(self
):
1134 def visit(self
, visitor
):
1135 visitor
.visit_alternate_type(self
.name
, self
.info
, self
.variants
)
1138 class QAPISchemaCommand(QAPISchemaEntity
):
1139 def __init__(self
, name
, info
, arg_type
, ret_type
, gen
, success_response
):
1140 QAPISchemaEntity
.__init
__(self
, name
, info
)
1141 assert not arg_type
or isinstance(arg_type
, str)
1142 assert not ret_type
or isinstance(ret_type
, str)
1143 self
._arg
_type
_name
= arg_type
1144 self
.arg_type
= None
1145 self
._ret
_type
_name
= ret_type
1146 self
.ret_type
= None
1148 self
.success_response
= success_response
1150 def check(self
, schema
):
1151 if self
._arg
_type
_name
:
1152 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1153 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1154 assert not self
.arg_type
.variants
# not implemented
1155 if self
._ret
_type
_name
:
1156 self
.ret_type
= schema
.lookup_type(self
._ret
_type
_name
)
1157 assert isinstance(self
.ret_type
, QAPISchemaType
)
1159 def visit(self
, visitor
):
1160 visitor
.visit_command(self
.name
, self
.info
,
1161 self
.arg_type
, self
.ret_type
,
1162 self
.gen
, self
.success_response
)
1165 class QAPISchemaEvent(QAPISchemaEntity
):
1166 def __init__(self
, name
, info
, arg_type
):
1167 QAPISchemaEntity
.__init
__(self
, name
, info
)
1168 assert not arg_type
or isinstance(arg_type
, str)
1169 self
._arg
_type
_name
= arg_type
1170 self
.arg_type
= None
1172 def check(self
, schema
):
1173 if self
._arg
_type
_name
:
1174 self
.arg_type
= schema
.lookup_type(self
._arg
_type
_name
)
1175 assert isinstance(self
.arg_type
, QAPISchemaObjectType
)
1176 assert not self
.arg_type
.variants
# not implemented
1178 def visit(self
, visitor
):
1179 visitor
.visit_event(self
.name
, self
.info
, self
.arg_type
)
1182 class QAPISchema(object):
1183 def __init__(self
, fname
):
1185 self
.exprs
= check_exprs(QAPISchemaParser(open(fname
, "r")).exprs
)
1186 self
._entity
_dict
= {}
1187 self
._predefining
= True
1188 self
._def
_predefineds
()
1189 self
._predefining
= False
1192 except (QAPISchemaError
, QAPIExprError
), err
:
1193 print >>sys
.stderr
, err
1196 def _def_entity(self
, ent
):
1197 # Only the predefined types are allowed to not have info
1198 assert ent
.info
or self
._predefining
1199 assert ent
.name
not in self
._entity
_dict
1200 self
._entity
_dict
[ent
.name
] = ent
1202 def lookup_entity(self
, name
, typ
=None):
1203 ent
= self
._entity
_dict
.get(name
)
1204 if typ
and not isinstance(ent
, typ
):
1208 def lookup_type(self
, name
):
1209 return self
.lookup_entity(name
, QAPISchemaType
)
1211 def _def_builtin_type(self
, name
, json_type
, c_type
, c_null
):
1212 self
._def
_entity
(QAPISchemaBuiltinType(name
, json_type
,
1214 # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple
1215 # qapi-types.h from a single .c, all arrays of builtins must be
1216 # declared in the first file whether or not they are used. Nicer
1217 # would be to use lazy instantiation, while figuring out how to
1218 # avoid compilation issues with multiple qapi-types.h.
1219 self
._make
_array
_type
(name
, None)
1221 def _def_predefineds(self
):
1222 for t
in [('str', 'string', 'char' + pointer_suffix
, 'NULL'),
1223 ('number', 'number', 'double', '0'),
1224 ('int', 'int', 'int64_t', '0'),
1225 ('int8', 'int', 'int8_t', '0'),
1226 ('int16', 'int', 'int16_t', '0'),
1227 ('int32', 'int', 'int32_t', '0'),
1228 ('int64', 'int', 'int64_t', '0'),
1229 ('uint8', 'int', 'uint8_t', '0'),
1230 ('uint16', 'int', 'uint16_t', '0'),
1231 ('uint32', 'int', 'uint32_t', '0'),
1232 ('uint64', 'int', 'uint64_t', '0'),
1233 ('size', 'int', 'uint64_t', '0'),
1234 ('bool', 'boolean', 'bool', 'false'),
1235 ('any', 'value', 'QObject' + pointer_suffix
, 'NULL')]:
1236 self
._def
_builtin
_type
(*t
)
1237 self
.the_empty_object_type
= QAPISchemaObjectType(':empty', None, None,
1239 self
._def
_entity
(self
.the_empty_object_type
)
1240 qtype_values
= self
._make
_enum
_members
(['none', 'qnull', 'qint',
1241 'qstring', 'qdict', 'qlist',
1243 self
._def
_entity
(QAPISchemaEnumType('QType', None, qtype_values
,
1246 def _make_enum_members(self
, values
):
1247 return [QAPISchemaMember(v
) for v
in values
]
1249 def _make_implicit_enum_type(self
, name
, info
, values
):
1250 # See also QAPISchemaObjectTypeMember._pretty_owner()
1251 name
= name
+ 'Kind' # Use namespace reserved by add_name()
1252 self
._def
_entity
(QAPISchemaEnumType(
1253 name
, info
, self
._make
_enum
_members
(values
), None))
1256 def _make_array_type(self
, element_type
, info
):
1257 name
= element_type
+ 'List' # Use namespace reserved by add_name()
1258 if not self
.lookup_type(name
):
1259 self
._def
_entity
(QAPISchemaArrayType(name
, info
, element_type
))
1262 def _make_implicit_object_type(self
, name
, info
, role
, members
):
1265 # See also QAPISchemaObjectTypeMember._pretty_owner()
1266 name
= ':obj-%s-%s' % (name
, role
)
1267 if not self
.lookup_entity(name
, QAPISchemaObjectType
):
1268 self
._def
_entity
(QAPISchemaObjectType(name
, info
, None,
1272 def _def_enum_type(self
, expr
, info
):
1275 prefix
= expr
.get('prefix')
1276 self
._def
_entity
(QAPISchemaEnumType(
1277 name
, info
, self
._make
_enum
_members
(data
), prefix
))
1279 def _make_member(self
, name
, typ
, info
):
1281 if name
.startswith('*'):
1284 if isinstance(typ
, list):
1285 assert len(typ
) == 1
1286 typ
= self
._make
_array
_type
(typ
[0], info
)
1287 return QAPISchemaObjectTypeMember(name
, typ
, optional
)
1289 def _make_members(self
, data
, info
):
1290 return [self
._make
_member
(key
, value
, info
)
1291 for (key
, value
) in data
.iteritems()]
1293 def _def_struct_type(self
, expr
, info
):
1294 name
= expr
['struct']
1295 base
= expr
.get('base')
1297 self
._def
_entity
(QAPISchemaObjectType(name
, info
, base
,
1298 self
._make
_members
(data
, info
),
1301 def _make_variant(self
, case
, typ
):
1302 return QAPISchemaObjectTypeVariant(case
, typ
)
1304 def _make_simple_variant(self
, case
, typ
, info
):
1305 if isinstance(typ
, list):
1306 assert len(typ
) == 1
1307 typ
= self
._make
_array
_type
(typ
[0], info
)
1308 typ
= self
._make
_implicit
_object
_type
(
1309 typ
, info
, 'wrapper', [self
._make
_member
('data', typ
, info
)])
1310 return QAPISchemaObjectTypeVariant(case
, typ
)
1312 def _def_union_type(self
, expr
, info
):
1313 name
= expr
['union']
1315 base
= expr
.get('base')
1316 tag_name
= expr
.get('discriminator')
1319 variants
= [self
._make
_variant
(key
, value
)
1320 for (key
, value
) in data
.iteritems()]
1323 variants
= [self
._make
_simple
_variant
(key
, value
, info
)
1324 for (key
, value
) in data
.iteritems()]
1325 typ
= self
._make
_implicit
_enum
_type
(name
, info
,
1326 [v
.name
for v
in variants
])
1327 tag_member
= QAPISchemaObjectTypeMember('type', typ
, False)
1328 members
= [tag_member
]
1330 QAPISchemaObjectType(name
, info
, base
, members
,
1331 QAPISchemaObjectTypeVariants(tag_name
,
1335 def _def_alternate_type(self
, expr
, info
):
1336 name
= expr
['alternate']
1338 variants
= [self
._make
_variant
(key
, value
)
1339 for (key
, value
) in data
.iteritems()]
1340 tag_member
= QAPISchemaObjectTypeMember('type', 'QType', False)
1342 QAPISchemaAlternateType(name
, info
,
1343 QAPISchemaObjectTypeVariants(None,
1347 def _def_command(self
, expr
, info
):
1348 name
= expr
['command']
1349 data
= expr
.get('data')
1350 rets
= expr
.get('returns')
1351 gen
= expr
.get('gen', True)
1352 success_response
= expr
.get('success-response', True)
1353 if isinstance(data
, OrderedDict
):
1354 data
= self
._make
_implicit
_object
_type
(
1355 name
, info
, 'arg', self
._make
_members
(data
, info
))
1356 if isinstance(rets
, list):
1357 assert len(rets
) == 1
1358 rets
= self
._make
_array
_type
(rets
[0], info
)
1359 self
._def
_entity
(QAPISchemaCommand(name
, info
, data
, rets
, gen
,
1362 def _def_event(self
, expr
, info
):
1363 name
= expr
['event']
1364 data
= expr
.get('data')
1365 if isinstance(data
, OrderedDict
):
1366 data
= self
._make
_implicit
_object
_type
(
1367 name
, info
, 'arg', self
._make
_members
(data
, info
))
1368 self
._def
_entity
(QAPISchemaEvent(name
, info
, data
))
1370 def _def_exprs(self
):
1371 for expr_elem
in self
.exprs
:
1372 expr
= expr_elem
['expr']
1373 info
= expr_elem
['info']
1375 self
._def
_enum
_type
(expr
, info
)
1376 elif 'struct' in expr
:
1377 self
._def
_struct
_type
(expr
, info
)
1378 elif 'union' in expr
:
1379 self
._def
_union
_type
(expr
, info
)
1380 elif 'alternate' in expr
:
1381 self
._def
_alternate
_type
(expr
, info
)
1382 elif 'command' in expr
:
1383 self
._def
_command
(expr
, info
)
1384 elif 'event' in expr
:
1385 self
._def
_event
(expr
, info
)
1390 for ent
in self
._entity
_dict
.values():
1393 def visit(self
, visitor
):
1394 visitor
.visit_begin(self
)
1395 for (name
, entity
) in sorted(self
._entity
_dict
.items()):
1396 if visitor
.visit_needed(entity
):
1397 entity
.visit(visitor
)
1402 # Code generation helpers
1405 def camel_case(name
):
1409 if ch
in ['_', '-']:
1412 new_name
+= ch
.upper()
1415 new_name
+= ch
.lower()
1419 # ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
1420 # ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
1421 # ENUM24_Name -> ENUM24_NAME
1422 def camel_to_upper(value
):
1423 c_fun_str
= c_name(value
, False)
1431 # When c is upper and no "_" appears before, do more checks
1432 if c
.isupper() and (i
> 0) and c_fun_str
[i
- 1] != "_":
1433 if i
< l
- 1 and c_fun_str
[i
+ 1].islower():
1435 elif c_fun_str
[i
- 1].isdigit():
1438 return new_name
.lstrip('_').upper()
1441 def c_enum_const(type_name
, const_name
, prefix
=None):
1442 if prefix
is not None:
1444 return camel_to_upper(type_name
) + '_' + c_name(const_name
, False).upper()
1446 c_name_trans
= string
.maketrans('.-', '__')
1449 # Map @name to a valid C identifier.
1450 # If @protect, avoid returning certain ticklish identifiers (like
1451 # C keywords) by prepending "q_".
1453 # Used for converting 'name' from a 'name':'type' qapi definition
1454 # into a generated struct member, as well as converting type names
1455 # into substrings of a generated C function name.
1456 # '__a.b_c' -> '__a_b_c', 'x-foo' -> 'x_foo'
1457 # protect=True: 'int' -> 'q_int'; protect=False: 'int' -> 'int'
1458 def c_name(name
, protect
=True):
1459 # ANSI X3J11/88-090, 3.1.1
1460 c89_words
= set(['auto', 'break', 'case', 'char', 'const', 'continue',
1461 'default', 'do', 'double', 'else', 'enum', 'extern',
1462 'float', 'for', 'goto', 'if', 'int', 'long', 'register',
1463 'return', 'short', 'signed', 'sizeof', 'static',
1464 'struct', 'switch', 'typedef', 'union', 'unsigned',
1465 'void', 'volatile', 'while'])
1466 # ISO/IEC 9899:1999, 6.4.1
1467 c99_words
= set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
1468 # ISO/IEC 9899:2011, 6.4.1
1469 c11_words
= set(['_Alignas', '_Alignof', '_Atomic', '_Generic',
1470 '_Noreturn', '_Static_assert', '_Thread_local'])
1471 # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
1473 gcc_words
= set(['asm', 'typeof'])
1474 # C++ ISO/IEC 14882:2003 2.11
1475 cpp_words
= set(['bool', 'catch', 'class', 'const_cast', 'delete',
1476 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
1477 'namespace', 'new', 'operator', 'private', 'protected',
1478 'public', 'reinterpret_cast', 'static_cast', 'template',
1479 'this', 'throw', 'true', 'try', 'typeid', 'typename',
1480 'using', 'virtual', 'wchar_t',
1481 # alternative representations
1482 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
1483 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
1484 # namespace pollution:
1485 polluted_words
= set(['unix', 'errno'])
1486 name
= name
.translate(c_name_trans
)
1487 if protect
and (name
in c89_words | c99_words | c11_words | gcc_words
1488 | cpp_words | polluted_words
):
1492 eatspace
= '\033EATSPACE.'
1493 pointer_suffix
= ' *' + eatspace
1496 def genindent(count
):
1498 for _
in range(count
):
1505 def push_indent(indent_amount
=4):
1507 indent_level
+= indent_amount
1510 def pop_indent(indent_amount
=4):
1512 indent_level
-= indent_amount
1515 # Generate @code with @kwds interpolated.
1516 # Obey indent_level, and strip eatspace.
1517 def cgen(code
, **kwds
):
1520 indent
= genindent(indent_level
)
1521 # re.subn() lacks flags support before Python 2.7, use re.compile()
1522 raw
= re
.subn(re
.compile("^.", re
.MULTILINE
),
1523 indent
+ r
'\g<0>', raw
)
1525 return re
.sub(re
.escape(eatspace
) + ' *', '', raw
)
1528 def mcgen(code
, **kwds
):
1531 return cgen(code
, **kwds
)
1534 def guardname(filename
):
1535 return c_name(filename
, protect
=False).upper()
1538 def guardstart(name
):
1545 name
=guardname(name
))
1551 #endif /* %(name)s */
1554 name
=guardname(name
))
1557 def gen_enum_lookup(name
, values
, prefix
=None):
1560 const char *const %(c_name)s_lookup[] = {
1562 c_name
=c_name(name
))
1563 for value
in values
:
1564 index
= c_enum_const(name
, value
, prefix
)
1566 [%(index)s] = "%(value)s",
1568 index
=index
, value
=value
)
1570 max_index
= c_enum_const(name
, '_MAX', prefix
)
1572 [%(max_index)s] = NULL,
1575 max_index
=max_index
)
1579 def gen_enum(name
, values
, prefix
=None):
1580 # append automatically generated _MAX value
1581 enum_values
= values
+ ['_MAX']
1585 typedef enum %(c_name)s {
1587 c_name
=c_name(name
))
1590 for value
in enum_values
:
1594 c_enum
=c_enum_const(name
, value
, prefix
),
1601 c_name
=c_name(name
))
1605 extern const char *const %(c_name)s_lookup[];
1607 c_name
=c_name(name
))
1611 def gen_params(arg_type
, extra
):
1614 assert not arg_type
.variants
1617 for memb
in arg_type
.members
:
1621 ret
+= 'bool has_%s, ' % c_name(memb
.name
)
1622 ret
+= '%s %s' % (memb
.type.c_type(is_param
=True), c_name(memb
.name
))
1628 def gen_err_check(label
='out', skiperr
=False):
1639 def gen_visit_fields(members
, prefix
='', need_cast
=False, skiperr
=False):
1646 for memb
in members
:
1649 if (visit_optional(v, &%(prefix)shas_%(c_name)s, "%(name)s")) {
1651 prefix
=prefix
, c_name
=c_name(memb
.name
),
1652 name
=memb
.name
, errp
=errparg
)
1655 # Ugly: sometimes we need to cast away const
1656 if need_cast
and memb
.type.name
== 'str':
1662 visit_type_%(c_type)s(v, %(cast)s&%(prefix)s%(c_name)s, "%(name)s", %(errp)s);
1664 c_type
=memb
.type.c_name(), prefix
=prefix
, cast
=cast
,
1665 c_name
=c_name(memb
.name
), name
=memb
.name
,
1667 ret
+= gen_err_check(skiperr
=skiperr
)
1678 # Common command line parsing
1682 def parse_command_line(extra_options
="", extra_long_options
=[]):
1685 opts
, args
= getopt
.gnu_getopt(sys
.argv
[1:],
1686 "chp:o:" + extra_options
,
1687 ["source", "header", "prefix=",
1688 "output-dir="] + extra_long_options
)
1689 except getopt
.GetoptError
, err
:
1690 print >>sys
.stderr
, "%s: %s" % (sys
.argv
[0], str(err
))
1701 if o
in ("-p", "--prefix"):
1702 match
= re
.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a
)
1703 if match
.end() != len(a
):
1704 print >>sys
.stderr
, \
1705 "%s: 'funny character '%s' in argument of --prefix" \
1706 % (sys
.argv
[0], a
[match
.end()])
1709 elif o
in ("-o", "--output-dir"):
1710 output_dir
= a
+ "/"
1711 elif o
in ("-c", "--source"):
1713 elif o
in ("-h", "--header"):
1716 extra_opts
.append(oa
)
1718 if not do_c
and not do_h
:
1723 print >>sys
.stderr
, "%s: need exactly one argument" % sys
.argv
[0]
1727 return (fname
, output_dir
, do_c
, do_h
, prefix
, extra_opts
)
1730 # Generate output files with boilerplate
1734 def open_output(output_dir
, do_c
, do_h
, prefix
, c_file
, h_file
,
1735 c_comment
, h_comment
):
1736 guard
= guardname(prefix
+ h_file
)
1737 c_file
= output_dir
+ prefix
+ c_file
1738 h_file
= output_dir
+ prefix
+ h_file
1742 os
.makedirs(output_dir
)
1744 if e
.errno
!= errno
.EEXIST
:
1747 def maybe_open(really
, name
, opt
):
1749 return open(name
, opt
)
1752 return StringIO
.StringIO()
1754 fdef
= maybe_open(do_c
, c_file
, 'w')
1755 fdecl
= maybe_open(do_h
, h_file
, 'w')
1757 fdef
.write(mcgen('''
1758 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1763 fdecl
.write(mcgen('''
1764 /* AUTOMATICALLY GENERATED, DO NOT MODIFY */
1770 comment
=h_comment
, guard
=guard
))
1772 return (fdef
, fdecl
)
1775 def close_output(fdef
, fdecl
):