Allows to specify a @declare attribute for messages and structure that can generate the needed C structures. Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- python_modules/ptypes.py | 64 ++++++++++++++++++++++++++++++++++++++++ spice_codegen.py | 47 +++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/python_modules/ptypes.py b/python_modules/ptypes.py index 7dca78d..64c198e 100644 --- a/python_modules/ptypes.py +++ b/python_modules/ptypes.py @@ -72,6 +72,8 @@ valid_attributes=set([ 'zero', # this attribute does not exist on the network, fill just structure with the value 'virtual', + # generate C structure declarations from protocol definition + 'declare', ]) attributes_with_arguments=set([ @@ -485,6 +487,26 @@ class ArrayType(Type): def c_type(self): return self.element_type.c_type() + def generate_c_declaration(self, writer, member): + name = member.name + if member.has_attr("chunk"): + return writer.writeln('SpiceChunks *%s;' % name) + if member.has_attr("as_ptr"): + len_var = member.attributes["as_ptr"][0] + writer.writeln('uint32_t %s;' % len_var) + return writer.writeln('%s *%s;' % (self.c_type(), name)) + if member.has_attr("to_ptr"): # TODO len + return writer.writeln('%s *%s;' % (self.c_type(), name)) + if member.has_attr("ptr_array"): # TODO where the length is stored? overflow? + return writer.writeln('%s *%s[0];' % (self.c_type(), name)) + if member.has_end_attr() or self.is_remaining_length(): # TODO len + return writer.writeln('%s %s[0];' % (self.c_type(), name)) + if self.is_constant_length(): + return writer.writeln('%s %s[%s];' % (self.c_type(), name, self.size)) + if self.is_identifier_length(): + return writer.writeln('%s *%s;' % (self.c_type(), name)) + raise NotImplementedError('unknown array %s' % str(self)) + class PointerType(Type): def __init__(self, target_type): Type.__init__(self) @@ -529,6 +551,15 @@ class PointerType(Type): def get_num_pointers(self): return 1 + def generate_c_declaration(self, writer, member): + target_type = self.target_type + is_array = target_type.is_array() + if not is_array or target_type.is_identifier_length(): + writer.writeln("%s *%s;" % (target_type.c_type(), member.name)) + return + raise NotImplementedError('Some pointers to array declarations are not implemented %s' % +member) + class Containee: def __init__(self): self.attributes = {} @@ -624,6 +655,14 @@ class Member(Containee): names = [prefix + "_" + name for name in names] return names + def generate_c_declaration(self, writer): + if self.has_attr("zero"): + return + if self.is_pointer() or self.is_array(): + self.member_type.generate_c_declaration(writer, self) + return + return writer.writeln("%s %s;" % (self.member_type.c_type(), self.name)) + class SwitchCase: def __init__(self, values, member): self.values = values @@ -747,6 +786,17 @@ class Switch(Containee): names = names + c.get_pointer_names(marshalled) return names + def generate_c_declaration(self, writer): + if self.has_attr("anon") and len(self.cases) == 1: + self.cases[0].member.generate_c_declaration(writer) + return + writer.writeln('union {') + writer.indent() + for m in self.cases: + m.member.generate_c_declaration(writer) + writer.unindent() + writer.writeln('} %s;' % self.name) + class ContainerType(Type): def is_fixed_sizeof(self): for m in self.members: @@ -857,6 +907,20 @@ class ContainerType(Type): return member + def generate_c_declaration(self, writer): + if not self.has_attr('declare'): + return + name = self.c_type() + writer.writeln('typedef struct %s {' % name) + writer.indent() + for m in self.members: + m.generate_c_declaration(writer) + if len(self.members) == 0: + # make sure generated structure are not empty + writer.writeln("char dummy[0];") + writer.unindent() + writer.writeln('} %s;' % name).newline() + class StructType(ContainerType): def __init__(self, name, members, attribute_list): Type.__init__(self) diff --git a/spice_codegen.py b/spice_codegen.py index 4664740..66f99a5 100755 --- a/spice_codegen.py +++ b/spice_codegen.py @@ -177,6 +177,8 @@ parser.add_option("--license", dest="license", help="license to use for generated file(s) (LGPL/BSD)", default="LGPL") parser.add_option("--generated-header", dest="generated_header", metavar="FILE", help="Name of the file to generate the header") +parser.add_option("--generated-declaration-file", dest="generated_declaration_file", metavar="FILE", + help="Name of the file to generate declarations") (options, args) = parser.parse_args() @@ -259,6 +261,51 @@ else: print >> sys.stderr, "Invalid license specified: %s" % options.license sys.exit(1) +all_structures = {} +def generate_declaration(t, writer_top): + writer = codegen.CodeWriter() + try: + c_type = t.c_type() + t.generate_c_declaration(writer) + value = writer.getvalue().strip() + if not value: + return + if c_type in all_structures: + assert all_structures[c_type] == value, """Structure %s redefinition +previous: +%s +--- +current: +%s +---""" % (c_type, all_structures[c_type], value) + else: + all_structures[c_type] = value + t.generate_c_declaration(writer_top) + except: + print >> sys.stderr, 'type %s' % t + print >> sys.stderr, writer.getvalue() + traceback.print_exc(sys.stderr) + +def generate_declarations(): + writer = codegen.CodeWriter() + writer.public_prefix = options.prefix + writer.write(license) + + # all types + for t in ptypes.get_named_types(): + if isinstance(t, ptypes.StructType): + generate_declaration(t, writer) + if isinstance(t, ptypes.ChannelType): + for m in t.client_messages + t.server_messages: + generate_declaration(m.message_type, writer) + + content = writer.getvalue() + write_content(options.generated_declaration_file, content, + options.keep_identical_file) + +if options.generated_declaration_file: + generate_declarations() + writer.public_prefix = options.prefix writer.writeln("/* this is a file autogenerated by spice_codegen.py */") -- 2.20.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel