Merge remote-tracking branch 'remotes/qmp-unstable/queue/qmp' into staging

* remotes/qmp-unstable/queue/qmp:
  qapi: skip redundant includes
  monitor: Add netdev_del id argument completion.
  monitor: Add netdev_add type argument completion.
  monitor: Add set_link arguments completion.
  monitor: Add chardev-add backend argument completion.
  monitor: Add chardev-remove command completion.
  monitor: Convert sendkey to use command_completion.
  qapi: Show qapi-commands.py invocation in qapi-code-gen.txt
  qapi: Replace uncommon use of the error API by the common one
  tests: Don't call visit_end_struct() after visit_start_struct() fails
  hw: Don't call visit_end_struct() after visit_start_struct() fails
  hmp: Call visit_end_struct() after visit_start_struct() succeeds
  qapi: Un-inline visit of implicit struct
  qapi-visit.py: Clean up a sloppy use of field prefix
  qapi: Clean up shadowing of parameters and locals in inner scopes
  qapi-visit.py: Clean up confusing push_indent() / pop_indent() use
  qapi: Replace start_optional()/end_optional() by optional()
  qapi: Remove unused Visitor callbacks start_handle(), end_handle()
  qapi: Normalize marshalling's visitor initialization and cleanup
  qapi: Update qapi-code-gen.txt example to match current code

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-05-19 14:10:00 +01:00
commit c5fa6c86d0
27 changed files with 756 additions and 449 deletions

View File

@ -48,7 +48,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
{ 'include': 'path/to/file.json'} { 'include': 'path/to/file.json'}
The directive is evaluated recursively, and include paths are relative to the The directive is evaluated recursively, and include paths are relative to the
file using the directive. file using the directive. Multiple includes of the same file are safe.
=== Complex types === === Complex types ===
@ -230,14 +230,13 @@ node structure that can be used to chain together a list of such types in
case we want to accept/return a list of this type with a command), and a case we want to accept/return a list of this type with a command), and a
command which takes that type as a parameter and returns the same type: command which takes that type as a parameter and returns the same type:
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json $ cat example-schema.json
{ 'type': 'UserDefOne', { 'type': 'UserDefOne',
'data': { 'integer': 'int', 'string': 'str' } } 'data': { 'integer': 'int', 'string': 'str' } }
{ 'command': 'my-command', { 'command': 'my-command',
'data': {'arg1': 'UserDefOne'}, 'data': {'arg1': 'UserDefOne'},
'returns': 'UserDefOne' } 'returns': 'UserDefOne' }
mdroth@illuin:~/w/qemu2.git$
=== scripts/qapi-types.py === === scripts/qapi-types.py ===
@ -255,14 +254,25 @@ created code.
Example: Example:
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \ $ python scripts/qapi-types.py --output-dir="qapi-generated" \
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json --prefix="example-" --input-file=example-schema.json
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c $ cat qapi-generated/example-qapi-types.c
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#include "qapi/qapi-dealloc-visitor.h" void qapi_free_UserDefOneList(UserDefOneList * obj)
#include "example-qapi-types.h" {
#include "example-qapi-visit.h" QapiDeallocVisitor *md;
Visitor *v;
if (!obj) {
return;
}
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOneList(v, &obj, NULL, NULL);
qapi_dealloc_visitor_cleanup(md);
}
void qapi_free_UserDefOne(UserDefOne * obj) void qapi_free_UserDefOne(UserDefOne * obj)
{ {
@ -279,32 +289,38 @@ Example:
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
} }
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h $ cat qapi-generated/example-qapi-types.h
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
#include "qapi/qapi-types-core.h" #ifndef EXAMPLE_QAPI_TYPES_H
#define EXAMPLE_QAPI_TYPES_H
[Builtin types omitted...]
typedef struct UserDefOne UserDefOne; typedef struct UserDefOne UserDefOne;
typedef struct UserDefOneList typedef struct UserDefOneList
{ {
UserDefOne *value; union {
UserDefOne *value;
uint64_t padding;
};
struct UserDefOneList *next; struct UserDefOneList *next;
} UserDefOneList; } UserDefOneList;
[Functions on builtin types omitted...]
struct UserDefOne struct UserDefOne
{ {
int64_t integer; int64_t integer;
char * string; char * string;
}; };
void qapi_free_UserDefOneList(UserDefOneList * obj);
void qapi_free_UserDefOne(UserDefOne * obj); void qapi_free_UserDefOne(UserDefOne * obj);
#endif #endif
=== scripts/qapi-visit.py === === scripts/qapi-visit.py ===
Used to generate the visitor functions used to walk through and convert Used to generate the visitor functions used to walk through and convert
@ -325,51 +341,78 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor
Example: Example:
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \ $ python scripts/qapi-visit.py --output-dir="qapi-generated"
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json --prefix="example-" --input-file=example-schema.json
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c $ cat qapi-generated/example-qapi-visit.c
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#include "example-qapi-visit.h" static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
{
Error *err = NULL;
visit_type_int(m, &(*obj)->integer, "integer", &err);
if (err) {
goto out;
}
visit_type_str(m, &(*obj)->string, "string", &err);
if (err) {
goto out;
}
out:
error_propagate(errp, err);
}
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp) void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
{ {
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp); Error *err = NULL;
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp); visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err);
visit_end_struct(m, errp); if (!err) {
if (*obj) {
visit_type_UserDefOne_fields(m, obj, errp);
}
visit_end_struct(m, &err);
}
error_propagate(errp, err);
} }
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp) void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
{ {
GenericList *i, **prev = (GenericList **)obj; Error *err = NULL;
GenericList *i, **prev;
visit_start_list(m, name, errp); visit_start_list(m, name, &err);
if (err) {
for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) { goto out;
UserDefOneList *native_i = (UserDefOneList *)i;
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
} }
visit_end_list(m, errp); for (prev = (GenericList **)obj;
!err && (i = visit_next_list(m, prev, &err)) != NULL;
prev = &i) {
UserDefOneList *native_i = (UserDefOneList *)i;
visit_type_UserDefOne(m, &native_i->value, NULL, &err);
}
error_propagate(errp, err);
err = NULL;
visit_end_list(m, &err);
out:
error_propagate(errp, err);
} }
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h $ python scripts/qapi-commands.py --output-dir="qapi-generated" \
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ --prefix="example-" --input-file=example-schema.json
$ cat qapi-generated/example-qapi-visit.h
[Uninteresting stuff omitted...]
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT #ifndef EXAMPLE_QAPI_VISIT_H
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT #define EXAMPLE_QAPI_VISIT_H
#include "qapi/qapi-visit-core.h" [Visitors for builtin types omitted...]
#include "example-qapi-types.h"
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp); void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp); void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
#endif #endif
mdroth@illuin:~/w/qemu2.git$
(The actual structure of the visit_type_* functions is a bit more complex
in order to propagate errors correctly and avoid leaking memory).
=== scripts/qapi-commands.py === === scripts/qapi-commands.py ===
@ -390,77 +433,80 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
Example: Example:
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c $ cat qapi-generated/example-qmp-marshal.c
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#include "qemu-objects.h"
#include "qapi/qmp-core.h"
#include "qapi/qapi-visit-core.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qapi-dealloc-visitor.h"
#include "example-qapi-types.h"
#include "example-qapi-visit.h"
#include "example-qmp-commands.h"
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp) static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
{ {
QapiDeallocVisitor *md = qapi_dealloc_visitor_new(); Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new(); QmpOutputVisitor *mo = qmp_output_visitor_new();
QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
v = qmp_output_get_visitor(mo); v = qmp_output_get_visitor(mo);
visit_type_UserDefOne(v, &ret_in, "unused", errp); visit_type_UserDefOne(v, &ret_in, "unused", &local_err);
v = qapi_dealloc_get_visitor(md); if (local_err) {
visit_type_UserDefOne(v, &ret_in, "unused", errp); goto out;
qapi_dealloc_visitor_cleanup(md); }
*ret_out = qmp_output_get_qobject(mo); *ret_out = qmp_output_get_qobject(mo);
out:
error_propagate(errp, local_err);
qmp_output_visitor_cleanup(mo);
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOne(v, &ret_in, "unused", NULL);
qapi_dealloc_visitor_cleanup(md);
} }
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp) static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
{ {
Error *local_err = NULL;
UserDefOne * retval = NULL; UserDefOne * retval = NULL;
QmpInputVisitor *mi; QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
UserDefOne * arg1 = NULL; UserDefOne * arg1 = NULL;
mi = qmp_input_visitor_new(QOBJECT(args));
v = qmp_input_get_visitor(mi); v = qmp_input_get_visitor(mi);
visit_type_UserDefOne(v, &arg1, "arg1", errp); visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
if (local_err) {
if (error_is_set(errp)) {
goto out; goto out;
} }
retval = qmp_my_command(arg1, errp);
qmp_marshal_output_my_command(retval, ret, errp); retval = qmp_my_command(arg1, &local_err);
if (local_err) {
goto out;
}
qmp_marshal_output_my_command(retval, ret, &local_err);
out: out:
error_propagate(errp, local_err);
qmp_input_visitor_cleanup(mi);
md = qapi_dealloc_visitor_new(); md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
visit_type_UserDefOne(v, &arg1, "arg1", errp); visit_type_UserDefOne(v, &arg1, "arg1", NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
return; return;
} }
static void qmp_init_marshal(void) static void qmp_init_marshal(void)
{ {
qmp_register_command("my-command", qmp_marshal_input_my_command); qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
} }
qapi_init(qmp_init_marshal); qapi_init(qmp_init_marshal);
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h $ cat qapi-generated/example-qmp-commands.h
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ [Uninteresting stuff omitted...]
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS #ifndef EXAMPLE_QMP_COMMANDS_H
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS #define EXAMPLE_QMP_COMMANDS_H
#include "example-qapi-types.h" #include "example-qapi-types.h"
#include "error.h" #include "qapi/qmp/qdict.h"
#include "qapi/error.h"
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp); UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
#endif #endif
mdroth@illuin:~/w/qemu2.git$

