3 # Flexible IDL framework
5 # Copyright IBM, Corp. 2010
8 # Anthony Liguori <aliguori@us.ibm.com>
10 # This work is licensed under the terms of the GNU GPL, version 2. See
11 # the COPYING file in the top-level directory.
14 from fidl
import parse
, scan
, ASTWalker
16 # Generate the function name of the marshalling function for a type
17 class Marshaller(ASTWalker
):
18 def n_type(self
, node
):
19 if node
.value
.endswith('_t'):
20 return node
.value
[:-2]
23 def n_input(self
, node
):
24 if node
.base
.value
== 'char':
27 return self
.walk(node
.base
)
29 def n_output(self
, node
):
30 return self
.walk(node
.base
)
32 def n_struct(self
, node
):
33 return 'struct_%s' % node
.name
37 return 'marshal_%s' % m
.walk(t
)
39 # Helper to emit code depending on the output mode
40 def emit(f
, definition
, body
, header
=False):
50 ''' % (definition
, '\n '.join(body
)))
52 # Walk the AST and generate marshalling code. We always generate the body but
53 # mark the function definitions in a special way. The header generation then
54 # discards everything but the function definitions.
55 class Walker(ASTWalker
):
56 def __init__(self
, f
, header
=False):
57 ASTWalker
.__init
__(self
)
61 # helper to generate the marshalling code for an array
62 def c_array(self
, node
, ns
):
64 body
.append('marshal_start_array(m, "%s", errp);' % node
.name
)
65 body
.append('if (error_is_set(errp)) {')
66 body
.append(' return;')
69 if node
.type.kind
== 'array':
70 body
.append('for (i = 0; i < %s; i++) {' % node
.size
)
71 elif node
.type.kind
== 'varray':
72 body
.append('for (i = 0; i < %s%s; i++) {' % (ns
, node
.type.size
))
73 marshaller
= marshalfn(node
.type.base
)
74 body
.append(' %s(m, &%s%s[i], NULL, errp);' %
75 (marshaller
, ns
, node
.name
))
76 body
.append(' if (error_is_set(errp)) {')
77 body
.append(' return;')
80 body
.append('marshal_end_array(m, errp);')
81 body
.append('if (error_is_set(errp)) {')
82 body
.append(' return;')
86 # helper to generate marshalling code for a structure
87 def c_struct(self
, node
, name
, ns
):
90 kind
= '"%s"' % node
.name
94 if hasattr(node
, 'feature'):
95 body
.append('marshal_start_feature(m, &%s%s, "%s", errp);' % (ns
, node
.feature
, node
.feature
))
96 body
.append('if (error_is_set(errp)) {')
97 body
.append(' return;')
100 body
.append('marshal_start_struct(m, %s, %s, errp);' % (kind
, name
))
101 body
.append('if (error_is_set(errp)) {')
102 body
.append(' return;')
104 for member
in node
.members
:
105 marshaller
= marshalfn(member
.type)
106 if hasattr(node
, 'feature') and member
.name
== node
.feature
:
108 if member
.type.kind
== 'output':
109 body
.append('%s(m, %s%s, "%s", errp);' % (marshaller
, ns
, member
.name
, member
.name
))
110 body
.append('if (error_is_set(errp)) {')
111 body
.append(' return;')
113 elif member
.type.kind
in ['array', 'varray']:
114 body
+= self
.c_array(member
, ns
)
115 elif member
.type.kind
== 'struct' and hasattr(member
.type, 'members'):
116 body
+= self
.c_struct(member
.type, '"%s"' % member
.name
, "%s%s." % (ns
, member
.name
))
118 body
.append('%s(m, &%s%s, "%s", errp);' % (marshaller
, ns
, member
.name
, member
.name
))
119 body
.append('if (error_is_set(errp)) {')
120 body
.append(' return;')
122 body
.append('marshal_end_struct(m, errp);')
123 body
.append('if (error_is_set(errp)) {')
124 body
.append(' return;')
126 if hasattr(node
, 'feature'):
127 body
.append('marshal_end_feature(m, errp);')
128 body
.append('if (error_is_set(errp)) {')
129 body
.append(' return;')
134 # visitor for structs
135 def n_struct(self
, node
):
136 if hasattr(node
, 'members'):
137 hdr
= 'void marshal_struct_%s(Marshaller *m, struct %s *obj, const char *name, Error **errp)' % (
138 node
.name
, node
.name
)
141 body
.append('int i = 0;')
142 body
.append('(void)i;')
143 body
+= self
.c_struct(node
, 'name', 'obj->')
144 emit(self
.f
, hdr
, body
, self
.header
)
147 # visitor for typedefs. we output a second function and call the marshaller
149 def n_typedef(self
, node
):
151 emit(self
.f
, 'void marshal_%s(Marshaller *m, %s *obj, const char *name, Error **errp)' %
152 (node
.alias
, node
.alias
),
153 ['%s(m, obj, name, errp);' % marshalfn(node
.base
)], self
.header
)
156 def walk(f
, tree
, header
=False):
157 walker
= Walker(f
, header
)
158 return walker
.walk(tree
)
160 # generate a C or H file
161 def generate(filename
, base
, tree
, header
=False):
162 f
= open(filename
, 'w')
164 f
.write('''/* THIS FILE IS AUTO-GENERATED, DO NOT EDIT */
168 guard
= base
.rsplit('.', 1)[0]
169 guard
= guard
.rsplit('/', 1)[-1]
170 guard
= guard
.upper()
171 guard
= guard
.replace('-', '_')
172 guard
= 'QEMU_%s_MARSHAL_H' % guard
173 f
.write('''#ifndef %s
179 ''' % (guard
, guard
, base
))
181 f
.write('''#include "%s.h"
183 ''' % filename
.rsplit('.', 1)[0])
185 walk(f
, tree
, header
)
195 print '''Usage: %s [OPTIONS] FILENAME OUTPUT
196 Generate marshalling code from header FILENAME
198 Where OPTIONS may be:
200 -h, --help display this help screen
201 --debug-scan display lexical pass results
202 --debug-parse display initial parse tree
203 --header generate marshalling header in OUTPUT
204 --body generating marshalling body in OUTPUT (default)
206 Report bugs to <qemu-devel@nongnu.org>''' % name
211 opts
, args
= getopt
.getopt(args
, 'h',
212 ['debug-scan', 'debug-parse',
213 'header', 'body', 'help'])
219 for opt
, value
in opts
:
220 if opt
in ['-h', '--help']:
221 usage('qemu-gen-marshal')
223 elif opt
in ['--debug-scan']:
225 elif opt
in ['--debug-parse']:
227 elif opt
in ['--header']:
229 elif opt
in ['--body']:
233 sys
.stderr
.write('Incorrect number of arguments\n')
234 usage('qemu-gen-marshal')
251 generate(output
, filename
, tree
, header
)
255 if __name__
== '__main__':