Statistics
| Branch: | Revision:

root / scripts / qapi-commands.py @ c17d9908

History | View | Annotate | Download (9.6 kB)

1
#
2
# QAPI command marshaller generator
3
#
4
# Copyright IBM, Corp. 2011
5
#
6
# Authors:
7
#  Anthony Liguori <aliguori@us.ibm.com>
8
#  Michael Roth    <mdroth@linux.vnet.ibm.com>
9
#
10
# This work is licensed under the terms of the GNU GPLv2.
11
# See the COPYING.LIB file in the top-level directory.
12

    
13
from ordereddict import OrderedDict
14
from qapi import *
15
import sys
16
import os
17
import getopt
18
import errno
19

    
20
def generate_decl_enum(name, members, genlist=True):
21
    return mcgen('''
22

23
void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
24
''',
25
                name=name)
26

    
27
def generate_command_decl(name, args, ret_type):
28
    arglist=""
29
    for argname, argtype, optional, structured in parse_args(args):
30
        argtype = c_type(argtype)
31
        if argtype == "char *":
32
            argtype = "const char *"
33
        if optional:
34
            arglist += "bool has_%s, " % c_var(argname)
35
        arglist += "%s %s, " % (argtype, c_var(argname))
36
    return mcgen('''
37
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
38
''',
39
                 ret_type=c_type(ret_type), name=c_var(name), args=arglist).strip()
40

    
41
def gen_sync_call(name, args, ret_type, indent=0):
42
    ret = ""
43
    arglist=""
44
    retval=""
45
    if ret_type:
46
        retval = "retval = "
47
    for argname, argtype, optional, structured in parse_args(args):
48
        if optional:
49
            arglist += "has_%s, " % c_var(argname)
50
        arglist += "%s, " % (c_var(argname))
51
    push_indent(indent)
52
    ret = mcgen('''
53
%(retval)sqmp_%(name)s(%(args)serrp);
54

55
''',
56
                name=c_var(name), args=arglist, retval=retval).rstrip()
57
    if ret_type:
