uploaded original spice-server-0.12.4 and celt-0.5.1.3
[sdk/emulator/libs/spice-server.git] / spice-common / spice_codegen.py
1 #!/usr/bin/env python
2
3 import os
4 import sys
5 from optparse import OptionParser
6 import traceback
7 from python_modules import spice_parser
8 from python_modules import ptypes
9 from python_modules import codegen
10 from python_modules import demarshal
11 from python_modules import marshal
12
13 def write_channel_enums(writer, channel, client):
14     messages = filter(lambda m : m.channel == channel, \
15                           channel.client_messages if client else channel.server_messages)
16     if len(messages) == 0:
17         return
18     writer.begin_block("enum")
19     i = 0
20     if client:
21         prefix = [ "MSGC" ]
22     else:
23         prefix = [ "MSG" ]
24     if channel.member_name:
25         prefix.append(channel.member_name.upper())
26     prefix.append(None) # To be replaced with name
27     for m in messages:
28         prefix[-1] = m.name.upper()
29         enum = codegen.prefix_underscore_upper(*prefix)
30         if m.value == i:
31             writer.writeln("%s," % enum)
32             i = i + 1
33         else:
34             writer.writeln("%s = %s," % (enum, m.value))
35             i = m.value + 1
36     if channel.member_name:
37         prefix[-1] = prefix[-2]
38         prefix[-2] = "END"
39         writer.newline()
40         writer.writeln("%s" % (codegen.prefix_underscore_upper(*prefix)))
41     writer.end_block(semicolon=True)
42     writer.newline()
43
44 def write_enums(writer):
45     writer.writeln("#ifndef _H_SPICE_ENUMS")
46     writer.writeln("#define _H_SPICE_ENUMS")
47     writer.newline()
48     writer.comment("Generated from %s, don't edit" % writer.options["source"]).newline()
49     writer.newline()
50
51     # Define enums
52     for t in ptypes.get_named_types():
53         if isinstance(t, ptypes.EnumBaseType):
54             t.c_define(writer)
55
56     i = 0
57     writer.begin_block("enum")
58     for c in proto.channels:
59         enum = codegen.prefix_underscore_upper("CHANNEL", c.name.upper())
60         if c.value == i:
61             writer.writeln("%s," % enum)
62             i = i + 1
63         else:
64             writer.writeln("%s = %s," % (enum, c.value))
65             i = c.value + 1
66     writer.newline()
67     writer.writeln("SPICE_END_CHANNEL")
68     writer.end_block(semicolon=True)
69     writer.newline()
70
71     for c in ptypes.get_named_types():
72         if not isinstance(c, ptypes.ChannelType):
73             continue
74         write_channel_enums(writer, c, False)
75         write_channel_enums(writer, c, True)
76
77     writer.writeln("#endif /* _H_SPICE_ENUMS */")
78
79 parser = OptionParser(usage="usage: %prog [options] <protocol_file> <destination file>")
80 parser.add_option("-e", "--generate-enums",
81                   action="store_true", dest="generate_enums", default=False,
82                   help="Generate enums")
83 parser.add_option("-d", "--generate-demarshallers",
84                   action="store_true", dest="generate_demarshallers", default=False,
85                   help="Generate demarshallers")
86 parser.add_option("-m", "--generate-marshallers",
87                   action="store_true", dest="generate_marshallers", default=False,
88                   help="Generate message marshallers")
89 parser.add_option("-P", "--private-marshallers",
90                   action="store_true", dest="private_marshallers", default=False,
91                   help="Generate private message marshallers")
92 parser.add_option("-M", "--generate-struct-marshaller",
93                   action="append", dest="struct_marshallers",
94                   help="Generate struct marshallers")
95 parser.add_option("-a", "--assert-on-error",
96                   action="store_true", dest="assert_on_error", default=False,
97                   help="Assert on error")
98 parser.add_option("-H", "--header",
99                   action="store_true", dest="header", default=False,
100                   help="Generate header")
101 parser.add_option("-p", "--print-error",
102                   action="store_true", dest="print_error", default=False,
103                   help="Print errors")
104 parser.add_option("-s", "--server",
105                   action="store_true", dest="server", default=False,
106                   help="Print errors")
107 parser.add_option("-c", "--client",
108                   action="store_true", dest="client", default=False,
109                   help="Print errors")
110 parser.add_option("-k", "--keep-identical-file",
111                   action="store_true", dest="keep_identical_file", default=False,
112                   help="Print errors")
113 parser.add_option("-i", "--include",
114                   action="append", dest="includes", metavar="FILE",
115                   help="Include FILE in generated code")
116 parser.add_option("--prefix", dest="prefix",
117                   help="set public symbol prefix", default="")
118 parser.add_option("--ptrsize", dest="ptrsize",
119                   help="set default pointer size", default="4")
120
121 (options, args) = parser.parse_args()
122
123 if len(args) == 0:
124     parser.error("No protocol file specified")
125
126 if len(args) == 1:
127     parser.error("No destination file specified")
128
129 ptypes.default_pointer_size = int(options.ptrsize)
130
131 proto_file = args[0]
132 dest_file = args[1]
133 proto = spice_parser.parse(proto_file)
134
135 if proto == None:
136     exit(1)
137
138 codegen.set_prefix(proto.name)
139 writer = codegen.CodeWriter()
140 writer.header = codegen.CodeWriter()
141 writer.set_option("source", os.path.basename(proto_file))
142
143 writer.public_prefix = options.prefix
144
145 writer.writeln("/* this is a file autogenerated by spice_codegen.py */")
146 writer.header.writeln("/* this is a file autogenerated by spice_codegen.py */")
147 if not options.header and not options.generate_enums:
148     writer.writeln("#ifdef HAVE_CONFIG_H")
149     writer.writeln("#include <config.h>")
150     writer.writeln("#endif")
151
152 if options.assert_on_error:
153     writer.set_option("assert_on_error")
154
155 if options.print_error:
156     writer.set_option("print_error")
157
158 if options.includes:
159     for i in options.includes:
160         writer.header.writeln('#include "%s"' % i)
161         writer.writeln('#include "%s"' % i)
162
163 if options.generate_enums:
164     write_enums(writer)
165
166 if options.generate_demarshallers:
167     if not options.server and not options.client:
168         print >> sys.stderr, "Must specify client and/or server"
169         sys.exit(1)
170     demarshal.write_includes(writer)
171
172     if options.server:
173         demarshal.write_protocol_parser(writer, proto, False)
174     if options.client:
175         demarshal.write_protocol_parser(writer, proto, True)
176
177 if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0):
178     marshal.write_includes(writer)
179
180 if options.generate_marshallers:
181     if not options.server and not options.client:
182         print >> sys.stderr, "Must specify client and/or server"
183         sys.exit(1)
184     if options.server:
185         marshal.write_protocol_marshaller(writer, proto, False, options.private_marshallers)
186     if options.client:
187         marshal.write_protocol_marshaller(writer, proto, True, options.private_marshallers)
188
189 if options.struct_marshallers:
190     for structname in options.struct_marshallers:
191         t = ptypes.lookup_type(structname)
192         marshal.write_marshal_ptr_function(writer, t, False)
193
194 if options.generate_marshallers or (options.struct_marshallers and len(options.struct_marshallers) > 0):
195     marshal.write_trailer(writer)
196
197 if options.header:
198     content = writer.header.getvalue()
199 else:
200     content = writer.getvalue()
201 if options.keep_identical_file:
202     try:
203         f = open(dest_file, 'rb')
204         old_content = f.read()
205         f.close()
206
207         if content == old_content:
208             print "No changes to %s" % dest_file
209             sys.exit(0)
210
211     except IOError:
212         pass
213
214 f = open(dest_file, 'wb')
215 f.write(content)
216 f.close()
217
218 print "Wrote %s" % dest_file
219 sys.exit(0)