View File

@ -556,6 +556,7 @@ ETEXI
.params = "keys [hold_ms]", .params = "keys [hold_ms]",
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
.mhandler.cmd = hmp_send_key, .mhandler.cmd = hmp_send_key,
.command_completion = sendkey_completion,
}, },
STEXI STEXI
@ -1233,9 +1234,10 @@ ETEXI
{ {
.name = "netdev_add", .name = "netdev_add",
.args_type = "netdev:O", .args_type = "netdev:O",
.params = "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]", .params = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
.help = "add host network device", .help = "add host network device",
.mhandler.cmd = hmp_netdev_add, .mhandler.cmd = hmp_netdev_add,
.command_completion = netdev_add_completion,
}, },
STEXI STEXI
@ -1250,6 +1252,7 @@ ETEXI
.params = "id", .params = "id",
.help = "remove host network device", .help = "remove host network device",
.mhandler.cmd = hmp_netdev_del, .mhandler.cmd = hmp_netdev_del,
.command_completion = netdev_del_completion,
}, },
STEXI STEXI
@ -1339,6 +1342,7 @@ ETEXI
.params = "name on|off", .params = "name on|off",
.help = "change the link status of a network adapter", .help = "change the link status of a network adapter",
.mhandler.cmd = hmp_set_link, .mhandler.cmd = hmp_set_link,
.command_completion = set_link_completion,
}, },
STEXI STEXI
@ -1622,6 +1626,7 @@ ETEXI
.params = "args", .params = "args",
.help = "add chardev", .help = "add chardev",
.mhandler.cmd = hmp_chardev_add, .mhandler.cmd = hmp_chardev_add,
.command_completion = chardev_add_completion,
}, },
STEXI STEXI
@ -1638,6 +1643,7 @@ ETEXI
.params = "id", .params = "id",
.help = "remove chardev", .help = "remove chardev",
.mhandler.cmd = hmp_chardev_remove, .mhandler.cmd = hmp_chardev_remove,
.command_completion = chardev_remove_completion,
}, },
STEXI STEXI

16
hmp.c
View File

@ -1388,6 +1388,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
void hmp_object_add(Monitor *mon, const QDict *qdict) void hmp_object_add(Monitor *mon, const QDict *qdict)
{ {
Error *err = NULL; Error *err = NULL;
Error *err_end = NULL;
QemuOpts *opts; QemuOpts *opts;
char *type = NULL; char *type = NULL;
char *id = NULL; char *id = NULL;
@ -1411,24 +1412,23 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
qdict_del(pdict, "qom-type"); qdict_del(pdict, "qom-type");
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
if (err) { if (err) {
goto out_clean; goto out_end;
} }
qdict_del(pdict, "id"); qdict_del(pdict, "id");
visit_type_str(opts_get_visitor(ov), &id, "id", &err); visit_type_str(opts_get_visitor(ov), &id, "id", &err);
if (err) { if (err) {
goto out_clean; goto out_end;
} }
object_add(type, id, pdict, opts_get_visitor(ov), &err); object_add(type, id, pdict, opts_get_visitor(ov), &err);
if (err) {
goto out_clean; out_end:
} visit_end_struct(opts_get_visitor(ov), &err_end);
visit_end_struct(opts_get_visitor(ov), &err); if (!err && err_end) {
if (err) {
qmp_object_del(id, NULL); qmp_object_del(id, NULL);
} }
error_propagate(&err, err_end);
out_clean: out_clean:
opts_visitor_cleanup(ov); opts_visitor_cleanup(ov);

6
hmp.h
View File

@ -97,5 +97,11 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
void object_del_completion(ReadLineState *rs, int nb_args, const char *str); void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
void device_add_completion(ReadLineState *rs, int nb_args, const char *str); void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
void device_del_completion(ReadLineState *rs, int nb_args, const char *str); void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
#endif #endif

View File

@ -793,19 +793,46 @@ static const MemoryRegionOps cmos_ops = {
static void rtc_get_date(Object *obj, Visitor *v, void *opaque, static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp) const char *name, Error **errp)
{ {
Error *err = NULL;
RTCState *s = MC146818_RTC(obj); RTCState *s = MC146818_RTC(obj);
struct tm current_tm; struct tm current_tm;
rtc_update_time(s); rtc_update_time(s);
rtc_get_time(s, &current_tm); rtc_get_time(s, &current_tm);
visit_start_struct(v, NULL, "struct tm", name, 0, errp); visit_start_struct(v, NULL, "struct tm", name, 0, &err);
visit_type_int32(v, &current_tm.tm_year, "tm_year", errp); if (err) {
visit_type_int32(v, &current_tm.tm_mon, "tm_mon", errp); goto out;
visit_type_int32(v, &current_tm.tm_mday, "tm_mday", errp); }
visit_type_int32(v, &current_tm.tm_hour, "tm_hour", errp); visit_type_int32(v, &current_tm.tm_year, "tm_year", &err);
visit_type_int32(v, &current_tm.tm_min, "tm_min", errp); if (err) {
visit_type_int32(v, &current_tm.tm_sec, "tm_sec", errp); goto out_end;
}
visit_type_int32(v, &current_tm.tm_mon, "tm_mon", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_mday, "tm_mday", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_hour, "tm_hour", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_min, "tm_min", &err);
if (err) {
goto out_end;
}
visit_type_int32(v, &current_tm.tm_sec, "tm_sec", &err);
if (err) {
goto out_end;
}
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, errp); visit_end_struct(v, errp);
out:
error_propagate(errp, err);
} }
static void rtc_realizefn(DeviceState *dev, Error **errp) static void rtc_realizefn(DeviceState *dev, Error **errp)

View File

@ -108,6 +108,7 @@ static void balloon_stats_poll_cb(void *opaque)
static void balloon_stats_get_all(Object *obj, struct Visitor *v, static void balloon_stats_get_all(Object *obj, struct Visitor *v,
void *opaque, const char *name, Error **errp) void *opaque, const char *name, Error **errp)
{ {
Error *err = NULL;
VirtIOBalloon *s = opaque; VirtIOBalloon *s = opaque;
int i; int i;
@ -116,17 +117,33 @@ static void balloon_stats_get_all(Object *obj, struct Visitor *v,
return; return;
} }
visit_start_struct(v, NULL, "guest-stats", name, 0, errp); visit_start_struct(v, NULL, "guest-stats", name, 0, &err);
visit_type_int(v, &s->stats_last_update, "last-update", errp); if (err) {
goto out;
visit_start_struct(v, NULL, NULL, "stats", 0, errp); }
for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { visit_type_int(v, &s->stats_last_update, "last-update", &err);
visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i], if (err) {
errp); goto out_end;
} }
visit_end_struct(v, errp);
visit_end_struct(v, errp); visit_start_struct(v, NULL, NULL, "stats", 0, &err);
if (err) {
goto out_end;
}
for (i = 0; !err && i < VIRTIO_BALLOON_S_NR; i++) {
visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i],
&err);
}
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v, static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v,

