Statistics
| Branch: | Revision:

root / scripts / qapi-commands.py @ 776574d6

History | View | Annotate | Download (10.7 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, middle_mode):
171
    if not ret_type:
172
        return ""
173

    
174
    ret = mcgen('''
175
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
176
{
177
    QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
178
    QmpOutputVisitor *mo = qmp_output_visitor_new();
179
    Visitor *v;
180

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

    
195
    return ret
196

    
197
def gen_marshal_input_decl(name, args, ret_type, middle_mode):
198
    if middle_mode:
199
        return 'int qmp_marshal_input_%s(Monitor *mon, const QDict *qdict, QObject **ret)' % c_var(name)
200
    else:
201
        return 'static void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_var(name)
202

    
203

    
204

    
205
def gen_marshal_input(name, args, ret_type, middle_mode):
206
    hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode)
207

    
208
    ret = mcgen('''
209
%(header)s
210
{
211
''',
212
                header=hdr)
213

    
214
    if middle_mode:
215
        ret += mcgen('''
216
    Error *local_err = NULL;
217
    Error **errp = &local_err;
218
    QDict *args = (QDict *)qdict;
219
''')
220

    
221
    if ret_type:
222
        if c_type(ret_type).endswith("*"):
223
            retval = "    %s retval = NULL;" % c_type(ret_type)
224
        else:
225
            retval = "    %s retval;" % c_type(ret_type)
226
        ret += mcgen('''
227
%(retval)s
228
''',
229
                     retval=retval)
230

    
231
    if len(args) > 0:
232
        ret += mcgen('''
233
%(visitor_input_containers_decl)s
234
%(visitor_input_vars_decl)s
235

236
%(visitor_input_block)s
237

238
''',
239
                     visitor_input_containers_decl=gen_visitor_input_containers_decl(args),
240
                     visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
241
                     visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)"))
242
    else:
243
        ret += mcgen('''
244
    (void)args;
245
''')
246

    
247
    ret += mcgen('''
248
    if (error_is_set(errp)) {
249
        goto out;
250
    }
251
%(sync_call)s
252
''',
253
                 sync_call=gen_sync_call(name, args, ret_type, indent=4))
254
    ret += mcgen('''
255

256
out:
257
''')
258
    ret += mcgen('''
259
%(visitor_input_block_cleanup)s
260
''',
261
                 visitor_input_block_cleanup=gen_visitor_input_block(args, None,
262
                                                                     dealloc=True))
263

    
264
    if middle_mode:
265
        ret += mcgen('''
266

267
    if (local_err) {
268
        qerror_report_err(local_err);
269
        error_free(local_err);
270
        return -1;
271
    }
272
    return 0;
273
''')
274
    else:
275
        ret += mcgen('''
276
    return;
277
''')
278

    
279
    ret += mcgen('''
280
}
281
''')
282

    
283
    return ret
284

    
285
def gen_registry(commands):
286
    registry=""
287
    push_indent()
288
    for cmd in commands:
289
        registry += mcgen('''
290
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s);
291
''',
292
                     name=cmd['command'], c_name=c_var(cmd['command']))
293
    pop_indent()
294
    ret = mcgen('''
295
static void qmp_init_marshal(void)
296
{
297
%(registry)s
298
}
299

300
qapi_init(qmp_init_marshal);
301
''',
302
                registry=registry.rstrip())
303
    return ret
304

    
305
def gen_command_decl_prologue(header, guard, prefix=""):
306
    ret = mcgen('''
307
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
308

309
/*
310
 * schema-defined QAPI function prototypes
311
 *
312
 * Copyright IBM, Corp. 2011
313
 *
314
 * Authors:
315
 *  Anthony Liguori   <aliguori@us.ibm.com>
316
 *
317
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
318
 * See the COPYING.LIB file in the top-level directory.
319
 *
320
 */
321

322
#ifndef %(guard)s
323
#define %(guard)s
324

325
#include "%(prefix)sqapi-types.h"
326
#include "error.h"
327

328
''',
329
                 header=basename(header), guard=guardname(header), prefix=prefix)
330
    return ret
331

    
332
def gen_command_def_prologue(prefix="", proxy=False):
333
    ret = mcgen('''
334
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
335

336
/*
337
 * schema-defined QMP->QAPI command dispatch
338
 *
339
 * Copyright IBM, Corp. 2011
340
 *
341
 * Authors:
342
 *  Anthony Liguori   <aliguori@us.ibm.com>
343
 *
344
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
345
 * See the COPYING.LIB file in the top-level directory.
346
 *
347
 */
348

349
#include "qemu-objects.h"
350
#include "qapi/qmp-core.h"
351
#include "qapi/qapi-visit-core.h"
352
#include "qapi/qmp-output-visitor.h"
353
#include "qapi/qmp-input-visitor.h"
354
#include "qapi/qapi-dealloc-visitor.h"
355
#include "%(prefix)sqapi-types.h"
356
#include "%(prefix)sqapi-visit.h"
357

358
''',
359
                prefix=prefix)
360
    if not proxy:
361
        ret += '#include "%sqmp-commands.h"' % prefix
362
    return ret + "\n\n"
363

    
364

    
365
try:
366
    opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:m", ["prefix=", "output-dir=", "type=", "middle"])
367
except getopt.GetoptError, err:
368
    print str(err)
369
    sys.exit(1)
370

    
371
output_dir = ""
372
prefix = ""
373
dispatch_type = "sync"
374
c_file = 'qmp-marshal.c'
375
h_file = 'qmp-commands.h'
376
middle_mode = False
377

    
378
for o, a in opts:
379
    if o in ("-p", "--prefix"):
380
        prefix = a
381
    elif o in ("-o", "--output-dir"):
382
        output_dir = a + "/"
383
    elif o in ("-t", "--type"):
384
        dispatch_type = a
385
    elif o in ("-m", "--middle"):
386
        middle_mode = True
387

    
388
c_file = output_dir + prefix + c_file
389
h_file = output_dir + prefix + h_file
390

    
391
try:
392
    os.makedirs(output_dir)
393
except os.error, e:
394
    if e.errno != errno.EEXIST:
395
        raise
396

    
397
exprs = parse_schema(sys.stdin)
398
commands = filter(lambda expr: expr.has_key('command'), exprs)
399

    
400
if dispatch_type == "sync":
401
    fdecl = open(h_file, 'w')
402
    fdef = open(c_file, 'w')
403
    ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix)
404
    fdecl.write(ret)
405
    ret = gen_command_def_prologue(prefix=prefix)
406
    fdef.write(ret)
407

    
408
    for cmd in commands:
409
        arglist = []
410
        ret_type = None
411
        if cmd.has_key('data'):
412
            arglist = cmd['data']
413
        if cmd.has_key('returns'):
414
            ret_type = cmd['returns']
415
        ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
416
        fdecl.write(ret)
417
        if ret_type:
418
            ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
419
            fdef.write(ret)
420

    
421
        if middle_mode:
422
            fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
423

    
424
        ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
425
        fdef.write(ret)
426

    
427
    fdecl.write("\n#endif\n");
428

    
429
    if not middle_mode:
430
        ret = gen_registry(commands)
431
        fdef.write(ret)
432

    
433
    fdef.flush()
434
    fdef.close()
435
    fdecl.flush()
436
    fdecl.close()