aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/qapi-commands.py109
-rw-r--r--scripts/qapi-event.py6
-rw-r--r--scripts/qapi-types.py110
-rw-r--r--scripts/qapi-visit.py93
-rw-r--r--scripts/qapi.py79
5 files changed, 204 insertions, 193 deletions
diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py
index ca22acc1d5..890ce5db92 100644
--- a/scripts/qapi-commands.py
+++ b/scripts/qapi-commands.py
@@ -27,18 +27,19 @@ def generate_command_decl(name, args, ret_type):
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
''',
ret_type=c_type(ret_type), name=c_name(name),
- args=arglist).strip()
+ args=arglist)
-def gen_err_check(errvar):
- if errvar:
- return mcgen('''
-if (local_err) {
+def gen_err_check(err):
+ if not err:
+ return ''
+ return mcgen('''
+if (%(err)s) {
goto out;
}
-''')
- return ''
+''',
+ err=err)
-def gen_sync_call(name, args, ret_type, indent=0):
+def gen_sync_call(name, args, ret_type):
ret = ""
arglist=""
retval=""
@@ -48,41 +49,34 @@ def gen_sync_call(name, args, ret_type, indent=0):
if optional:
arglist += "has_%s, " % c_name(argname)
arglist += "%s, " % (c_name(argname))
- push_indent(indent)
+ push_indent()
ret = mcgen('''
%(retval)sqmp_%(name)s(%(args)s&local_err);
-
''',
- name=c_name(name), args=arglist, retval=retval).rstrip()
+ name=c_name(name), args=arglist, retval=retval)
if ret_type:
- ret += "\n" + gen_err_check('local_err')
- ret += "\n" + mcgen(''''
-%(marshal_output_call)s
-''',
- marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
- pop_indent(indent)
- return ret.rstrip()
-
+ ret += gen_err_check('local_err')
+ ret += mcgen('''
-def gen_marshal_output_call(name, ret_type):
- if not ret_type:
- return ""
- return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_name(name)
+qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
+''',
+ c_name=c_name(name))
+ pop_indent()
+ return ret
-def gen_visitor_input_containers_decl(args, obj):
+def gen_visitor_input_containers_decl(args):
ret = ""
push_indent()
if len(args) > 0:
ret += mcgen('''
-QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s);
+QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md;
Visitor *v;
-''',
- obj=obj)
+''')
pop_indent()
- return ret.rstrip()
+ return ret
def gen_visitor_input_vars_decl(args):
ret = ""
@@ -105,7 +99,7 @@ bool has_%(argname)s = false;
argname=c_name(argname), argtype=c_type(argtype))
pop_indent()
- return ret.rstrip()
+ return ret
def gen_visitor_input_block(args, dealloc=False):
ret = ""
@@ -159,9 +153,9 @@ visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
qapi_dealloc_visitor_cleanup(md);
''')
pop_indent()
- return ret.rstrip()
+ return ret
-def gen_marshal_output(name, args, ret_type, middle_mode):
+def gen_marshal_output(name, ret_type):
if not ret_type:
return ""
@@ -194,14 +188,14 @@ out:
return ret
-def gen_marshal_input_decl(name, args, ret_type, middle_mode):
+def gen_marshal_input_decl(name, middle_mode):
ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
if not middle_mode:
ret = "static " + ret
return ret
def gen_marshal_input(name, args, ret_type, middle_mode):
- hdr = gen_marshal_input_decl(name, args, ret_type, middle_mode)
+ hdr = gen_marshal_input_decl(name, middle_mode)
ret = mcgen('''
%(header)s
@@ -211,36 +205,24 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
header=hdr)
if ret_type:
- if is_c_ptr(ret_type):
- retval = " %s retval = NULL;" % c_type(ret_type)
- else:
- retval = " %s retval;" % c_type(ret_type)
ret += mcgen('''
-%(retval)s
+ %(c_type)s retval;
''',
- retval=retval)
+ c_type=c_type(ret_type))
if len(args) > 0:
- ret += mcgen('''
-%(visitor_input_containers_decl)s
-%(visitor_input_vars_decl)s
-
-%(visitor_input_block)s
-
-''',
- visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"),
- visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
- visitor_input_block=gen_visitor_input_block(args))
+ ret += gen_visitor_input_containers_decl(args)
+ ret += gen_visitor_input_vars_decl(args) + '\n'
+ ret += gen_visitor_input_block(args) + '\n'
else:
ret += mcgen('''
(void)args;
+
''')
- ret += mcgen('''
-%(sync_call)s
-''',
- sync_call=gen_sync_call(name, args, ret_type, indent=4))
+ ret += gen_sync_call(name, args, ret_type)
+
if re.search('^ *goto out\\;', ret, re.MULTILINE):
ret += mcgen('''
@@ -248,11 +230,11 @@ out:
''')
ret += mcgen('''
error_propagate(errp, local_err);
-%(visitor_input_block_cleanup)s
+''')
+ ret += gen_visitor_input_block(args, dealloc=True)
+ ret += mcgen('''
}
-''',
- visitor_input_block_cleanup=gen_visitor_input_block(args,
- dealloc=True))
+''')
return ret
def gen_registry(commands):
@@ -272,12 +254,13 @@ qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
ret = mcgen('''
static void qmp_init_marshal(void)
{
-%(registry)s
+''')
+ ret += registry
+ ret += mcgen('''
}
qapi_init(qmp_init_marshal);
-''',
- registry=registry.rstrip())
+''')
return ret
middle_mode = False
@@ -357,14 +340,14 @@ for cmd in commands:
arglist = cmd['data']
if cmd.has_key('returns'):
ret_type = cmd['returns']
- ret = generate_command_decl(cmd['command'], arglist, ret_type) + "\n"
+ ret = generate_command_decl(cmd['command'], arglist, ret_type)
fdecl.write(ret)
if ret_type:
- ret = gen_marshal_output(cmd['command'], arglist, ret_type, middle_mode) + "\n"
+ ret = gen_marshal_output(cmd['command'], ret_type) + "\n"
fdef.write(ret)
if middle_mode:
- fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], arglist, ret_type, middle_mode))
+ fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], middle_mode))
ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
fdef.write(ret)
diff --git a/scripts/qapi-event.py b/scripts/qapi-event.py
index 56bc602a6d..7f238df5b2 100644
--- a/scripts/qapi-event.py
+++ b/scripts/qapi-event.py
@@ -167,8 +167,7 @@ extern const char *%(event_enum_name)s_lookup[];
event_enum_name = event_enum_name)
enum_decl = mcgen('''
-typedef enum %(event_enum_name)s
-{
+typedef enum %(event_enum_name)s {
''',
event_enum_name = event_enum_name)
@@ -199,7 +198,6 @@ const char *%(event_enum_name)s_lookup[] = {
''',
event_enum_name = event_enum_name)
- i = 0
for string in event_enum_strings:
ret += mcgen('''
"%(string)s",
@@ -267,7 +265,7 @@ fdecl.write(mcgen('''
exprs = parse_schema(input_file)
-event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent"
+event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
event_enum_values = []
event_enum_strings = []
diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py
index e6eb4b613a..f2428f3807 100644
--- a/scripts/qapi-types.py
+++ b/scripts/qapi-types.py
@@ -15,8 +15,7 @@ from qapi import *
def generate_fwd_builtin(name):
return mcgen('''
-typedef struct %(name)sList
-{
+typedef struct %(name)sList {
union {
%(type)s value;
uint64_t padding;
@@ -32,8 +31,7 @@ def generate_fwd_struct(name):
typedef struct %(name)s %(name)s;
-typedef struct %(name)sList
-{
+typedef struct %(name)sList {
union {
%(name)s *value;
uint64_t padding;
@@ -45,8 +43,8 @@ typedef struct %(name)sList
def generate_fwd_enum_struct(name):
return mcgen('''
-typedef struct %(name)sList
-{
+
+typedef struct %(name)sList {
union {
%(name)s value;
uint64_t padding;
@@ -79,8 +77,8 @@ def generate_struct(expr):
base = expr.get('base')
ret = mcgen('''
-struct %(name)s
-{
+
+struct %(name)s {
''',
name=c_name(structname))
@@ -105,10 +103,10 @@ struct %(name)s
def generate_enum_lookup(name, values):
ret = mcgen('''
-const char * const %(name)s_lookup[] = {
+
+const char *const %(name)s_lookup[] = {
''',
name=c_name(name))
- i = 0
for value in values:
index = c_enum_const(name, value)
ret += mcgen('''
@@ -120,7 +118,6 @@ const char * const %(name)s_lookup[] = {
ret += mcgen('''
[%(max_index)s] = NULL,
};
-
''',
max_index=max_index)
return ret
@@ -128,13 +125,14 @@ const char * const %(name)s_lookup[] = {
def generate_enum(name, values):
name = c_name(name)
lookup_decl = mcgen('''
-extern const char * const %(name)s_lookup[];
+
+extern const char *const %(name)s_lookup[];
''',
name=name)
enum_decl = mcgen('''
-typedef enum %(name)s
-{
+
+typedef enum %(name)s {
''',
name=name)
@@ -156,7 +154,7 @@ typedef enum %(name)s
''',
name=name)
- return lookup_decl + enum_decl
+ return enum_decl + lookup_decl
def generate_alternate_qtypes(expr):
@@ -164,6 +162,7 @@ def generate_alternate_qtypes(expr):
members = expr['data']
ret = mcgen('''
+
const int %(name)s_qtypes[QTYPE_MAX] = {
''',
name=c_name(name))
@@ -199,14 +198,40 @@ def generate_union(expr, meta):
discriminator_type_name = '%sKind' % (name)
ret = mcgen('''
-struct %(name)s
-{
+
+struct %(name)s {
+''',
+ name=name)
+ if base:
+ ret += mcgen('''
+ /* Members inherited from %(c_name)s: */
+''',
+ c_name=c_name(base))
+ base_fields = find_struct(base)['data']
+ ret += generate_struct_fields(base_fields)
+ ret += mcgen('''
+ /* Own members: */
+''')
+ else:
+ assert not discriminator
+ ret += mcgen('''
%(discriminator_type_name)s kind;
- union {
+''',
+ discriminator_type_name=c_name(discriminator_type_name))
+
+ # FIXME: What purpose does data serve, besides preventing a union that
+ # has a branch named 'data'? We use it in qapi-visit.py to decide
+ # whether to bypass the switch statement if visiting the discriminator
+ # failed; but since we 0-initialize structs, and cannot tell what
+ # branch of the union is in use if the discriminator is invalid, there
+ # should not be any data leaks even without a data pointer. Or, if
+ # 'data' is merely added to guarantee we don't have an empty union,
+ # shouldn't we enforce that at .json parse time?
+ ret += mcgen('''
+ union { /* union tag is @%(c_name)s */
void *data;
''',
- name=name,
- discriminator_type_name=c_name(discriminator_type_name))
+ c_name=c_name(discriminator or 'kind'))
for key in typeinfo:
ret += mcgen('''
@@ -217,17 +242,6 @@ struct %(name)s
ret += mcgen('''
};
-''')
-
- if base:
- assert discriminator
- base_fields = find_struct(base)['data'].copy()
- del base_fields[discriminator]
- ret += generate_struct_fields(base_fields)
- else:
- assert not discriminator
-
- ret += mcgen('''
};
''')
if meta == 'alternate':
@@ -314,14 +328,12 @@ fdef.write(mcgen('''
#include "qapi/dealloc-visitor.h"
#include "%(prefix)sqapi-types.h"
#include "%(prefix)sqapi-visit.h"
-
''',
prefix=prefix))
fdecl.write(mcgen('''
#include <stdbool.h>
#include <stdint.h>
-
'''))
exprs = parse_schema(input_file)
@@ -332,22 +344,22 @@ for typename in builtin_types.keys():
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
for expr in exprs:
- ret = "\n"
+ ret = ""
if expr.has_key('struct'):
ret += generate_fwd_struct(expr['struct'])
elif expr.has_key('enum'):
- ret += generate_enum(expr['enum'], expr['data']) + "\n"
+ ret += generate_enum(expr['enum'], expr['data'])
ret += generate_fwd_enum_struct(expr['enum'])
fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
elif expr.has_key('union'):
- ret += generate_fwd_struct(expr['union']) + "\n"
+ ret += generate_fwd_struct(expr['union'])
enum_define = discriminator_find_enum_define(expr)
if not enum_define:
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
expr['data'].keys()))
elif expr.has_key('alternate'):
- ret += generate_fwd_struct(expr['alternate']) + "\n"
+ ret += generate_fwd_struct(expr['alternate'])
ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
expr['data'].keys()))
@@ -367,34 +379,32 @@ fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
# have the functions defined, so we use -b option to provide control
# over these cases
if do_builtins:
- fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for typename in builtin_types.keys():
fdef.write(generate_type_cleanup(typename + "List"))
- fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
for expr in exprs:
- ret = "\n"
+ ret = ""
if expr.has_key('struct'):
ret += generate_struct(expr) + "\n"
ret += generate_type_cleanup_decl(expr['struct'] + "List")
- fdef.write(generate_type_cleanup(expr['struct'] + "List") + "\n")
+ fdef.write(generate_type_cleanup(expr['struct'] + "List"))
ret += generate_type_cleanup_decl(expr['struct'])
- fdef.write(generate_type_cleanup(expr['struct']) + "\n")
+ fdef.write(generate_type_cleanup(expr['struct']))
elif expr.has_key('union'):
- ret += generate_union(expr, 'union')
+ ret += generate_union(expr, 'union') + "\n"
ret += generate_type_cleanup_decl(expr['union'] + "List")
- fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
+ fdef.write(generate_type_cleanup(expr['union'] + "List"))
ret += generate_type_cleanup_decl(expr['union'])
- fdef.write(generate_type_cleanup(expr['union']) + "\n")
+ fdef.write(generate_type_cleanup(expr['union']))
elif expr.has_key('alternate'):
- ret += generate_union(expr, 'alternate')
+ ret += generate_union(expr, 'alternate') + "\n"
ret += generate_type_cleanup_decl(expr['alternate'] + "List")
- fdef.write(generate_type_cleanup(expr['alternate'] + "List") + "\n")
+ fdef.write(generate_type_cleanup(expr['alternate'] + "List"))
ret += generate_type_cleanup_decl(expr['alternate'])
- fdef.write(generate_type_cleanup(expr['alternate']) + "\n")
+ fdef.write(generate_type_cleanup(expr['alternate']))
elif expr.has_key('enum'):
- ret += generate_type_cleanup_decl(expr['enum'] + "List")
- fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
+ ret += "\n" + generate_type_cleanup_decl(expr['enum'] + "List")
+ fdef.write(generate_type_cleanup(expr['enum'] + "List"))
else:
continue
fdecl.write(ret)
diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py
index 5b99336488..3cd662bd6b 100644
--- a/scripts/qapi-visit.py
+++ b/scripts/qapi-visit.py
@@ -16,14 +16,23 @@ from ordereddict import OrderedDict
from qapi import *
import re
-implicit_structs = []
+implicit_structs_seen = set()
+struct_fields_seen = set()
def generate_visit_implicit_struct(type):
- global implicit_structs
- if type in implicit_structs:
+ if type in implicit_structs_seen:
return ''
- implicit_structs.append(type)
- return mcgen('''
+ implicit_structs_seen.add(type)
+ ret = ''
+ if type not in struct_fields_seen:
+ # Need a forward declaration
+ ret += mcgen('''
+
+static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
+''',
+ c_type=type_name(type))
+
+ ret += mcgen('''
static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
{
@@ -38,9 +47,11 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error *
}
''',
c_type=type_name(type))
+ return ret
def generate_visit_struct_fields(name, members, base = None):
- substructs = []
+ struct_fields_seen.add(name)
+
ret = ''
if base:
@@ -51,6 +62,7 @@ def generate_visit_struct_fields(name, members, base = None):
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
{
Error *err = NULL;
+
''',
name=c_name(name))
push_indent()
@@ -103,7 +115,11 @@ out:
return ret
-def generate_visit_struct_body(name, members):
+def generate_visit_struct_body(name):
+ # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
+ # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
+ # rather than leaving it non-NULL. As currently written, the caller must
+ # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
ret = mcgen('''
Error *err = NULL;
@@ -135,14 +151,14 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
''',
name=c_name(name))
- ret += generate_visit_struct_body(name, members)
+ ret += generate_visit_struct_body(name)
ret += mcgen('''
}
''')
return ret
-def generate_visit_list(name, members):
+def generate_visit_list(name):
return mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
@@ -171,15 +187,15 @@ out:
''',
name=type_name(name))
-def generate_visit_enum(name, members):
+def generate_visit_enum(name):
return mcgen('''
-void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
+void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp)
{
- visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
+ visit_type_enum(m, (int *)obj, %(c_name)s_lookup, "%(name)s", name, errp);
}
''',
- name=c_name(name))
+ c_name=c_name(name), name=name)
def generate_visit_alternate(name, members):
ret = mcgen('''
@@ -252,7 +268,7 @@ def generate_visit_union(expr):
else:
# There will always be a discriminator in the C switch code, by default
# it is an enum type generated silently
- ret = generate_visit_enum(name + 'Kind', members.keys())
+ ret = generate_visit_enum(name + 'Kind')
disc_type = c_name(name) + 'Kind'
if base:
@@ -267,17 +283,17 @@ def generate_visit_union(expr):
ret += mcgen('''
-void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
+void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
{
Error *err = NULL;
- visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
+ visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
if (err) {
goto out;
}
if (*obj) {
''',
- name=c_name(name))
+ c_name=c_name(name), name=name)
if base:
ret += mcgen('''
@@ -289,20 +305,23 @@ void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **e
name=c_name(name))
if not discriminator:
+ tag = 'kind'
disc_key = "type"
else:
+ tag = discriminator
disc_key = discriminator
ret += mcgen('''
- visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
+ visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
if (err) {
goto out_obj;
}
if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
goto out_obj;
}
- switch ((*obj)->kind) {
+ switch ((*obj)->%(c_tag)s) {
''',
disc_type = disc_type,
+ c_tag=c_name(tag),
disc_key = disc_key)
for key in members:
@@ -340,7 +359,7 @@ out:
return ret
-def generate_declaration(name, members, builtin_type=False):
+def generate_declaration(name, builtin_type=False):
ret = ""
if not builtin_type:
name = c_name(name)
@@ -357,7 +376,7 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
return ret
-def generate_enum_declaration(name, members):
+def generate_enum_declaration(name):
ret = mcgen('''
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
''',
@@ -365,7 +384,7 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
return ret
-def generate_decl_enum(name, members):
+def generate_decl_enum(name):
return mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
@@ -433,7 +452,7 @@ exprs = parse_schema(input_file)
# for built-in types in our header files and simply guard them
fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
for typename in builtin_types.keys():
- fdecl.write(generate_declaration(typename, None, builtin_type=True))
+ fdecl.write(generate_declaration(typename, builtin_type=True))
fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# ...this doesn't work for cases where we link in multiple objects that
@@ -441,44 +460,42 @@ fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
# over these cases
if do_builtins:
for typename in builtin_types.keys():
- fdef.write(generate_visit_list(typename, None))
+ fdef.write(generate_visit_list(typename))
for expr in exprs:
if expr.has_key('struct'):
ret = generate_visit_struct(expr)
- ret += generate_visit_list(expr['struct'], expr['data'])
+ ret += generate_visit_list(expr['struct'])
fdef.write(ret)
- ret = generate_declaration(expr['struct'], expr['data'])
+ ret = generate_declaration(expr['struct'])
fdecl.write(ret)
elif expr.has_key('union'):
ret = generate_visit_union(expr)
- ret += generate_visit_list(expr['union'], expr['data'])
+ ret += generate_visit_list(expr['union'])
fdef.write(ret)
enum_define = discriminator_find_enum_define(expr)
ret = ""
if not enum_define:
- ret = generate_decl_enum('%sKind' % expr['union'],
- expr['data'].keys())
- ret += generate_declaration(expr['union'], expr['data'])
+ ret = generate_decl_enum('%sKind' % expr['union'])
+ ret += generate_declaration(expr['union'])
fdecl.write(ret)
elif expr.has_key('alternate'):
ret = generate_visit_alternate(expr['alternate'], expr['data'])
- ret += generate_visit_list(expr['alternate'], expr['data'])
+ ret += generate_visit_list(expr['alternate'])
fdef.write(ret)
- ret = generate_decl_enum('%sKind' % expr['alternate'],
- expr['data'].keys())
- ret += generate_declaration(expr['alternate'], expr['data'])
+ ret = generate_decl_enum('%sKind' % expr['alternate'])
+ ret += generate_declaration(expr['alternate'])
fdecl.write(ret)
elif expr.has_key('enum'):
- ret = generate_visit_list(expr['enum'], expr['data'])
- ret += generate_visit_enum(expr['enum'], expr['data'])
+ ret = generate_visit_list(expr['enum'])
+ ret += generate_visit_enum(expr['enum'])
fdef.write(ret)
- ret = generate_decl_enum(expr['enum'], expr['data'])
- ret += generate_enum_declaration(expr['enum'], expr['data'])
+ ret = generate_decl_enum(expr['enum'])
+ ret += generate_enum_declaration(expr['enum'])
fdecl.write(ret)
close_output(fdef, fdecl)
diff --git a/scripts/qapi.py b/scripts/qapi.py
index 06d7fc2848..817d824bea 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -341,6 +341,8 @@ def discriminator_find_enum_define(expr):
return find_enum(discriminator_type)
+# FIXME should enforce "other than downstream extensions [...], all
+# names should begin with a letter".
valid_name = re.compile('^[a-zA-Z_][a-zA-Z0-9_.-]*$')
def check_name(expr_info, source, name, allow_optional = False,
enum_member = False):
@@ -367,6 +369,8 @@ def check_name(expr_info, source, name, allow_optional = False,
def add_name(name, info, meta, implicit = False):
global all_names
check_name(info, "'%s'" % meta, name)
+ # FIXME should reject names that differ only in '_' vs. '.'
+ # vs. '-', because they're liable to clash in generated C.
if name in all_names:
raise QAPIExprError(info,
"%s '%s' is already defined"
@@ -422,7 +426,6 @@ def check_type(expr_info, source, value, allow_array = False,
allow_dict = False, allow_optional = False,
allow_star = False, allow_metas = []):
global all_names
- orig_value = value
if value is None:
return
@@ -440,7 +443,6 @@ def check_type(expr_info, source, value, allow_array = False,
"%s: array type must contain single type name"
% source)
value = value[0]
- orig_value = "array of %s" %value
# Check if type name for value is okay
if isinstance(value, str):
@@ -451,20 +453,22 @@ def check_type(expr_info, source, value, allow_array = False,
if not value in all_names:
raise QAPIExprError(expr_info,
"%s uses unknown type '%s'"
- % (source, orig_value))
+ % (source, value))
if not all_names[value] in allow_metas:
raise QAPIExprError(expr_info,
"%s cannot use %s type '%s'"
- % (source, all_names[value], orig_value))
+ % (source, all_names[value], value))
return
- # value is a dictionary, check that each member is okay
- if not isinstance(value, OrderedDict):
- raise QAPIExprError(expr_info,
- "%s should be a dictionary" % source)
if not allow_dict:
raise QAPIExprError(expr_info,
"%s should be a type name" % source)
+
+ if not isinstance(value, OrderedDict):
+ raise QAPIExprError(expr_info,
+ "%s should be a dictionary or type name" % source)
+
+ # value is a dictionary, check that each member is okay
for (key, arg) in value.items():
check_name(expr_info, "Member of %s" % source, key,
allow_optional=allow_optional)
@@ -495,26 +499,25 @@ def check_command(expr, expr_info):
check_type(expr_info, "'data' for command '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
- allow_metas=['union', 'struct'], allow_star=allow_star)
+ allow_metas=['struct'], allow_star=allow_star)
returns_meta = ['union', 'struct']
if name in returns_whitelist:
returns_meta += ['built-in', 'alternate', 'enum']
check_type(expr_info, "'returns' for command '%s'" % name,
- expr.get('returns'), allow_array=True, allow_dict=True,
+ expr.get('returns'), allow_array=True,
allow_optional=True, allow_metas=returns_meta,
allow_star=allow_star)
def check_event(expr, expr_info):
global events
name = expr['event']
- params = expr.get('data')
if name.upper() == 'MAX':
raise QAPIExprError(expr_info, "Event name 'MAX' cannot be created")
events.append(name)
check_type(expr_info, "'data' for event '%s'" % name,
expr.get('data'), allow_dict=True, allow_optional=True,
- allow_metas=['union', 'struct'])
+ allow_metas=['struct'])
def check_union(expr, expr_info):
name = expr['union']
@@ -523,14 +526,6 @@ def check_union(expr, expr_info):
members = expr['data']
values = { 'MAX': '(automatic)' }
- # If the object has a member 'base', its value must name a struct,
- # and there must be a discriminator.
- if base is not None:
- if discriminator is None:
- raise QAPIExprError(expr_info,
- "Union '%s' requires a discriminator to go "
- "along with base" %name)
-
# Two types of unions, determined by discriminator.
# With no discriminator it is a simple union.
@@ -943,24 +938,24 @@ def pop_indent(indent_amount=4):
global indent_level
indent_level -= indent_amount
+# Generate @code with @kwds interpolated.
+# Obey indent_level, and strip eatspace.
def cgen(code, **kwds):
- indent = genindent(indent_level)
- lines = code.split('\n')
- lines = map(lambda x: indent + x, lines)
- return '\n'.join(lines) % kwds + '\n'
+ raw = code % kwds
+ if indent_level:
+ indent = genindent(indent_level)
+ raw = re.subn("^.", indent + r'\g<0>', raw, 0, re.MULTILINE)
+ raw = raw[0]
+ return re.sub(re.escape(eatspace) + ' *', '', raw)
def mcgen(code, **kwds):
- raw = cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
- return re.sub(re.escape(eatspace) + ' *', '', raw)
+ if code[0] == '\n':
+ code = code[1:]
+ return cgen(code, **kwds)
-def basename(filename):
- return filename.split("/")[-1]
def guardname(filename):
- guard = basename(filename).rsplit(".", 1)[0]
- for substr in [".", " ", "-"]:
- guard = guard.replace(substr, "_")
- return guard.upper() + '_H'
+ return c_name(filename, protect=False).upper()
def guardstart(name):
return mcgen('''
@@ -1003,6 +998,12 @@ def parse_command_line(extra_options = "", extra_long_options = []):
for oa in opts:
o, a = oa
if o in ("-p", "--prefix"):
+ match = re.match('([A-Za-z_.-][A-Za-z0-9_.-]*)?', a)
+ if match.end() != len(a):
+ print >>sys.stderr, \
+ "%s: 'funny character '%s' in argument of --prefix" \
+ % (sys.argv[0], a[match.end()])
+ sys.exit(1)
prefix = a
elif o in ("-o", "--output-dir"):
output_dir = a + "/"
@@ -1030,14 +1031,16 @@ def parse_command_line(extra_options = "", extra_long_options = []):
def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
c_comment, h_comment):
+ guard = guardname(prefix + h_file)
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
+ if output_dir:
+ try:
+ os.makedirs(output_dir)
+ except os.error, e:
+ if e.errno != errno.EEXIST:
+ raise
def maybe_open(really, name, opt):
if really:
@@ -1062,7 +1065,7 @@ def open_output(output_dir, do_c, do_h, prefix, c_file, h_file,
#define %(guard)s
''',
- comment = h_comment, guard = guardname(h_file)))
+ comment = h_comment, guard = guard))
return (fdef, fdecl)