2011-07-19 23:50:41 +04:00
|
|
|
#
|
|
|
|
# QAPI visitor generator
|
|
|
|
#
|
|
|
|
# Copyright IBM, Corp. 2011
|
|
|
|
#
|
|
|
|
# Authors:
|
|
|
|
# Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
# Michael Roth <mdroth@linux.vnet.ibm.com>
|
|
|
|
#
|
|
|
|
# This work is licensed under the terms of the GNU GPLv2.
|
|
|
|
# See the COPYING.LIB file in the top-level directory.
|
|
|
|
|
|
|
|
from ordereddict import OrderedDict
|
|
|
|
from qapi import *
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import getopt
|
|
|
|
import errno
|
|
|
|
|
2012-07-17 18:17:04 +04:00
|
|
|
def generate_visit_struct_body(field_prefix, name, members):
|
|
|
|
ret = mcgen('''
|
|
|
|
if (!error_is_set(errp)) {
|
|
|
|
''')
|
|
|
|
push_indent()
|
|
|
|
|
2011-07-19 23:50:41 +04:00
|
|
|
if len(field_prefix):
|
|
|
|
field_prefix = field_prefix + "."
|
2012-07-17 18:17:04 +04:00
|
|
|
ret += mcgen('''
|
|
|
|
Error **errp = &err; /* from outer scope */
|
|
|
|
Error *err = NULL;
|
|
|
|
visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
else:
|
|
|
|
ret += mcgen('''
|
|
|
|
Error *err = NULL;
|
|
|
|
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
ret += mcgen('''
|
|
|
|
if (!err) {
|
|
|
|
if (!obj || *obj) {
|
|
|
|
''')
|
|
|
|
|
|
|
|
push_indent()
|
|
|
|
push_indent()
|
2011-07-19 23:50:41 +04:00
|
|
|
for argname, argentry, optional, structured in parse_args(members):
|
|
|
|
if optional:
|
|
|
|
ret += mcgen('''
|
2012-07-17 18:17:04 +04:00
|
|
|
visit_start_optional(m, obj ? &(*obj)->%(c_prefix)shas_%(c_name)s : NULL, "%(name)s", &err);
|
|
|
|
if (obj && (*obj)->%(prefix)shas_%(c_name)s) {
|
2011-07-19 23:50:41 +04:00
|
|
|
''',
|
|
|
|
c_prefix=c_var(field_prefix), prefix=field_prefix,
|
|
|
|
c_name=c_var(argname), name=argname)
|
|
|
|
push_indent()
|
|
|
|
|
|
|
|
if structured:
|
2012-07-17 18:17:04 +04:00
|
|
|
ret += generate_visit_struct_body(field_prefix + argname, argname, argentry)
|
2011-07-19 23:50:41 +04:00
|
|
|
else:
|
|
|
|
ret += mcgen('''
|
2012-07-17 18:17:04 +04:00
|
|
|
visit_type_%(type)s(m, obj ? &(*obj)->%(c_prefix)s%(c_name)s : NULL, "%(name)s", &err);
|
2011-07-19 23:50:41 +04:00
|
|
|
''',
|
|
|
|
c_prefix=c_var(field_prefix), prefix=field_prefix,
|
|
|
|
type=type_name(argentry), c_name=c_var(argname),
|
|
|
|
name=argname)
|
|
|
|
|
|
|
|
if optional:
|
|
|
|
pop_indent()
|
|
|
|
ret += mcgen('''
|
|
|
|
}
|
2012-07-17 18:17:04 +04:00
|
|
|
visit_end_optional(m, &err);
|
|
|
|
''')
|
|
|
|
|
|
|
|
pop_indent()
|
|
|
|
ret += mcgen('''
|
|
|
|
|
|
|
|
error_propagate(errp, err);
|
|
|
|
err = NULL;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
|
|
|
pop_indent()
|
|
|
|
pop_indent()
|
|
|
|
ret += mcgen('''
|
|
|
|
/* Always call end_struct if start_struct succeeded. */
|
|
|
|
visit_end_struct(m, &err);
|
|
|
|
}
|
|
|
|
error_propagate(errp, err);
|
|
|
|
}
|
2011-07-19 23:50:41 +04:00
|
|
|
''')
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def generate_visit_struct(name, members):
|
|
|
|
ret = mcgen('''
|
|
|
|
|
|
|
|
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
''',
|
|
|
|
name=name)
|
2012-07-17 18:17:04 +04:00
|
|
|
|
2011-07-19 23:50:41 +04:00
|
|
|
push_indent()
|
2012-07-17 18:17:04 +04:00
|
|
|
ret += generate_visit_struct_body("", name, members)
|
2011-07-19 23:50:41 +04:00
|
|
|
pop_indent()
|
|
|
|
|
|
|
|
ret += mcgen('''
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def generate_visit_list(name, members):
|
|
|
|
return mcgen('''
|
|
|
|
|
|
|
|
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
|
|
|
|
{
|
2012-03-23 01:38:40 +04:00
|
|
|
GenericList *i, **prev = (GenericList **)obj;
|
2012-07-17 18:17:04 +04:00
|
|
|
Error *err = NULL;
|
2011-07-19 23:50:41 +04:00
|
|
|
|
2012-07-17 18:17:04 +04:00
|
|
|
if (!error_is_set(errp)) {
|
|
|
|
visit_start_list(m, name, &err);
|
|
|
|
if (!err) {
|
|
|
|
for (; (i = visit_next_list(m, prev, &err)) != NULL; prev = &i) {
|
|
|
|
%(name)sList *native_i = (%(name)sList *)i;
|
|
|
|
visit_type_%(name)s(m, &native_i->value, NULL, &err);
|
|
|
|
}
|
|
|
|
error_propagate(errp, err);
|
|
|
|
err = NULL;
|
|
|
|
|
|
|
|
/* Always call end_list if start_list succeeded. */
|
|
|
|
visit_end_list(m, &err);
|
|
|
|
}
|
|
|
|
error_propagate(errp, err);
|
2011-07-19 23:50:41 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
def generate_visit_enum(name, members):
|
|
|
|
return mcgen('''
|
|
|
|
|
|
|
|
void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp)
|
|
|
|
{
|
|
|
|
visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
|
|
|
|
}
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
def generate_visit_union(name, members):
|
|
|
|
ret = generate_visit_enum('%sKind' % name, members.keys())
|
|
|
|
|
|
|
|
ret += mcgen('''
|
|
|
|
|
|
|
|
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
|
|
|
|
{
|
2012-03-06 21:55:56 +04:00
|
|
|
Error *err = NULL;
|
|
|
|
|
2012-07-17 18:17:04 +04:00
|
|
|
if (!error_is_set(errp)) {
|
|
|
|
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
|
|
|
|
if (!err) {
|
2012-09-01 11:30:39 +04:00
|
|
|
if (obj && *obj) {
|
2012-07-17 18:17:04 +04:00
|
|
|
visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err);
|
|
|
|
if (!err) {
|
|
|
|
switch ((*obj)->kind) {
|
2011-07-19 23:50:41 +04:00
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
2012-07-17 18:17:04 +04:00
|
|
|
push_indent()
|
|
|
|
push_indent()
|
2012-03-06 21:55:56 +04:00
|
|
|
for key in members:
|
|
|
|
ret += mcgen('''
|
2012-07-17 18:17:04 +04:00
|
|
|
case %(abbrev)s_KIND_%(enum)s:
|
|
|
|
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
|
|
|
|
break;
|
2012-03-06 21:55:56 +04:00
|
|
|
''',
|
|
|
|
abbrev = de_camel_case(name).upper(),
|
2012-09-19 18:31:06 +04:00
|
|
|
enum = c_fun(de_camel_case(key),False).upper(),
|
2012-03-06 21:55:56 +04:00
|
|
|
c_type=members[key],
|
2012-03-20 17:54:35 +04:00
|
|
|
c_name=c_fun(key))
|
2012-03-06 21:55:56 +04:00
|
|
|
|
|
|
|
ret += mcgen('''
|
2012-07-17 18:17:04 +04:00
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
error_propagate(errp, err);
|
|
|
|
err = NULL;
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
pop_indent()
|
|
|
|
ret += mcgen('''
|
|
|
|
/* Always call end_struct if start_struct succeeded. */
|
|
|
|
visit_end_struct(m, &err);
|
2012-03-06 21:55:56 +04:00
|
|
|
}
|
2012-07-17 18:17:04 +04:00
|
|
|
error_propagate(errp, err);
|
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
|
|
|
pop_indent();
|
|
|
|
ret += mcgen('''
|
2012-03-06 21:55:56 +04:00
|
|
|
}
|
|
|
|
''')
|
|
|
|
|
2011-07-19 23:50:41 +04:00
|
|
|
return ret
|
|
|
|
|
|
|
|
def generate_declaration(name, members, genlist=True):
|
|
|
|
ret = mcgen('''
|
|
|
|
|
|
|
|
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp);
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
if genlist:
|
|
|
|
ret += mcgen('''
|
|
|
|
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
qapi: generate list struct and visit_list for enum
Currently, if we define an 'enum' and use it in one command's
data, list struct for enum could not be generated, but it's
used in qmp function.
For example: KeyCodesList could not be generated.
>>> qapi-schema.json:
{ 'enum': 'KeyCodes',
'data': [ 'shift', 'alt' ... ] }
{ 'command': 'sendkey',
'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } }
>>> qmp-command.h:
void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t
hold_time, Error **errp);
This patch lets qapi generate list struct and visit_list for enum.
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2012-08-31 06:56:23 +04:00
|
|
|
def generate_enum_declaration(name, members, genlist=True):
|
|
|
|
ret = ""
|
|
|
|
if genlist:
|
|
|
|
ret += mcgen('''
|
|
|
|
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp);
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
2011-07-19 23:50:41 +04:00
|
|
|
def generate_decl_enum(name, members, genlist=True):
|
|
|
|
return mcgen('''
|
|
|
|
|
|
|
|
void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **errp);
|
|
|
|
''',
|
|
|
|
name=name)
|
|
|
|
|
|
|
|
try:
|
2011-12-27 18:02:16 +04:00
|
|
|
opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:",
|
|
|
|
["source", "header", "prefix=", "output-dir="])
|
2011-07-19 23:50:41 +04:00
|
|
|
except getopt.GetoptError, err:
|
|
|
|
print str(err)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
output_dir = ""
|
|
|
|
prefix = ""
|
|
|
|
c_file = 'qapi-visit.c'
|
|
|
|
h_file = 'qapi-visit.h'
|
|
|
|
|
2011-12-27 18:02:16 +04:00
|
|
|
do_c = False
|
|
|
|
do_h = False
|
|
|
|
|
2011-07-19 23:50:41 +04:00
|
|
|
for o, a in opts:
|
|
|
|
if o in ("-p", "--prefix"):
|
|
|
|
prefix = a
|
|
|
|
elif o in ("-o", "--output-dir"):
|
|
|
|
output_dir = a + "/"
|
2011-12-27 18:02:16 +04:00
|
|
|
elif o in ("-c", "--source"):
|
|
|
|
do_c = True
|
2011-12-28 14:26:58 +04:00
|
|
|
elif o in ("-h", "--header"):
|
|
|
|
do_h = True
|
2011-12-27 18:02:16 +04:00
|
|
|
|
|
|
|
if not do_c and not do_h:
|
|
|
|
do_c = True
|
|
|
|
do_h = True
|
2011-07-19 23:50:41 +04:00
|
|
|
|
|
|
|
c_file = output_dir + prefix + c_file
|
|
|
|
h_file = output_dir + prefix + h_file
|
|
|
|
|
|
|
|
try:
|
|
|
|
os.makedirs(output_dir)
|
|
|
|
except os.error, e:
|
|
|
|
if e.errno != errno.EEXIST:
|
|
|
|
raise
|
|
|
|
|
2011-12-27 18:02:16 +04:00
|
|
|
def maybe_open(really, name, opt):
|
|
|
|
if really:
|
|
|
|
return open(name, opt)
|
2011-12-28 14:26:58 +04:00
|
|
|
else:
|
|
|
|
import StringIO
|
|
|
|
return StringIO.StringIO()
|
2011-12-27 18:02:16 +04:00
|
|
|
|
|
|
|
fdef = maybe_open(do_c, c_file, 'w')
|
|
|
|
fdecl = maybe_open(do_h, h_file, 'w')
|
2011-07-19 23:50:41 +04:00
|
|
|
|
|
|
|
fdef.write(mcgen('''
|
|
|
|
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* schema-defined QAPI visitor functions
|
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2011
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
|
|
|
* See the COPYING.LIB file in the top-level directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "%(header)s"
|
|
|
|
''',
|
|
|
|
header=basename(h_file)))
|
|
|
|
|
|
|
|
fdecl.write(mcgen('''
|
|
|
|
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* schema-defined QAPI visitor function
|
|
|
|
*
|
|
|
|
* Copyright IBM, Corp. 2011
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
|
|
|
* See the COPYING.LIB file in the top-level directory.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef %(guard)s
|
|
|
|
#define %(guard)s
|
|
|
|
|
|
|
|
#include "qapi/qapi-visit-core.h"
|
|
|
|
#include "%(prefix)sqapi-types.h"
|
|
|
|
''',
|
|
|
|
prefix=prefix, guard=guardname(h_file)))
|
|
|
|
|
|
|
|
exprs = parse_schema(sys.stdin)
|
|
|
|
|
|
|
|
for expr in exprs:
|
|
|
|
if expr.has_key('type'):
|
|
|
|
ret = generate_visit_struct(expr['type'], expr['data'])
|
|
|
|
ret += generate_visit_list(expr['type'], expr['data'])
|
|
|
|
fdef.write(ret)
|
|
|
|
|
|
|
|
ret = generate_declaration(expr['type'], expr['data'])
|
|
|
|
fdecl.write(ret)
|
|
|
|
elif expr.has_key('union'):
|
|
|
|
ret = generate_visit_union(expr['union'], expr['data'])
|
2012-03-06 21:55:56 +04:00
|
|
|
ret += generate_visit_list(expr['union'], expr['data'])
|
2011-07-19 23:50:41 +04:00
|
|
|
fdef.write(ret)
|
|
|
|
|
|
|
|
ret = generate_decl_enum('%sKind' % expr['union'], expr['data'].keys())
|
|
|
|
ret += generate_declaration(expr['union'], expr['data'])
|
|
|
|
fdecl.write(ret)
|
|
|
|
elif expr.has_key('enum'):
|
qapi: generate list struct and visit_list for enum
Currently, if we define an 'enum' and use it in one command's
data, list struct for enum could not be generated, but it's
used in qmp function.
For example: KeyCodesList could not be generated.
>>> qapi-schema.json:
{ 'enum': 'KeyCodes',
'data': [ 'shift', 'alt' ... ] }
{ 'command': 'sendkey',
'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } }
>>> qmp-command.h:
void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t
hold_time, Error **errp);
This patch lets qapi generate list struct and visit_list for enum.
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2012-08-31 06:56:23 +04:00
|
|
|
ret = generate_visit_list(expr['enum'], expr['data'])
|
|
|
|
ret += generate_visit_enum(expr['enum'], expr['data'])
|
2011-07-19 23:50:41 +04:00
|
|
|
fdef.write(ret)
|
|
|
|
|
|
|
|
ret = generate_decl_enum(expr['enum'], expr['data'])
|
qapi: generate list struct and visit_list for enum
Currently, if we define an 'enum' and use it in one command's
data, list struct for enum could not be generated, but it's
used in qmp function.
For example: KeyCodesList could not be generated.
>>> qapi-schema.json:
{ 'enum': 'KeyCodes',
'data': [ 'shift', 'alt' ... ] }
{ 'command': 'sendkey',
'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } }
>>> qmp-command.h:
void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t
hold_time, Error **errp);
This patch lets qapi generate list struct and visit_list for enum.
Signed-off-by: Amos Kong <akong@redhat.com>
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
2012-08-31 06:56:23 +04:00
|
|
|
ret += generate_enum_declaration(expr['enum'], expr['data'])
|
2011-07-19 23:50:41 +04:00
|
|
|
fdecl.write(ret)
|
|
|
|
|
|
|
|
fdecl.write('''
|
|
|
|
#endif
|
|
|
|
''')
|
|
|
|
|
|
|
|
fdecl.flush()
|
|
|
|
fdecl.close()
|
|
|
|
|
|
|
|
fdef.flush()
|
|
|
|
fdef.close()
|