58
        ret += "\n" + mcgen(''''
59
%(marshal_output_call)s
60
''',
61
                            marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
62
    pop_indent(indent)
63
    return ret.rstrip()
64

    
65

    
66
def gen_marshal_output_call(name, ret_type):
67
    if not ret_type:
68
        return ""
69
    return "qmp_marshal_output_%s(retval, ret, errp);" % c_var(name)
70

    
71
def gen_visitor_output_containers_decl(ret_type):
72
    ret = ""
73
    push_indent()
74
    if ret_type:
75
        ret += mcgen('''
76
QmpOutputVisitor *mo;
77
QapiDeallocVisitor *md;
78
Visitor *v;
79
''')
80
    pop_indent()
81

    
82
    return ret
83

    
84
def gen_visitor_input_containers_decl(args):
85
    ret = ""
86

    
87
    push_indent()
88
    if len(args) > 0:
89
        ret += mcgen('''
90
QmpInputVisitor *mi;
91
QapiDeallocVisitor *md;
92
Visitor *v;
93
''')
94
    pop_indent()
95

    
96
    return ret.rstrip()
97

    
98
def gen_visitor_input_vars_decl(args):
99
    ret = ""
100
    push_indent()
101
    for argname, argtype, optional, structured in parse_args(args):
102
        if optional:
103
            ret += mcgen('''
104
bool has_%(argname)s = false;
105
''',
106
                         argname=c_var(argname))
107
        if c_type(argtype).endswith("*"):
108
            ret += mcgen('''
109
%(argtype)s %(argname)s = NULL;
110
''',
111
                         argname=c_var(argname), argtype=c_type(argtype))
112
        else:
113
            ret += mcgen('''
114
%(argtype)s %(argname)s;
115
''',
116
                         argname=c_var(argname), argtype=c_type(argtype))
117

    
118
    pop_indent()
119
    return ret.rstrip()
120

    
121
def gen_visitor_input_block(args, obj, dealloc=False):
122
    ret = ""
123
    if len(args) == 0:
124
        return ret
125

    
126
    push_indent()
127

    
128
    if dealloc:
129
        ret += mcgen('''
130
md = qapi_dealloc_visitor_new();
131
v = qapi_dealloc_get_visitor(md);
132
''')
133
    else:
134
        ret += mcgen('''
135
mi = qmp_input_visitor_new(%(obj)s);
136
v = qmp_input_get_visitor(mi);
137
''',
138
                     obj=obj)
139

    
140
    for argname, argtype, optional, structured in parse_args(args):
141
        if optional:
142
            ret += mcgen('''
143
visit_start_optional(v, &has_%(c_name)s, "%(name)s", errp);
144
if (has_%(c_name)s) {
145
''',
146
                         c_name=c_var(argname), name=argname)
147
            push_indent()
148
        ret += mcgen('''
149
visit_type_%(argtype)s(v, &%(c_name)s, "%(name)s", errp);
150
''',
151
                      c_name=c_var(argname), name=argname, argtype=argtype)
152
        if optional:
153
            pop_indent()
154
            ret += mcgen('''
155
}
156
visit_end_optional(v, errp);
157
''')
158

    
159
    if dealloc:
160
        ret += mcgen('''
161
qapi_dealloc_visitor_cleanup(md);
162
''')
163
    else:
164
        ret += mcgen('''
165
qmp_input_visitor_cleanup(mi);
166
''')
167
    pop_indent()
168
    return ret.rstrip()
169

    
170
def gen_marshal_output(name, args, ret_type):
171
    if not ret_type:
172
        return ""
173
    ret = mcgen('''
174
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
175
{
176
    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
177
    QmpOutputVisitor *mo = qmp_output_visitor_new();
178
    Visitor *v;
179

180
    v = qmp_output_get_visitor(mo);
181
    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
182
    if (!error_is_set(errp)) {
183
        *ret_out = qmp_output_get_qobject(mo);
184
    }
185
    qmp_output_visitor_cleanup(mo);
186
    v = qapi_dealloc_get_visitor(md);
187
    visit_type_%(ret_type)s(v, &ret_in, "unused", errp);
188
    qapi_dealloc_visitor_cleanup(md);
189
}
190
''',
191
            c_ret_type=c_type(ret_type), c_name=c_var(name), ret_type=ret_type)
192

    
193
    return ret
194

    
195
def gen_marshal_input(name, args, ret_type):
196
    ret = mcgen('''
197
static void qmp_marshal_input_%(c_name)s(QDict *args, QObject **ret, Error **errp)
198
{
199
''',
200
                c_name=c_var(name))
201

    
202
    if ret_type:
203
        if c_type(ret_type).endswith("*"):
204
            retval = "    %s retval = NULL;" % c_type(ret_type)
205
        else:
206
            retval = "    %s retval;" % c_type(ret_type)
207
        ret += mcgen('''
208
%(retval)s
209
''',
210
                     retval=retval)
211

    
212
    if len(args) > 0:
213
        ret += mcgen('''
214
%(visitor_input_containers_decl)s
215
%(visitor_input_vars_decl)s
216

217
%(visitor_input_block)s
218

219
''',
220
                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
221
                     visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
222
                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
223

    
224
    ret += mcgen('''
225
    if (error_is_set(errp)) {
226
        goto out;
227
    }
228
%(sync_call)s
229
''',
230
                 sync_call=gen_sync_call(name, args, ret_type, indent=4))
231
    ret += mcgen('''
232

233
out:
234
''')
235
    ret += mcgen('''
236
%(visitor_input_block_cleanup)s
237
    return;
238
}
239
''',
240
                 visitor_input_block_cleanup=gen_visitor_input_block(args, None, dealloc=True))
241
    return ret
242

    
243
def gen_registry(commands):
244
    registry=""
245
    push_indent()
246
    for cmd in commands:
247
        registry += mcgen('''
248
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
249
''',
250
                     name=cmd['command'], c_name=c_var(cmd['command']))
251
    pop_indent()
252
    ret = mcgen('''
253
static void qmp_init_marshal(void)
254
{
255
%(registry)s
256
}
257

258
qapi_init(qmp_init_marshal);
259
''',
260
                registry=registry.rstrip())
261
    return ret
262

    
263
def gen_command_decl_prologue(header, guard, prefix=""):
264
    ret = mcgen('''
265
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
266

267
/*
268
 * schema-defined QAPI function prototypes
269
 *
270
 * Copyright IBM, Corp. 2011
271
 *
272
 * Authors:
273
 *  Anthony Liguori   <aliguori@us.ibm.com>
274
 *
275
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
276
 * See the COPYING.LIB file in the top-level directory.
277
 *
278
 */
279

280
#ifndef %(guard)s
281
#define %(guard)s
282

283
#include "%(prefix)sqapi-types.h"
284
#include "error.h"
285

286
''',
287
                 header=basename(h_file), guard=guardname(h_file), prefix=prefix)
288
    return ret
289

    
290
def gen_command_def_prologue(prefix="", proxy=False):
291
    ret = mcgen('''
292
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
293

294
/*
295
 * schema-defined QMP->QAPI command dispatch
296
 *
297
 * Copyright IBM, Corp. 2011
298
 *
299
 * Authors:
300
 *  Anthony Liguori   <aliguori@us.ibm.com>
301
 *
302
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
303
 * See the COPYING.LIB file in the top-level directory.
304
 *
305
 */
306

307
#include "qemu-objects.h"
308
#include "qapi/qmp-core.h"
309
#include "qapi/qapi-visit-core.h"
310
#include "qapi/qmp-output-visitor.h"
311
#include "qapi/qmp-input-visitor.h"
312
#include "qapi/qapi-dealloc-visitor.h"
313
#include "%(prefix)sqapi-types.h"
314
#include "%(prefix)sqapi-visit.h"
315

316
''',
317
                prefix=prefix)
318
    if not proxy:
319
        ret += '#include "%sqmp-commands.h"' % prefix
320
    return ret + "\n"
321

    
322

    
323
try:
324
    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir=", "type="])
325
except getopt.GetoptError, err:
326
    print str(err)
327
    sys.exit(1)
328

    
329
output_dir = ""
330
prefix = ""
331
dispatch_type = "sync"
332
c_file = 'qmp-marshal.c'
333
h_file = 'qmp-commands.h'
334

    
335
for o, a in opts:
336
    if o in ("-p", "--prefix"):
337
        prefix = a
338
    elif o in ("-o", "--output-dir"):
339
        output_dir = a + "/"
340
    elif o in ("-t", "--type"):
341
        dispatch_type = a
342

    
343
c_file = output_dir + prefix + c_file
344
h_file = output_dir + prefix + h_file
345

    
346
try:
347
    os.makedirs(output_dir)
348
except os.error, e:
349
    if e.errno != errno.EEXIST:
350
        raise
351

    
352
exprs = parse_schema(sys.stdin)
353
commands = filter(lambda expr: expr.has_key('command'), exprs)
354

    
355
if dispatch_type == "sync":
356
    fdecl = open(h_file, 'w')
357
    fdef = open(c_file, 'w')
358
    ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
359
    fdecl.write(ret)
360
    ret = gen_command_def_prologue(prefix=prefix)
361
    fdef.write(ret)
362

    
363
    for cmd in commands:
364
        arglist = []
365
        ret_type = None
366
        if cmd.has_key('data'):
367
            arglist = cmd['data']
368
        if cmd.has_key('returns'):
369
            ret_type = cmd['returns']
370
        ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
371
        fdecl.write(ret)
372
        if ret_type:
373
            ret = gen_marshal_output(cmd['command'], arglist, ret_type) + "\n"
374
            fdef.write(ret)
375
        ret = gen_marshal_input(cmd['command'], arglist, ret_type) + "\n"
376
        fdef.write(ret)
377

    
378
    fdecl.write("\n#endif");
379
    ret = gen_registry(commands)
380
    fdef.write(ret)
381

    
382
    fdef.flush()
383
    fdef.close()
384
    fdecl.flush()
385
    fdecl.close()