View File

@ -42,13 +42,9 @@ struct Visitor
Error **errp); Error **errp);
/* May be NULL */ /* May be NULL */
void (*start_optional)(Visitor *v, bool *present, const char *name, void (*optional)(Visitor *v, bool *present, const char *name,
Error **errp); Error **errp);
void (*end_optional)(Visitor *v, Error **errp);
void (*start_handle)(Visitor *v, void **obj, const char *kind,
const char *name, Error **errp);
void (*end_handle)(Visitor *v, Error **errp);
void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp); void (*type_uint8)(Visitor *v, uint8_t *obj, const char *name, Error **errp);
void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp); void (*type_uint16)(Visitor *v, uint16_t *obj, const char *name, Error **errp);
void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp); void (*type_uint32)(Visitor *v, uint32_t *obj, const char *name, Error **errp);

View File

@ -39,9 +39,8 @@ void visit_end_implicit_struct(Visitor *v, Error **errp);
void visit_start_list(Visitor *v, const char *name, Error **errp); void visit_start_list(Visitor *v, const char *name, Error **errp);
GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp); GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp);
void visit_end_list(Visitor *v, Error **errp); void visit_end_list(Visitor *v, Error **errp);
void visit_start_optional(Visitor *v, bool *present, const char *name, void visit_optional(Visitor *v, bool *present, const char *name,
Error **errp); Error **errp);
void visit_end_optional(Visitor *v, Error **errp);
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
const char *name, Error **errp); const char *name, Error **errp);
void visit_type_enum(Visitor *v, int *obj, const char *strings[], void visit_type_enum(Visitor *v, int *obj, const char *strings[],

153
monitor.c
View File

@ -4269,6 +4269,55 @@ static const char *next_arg_type(const char *typestr)
return (p != NULL ? ++p : typestr); return (p != NULL ? ++p : typestr);
} }
static void add_completion_option(ReadLineState *rs, const char *str,
const char *option)
{
if (!str || !option) {
return;
}
if (!strncmp(option, str, strlen(str))) {
readline_add_completion(rs, option);
}
}
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
ChardevBackendInfoList *list, *start;
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
start = list = qmp_query_chardev_backends(NULL);
while (list) {
const char *chr_name = list->value->name;
if (!strncmp(chr_name, str, len)) {
readline_add_completion(rs, chr_name);
}
list = list->next;
}
qapi_free_ChardevBackendInfoList(start);
}
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
int i;
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
for (i = 0; NetClientOptionsKind_lookup[i]; i++) {
add_completion_option(rs, str, NetClientOptionsKind_lookup[i]);
}
}
void device_add_completion(ReadLineState *rs, int nb_args, const char *str) void device_add_completion(ReadLineState *rs, int nb_args, const char *str)
{ {
GSList *list, *elt; GSList *list, *elt;
@ -4339,6 +4388,29 @@ static void device_del_bus_completion(ReadLineState *rs, BusState *bus,
} }
} }
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
ChardevInfoList *list, *start;
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
start = list = qmp_query_chardev(NULL);
while (list) {
ChardevInfo *chr = list->value;
if (!strncmp(chr->label, str, len)) {
readline_add_completion(rs, chr->label);
}
list = list->next;
}
qapi_free_ChardevInfoList(start);
}
void device_del_completion(ReadLineState *rs, int nb_args, const char *str) void device_del_completion(ReadLineState *rs, int nb_args, const char *str)
{ {
size_t len; size_t len;
@ -4376,6 +4448,77 @@ void object_del_completion(ReadLineState *rs, int nb_args, const char *str)
qapi_free_ObjectPropertyInfoList(start); qapi_free_ObjectPropertyInfoList(start);
} }
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str)
{
int i;
char *sep;
size_t len;
if (nb_args != 2) {
return;
}
sep = strrchr(str, '-');
if (sep) {
str = sep + 1;
}
len = strlen(str);
readline_set_completion_index(rs, len);
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
if (!strncmp(str, QKeyCode_lookup[i], len)) {
readline_add_completion(rs, QKeyCode_lookup[i]);
}
}
}
void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
{
size_t len;
len = strlen(str);
readline_set_completion_index(rs, len);
if (nb_args == 2) {
NetClientState *ncs[255];
int count, i;
count = qemu_find_net_clients_except(NULL, ncs,
NET_CLIENT_OPTIONS_KIND_NONE, 255);
for (i = 0; i < count; i++) {
const char *name = ncs[i]->name;
if (!strncmp(str, name, len)) {
readline_add_completion(rs, name);
}
}
} else if (nb_args == 3) {
add_completion_option(rs, str, "on");
add_completion_option(rs, str, "off");
}
}
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
{
int len, count, i;
NetClientState *ncs[255];
if (nb_args != 2) {
return;
}
len = strlen(str);
readline_set_completion_index(rs, len);
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
255);
for (i = 0; i < count; i++) {
QemuOpts *opts;
const char *name = ncs[i]->name;
if (strncmp(str, name, len)) {
continue;
}
opts = qemu_opts_find(qemu_find_opts_err("netdev", NULL), name);
if (opts) {
readline_add_completion(rs, name);
}
}
}
static void monitor_find_completion_by_table(Monitor *mon, static void monitor_find_completion_by_table(Monitor *mon,
const mon_cmd_t *cmd_table, const mon_cmd_t *cmd_table,
char **args, char **args,
@ -4444,15 +4587,7 @@ static void monitor_find_completion_by_table(Monitor *mon,
break; break;
case 's': case 's':
case 'S': case 'S':
if (!strcmp(cmd->name, "sendkey")) { if (!strcmp(cmd->name, "help|?")) {
char *sep = strrchr(str, '-');
if (sep)
str = sep + 1;
readline_set_completion_index(mon->rs, strlen(str));
for (i = 0; i < Q_KEY_CODE_MAX; i++) {
cmd_completion(mon, str, QKeyCode_lookup[i]);
}
} else if (!strcmp(cmd->name, "help|?")) {
monitor_find_completion_by_table(mon, cmd_table, monitor_find_completion_by_table(mon, cmd_table,
&args[1], nb_args - 1); &args[1], nb_args - 1);
} }

View File

@ -633,7 +633,7 @@ int qemu_find_net_clients_except(const char *id, NetClientState **ncs,
if (nc->info->type == type) { if (nc->info->type == type) {
continue; continue;
} }
if (!strcmp(nc->name, id)) { if (!id || !strcmp(nc->name, id)) {
if (ret < max) { if (ret < max) {
ncs[ret] = nc; ncs[ret] = nc;
} }

View File

@ -484,8 +484,7 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
static void static void
opts_start_optional(Visitor *v, bool *present, const char *name, opts_optional(Visitor *v, bool *present, const char *name, Error **errp)
Error **errp)
{ {
OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v);
@ -528,7 +527,7 @@ opts_visitor_new(const QemuOpts *opts)
/* type_number() is not filled in, but this is not the first visitor to /* type_number() is not filled in, but this is not the first visitor to
* skip some mandatory methods... */ * skip some mandatory methods... */
ov->visitor.start_optional = &opts_start_optional; ov->visitor.optional = &opts_optional;
ov->opts_root = opts; ov->opts_root = opts;

View File

@ -17,46 +17,27 @@
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "qapi/visitor-impl.h" #include "qapi/visitor-impl.h"
void visit_start_handle(Visitor *v, void **obj, const char *kind,
const char *name, Error **errp)
{
if (!error_is_set(errp) && v->start_handle) {
v->start_handle(v, obj, kind, name, errp);
}
}
void visit_end_handle(Visitor *v, Error **errp)
{
if (!error_is_set(errp) && v->end_handle) {
v->end_handle(v, errp);
}
}
void visit_start_struct(Visitor *v, void **obj, const char *kind, void visit_start_struct(Visitor *v, void **obj, const char *kind,
const char *name, size_t size, Error **errp) const char *name, size_t size, Error **errp)
{ {
if (!error_is_set(errp)) { v->start_struct(v, obj, kind, name, size, errp);
v->start_struct(v, obj, kind, name, size, errp);
}
} }
void visit_end_struct(Visitor *v, Error **errp) void visit_end_struct(Visitor *v, Error **errp)
{ {
assert(!error_is_set(errp));
v->end_struct(v, errp); v->end_struct(v, errp);
} }
void visit_start_implicit_struct(Visitor *v, void **obj, size_t size, void visit_start_implicit_struct(Visitor *v, void **obj, size_t size,
Error **errp) Error **errp)
{ {
if (!error_is_set(errp) && v->start_implicit_struct) { if (v->start_implicit_struct) {
v->start_implicit_struct(v, obj, size, errp); v->start_implicit_struct(v, obj, size, errp);
} }
} }
void visit_end_implicit_struct(Visitor *v, Error **errp) void visit_end_implicit_struct(Visitor *v, Error **errp)
{ {
assert(!error_is_set(errp));
if (v->end_implicit_struct) { if (v->end_implicit_struct) {
v->end_implicit_struct(v, errp); v->end_implicit_struct(v, errp);
} }
@ -64,45 +45,31 @@ void visit_end_implicit_struct(Visitor *v, Error **errp)
void visit_start_list(Visitor *v, const char *name, Error **errp) void visit_start_list(Visitor *v, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->start_list(v, name, errp);
v->start_list(v, name, errp);
}
} }
GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp) GenericList *visit_next_list(Visitor *v, GenericList **list, Error **errp)
{ {
if (!error_is_set(errp)) { return v->next_list(v, list, errp);
return v->next_list(v, list, errp);
}
return 0;
} }
void visit_end_list(Visitor *v, Error **errp) void visit_end_list(Visitor *v, Error **errp)
{ {
assert(!error_is_set(errp));
v->end_list(v, errp); v->end_list(v, errp);
} }
void visit_start_optional(Visitor *v, bool *present, const char *name, void visit_optional(Visitor *v, bool *present, const char *name,
Error **errp) Error **errp)
{ {
if (!error_is_set(errp) && v->start_optional) { if (v->optional) {
v->start_optional(v, present, name, errp); v->optional(v, present, name, errp);
}
}
void visit_end_optional(Visitor *v, Error **errp)
{
if (!error_is_set(errp) && v->end_optional) {
v->end_optional(v, errp);
} }
} }
void visit_get_next_type(Visitor *v, int *obj, const int *qtypes, void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
const char *name, Error **errp) const char *name, Error **errp)
{ {
if (!error_is_set(errp) && v->get_next_type) { if (v->get_next_type) {
v->get_next_type(v, obj, qtypes, name, errp); v->get_next_type(v, obj, qtypes, name, errp);
} }
} }
@ -110,192 +77,172 @@ void visit_get_next_type(Visitor *v, int *obj, const int *qtypes,
void visit_type_enum(Visitor *v, int *obj, const char *strings[], void visit_type_enum(Visitor *v, int *obj, const char *strings[],
const char *kind, const char *name, Error **errp) const char *kind, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_enum(v, obj, strings, kind, name, errp);
v->type_enum(v, obj, strings, kind, name, errp);
}
} }
void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) void visit_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_int(v, obj, name, errp);
v->type_int(v, obj, name, errp);
}
} }
void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp) void visit_type_uint8(Visitor *v, uint8_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint8) { if (v->type_uint8) {
v->type_uint8(v, obj, name, errp); v->type_uint8(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < 0 || value > UINT8_MAX) { if (value < 0 || value > UINT8_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"uint8_t"); "uint8_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp) void visit_type_uint16(Visitor *v, uint16_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint16) { if (v->type_uint16) {
v->type_uint16(v, obj, name, errp); v->type_uint16(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < 0 || value > UINT16_MAX) { if (value < 0 || value > UINT16_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"uint16_t"); "uint16_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp) void visit_type_uint32(Visitor *v, uint32_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint32) { if (v->type_uint32) {
v->type_uint32(v, obj, name, errp); v->type_uint32(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < 0 || value > UINT32_MAX) { if (value < 0 || value > UINT32_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"uint32_t"); "uint32_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) void visit_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_uint64) { if (v->type_uint64) {
v->type_uint64(v, obj, name, errp); v->type_uint64(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
*obj = value; *obj = value;
}
} }
} }
void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp) void visit_type_int8(Visitor *v, int8_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_int8) { if (v->type_int8) {
v->type_int8(v, obj, name, errp); v->type_int8(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < INT8_MIN || value > INT8_MAX) { if (value < INT8_MIN || value > INT8_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"int8_t"); "int8_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp) void visit_type_int16(Visitor *v, int16_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_int16) { if (v->type_int16) {
v->type_int16(v, obj, name, errp); v->type_int16(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < INT16_MIN || value > INT16_MAX) { if (value < INT16_MIN || value > INT16_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"int16_t"); "int16_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp) void visit_type_int32(Visitor *v, int32_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_int32) { if (v->type_int32) {
v->type_int32(v, obj, name, errp); v->type_int32(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
if (value < INT32_MIN || value > INT32_MAX) { if (value < INT32_MIN || value > INT32_MAX) {
error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"int32_t"); "int32_t");
return; return;
}
*obj = value;
} }
*obj = value;
} }
} }
void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp) void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { if (v->type_int64) {
if (v->type_int64) { v->type_int64(v, obj, name, errp);
v->type_int64(v, obj, name, errp); } else {
} else { v->type_int(v, obj, name, errp);
v->type_int(v, obj, name, errp);
}
} }
} }
void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)
{ {
int64_t value; int64_t value;
if (!error_is_set(errp)) {
if (v->type_size) { if (v->type_size) {
v->type_size(v, obj, name, errp); v->type_size(v, obj, name, errp);
} else if (v->type_uint64) { } else if (v->type_uint64) {
v->type_uint64(v, obj, name, errp); v->type_uint64(v, obj, name, errp);
} else { } else {
value = *obj; value = *obj;
v->type_int(v, &value, name, errp); v->type_int(v, &value, name, errp);
*obj = value; *obj = value;
}
} }
} }
void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_bool(v, obj, name, errp);
v->type_bool(v, obj, name, errp);
}
} }
void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp) void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_str(v, obj, name, errp);
v->type_str(v, obj, name, errp);
}
} }
void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp) void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
{ {
if (!error_is_set(errp)) { v->type_number(v, obj, name, errp);
v->type_number(v, obj, name, errp);
}
} }
void output_type_enum(Visitor *v, int *obj, const char *strings[], void output_type_enum(Visitor *v, int *obj, const char *strings[],
@ -321,13 +268,15 @@ void input_type_enum(Visitor *v, int *obj, const char *strings[],
const char *kind, const char *name, const char *kind, const char *name,
Error **errp) Error **errp)
{ {
Error *local_err = NULL;
int64_t value = 0; int64_t value = 0;
char *enum_str; char *enum_str;
assert(strings); assert(strings);
visit_type_str(v, &enum_str, name, errp); visit_type_str(v, &enum_str, name, &local_err);
if (error_is_set(errp)) { if (local_err) {
error_propagate(errp, local_err);
return; return;
} }

View File

@ -286,8 +286,8 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
} }
} }
static void qmp_input_start_optional(Visitor *v, bool *present, static void qmp_input_optional(Visitor *v, bool *present, const char *name,
const char *name, Error **errp) Error **errp)
{ {
QmpInputVisitor *qiv = to_qiv(v); QmpInputVisitor *qiv = to_qiv(v);
QObject *qobj = qmp_input_get_object(qiv, name, true); QObject *qobj = qmp_input_get_object(qiv, name, true);
@ -329,7 +329,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
v->visitor.type_bool = qmp_input_type_bool; v->visitor.type_bool = qmp_input_type_bool;
v->visitor.type_str = qmp_input_type_str; v->visitor.type_str = qmp_input_type_str;
v->visitor.type_number = qmp_input_type_number; v->visitor.type_number = qmp_input_type_number;
v->visitor.start_optional = qmp_input_start_optional; v->visitor.optional = qmp_input_optional;
v->visitor.get_next_type = qmp_input_get_next_type; v->visitor.get_next_type = qmp_input_get_next_type;
qmp_input_push(v, obj, NULL); qmp_input_push(v, obj, NULL);

View File

@ -120,8 +120,8 @@ static void parse_type_number(Visitor *v, double *obj, const char *name,
*obj = val; *obj = val;
} }
static void parse_start_optional(Visitor *v, bool *present, static void parse_optional(Visitor *v, bool *present, const char *name,
const char *name, Error **errp) Error **errp)
{ {
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v); StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
@ -155,7 +155,7 @@ StringInputVisitor *string_input_visitor_new(const char *str)
v->visitor.type_bool = parse_type_bool; v->visitor.type_bool = parse_type_bool;
v->visitor.type_str = parse_type_str; v->visitor.type_str = parse_type_str;
v->visitor.type_number = parse_type_number; v->visitor.type_number = parse_type_number;
v->visitor.start_optional = parse_start_optional; v->visitor.optional = parse_optional;
v->string = str; v->string = str;
return v; return v;

View File

@ -2,16 +2,19 @@
# QAPI command marshaller generator # QAPI command marshaller generator
# #
# Copyright IBM, Corp. 2011 # Copyright IBM, Corp. 2011
# Copyright (C) 2014 Red Hat, Inc.
# #
# Authors: # Authors:
# Anthony Liguori <aliguori@us.ibm.com> # Anthony Liguori <aliguori@us.ibm.com>
# Michael Roth <mdroth@linux.vnet.ibm.com> # Michael Roth <mdroth@linux.vnet.ibm.com>
# Markus Armbruster <armbru@redhat.com>
# #
# This work is licensed under the terms of the GNU GPL, version 2. # This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory. # See the COPYING file in the top-level directory.
from ordereddict import OrderedDict from ordereddict import OrderedDict
from qapi import * from qapi import *
import re
import sys import sys
import os import os
import getopt import getopt
@ -37,6 +40,15 @@ def generate_command_decl(name, args, ret_type):
''', ''',
ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip() ret_type=c_type(ret_type), name=c_fun(name), args=arglist).strip()
def gen_err_check(errvar):
if errvar:
return mcgen('''
if (local_err) {
goto out;
}
''')
return ''
def gen_sync_call(name, args, ret_type, indent=0): def gen_sync_call(name, args, ret_type, indent=0):
ret = "" ret = ""
arglist="" arglist=""
@ -49,15 +61,14 @@ def gen_sync_call(name, args, ret_type, indent=0):
arglist += "%s, " % (c_var(argname)) arglist += "%s, " % (c_var(argname))
push_indent(indent) push_indent(indent)
ret = mcgen(''' ret = mcgen('''
%(retval)sqmp_%(name)s(%(args)serrp); %(retval)sqmp_%(name)s(%(args)s&local_err);
''', ''',
name=c_fun(name), args=arglist, retval=retval).rstrip() name=c_fun(name), args=arglist, retval=retval).rstrip()
if ret_type: if ret_type:
ret += "\n" + gen_err_check('local_err')
ret += "\n" + mcgen('''' ret += "\n" + mcgen(''''
if (!error_is_set(errp)) { %(marshal_output_call)s
%(marshal_output_call)s
}
''', ''',
marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip() marshal_output_call=gen_marshal_output_call(name, ret_type)).rstrip()
pop_indent(indent) pop_indent(indent)
@ -67,18 +78,19 @@ if (!error_is_set(errp)) {
def gen_marshal_output_call(name, ret_type): def gen_marshal_output_call(name, ret_type):
if not ret_type: if not ret_type:
return "" return ""
return "qmp_marshal_output_%s(retval, ret, errp);" % c_fun(name) return "qmp_marshal_output_%s(retval, ret, &local_err);" % c_fun(name)
def gen_visitor_input_containers_decl(args): def gen_visitor_input_containers_decl(args, obj):
ret = "" ret = ""
push_indent() push_indent()
if len(args) > 0: if len(args) > 0:
ret += mcgen(''' ret += mcgen('''
QmpInputVisitor *mi; QmpInputVisitor *mi = qmp_input_visitor_new_strict(%(obj)s);
QapiDeallocVisitor *md; QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
''') ''',
obj=obj)
pop_indent() pop_indent()
return ret.rstrip() return ret.rstrip()
@ -106,9 +118,10 @@ bool has_%(argname)s = false;
pop_indent() pop_indent()
return ret.rstrip() return ret.rstrip()
def gen_visitor_input_block(args, obj, dealloc=False): def gen_visitor_input_block(args, dealloc=False):
ret = "" ret = ""
errparg = 'errp' errparg = '&local_err'
errarg = 'local_err'
if len(args) == 0: if len(args) == 0:
return ret return ret
@ -117,44 +130,44 @@ def gen_visitor_input_block(args, obj, dealloc=False):
if dealloc: if dealloc:
errparg = 'NULL' errparg = 'NULL'
errarg = None;
ret += mcgen(''' ret += mcgen('''
qmp_input_visitor_cleanup(mi);
md = qapi_dealloc_visitor_new(); md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
''') ''')
else: else:
ret += mcgen(''' ret += mcgen('''
mi = qmp_input_visitor_new_strict(%(obj)s);
v = qmp_input_get_visitor(mi); v = qmp_input_get_visitor(mi);
''', ''')
obj=obj)
for argname, argtype, optional, structured in parse_args(args): for argname, argtype, optional, structured in parse_args(args):
if optional: if optional:
ret += mcgen(''' ret += mcgen('''
visit_start_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s); visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
if (has_%(c_name)s) {
''', ''',
c_name=c_var(argname), name=argname, errp=errparg) c_name=c_var(argname), name=argname, errp=errparg)
ret += gen_err_check(errarg)
ret += mcgen('''
if (has_%(c_name)s) {
''',
c_name=c_var(argname))
push_indent() push_indent()
ret += mcgen(''' ret += mcgen('''
%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s); %(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
''', ''',
c_name=c_var(argname), name=argname, argtype=argtype, c_name=c_var(argname), name=argname, argtype=argtype,
visitor=type_visitor(argtype), errp=errparg) visitor=type_visitor(argtype), errp=errparg)
ret += gen_err_check(errarg)
if optional: if optional:
pop_indent() pop_indent()
ret += mcgen(''' ret += mcgen('''
} }
visit_end_optional(v, %(errp)s); ''')
''', errp=errparg)
if dealloc: if dealloc:
ret += mcgen(''' ret += mcgen('''
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
''')
else:
ret += mcgen('''
qmp_input_visitor_cleanup(mi);
''') ''')
pop_indent() pop_indent()
return ret.rstrip() return ret.rstrip()
@ -166,16 +179,22 @@ def gen_marshal_output(name, args, ret_type, middle_mode):
ret = mcgen(''' ret = mcgen('''
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp) static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
{ {
QapiDeallocVisitor *md = qapi_dealloc_visitor_new(); Error *local_err = NULL;
QmpOutputVisitor *mo = qmp_output_visitor_new(); QmpOutputVisitor *mo = qmp_output_visitor_new();
QapiDeallocVisitor *md;
Visitor *v; Visitor *v;
v = qmp_output_get_visitor(mo); v = qmp_output_get_visitor(mo);
%(visitor)s(v, &ret_in, "unused", errp); %(visitor)s(v, &ret_in, "unused", &local_err);
if (!error_is_set(errp)) { if (local_err) {
*ret_out = qmp_output_get_qobject(mo); goto out;
} }
*ret_out = qmp_output_get_qobject(mo);
out:
error_propagate(errp, local_err);
qmp_output_visitor_cleanup(mo); qmp_output_visitor_cleanup(mo);
md = qapi_dealloc_visitor_new();
v = qapi_dealloc_get_visitor(md); v = qapi_dealloc_get_visitor(md);
%(visitor)s(v, &ret_in, "unused", NULL); %(visitor)s(v, &ret_in, "unused", NULL);
qapi_dealloc_visitor_cleanup(md); qapi_dealloc_visitor_cleanup(md);
@ -200,13 +219,12 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
ret = mcgen(''' ret = mcgen('''
%(header)s %(header)s
{ {
Error *local_err = NULL;
''', ''',
header=hdr) header=hdr)
if middle_mode: if middle_mode:
ret += mcgen(''' ret += mcgen('''
Error *local_err = NULL;
Error **errp = &local_err;
QDict *args = (QDict *)qdict; QDict *args = (QDict *)qdict;
''') ''')
@ -228,29 +246,32 @@ def gen_marshal_input(name, args, ret_type, middle_mode):
%(visitor_input_block)s %(visitor_input_block)s
''', ''',
visitor_input_containers_decl=gen_visitor_input_containers_decl(args), visitor_input_containers_decl=gen_visitor_input_containers_decl(args, "QOBJECT(args)"),
visitor_input_vars_decl=gen_visitor_input_vars_decl(args), visitor_input_vars_decl=gen_visitor_input_vars_decl(args),
visitor_input_block=gen_visitor_input_block(args, "QOBJECT(args)")) visitor_input_block=gen_visitor_input_block(args))
else: else:
ret += mcgen(''' ret += mcgen('''
(void)args; (void)args;
''') ''')
ret += mcgen(''' ret += mcgen('''
if (error_is_set(errp)) {
goto out;
}
%(sync_call)s %(sync_call)s
''', ''',
sync_call=gen_sync_call(name, args, ret_type, indent=4)) sync_call=gen_sync_call(name, args, ret_type, indent=4))
ret += mcgen(''' if re.search('^ *goto out\\;', ret, re.MULTILINE):
ret += mcgen('''
out: out:
''')
if not middle_mode:
ret += mcgen('''
error_propagate(errp, local_err);
''') ''')
ret += mcgen(''' ret += mcgen('''
%(visitor_input_block_cleanup)s %(visitor_input_block_cleanup)s
''', ''',
visitor_input_block_cleanup=gen_visitor_input_block(args, None, visitor_input_block_cleanup=gen_visitor_input_block(args,
dealloc=True)) dealloc=True))
if middle_mode: if middle_mode:

