diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/qapi-commands.py | 117 | ||||
-rw-r--r-- | scripts/qapi-event.py | 53 | ||||
-rw-r--r-- | scripts/qapi-types.py | 34 | ||||
-rw-r--r-- | scripts/qapi-visit.py | 68 | ||||
-rw-r--r-- | scripts/qapi.py | 171 |
5 files changed, 203 insertions, 240 deletions
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index f44e01f004..b570069faa 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -2,7 +2,7 @@ # QAPI command marshaller generator # # Copyright IBM, Corp. 2011 -# Copyright (C) 2014-2015 Red Hat, Inc. +# Copyright (C) 2014-2016 Red Hat, Inc. # # Authors: # Anthony Liguori <aliguori@us.ibm.com> @@ -30,10 +30,11 @@ def gen_call(name, arg_type, ret_type): argstr = '' if arg_type: + assert not arg_type.variants for memb in arg_type.members: if memb.optional: - argstr += 'has_%s, ' % c_name(memb.name) - argstr += '%s, ' % c_name(memb.name) + argstr += 'arg.has_%s, ' % c_name(memb.name) + argstr += 'arg.%s, ' % c_name(memb.name) lhs = '' if ret_type: @@ -54,72 +55,6 @@ def gen_call(name, arg_type, ret_type): return ret -def gen_marshal_vars(arg_type, ret_type): - ret = mcgen(''' - Error *err = NULL; -''') - - if ret_type: - ret += mcgen(''' - %(c_type)s retval; -''', - c_type=ret_type.c_type()) - - if arg_type: - ret += mcgen(''' - QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args)); - QapiDeallocVisitor *qdv; - Visitor *v; -''') - - for memb in arg_type.members: - if memb.optional: - ret += mcgen(''' - bool has_%(c_name)s = false; -''', - c_name=c_name(memb.name)) - ret += mcgen(''' - %(c_type)s %(c_name)s = %(c_null)s; -''', - c_name=c_name(memb.name), - c_type=memb.type.c_type(), - c_null=memb.type.c_null()) - ret += '\n' - else: - ret += mcgen(''' - - (void)args; -''') - - return ret - - -def gen_marshal_input_visit(arg_type, dealloc=False): - ret = '' - - if not arg_type: - return ret - - if dealloc: - ret += mcgen(''' - qmp_input_visitor_cleanup(qiv); - qdv = qapi_dealloc_visitor_new(); - v = qapi_dealloc_get_visitor(qdv); -''') - else: - ret += mcgen(''' - v = qmp_input_get_visitor(qiv); -''') - - ret += gen_visit_members(arg_type.members, skiperr=dealloc) - - if dealloc: - ret += mcgen(''' - qapi_dealloc_visitor_cleanup(qdv); -''') - return ret - - def gen_marshal_output(ret_type): return mcgen(''' @@ -168,15 +103,40 @@ def gen_marshal(name, arg_type, ret_type): %(proto)s { + Error *err = NULL; ''', proto=gen_marshal_proto(name)) - ret += gen_marshal_vars(arg_type, ret_type) - ret += gen_marshal_input_visit(arg_type) + if ret_type: + ret += mcgen(''' + %(c_type)s retval; +''', + c_type=ret_type.c_type()) + + if arg_type and arg_type.members: + ret += mcgen(''' + QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args)); + QapiDeallocVisitor *qdv; + Visitor *v; + %(c_name)s arg = {0}; + + v = qmp_input_get_visitor(qiv); + visit_type_%(c_name)s_members(v, &arg, &err); + if (err) { + goto out; + } +''', + c_name=arg_type.c_name()) + + else: + ret += mcgen(''' + + (void)args; +''') + ret += gen_call(name, arg_type, ret_type) - # 'goto out' produced by gen_marshal_input_visit->gen_visit_members() - # for each arg_type member, and by gen_call() for ret_type + # 'goto out' produced above for arg_type, and by gen_call() for ret_type if (arg_type and arg_type.members) or ret_type: ret += mcgen(''' @@ -185,7 +145,16 @@ out: ret += mcgen(''' error_propagate(errp, err); ''') - ret += gen_marshal_input_visit(arg_type, dealloc=True) + if arg_type and arg_type.members: + ret += mcgen(''' + qmp_input_visitor_cleanup(qiv); + qdv = qapi_dealloc_visitor_new(); + v = qapi_dealloc_get_visitor(qdv); + visit_type_%(c_name)s_members(v, &arg, NULL); + qapi_dealloc_visitor_cleanup(qdv); +''', + c_name=arg_type.c_name()) + ret += mcgen(''' } ''') diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py index fb579dd098..9b5c5b535d 100644 --- a/scripts/qapi-event.py +++ b/scripts/qapi-event.py @@ -28,7 +28,37 @@ def gen_event_send_decl(name, arg_type): proto=gen_event_send_proto(name, arg_type)) +# Declare and initialize an object 'qapi' using parameters from gen_params() +def gen_param_var(typ): + assert not typ.variants + ret = mcgen(''' + %(c_name)s param = { +''', + c_name=typ.c_name()) + sep = ' ' + for memb in typ.members: + ret += sep + sep = ', ' + if memb.optional: + ret += 'has_' + c_name(memb.name) + sep + if memb.type.name == 'str': + # Cast away const added in gen_params() + ret += '(char *)' + ret += c_name(memb.name) + ret += mcgen(''' + + }; +''') + return ret + + def gen_event_send(name, arg_type): + # FIXME: Our declaration of local variables (and of 'errp' in the + # parameter list) can collide with exploded members of the event's + # data type passed in as parameters. If this collision ever hits in + # practice, we can rename our local variables with a leading _ prefix, + # or split the code into a wrapper function that creates a boxed + # 'param' object then calls another to do the real work. ret = mcgen(''' %(proto)s @@ -43,11 +73,11 @@ def gen_event_send(name, arg_type): ret += mcgen(''' QmpOutputVisitor *qov; Visitor *v; - QObject *obj; - ''') + ret += gen_param_var(arg_type) ret += mcgen(''' + emit = qmp_event_get_func_emit(); if (!emit) { return; @@ -64,23 +94,18 @@ def gen_event_send(name, arg_type): v = qmp_output_get_visitor(qov); visit_start_struct(v, "%(name)s", NULL, 0, &err); -''', - name=name) - ret += gen_err_check() - ret += gen_visit_members(arg_type.members, need_cast=True, - label='out_obj') - ret += mcgen(''' -out_obj: + if (err) { + goto out; + } + visit_type_%(c_name)s_members(v, ¶m, &err); visit_end_struct(v, err ? NULL : &err); if (err) { goto out; } - obj = qmp_output_get_qobject(qov); - g_assert(obj); - - qdict_put_obj(qmp, "data", obj); -''') + qdict_put_obj(qmp, "data", qmp_output_get_qobject(qov)); +''', + name=name, c_name=arg_type.c_name()) ret += mcgen(''' emit(%(c_enum)s, qmp, &err); diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 0306a884c3..e09c8751a9 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -61,8 +61,7 @@ def gen_object(name, base, members, variants): ret = '' if variants: for v in variants.variants: - if (isinstance(v.type, QAPISchemaObjectType) and - not v.type.is_implicit()): + if isinstance(v.type, QAPISchemaObjectType): ret += gen_object(v.type.name, v.type.base, v.type.local_members, v.type.variants) @@ -73,12 +72,14 @@ struct %(c_name)s { c_name=c_name(name)) if base: - ret += mcgen(''' + if not base.is_implicit(): + ret += mcgen(''' /* Members inherited from %(c_name)s: */ ''', - c_name=base.c_name()) + c_name=base.c_name()) ret += gen_struct_members(base.members) - ret += mcgen(''' + if not base.is_implicit(): + ret += mcgen(''' /* Own members: */ ''') ret += gen_struct_members(members) @@ -122,13 +123,10 @@ def gen_variants(variants): c_name=c_name(variants.tag_member.name)) for var in variants.variants: - # Ugly special case for simple union TODO get rid of it - simple_union_type = var.simple_union_type() - typ = simple_union_type or var.type ret += mcgen(''' %(c_type)s %(c_name)s; ''', - c_type=typ.c_type(is_unboxed=not simple_union_type), + c_type=var.type.c_unboxed_type(), c_name=c_name(var.name)) ret += mcgen(''' @@ -177,6 +175,8 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor): self._btin = None def visit_begin(self, schema): + # gen_object() is recursive, ensure it doesn't visit the empty type + objects_seen.add(schema.the_empty_object_type.name) self.decl = '' self.defn = '' self._fwdecl = '' @@ -193,11 +193,6 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor): self.decl = self._btin + self.decl self._btin = None - def visit_needed(self, entity): - # Visit everything except implicit objects - return not (entity.is_implicit() and - isinstance(entity, QAPISchemaObjectType)) - def _gen_type_cleanup(self, name): self.decl += gen_type_cleanup_decl(name) self.defn += gen_type_cleanup(name) @@ -226,11 +221,18 @@ class QAPISchemaGenTypeVisitor(QAPISchemaVisitor): self._gen_type_cleanup(name) def visit_object_type(self, name, info, base, members, variants): + # Nothing to do for the special empty builtin + if name == 'q_empty': + return self._fwdecl += gen_fwd_object_or_array(name) self.decl += gen_object(name, base, members, variants) - if base: + if base and not base.is_implicit(): self.decl += gen_upcast(name, base) - self._gen_type_cleanup(name) + # TODO Worth changing the visitor signature, so we could + # directly use rather than repeat type.is_implicit()? + if not name.startswith('q_'): + # implicit types won't be directly allocated/freed + self._gen_type_cleanup(name) def visit_alternate_type(self, name, info, variants): self._fwdecl += gen_fwd_object_or_array(name) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index a712e9af8a..c147990efe 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -51,7 +51,24 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) c_type=base.c_name()) ret += gen_err_check() - ret += gen_visit_members(members, prefix='obj->') + for memb in members: + if memb.optional: + ret += mcgen(''' + if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) { +''', + name=memb.name, c_name=c_name(memb.name)) + push_indent() + ret += mcgen(''' + visit_type_%(c_type)s(v, "%(name)s", &obj->%(c_name)s, &err); +''', + c_type=memb.type.c_name(), name=memb.name, + c_name=c_name(memb.name)) + ret += gen_err_check() + if memb.optional: + pop_indent() + ret += mcgen(''' + } +''') if variants: ret += mcgen(''' @@ -60,29 +77,15 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) c_name=c_name(variants.tag_member.name)) for var in variants.variants: - # TODO ugly special case for simple union - simple_union_type = var.simple_union_type() ret += mcgen(''' case %(case)s: + visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err); + break; ''', case=c_enum_const(variants.tag_member.type.name, var.name, - variants.tag_member.type.prefix)) - if simple_union_type: - ret += mcgen(''' - visit_type_%(c_type)s(v, "data", &obj->u.%(c_name)s, &err); -''', - c_type=simple_union_type.c_name(), - c_name=c_name(var.name)) - else: - ret += mcgen(''' - visit_type_%(c_type)s_members(v, &obj->u.%(c_name)s, &err); -''', - c_type=var.type.c_name(), - c_name=c_name(var.name)) - ret += mcgen(''' - break; -''') + variants.tag_member.type.prefix), + c_type=var.type.c_name(), c_name=c_name(var.name)) ret += mcgen(''' default: @@ -90,8 +93,8 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp) } ''') - # 'goto out' produced for base, by gen_visit_members() for each member, - # and if variants were present + # 'goto out' produced for base, for each member, and if variants were + # present if base or members or variants: ret += mcgen(''' @@ -215,13 +218,11 @@ out: def gen_visit_object(name, base, members, variants): - ret = gen_visit_object_members(name, base, members, variants) - # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to # *obj, but then visit_type_FOO_members() fails, we should clean up *obj # rather than leaving it non-NULL. As currently written, the caller must # call qapi_free_FOO() to avoid a memory leak of the partial FOO. - ret += mcgen(''' + return mcgen(''' void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error **errp) { @@ -245,8 +246,6 @@ out: ''', c_name=c_name(name)) - return ret - class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): def __init__(self): @@ -268,11 +267,6 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.decl = self._btin + self.decl self._btin = None - def visit_needed(self, entity): - # Visit everything except implicit objects - return not (entity.is_implicit() and - isinstance(entity, QAPISchemaObjectType)) - def visit_enum_type(self, name, info, values, prefix): # Special case for our lone builtin enum type # TODO use something cleaner than existence of info @@ -296,9 +290,17 @@ class QAPISchemaGenVisitVisitor(QAPISchemaVisitor): self.defn += defn def visit_object_type(self, name, info, base, members, variants): + # Nothing to do for the special empty builtin + if name == 'q_empty': + return self.decl += gen_visit_members_decl(name) - self.decl += gen_visit_decl(name) - self.defn += gen_visit_object(name, base, members, variants) + self.defn += gen_visit_object_members(name, base, members, variants) + # TODO Worth changing the visitor signature, so we could + # directly use rather than repeat type.is_implicit()? + if not name.startswith('q_'): + # only explicit types need an allocating visit + self.decl += gen_visit_decl(name) + self.defn += gen_visit_object(name, base, members, variants) def visit_alternate_type(self, name, info, variants): self.decl += gen_visit_decl(name) diff --git a/scripts/qapi.py b/scripts/qapi.py index 6b2aa6e3df..b13ae47899 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -63,12 +63,12 @@ returns_whitelist = [ case_whitelist = [ # From QMP: 'ACPISlotType', # DIMM, visible through query-acpi-ospm-status - 'CpuInfoBase', # CPU, visible through query-cpu 'CpuInfoMIPS', # PC, visible through query-cpu 'CpuInfoTricore', # PC, visible through query-cpu 'QapiErrorClass', # all members, visible through errors 'UuidInfo', # UUID, visible through query-uuid 'X86CPURegister32', # all members, visible indirectly through qom-get + 'q_obj_CpuInfo-base', # CPU, visible through query-cpu ] enum_types = [] @@ -327,6 +327,8 @@ class QAPISchemaParser(object): def find_base_members(base): + if isinstance(base, dict): + return base base_struct_define = find_struct(base) if not base_struct_define: return None @@ -391,7 +393,8 @@ def check_name(expr_info, source, name, allow_optional=False, # code always prefixes it with the enum name if enum_member and membername[0].isdigit(): membername = 'D' + membername - # Reserve the entire 'q_' namespace for c_name() + # Reserve the entire 'q_' namespace for c_name(), and for 'q_empty' + # and 'q_obj_*' implicit type names. if not valid_name.match(membername) or \ c_name(membername, False).startswith('q_'): raise QAPIExprError(expr_info, @@ -560,9 +563,10 @@ def check_union(expr, expr_info): # Else, it's a flat union. else: - # The object must have a string member 'base'. + # The object must have a string or dictionary 'base'. check_type(expr_info, "'base' for union '%s'" % name, - base, allow_metas=['struct']) + base, allow_dict=True, allow_optional=True, + allow_metas=['struct']) if not base: raise QAPIExprError(expr_info, "Flat union '%s' must have a base" @@ -822,11 +826,18 @@ class QAPISchemaVisitor(object): class QAPISchemaType(QAPISchemaEntity): - def c_type(self, is_param=False, is_unboxed=False): - return c_name(self.name) + pointer_suffix + # Return the C type for common use. + # For the types we commonly box, this is a pointer type. + def c_type(self): + pass + + # Return the C type to be used in a parameter list. + def c_param_type(self): + return self.c_type() - def c_null(self): - return 'NULL' + # Return the C type to be used where we suppress boxing. + def c_unboxed_type(self): + return self.c_type() def json_type(self): pass @@ -843,25 +854,24 @@ class QAPISchemaType(QAPISchemaEntity): class QAPISchemaBuiltinType(QAPISchemaType): - def __init__(self, name, json_type, c_type, c_null): + def __init__(self, name, json_type, c_type): QAPISchemaType.__init__(self, name, None) assert not c_type or isinstance(c_type, str) assert json_type in ('string', 'number', 'int', 'boolean', 'null', 'value') self._json_type_name = json_type self._c_type_name = c_type - self._c_null_val = c_null def c_name(self): return self.name - def c_type(self, is_param=False, is_unboxed=False): - if is_param and self.name == 'str': - return 'const ' + self._c_type_name + def c_type(self): return self._c_type_name - def c_null(self): - return self._c_null_val + def c_param_type(self): + if self.name == 'str': + return 'const ' + self._c_type_name + return self._c_type_name def json_type(self): return self._json_type_name @@ -889,16 +899,12 @@ class QAPISchemaEnumType(QAPISchemaType): # See QAPISchema._make_implicit_enum_type() return self.name.endswith('Kind') - def c_type(self, is_param=False, is_unboxed=False): + def c_type(self): return c_name(self.name) def member_names(self): return [v.name for v in self.values] - def c_null(self): - return c_enum_const(self.name, (self.member_names() + ['_MAX'])[0], - self.prefix) - def json_type(self): return 'string' @@ -921,6 +927,9 @@ class QAPISchemaArrayType(QAPISchemaType): def is_implicit(self): return True + def c_type(self): + return c_name(self.name) + pointer_suffix + def json_type(self): return 'array' @@ -978,19 +987,20 @@ class QAPISchemaObjectType(QAPISchemaType): m.check_clash(info, seen) def is_implicit(self): - # See QAPISchema._make_implicit_object_type() - return self.name[0] == ':' + # See QAPISchema._make_implicit_object_type(), as well as + # _def_predefineds() + return self.name.startswith('q_') def c_name(self): - assert not self.is_implicit() return QAPISchemaType.c_name(self) - def c_type(self, is_param=False, is_unboxed=False): + def c_type(self): assert not self.is_implicit() - if is_unboxed: - return c_name(self.name) return c_name(self.name) + pointer_suffix + def c_unboxed_type(self): + return c_name(self.name) + def json_type(self): return 'object' @@ -1026,12 +1036,14 @@ class QAPISchemaMember(object): def _pretty_owner(self): owner = self.owner - if owner.startswith(':obj-'): + if owner.startswith('q_obj_'): # See QAPISchema._make_implicit_object_type() - reverse the # mapping there to create a nice human-readable description - owner = owner[5:] + owner = owner[6:] if owner.endswith('-arg'): return '(parameter of %s)' % owner[:-4] + elif owner.endswith('-base'): + return '(base of %s)' % owner[:-5] else: assert owner.endswith('-wrapper') # Unreachable and not implemented @@ -1108,16 +1120,6 @@ class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember): def __init__(self, name, typ): QAPISchemaObjectTypeMember.__init__(self, name, typ, False) - # This function exists to support ugly simple union special cases - # TODO get rid of them, and drop the function - def simple_union_type(self): - if (self.type.is_implicit() and - isinstance(self.type, QAPISchemaObjectType)): - assert len(self.type.members) == 1 - assert not self.type.variants - return self.type.members[0].type - return None - class QAPISchemaAlternateType(QAPISchemaType): def __init__(self, name, info, variants): @@ -1139,6 +1141,9 @@ class QAPISchemaAlternateType(QAPISchemaType): for v in self.variants.variants: v.check_clash(self.info, seen) + def c_type(self): + return c_name(self.name) + pointer_suffix + def json_type(self): return 'value' @@ -1219,9 +1224,8 @@ class QAPISchema(object): def lookup_type(self, name): return self.lookup_entity(name, QAPISchemaType) - def _def_builtin_type(self, name, json_type, c_type, c_null): - self._def_entity(QAPISchemaBuiltinType(name, json_type, - c_type, c_null)) + def _def_builtin_type(self, name, json_type, c_type): + self._def_entity(QAPISchemaBuiltinType(name, json_type, c_type)) # TODO As long as we have QAPI_TYPES_BUILTIN to share multiple # qapi-types.h from a single .c, all arrays of builtins must be # declared in the first file whether or not they are used. Nicer @@ -1230,23 +1234,23 @@ class QAPISchema(object): self._make_array_type(name, None) def _def_predefineds(self): - for t in [('str', 'string', 'char' + pointer_suffix, 'NULL'), - ('number', 'number', 'double', '0'), - ('int', 'int', 'int64_t', '0'), - ('int8', 'int', 'int8_t', '0'), - ('int16', 'int', 'int16_t', '0'), - ('int32', 'int', 'int32_t', '0'), - ('int64', 'int', 'int64_t', '0'), - ('uint8', 'int', 'uint8_t', '0'), - ('uint16', 'int', 'uint16_t', '0'), - ('uint32', 'int', 'uint32_t', '0'), - ('uint64', 'int', 'uint64_t', '0'), - ('size', 'int', 'uint64_t', '0'), - ('bool', 'boolean', 'bool', 'false'), - ('any', 'value', 'QObject' + pointer_suffix, 'NULL')]: + for t in [('str', 'string', 'char' + pointer_suffix), + ('number', 'number', 'double'), + ('int', 'int', 'int64_t'), + ('int8', 'int', 'int8_t'), + ('int16', 'int', 'int16_t'), + ('int32', 'int', 'int32_t'), + ('int64', 'int', 'int64_t'), + ('uint8', 'int', 'uint8_t'), + ('uint16', 'int', 'uint16_t'), + ('uint32', 'int', 'uint32_t'), + ('uint64', 'int', 'uint64_t'), + ('size', 'int', 'uint64_t'), + ('bool', 'boolean', 'bool'), + ('any', 'value', 'QObject' + pointer_suffix)]: self._def_builtin_type(*t) - self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None, - [], None) + self.the_empty_object_type = QAPISchemaObjectType('q_empty', None, + None, [], None) self._def_entity(self.the_empty_object_type) qtype_values = self._make_enum_members(['none', 'qnull', 'qint', 'qstring', 'qdict', 'qlist', @@ -1274,7 +1278,7 @@ class QAPISchema(object): if not members: return None # See also QAPISchemaObjectTypeMember._pretty_owner() - name = ':obj-%s-%s' % (name, role) + name = 'q_obj_%s-%s' % (name, role) if not self.lookup_entity(name, QAPISchemaObjectType): self._def_entity(QAPISchemaObjectType(name, info, None, members, None)) @@ -1326,6 +1330,9 @@ class QAPISchema(object): base = expr.get('base') tag_name = expr.get('discriminator') tag_member = None + if isinstance(base, dict): + base = (self._make_implicit_object_type( + name, info, 'base', self._make_members(base, info))) if tag_name: variants = [self._make_variant(key, value) for (key, value) in data.iteritems()] @@ -1630,60 +1637,18 @@ def gen_params(arg_type, extra): sep = ', ' if memb.optional: ret += 'bool has_%s, ' % c_name(memb.name) - ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name)) + ret += '%s %s' % (memb.type.c_param_type(), c_name(memb.name)) if extra: ret += sep + extra return ret -def gen_err_check(label='out', skiperr=False): - if skiperr: - return '' +def gen_err_check(): return mcgen(''' if (err) { - goto %(label)s; - } -''', - label=label) - - -def gen_visit_members(members, prefix='', need_cast=False, skiperr=False, - label='out'): - ret = '' - if skiperr: - errparg = 'NULL' - else: - errparg = '&err' - - for memb in members: - if memb.optional: - ret += mcgen(''' - if (visit_optional(v, "%(name)s", &%(prefix)shas_%(c_name)s)) { -''', - prefix=prefix, c_name=c_name(memb.name), - name=memb.name) - push_indent() - - # Ugly: sometimes we need to cast away const - if need_cast and memb.type.name == 'str': - cast = '(char **)' - else: - cast = '' - - ret += mcgen(''' - visit_type_%(c_type)s(v, "%(name)s", %(cast)s&%(prefix)s%(c_name)s, %(errp)s); -''', - c_type=memb.type.c_name(), prefix=prefix, cast=cast, - c_name=c_name(memb.name), name=memb.name, - errp=errparg) - ret += gen_err_check(skiperr=skiperr, label=label) - - if memb.optional: - pop_indent() - ret += mcgen(''' + goto out; } ''') - return ret # |