#!/usr/bin/env python import os import sys from optparse import OptionParser import traceback from python_modules import spice_parser from python_modules import ptypes from python_modules import codegen from python_modules import demarshal from python_modules import marshal import six def write_channel_enums(writer, channel, client, describe): messages = list(filter(lambda m : m.channel == channel, \ channel.client_messages if client else channel.server_messages)) if len(messages) == 0: return if client: prefix = [ "MSGC" ] else: prefix = [ "MSG" ] if channel.member_name: prefix.append(channel.member_name.upper()) if not describe: writer.begin_block("enum") else: writer.begin_block("static const value_string %s_vs[] = " % (codegen.prefix_underscore_lower(*[x.lower() for x in prefix]))) i = 0 prefix.append(None) # To be replaced with name for m in messages: prefix[-1] = m.name.upper() enum = codegen.prefix_underscore_upper(*prefix) if describe: writer.writeln("{ %s, \"%s %s\" }," % (enum, "Client" if client else "Server", m.name.upper())) else: if m.value == i: writer.writeln("%s," % enum) i = i + 1 else: writer.writeln("%s = %s," % (enum, m.value)) i = m.value + 1 if describe: writer.writeln("{ 0, NULL }"); else: if channel.member_name: prefix[-1] = prefix[-2] prefix[-2] = "END" writer.newline() writer.writeln("%s" % (codegen.prefix_underscore_upper(*prefix))) writer.end_block(semicolon=True) writer.newline() def write_channel_type_enum(writer, describe=False): i = 0 if describe: writer.begin_block("static const value_string channel_types_vs[] =") else: writer.begin_block("enum") for c in proto.channels: enum = codegen.prefix_underscore_upper("CHANNEL", c.name.upper()) if describe: writer.writeln("{ %s, \"%s\" }," % (enum, c.name.upper())) else: if c.value == i: writer.writeln("%s," % enum) i = i + 1 else: writer.writeln("%s = %s," % (enum, c.value)) i = c.value + 1 writer.newline() if describe: writer.writeln("{ 0, NULL }") else: writer.writeln("SPICE_END_CHANNEL") writer.end_block(semicolon=True) writer.newline() def write_enums(writer, describe=False): writer.writeln("#ifndef _H_SPICE_ENUMS") writer.writeln("#define _H_SPICE_ENUMS") writer.newline() # Define enums for t in ptypes.get_named_types(): if isinstance(t, ptypes.EnumBaseType): t.c_define(writer) if describe: t.c_describe(writer) write_channel_type_enum(writer) if (describe): write_channel_type_enum(writer, True) for c in ptypes.get_named_types(): if not isinstance(c, ptypes.ChannelType): continue write_channel_enums(writer, c, False, False) if describe: write_channel_enums(writer, c, False, describe) write_channel_enums(writer, c, True, False) if describe: write_channel_enums(writer, c, True, describe) writer.writeln("#endif /* _H_SPICE_ENUMS */") parser = OptionParser(usage="usage: %prog [options] ") parser.add_option("-e", "--generate-enums", action="store_true", dest="generate_enums", default=False, help="Generate enums") parser.add_option("-w", "--generate-wireshark-dissector", action="store_true", dest="generate_dissector", default=False, help="Generate Wireshark dissector definitions") parser.add_option("-d", "--generate-demarshallers", action="store_true", dest="generate_demarshallers", default=False, help="Generate demarshallers") parser.add_option("-m", "--generate-marshallers", action="store_true", dest="generate_marshallers", default=False, help="Generate message marshallers") parser.add_option("-P", "--private-marshallers", action="store_true", dest="private_marshallers", default=False, help="Generate private message marshallers") parser.add_option("-M", "--generate-struct-marshaller", action="append", dest="struct_marshallers", help="Generate struct marshallers") parser.add_option("-a", "--assert-on-error", action="store_true", dest="assert_on_error", default=False, help="Assert on error") parser.add_option("-H", "--header", action="store_true", dest="header", default=False, help="Generate header") parser.add_option("-p", "--print-error", action="store_true", dest="print_error", default=False, help="Print errors") parser.add_option("-s", "--server", action="store_true", dest="server", default=False, help="Print errors") parser.add_option("-c", "--client", action="store_true", dest="client", default=False, help="Print errors") parser.add_option("-k", "--keep-identical-file", action="store_true", dest="keep_identical_file", default=False, help="Print errors") parser.add_option("-i", "--include", action="append", dest="includes", metavar="FILE", help="Include FILE in generated code") parser.add_option("--prefix", dest="prefix", help="set public symbol prefix", default="") parser.add_option("--ptrsize", dest="ptrsize", help="set default pointer size", default="4") (options, args) = parser.parse_args() if len(args) == 0: parser.error("No protocol file specified") if len(args) == 1: parser.error("No destination file specified") ptypes.default_pointer_size = int(options.ptrsize) proto_file = args[0] dest_file = args[1] proto = spice_parser.parse(proto_file) if proto == None: exit(1) codegen.set_prefix(proto.name) writer = codegen.CodeWriter() writer.header = codegen.CodeWriter() writer.set_option("source", os.path.basename(proto_file)) license = """/* Copyright (C) 2013 Red Hat, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ """ writer.public_prefix = options.prefix writer.writeln("/* this is a file autogenerated by spice_codegen.py */") writer.write(license) writer.header.writeln("/* this is a file autogenerated by spice_codegen.py */") writer.header.write(license) if not options.header and not options.generate_enums: writer.writeln("#ifdef HAVE_CONFIG_H") writer.writeln("#include ") writer.writeln("#endif") if options.assert_on_error: writer.set_option("assert_on_error") if options.print_error: writer.set_option("print_error") if options.includes: for i in options.includes: writer.header.writeln('#include <%s>' % i) writer.writeln('#include <%s>' % i) if options.generate_enums or options.generate_dissector: write_enums(writer, options.generate_dissector) if options.generate_demarshallers: if not options.server and not options.client: print >> sys.stderr, "Must specify client and/or server" sys.exit(1) demarshal.write_includes(writer) if options.server: demarshal.write_protocol_parser(writer, proto, False) if options.client: demarshal.write_protocol_parser(writer, proto, True) if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0): marshal.write_includes(writer) if options.generate_marshallers: if not options.server and not options.client: print >> sys.stderr, "Must specify client and/or server" sys.exit(1) if options.server: marshal.write_protocol_marshaller(writer, proto, False, options.private_marshallers) if options.client: marshal.write_protocol_marshaller(writer, proto, True, options.private_marshallers) if options.struct_marshallers: for structname in options.struct_marshallers: t = ptypes.lookup_type(structname) marshal.write_marshal_ptr_function(writer, t, False) if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0): marshal.write_trailer(writer) if options.header: content = writer.header.getvalue() else: content = writer.getvalue() if options.keep_identical_file: try: f = open(dest_file, 'rb') old_content = f.read() f.close() if content == old_content: six.print_("No changes to %s" % dest_file) sys.exit(0) except IOError: pass f = open(dest_file, 'wb') if six.PY3: f.write(bytes(content, 'UTF-8')) else: f.write(content) f.close() six.print_("Wrote %s" % dest_file) sys.exit(0)