View File

@ -2,21 +2,47 @@
# QAPI visitor generator # QAPI visitor generator
# #
# Copyright IBM, Corp. 2011 # Copyright IBM, Corp. 2011
# Copyright (C) 2014 Red Hat, Inc.
# #
# Authors: # Authors:
# Anthony Liguori <aliguori@us.ibm.com> # Anthony Liguori <aliguori@us.ibm.com>
# Michael Roth <mdroth@linux.vnet.ibm.com> # Michael Roth <mdroth@linux.vnet.ibm.com>
# Markus Armbruster <armbru@redhat.com>
# #
# This work is licensed under the terms of the GNU GPL, version 2. # This work is licensed under the terms of the GNU GPL, version 2.
# See the COPYING file in the top-level directory. # See the COPYING file in the top-level directory.
from ordereddict import OrderedDict from ordereddict import OrderedDict
from qapi import * from qapi import *
import re
import sys import sys
import os import os
import getopt import getopt
import errno import errno
implicit_structs = []
def generate_visit_implicit_struct(type):
global implicit_structs
if type in implicit_structs:
return ''
implicit_structs.append(type)
return mcgen('''
static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
{
Error *err = NULL;
visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
if (!err) {
visit_type_%(c_type)s_fields(m, obj, errp);
visit_end_implicit_struct(m, &err);
}
error_propagate(errp, err);
}
''',
c_type=type_name(type))
def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None): def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
substructs = [] substructs = []
ret = '' ret = ''
@ -35,6 +61,19 @@ def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base =
nested_field_prefix = "%s%s." % (field_prefix, argname) nested_field_prefix = "%s%s." % (field_prefix, argname)
ret += generate_visit_struct_fields(name, nested_field_prefix, ret += generate_visit_struct_fields(name, nested_field_prefix,
nested_fn_prefix, argentry) nested_fn_prefix, argentry)
ret += mcgen('''
static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp)
{
''',
name=name, full_name=full_name, c_name=c_var(argname))
ret += generate_visit_struct_body(full_name, argname, argentry)
ret += mcgen('''
}
''')
if base:
ret += generate_visit_implicit_struct(base)
ret += mcgen(''' ret += mcgen('''
@ -47,12 +86,9 @@ static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s ** obj, Error *
if base: if base:
ret += mcgen(''' ret += mcgen('''
visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(type)s), &err); visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
if (!err) { if (err) {
visit_type_%(type)s_fields(m, &(*obj)->%(c_prefix)s%(c_name)s, &err); goto out;
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
} }
''', ''',
c_prefix=c_var(field_prefix), c_prefix=c_var(field_prefix),
@ -61,15 +97,18 @@ if (!err) {
for argname, argentry, optional, structured in parse_args(members): for argname, argentry, optional, structured in parse_args(members):
if optional: if optional:
ret += mcgen(''' ret += mcgen('''
visit_start_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err); visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
if ((*obj)->%(prefix)shas_%(c_name)s) { if (!err && (*obj)->%(prefix)shas_%(c_name)s) {
''', ''',
c_prefix=c_var(field_prefix), prefix=field_prefix, c_prefix=c_var(field_prefix), prefix=field_prefix,
c_name=c_var(argname), name=argname) c_name=c_var(argname), name=argname)
push_indent() push_indent()
if structured: if structured:
ret += generate_visit_struct_body(full_name, argname, argentry) ret += mcgen('''
visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err);
''',
full_name=full_name, c_name=c_var(argname))
else: else:
ret += mcgen(''' ret += mcgen('''
visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err); visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
@ -82,12 +121,20 @@ visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
pop_indent() pop_indent()
ret += mcgen(''' ret += mcgen('''
} }
visit_end_optional(m, &err); ''')
ret += mcgen('''
if (err) {
goto out;
}
''') ''')
pop_indent() pop_indent()
ret += mcgen(''' if re.search('^ *goto out\\;', ret, re.MULTILINE):
ret += mcgen('''
out:
''')
ret += mcgen('''
error_propagate(errp, err); error_propagate(errp, err);
} }
''') ''')
@ -96,9 +143,9 @@ visit_end_optional(m, &err);
def generate_visit_struct_body(field_prefix, name, members): def generate_visit_struct_body(field_prefix, name, members):
ret = mcgen(''' ret = mcgen('''
if (!error_is_set(errp)) { Error *err = NULL;
''') ''')
push_indent()
if not field_prefix: if not field_prefix:
full_name = name full_name = name
@ -107,36 +154,26 @@ if (!error_is_set(errp)) {
if len(field_prefix): if len(field_prefix):
ret += mcgen(''' ret += mcgen('''
Error **errp = &err; /* from outer scope */ visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
Error *err = NULL;
visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
''', ''',
name=name) name=name)
else: else:
ret += mcgen(''' ret += mcgen('''
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(%(name)s), &err);
''', ''',
name=name) name=name)
ret += mcgen(''' ret += mcgen('''
if (!err) { if (!err) {
if (*obj) { if (*obj) {
visit_type_%(name)s_fields(m, obj, &err); visit_type_%(name)s_fields(m, obj, errp);
error_propagate(errp, err); }
err = NULL;
}
''',
name=full_name)
pop_indent()
ret += mcgen('''
/* Always call end_struct if start_struct succeeded. */
visit_end_struct(m, &err); visit_end_struct(m, &err);
} }
error_propagate(errp, err); error_propagate(errp, err);
} ''',
''') name=full_name)
return ret return ret
def generate_visit_struct(expr): def generate_visit_struct(expr):
@ -154,9 +191,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
''', ''',
name=name) name=name)
push_indent()
ret += generate_visit_struct_body("", name, members) ret += generate_visit_struct_body("", name, members)
pop_indent()
ret += mcgen(''' ret += mcgen('''
} }
@ -168,24 +203,26 @@ def generate_visit_list(name, members):
void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp) void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp)
{ {
GenericList *i, **prev = (GenericList **)obj;
Error *err = NULL; Error *err = NULL;
GenericList *i, **prev;
if (!error_is_set(errp)) { visit_start_list(m, name, &err);
visit_start_list(m, name, &err); if (err) {
if (!err) { goto out;
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);
} }
for (prev = (GenericList **)obj;
!err && (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;
visit_end_list(m, &err);
out:
error_propagate(errp, err);
} }
''', ''',
name=name) name=name)
@ -207,10 +244,15 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
{ {
Error *err = NULL; Error *err = NULL;
if (!error_is_set(errp)) { visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err); if (err) {
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err); goto out;
switch ((*obj)->kind) { }
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
if (err) {
goto out_end;
}
switch ((*obj)->kind) {
''', ''',
name=name) name=name)
@ -225,22 +267,24 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
enum_full_value = generate_enum_full_value(disc_type, key) enum_full_value = generate_enum_full_value(disc_type, key)
ret += mcgen(''' ret += mcgen('''
case %(enum_full_value)s: case %(enum_full_value)s:
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err); visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
break; break;
''', ''',
enum_full_value = enum_full_value, enum_full_value = enum_full_value,
c_type = type_name(members[key]), c_type = type_name(members[key]),
c_name = c_fun(key)) c_name = c_fun(key))
ret += mcgen(''' ret += mcgen('''
default: default:
abort(); abort();
}
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
} }
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
out:
error_propagate(errp, err);
} }
''') ''')
@ -277,40 +321,43 @@ def generate_visit_union(expr):
del base_fields[discriminator] del base_fields[discriminator]
ret += generate_visit_struct_fields(name, "", "", base_fields) ret += generate_visit_struct_fields(name, "", "", base_fields)
if discriminator:
for key in members:
ret += generate_visit_implicit_struct(members[key])
ret += mcgen(''' ret += mcgen('''
void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp) void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **errp)
{ {
Error *err = NULL; Error *err = NULL;
if (!error_is_set(errp)) { visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); if (err) {
if (!err) { goto out;
if (*obj) { }
if (*obj) {
''', ''',
name=name) name=name)
push_indent()
push_indent()
push_indent()
if base: if base:
ret += mcgen(''' ret += mcgen('''
visit_type_%(name)s_fields(m, obj, &err); visit_type_%(name)s_fields(m, obj, &err);
if (err) {
goto out_obj;
}
''', ''',
name=name) name=name)
pop_indent()
if not discriminator: if not discriminator:
disc_key = "type" disc_key = "type"
else: else:
disc_key = discriminator disc_key = discriminator
ret += mcgen(''' ret += mcgen('''
visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err); visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
if (!err) { if (err) {
switch ((*obj)->kind) { goto out_obj;
}
switch ((*obj)->kind) {
''', ''',
disc_type = disc_type, disc_type = disc_type,
disc_key = disc_key) disc_key = disc_key)
@ -319,45 +366,30 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error **
if not discriminator: if not discriminator:
fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);' fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
else: else:
fmt = '''visit_start_implicit_struct(m, (void**) &(*obj)->%(c_name)s, sizeof(%(c_type)s), &err); fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
if (!err) {
visit_type_%(c_type)s_fields(m, &(*obj)->%(c_name)s, &err);
error_propagate(errp, err);
err = NULL;
visit_end_implicit_struct(m, &err);
}'''
enum_full_value = generate_enum_full_value(disc_type, key) enum_full_value = generate_enum_full_value(disc_type, key)
ret += mcgen(''' ret += mcgen('''
case %(enum_full_value)s: case %(enum_full_value)s:
''' + fmt + ''' ''' + fmt + '''
break; break;
''', ''',
enum_full_value = enum_full_value, enum_full_value = enum_full_value,
c_type=type_name(members[key]), c_type=type_name(members[key]),
c_name=c_fun(key)) c_name=c_fun(key))
ret += mcgen(''' ret += mcgen('''
default: default:
abort(); abort();
}
} }
out_obj:
error_propagate(errp, err); error_propagate(errp, err);
err = NULL; err = NULL;
} }
''') visit_end_struct(m, &err);
pop_indent() out:
ret += mcgen('''
/* Always call end_struct if start_struct succeeded. */
visit_end_struct(m, &err);
}
error_propagate(errp, err); error_propagate(errp, err);
} }
''')
pop_indent();
ret += mcgen('''
}
''') ''')
return ret return ret
@ -476,7 +508,7 @@ fdecl.write(mcgen('''
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
/* /*
* schema-defined QAPI visitor function * schema-defined QAPI visitor functions
* *
* Copyright IBM, Corp. 2011 * Copyright IBM, Corp. 2011
* *

View File

@ -73,13 +73,18 @@ class QAPIExprError(Exception):
class QAPISchema: class QAPISchema:
def __init__(self, fp, input_relname=None, include_hist=[], parent_info=None): def __init__(self, fp, input_relname=None, include_hist=[],
previously_included=[], parent_info=None):
""" include_hist is a stack used to detect inclusion cycles
previously_included is a global state used to avoid multiple
inclusions of the same file"""
input_fname = os.path.abspath(fp.name) input_fname = os.path.abspath(fp.name)
if input_relname is None: if input_relname is None:
input_relname = fp.name input_relname = fp.name
self.input_dir = os.path.dirname(input_fname) self.input_dir = os.path.dirname(input_fname)
self.input_file = input_relname self.input_file = input_relname
self.include_hist = include_hist + [(input_relname, input_fname)] self.include_hist = include_hist + [(input_relname, input_fname)]
previously_included.append(input_fname)
self.parent_info = parent_info self.parent_info = parent_info
self.src = fp.read() self.src = fp.read()
if self.src == '' or self.src[-1] != '\n': if self.src == '' or self.src[-1] != '\n':
@ -106,13 +111,16 @@ class QAPISchema:
for elem in self.include_hist): for elem in self.include_hist):
raise QAPIExprError(expr_info, "Inclusion loop for %s" raise QAPIExprError(expr_info, "Inclusion loop for %s"
% include) % include)
# skip multiple include of the same file
if include_path in previously_included:
continue
try: try:
fobj = open(include_path, 'r') fobj = open(include_path, 'r')
except IOError as e: except IOError as e:
raise QAPIExprError(expr_info, raise QAPIExprError(expr_info,
'%s: %s' % (e.strerror, include)) '%s: %s' % (e.strerror, include))
exprs_include = QAPISchema(fobj, include, exprs_include = QAPISchema(fobj, include, self.include_hist,
self.include_hist, expr_info) previously_included, expr_info)
self.exprs.extend(exprs_include.exprs) self.exprs.extend(exprs_include.exprs)
else: else:
expr_elem = {'expr': expr, expr_elem = {'expr': expr,

View File

@ -193,7 +193,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
flat-union-string-discriminator.json \ flat-union-string-discriminator.json \
include-simple.json include-relpath.json include-format-err.json \ include-simple.json include-relpath.json include-format-err.json \
include-non-file.json include-no-file.json include-before-err.json \ include-non-file.json include-no-file.json include-before-err.json \
include-nested-err.json include-self-cycle.json include-cycle.json) include-nested-err.json include-self-cycle.json include-cycle.json \
include-repetition.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h

View File

@ -0,0 +1,2 @@
{ 'include': 'comments.json' }
{ 'include': 'comments.json' }

View File

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1,3 @@
{ 'include': 'comments.json' }
{ 'include': 'include-repetition-sub.json' }
{ 'include': 'comments.json' }

View File

@ -0,0 +1,3 @@
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
[]

View File

@ -72,14 +72,30 @@ typedef struct TestStruct
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp) const char *name, Error **errp)
{ {
Error *err = NULL;
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
errp); &err);
if (err) {
goto out;
}
visit_type_int(v, &(*obj)->integer, "integer", errp); visit_type_int(v, &(*obj)->integer, "integer", &err);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp); if (err) {
visit_type_str(v, &(*obj)->string, "string", errp); goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
visit_end_struct(v, errp); out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static void test_validate_struct(TestInputVisitorData *data, static void test_validate_struct(TestInputVisitorData *data,

View File

@ -199,16 +199,24 @@ static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
&err); &err);
if (!err) { if (err) {
visit_type_int(v, &(*obj)->integer, "integer", &err); goto out;
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
visit_type_str(v, &(*obj)->string, "string", &err);
/* Always call end_struct if start_struct succeeded. */
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
} }
visit_type_int(v, &(*obj)->integer, "integer", &err);
if (err) {
goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err); error_propagate(errp, err);
} }

View File

@ -176,14 +176,30 @@ typedef struct TestStruct
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp) const char *name, Error **errp)
{ {
Error *err = NULL;
visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
errp); &err);
if (err) {
goto out;
}
visit_type_int(v, &(*obj)->integer, "integer", errp); visit_type_int(v, &(*obj)->integer, "integer", &err);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp); if (err) {
visit_type_str(v, &(*obj)->string, "string", errp); goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
visit_end_struct(v, errp); out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static void test_visitor_out_struct(TestOutputVisitorData *data, static void test_visitor_out_struct(TestOutputVisitorData *data,

View File

@ -195,13 +195,29 @@ typedef struct TestStruct
static void visit_type_TestStruct(Visitor *v, TestStruct **obj, static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
const char *name, Error **errp) const char *name, Error **errp)
{ {
visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), errp); Error *err = NULL;
visit_type_int(v, &(*obj)->integer, "integer", errp); visit_start_struct(v, (void **)obj, NULL, name, sizeof(TestStruct), &err);
visit_type_bool(v, &(*obj)->boolean, "boolean", errp); if (err) {
visit_type_str(v, &(*obj)->string, "string", errp); goto out;
}
visit_end_struct(v, errp); visit_type_int(v, &(*obj)->integer, "integer", &err);
if (err) {
goto out_end;
}
visit_type_bool(v, &(*obj)->boolean, "boolean", &err);
if (err) {
goto out_end;
}
visit_type_str(v, &(*obj)->string, "string", &err);
out_end:
error_propagate(errp, err);
err = NULL;
visit_end_struct(v, &err);
out:
error_propagate(errp, err);
} }
static TestStruct *struct_create(void) static TestStruct *struct_create(void)