qemu/scripts/qapi-commands.py
<<
>>
Prefs
   1#
   2# QAPI command marshaller generator
   3#
   4# Copyright IBM, Corp. 2011
   5# Copyright (C) 2014-2016 Red Hat, Inc.
   6#
   7# Authors:
   8#  Anthony Liguori <aliguori@us.ibm.com>
   9#  Michael Roth    <mdroth@linux.vnet.ibm.com>
  10#  Markus Armbruster <armbru@redhat.com>
  11#
  12# This work is licensed under the terms of the GNU GPL, version 2.
  13# See the COPYING file in the top-level directory.
  14
  15from qapi import *
  16import re
  17
  18
  19def gen_command_decl(name, arg_type, ret_type):
  20    return mcgen('''
  21%(c_type)s qmp_%(c_name)s(%(params)s);
  22''',
  23                 c_type=(ret_type and ret_type.c_type()) or 'void',
  24                 c_name=c_name(name),
  25                 params=gen_params(arg_type, 'Error **errp'))
  26
  27
  28def gen_call(name, arg_type, ret_type):
  29    ret = ''
  30
  31    argstr = ''
  32    if arg_type:
  33        assert not arg_type.variants
  34        for memb in arg_type.members:
  35            if memb.optional:
  36                argstr += 'arg.has_%s, ' % c_name(memb.name)
  37            argstr += 'arg.%s, ' % c_name(memb.name)
  38
  39    lhs = ''
  40    if ret_type:
  41        lhs = 'retval = '
  42
  43    ret = mcgen('''
  44
  45    %(lhs)sqmp_%(c_name)s(%(args)s&err);
  46''',
  47                c_name=c_name(name), args=argstr, lhs=lhs)
  48    if ret_type:
  49        ret += gen_err_check()
  50        ret += mcgen('''
  51
  52    qmp_marshal_output_%(c_name)s(retval, ret, &err);
  53''',
  54                     c_name=ret_type.c_name())
  55    return ret
  56
  57
  58def gen_marshal_output(ret_type):
  59    return mcgen('''
  60
  61static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
  62{
  63    Error *err = NULL;
  64    QmpOutputVisitor *qov = qmp_output_visitor_new();
  65    QapiDeallocVisitor *qdv;
  66    Visitor *v;
  67
  68    v = qmp_output_get_visitor(qov);
  69    visit_type_%(c_name)s(v, "unused", &ret_in, &err);
  70    if (err) {
  71        goto out;
  72    }
  73    *ret_out = qmp_output_get_qobject(qov);
  74
  75out:
  76    error_propagate(errp, err);
  77    qmp_output_visitor_cleanup(qov);
  78    qdv = qapi_dealloc_visitor_new();
  79    v = qapi_dealloc_get_visitor(qdv);
  80    visit_type_%(c_name)s(v, "unused", &ret_in, NULL);
  81    qapi_dealloc_visitor_cleanup(qdv);
  82}
  83''',
  84                 c_type=ret_type.c_type(), c_name=ret_type.c_name())
  85
  86
  87def gen_marshal_proto(name):
  88    ret = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
  89    if not middle_mode:
  90        ret = 'static ' + ret
  91    return ret
  92
  93
  94def gen_marshal_decl(name):
  95    return mcgen('''
  96%(proto)s;
  97''',
  98                 proto=gen_marshal_proto(name))
  99
 100
 101def gen_marshal(name, arg_type, ret_type):
 102    ret = mcgen('''
 103
 104%(proto)s
 105{
 106    Error *err = NULL;
 107''',
 108                proto=gen_marshal_proto(name))
 109
 110    if ret_type:
 111        ret += mcgen('''
 112    %(c_type)s retval;
 113''',
 114                     c_type=ret_type.c_type())
 115
 116    if arg_type and arg_type.members:
 117        ret += mcgen('''
 118    QmpInputVisitor *qiv = qmp_input_visitor_new_strict(QOBJECT(args));
 119    QapiDeallocVisitor *qdv;
 120    Visitor *v;
 121    %(c_name)s arg = {0};
 122
 123    v = qmp_input_get_visitor(qiv);
 124    visit_type_%(c_name)s_members(v, &arg, &err);
 125    if (err) {
 126        goto out;
 127    }
 128''',
 129                     c_name=arg_type.c_name())
 130
 131    else:
 132        ret += mcgen('''
 133
 134    (void)args;
 135''')
 136
 137    ret += gen_call(name, arg_type, ret_type)
 138
 139    # 'goto out' produced above for arg_type, and by gen_call() for ret_type
 140    if (arg_type and arg_type.members) or ret_type:
 141        ret += mcgen('''
 142
 143out:
 144''')
 145    ret += mcgen('''
 146    error_propagate(errp, err);
 147''')
 148    if arg_type and arg_type.members:
 149        ret += mcgen('''
 150    qmp_input_visitor_cleanup(qiv);
 151    qdv = qapi_dealloc_visitor_new();
 152    v = qapi_dealloc_get_visitor(qdv);
 153    visit_type_%(c_name)s_members(v, &arg, NULL);
 154    qapi_dealloc_visitor_cleanup(qdv);
 155''',
 156                     c_name=arg_type.c_name())
 157
 158    ret += mcgen('''
 159}
 160''')
 161    return ret
 162
 163
 164def gen_register_command(name, success_response):
 165    options = 'QCO_NO_OPTIONS'
 166    if not success_response:
 167        options = 'QCO_NO_SUCCESS_RESP'
 168
 169    ret = mcgen('''
 170    qmp_register_command("%(name)s", qmp_marshal_%(c_name)s, %(opts)s);
 171''',
 172                name=name, c_name=c_name(name),
 173                opts=options)
 174    return ret
 175
 176
 177def gen_registry(registry):
 178    ret = mcgen('''
 179
 180static void qmp_init_marshal(void)
 181{
 182''')
 183    ret += registry
 184    ret += mcgen('''
 185}
 186
 187qapi_init(qmp_init_marshal);
 188''')
 189    return ret
 190
 191
 192class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
 193    def __init__(self):
 194        self.decl = None
 195        self.defn = None
 196        self._regy = None
 197        self._visited_ret_types = None
 198
 199    def visit_begin(self, schema):
 200        self.decl = ''
 201        self.defn = ''
 202        self._regy = ''
 203        self._visited_ret_types = set()
 204
 205    def visit_end(self):
 206        if not middle_mode:
 207            self.defn += gen_registry(self._regy)
 208        self._regy = None
 209        self._visited_ret_types = None
 210
 211    def visit_command(self, name, info, arg_type, ret_type,
 212                      gen, success_response):
 213        if not gen:
 214            return
 215        self.decl += gen_command_decl(name, arg_type, ret_type)
 216        if ret_type and ret_type not in self._visited_ret_types:
 217            self._visited_ret_types.add(ret_type)
 218            self.defn += gen_marshal_output(ret_type)
 219        if middle_mode:
 220            self.decl += gen_marshal_decl(name)
 221        self.defn += gen_marshal(name, arg_type, ret_type)
 222        if not middle_mode:
 223            self._regy += gen_register_command(name, success_response)
 224
 225
 226middle_mode = False
 227
 228(input_file, output_dir, do_c, do_h, prefix, opts) = \
 229    parse_command_line("m", ["middle"])
 230
 231for o, a in opts:
 232    if o in ("-m", "--middle"):
 233        middle_mode = True
 234
 235c_comment = '''
 236/*
 237 * schema-defined QMP->QAPI command dispatch
 238 *
 239 * Copyright IBM, Corp. 2011
 240 *
 241 * Authors:
 242 *  Anthony Liguori   <aliguori@us.ibm.com>
 243 *
 244 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 245 * See the COPYING.LIB file in the top-level directory.
 246 *
 247 */
 248'''
 249h_comment = '''
 250/*
 251 * schema-defined QAPI function prototypes
 252 *
 253 * Copyright IBM, Corp. 2011
 254 *
 255 * Authors:
 256 *  Anthony Liguori   <aliguori@us.ibm.com>
 257 *
 258 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 259 * See the COPYING.LIB file in the top-level directory.
 260 *
 261 */
 262'''
 263
 264(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
 265                            'qmp-marshal.c', 'qmp-commands.h',
 266                            c_comment, h_comment)
 267
 268fdef.write(mcgen('''
 269#include "qemu/osdep.h"
 270#include "qemu-common.h"
 271#include "qemu/module.h"
 272#include "qapi/qmp/types.h"
 273#include "qapi/qmp/dispatch.h"
 274#include "qapi/visitor.h"
 275#include "qapi/qmp-output-visitor.h"
 276#include "qapi/qmp-input-visitor.h"
 277#include "qapi/dealloc-visitor.h"
 278#include "%(prefix)sqapi-types.h"
 279#include "%(prefix)sqapi-visit.h"
 280#include "%(prefix)sqmp-commands.h"
 281
 282''',
 283                 prefix=prefix))
 284
 285fdecl.write(mcgen('''
 286#include "%(prefix)sqapi-types.h"
 287#include "qapi/qmp/qdict.h"
 288#include "qapi/error.h"
 289
 290''',
 291                  prefix=prefix))
 292
 293schema = QAPISchema(input_file)
 294gen = QAPISchemaGenCommandVisitor()
 295schema.visit(gen)
 296fdef.write(gen.defn)
 297fdecl.write(gen.decl)
 298
 299close_output(fdef, fdecl)
 300