diff options
Diffstat (limited to 'qapi')
-rw-r--r-- | qapi/opts-visitor.c | 70 | ||||
-rw-r--r-- | qapi/qapi-dealloc-visitor.c | 43 | ||||
-rw-r--r-- | qapi/qapi-visit-core.c | 111 | ||||
-rw-r--r-- | qapi/qmp-dispatch.c | 18 | ||||
-rw-r--r-- | qapi/qmp-input-visitor.c | 187 | ||||
-rw-r--r-- | qapi/qmp-output-visitor.c | 63 | ||||
-rw-r--r-- | qapi/qmp-registry.c | 1 | ||||
-rw-r--r-- | qapi/string-input-visitor.c | 49 | ||||
-rw-r--r-- | qapi/string-output-visitor.c | 43 |
9 files changed, 330 insertions, 255 deletions
diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 602f2609cc..4cf1cf885b 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -23,9 +23,8 @@ enum ListMode { LM_NONE, /* not traversing a list of repeated options */ - LM_STARTED, /* opts_start_list() succeeded */ - LM_IN_PROGRESS, /* opts_next_list() has been called. + LM_IN_PROGRESS, /* opts_next_list() ready to be called. * * Generating the next list link will consume the most * recently parsed QemuOpt instance of the repeated @@ -133,7 +132,7 @@ opts_start_struct(Visitor *v, const char *name, void **obj, const QemuOpt *opt; if (obj) { - *obj = g_malloc0(size > 0 ? size : 1); + *obj = g_malloc0(size); } if (ov->depth++ > 0) { return; @@ -159,13 +158,13 @@ opts_start_struct(Visitor *v, const char *name, void **obj, static void -opts_end_struct(Visitor *v, Error **errp) +opts_check_struct(Visitor *v, Error **errp) { OptsVisitor *ov = to_ov(v); GHashTableIter iter; GQueue *any; - if (--ov->depth > 0) { + if (ov->depth > 0) { return; } @@ -177,6 +176,18 @@ opts_end_struct(Visitor *v, Error **errp) first = g_queue_peek_head(any); error_setg(errp, QERR_INVALID_PARAMETER, first->name); } +} + + +static void +opts_end_struct(Visitor *v) +{ + OptsVisitor *ov = to_ov(v); + + if (--ov->depth > 0) { + return; + } + g_hash_table_destroy(ov->unprocessed_opts); ov->unprocessed_opts = NULL; if (ov->fake_id_opt) { @@ -202,35 +213,33 @@ lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp) static void -opts_start_list(Visitor *v, const char *name, Error **errp) +opts_start_list(Visitor *v, const char *name, GenericList **list, size_t size, + Error **errp) { OptsVisitor *ov = to_ov(v); /* we can't traverse a list in a list */ assert(ov->list_mode == LM_NONE); + /* we don't support visits without a list */ + assert(list); ov->repeated_opts = lookup_distinct(ov, name, errp); - if (ov->repeated_opts != NULL) { - ov->list_mode = LM_STARTED; + if (ov->repeated_opts) { + ov->list_mode = LM_IN_PROGRESS; + *list = g_malloc0(size); + } else { + *list = NULL; } } static GenericList * -opts_next_list(Visitor *v, GenericList **list, size_t size) +opts_next_list(Visitor *v, GenericList *tail, size_t size) { OptsVisitor *ov = to_ov(v); - GenericList **link; switch (ov->list_mode) { - case LM_STARTED: - ov->list_mode = LM_IN_PROGRESS; - link = list; - break; - case LM_SIGNED_INTERVAL: case LM_UNSIGNED_INTERVAL: - link = &(*list)->next; - if (ov->list_mode == LM_SIGNED_INTERVAL) { if (ov->range_next.s < ov->range_limit.s) { ++ov->range_next.s; @@ -251,7 +260,6 @@ opts_next_list(Visitor *v, GenericList **list, size_t size) g_hash_table_remove(ov->unprocessed_opts, opt->name); return NULL; } - link = &(*list)->next; break; } @@ -259,8 +267,8 @@ opts_next_list(Visitor *v, GenericList **list, size_t size) abort(); } - *link = g_malloc0(size); - return *link; + tail->next = g_malloc0(size); + return tail->next; } @@ -269,8 +277,7 @@ opts_end_list(Visitor *v) { OptsVisitor *ov = to_ov(v); - assert(ov->list_mode == LM_STARTED || - ov->list_mode == LM_IN_PROGRESS || + assert(ov->list_mode == LM_IN_PROGRESS || ov->list_mode == LM_SIGNED_INTERVAL || ov->list_mode == LM_UNSIGNED_INTERVAL); ov->repeated_opts = NULL; @@ -314,9 +321,15 @@ opts_type_str(Visitor *v, const char *name, char **obj, Error **errp) opt = lookup_scalar(ov, name, errp); if (!opt) { + *obj = NULL; return; } *obj = g_strdup(opt->str ? opt->str : ""); + /* Note that we consume a string even if this is called as part of + * an enum visit that later fails because the string is not a + * valid enum value; this is harmless because tracking what gets + * consumed only matters to visit_end_struct() as the final error + * check if there were no other failures during the visit. */ processed(ov, name); } @@ -507,23 +520,16 @@ opts_visitor_new(const QemuOpts *opts) ov = g_malloc0(sizeof *ov); + ov->visitor.type = VISITOR_INPUT; + ov->visitor.start_struct = &opts_start_struct; + ov->visitor.check_struct = &opts_check_struct; ov->visitor.end_struct = &opts_end_struct; ov->visitor.start_list = &opts_start_list; ov->visitor.next_list = &opts_next_list; ov->visitor.end_list = &opts_end_list; - /* input_type_enum() covers both "normal" enums and union discriminators. - * The union discriminator field is always generated as "type"; it should - * match the "type" QemuOpt child of any QemuOpts. - * - * input_type_enum() will remove the looked-up key from the - * "unprocessed_opts" hash even if the lookup fails, because the removal is - * done earlier in opts_type_str(). This should be harmless. - */ - ov->visitor.type_enum = &input_type_enum; - ov->visitor.type_int64 = &opts_type_int64; ov->visitor.type_uint64 = &opts_type_uint64; ov->visitor.type_size = &opts_type_size; diff --git a/qapi/qapi-dealloc-visitor.c b/qapi/qapi-dealloc-visitor.c index 69221794ec..cd68b55a1a 100644 --- a/qapi/qapi-dealloc-visitor.c +++ b/qapi/qapi-dealloc-visitor.c @@ -22,7 +22,6 @@ typedef struct StackEntry { void *value; - bool is_list_head; QTAILQ_ENTRY(StackEntry) node; } StackEntry; @@ -43,10 +42,6 @@ static void qapi_dealloc_push(QapiDeallocVisitor *qov, void *value) e->value = value; - /* see if we're just pushing a list head tracker */ - if (value == NULL) { - e->is_list_head = true; - } QTAILQ_INSERT_HEAD(&qov->stack, e, node); } @@ -67,7 +62,7 @@ static void qapi_dealloc_start_struct(Visitor *v, const char *name, void **obj, qapi_dealloc_push(qov, obj); } -static void qapi_dealloc_end_struct(Visitor *v, Error **errp) +static void qapi_dealloc_end_struct(Visitor *v) { QapiDeallocVisitor *qov = to_qov(v); void **obj = qapi_dealloc_pop(qov); @@ -93,38 +88,22 @@ static void qapi_dealloc_end_alternate(Visitor *v) } } -static void qapi_dealloc_start_list(Visitor *v, const char *name, Error **errp) +static void qapi_dealloc_start_list(Visitor *v, const char *name, + GenericList **list, size_t size, + Error **errp) { - QapiDeallocVisitor *qov = to_qov(v); - qapi_dealloc_push(qov, NULL); } -static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList **listp, +static GenericList *qapi_dealloc_next_list(Visitor *v, GenericList *tail, size_t size) { - GenericList *list = *listp; - QapiDeallocVisitor *qov = to_qov(v); - StackEntry *e = QTAILQ_FIRST(&qov->stack); - - if (e && e->is_list_head) { - e->is_list_head = false; - return list; - } - - if (list) { - list = list->next; - g_free(*listp); - return list; - } - - return NULL; + GenericList *next = tail->next; + g_free(tail); + return next; } static void qapi_dealloc_end_list(Visitor *v) { - QapiDeallocVisitor *qov = to_qov(v); - void *obj = qapi_dealloc_pop(qov); - assert(obj == NULL); /* should've been list head tracker with no payload */ } static void qapi_dealloc_type_str(Visitor *v, const char *name, char **obj, @@ -163,8 +142,7 @@ static void qapi_dealloc_type_anything(Visitor *v, const char *name, } } -static void qapi_dealloc_type_enum(Visitor *v, const char *name, int *obj, - const char * const strings[], Error **errp) +static void qapi_dealloc_type_null(Visitor *v, const char *name, Error **errp) { } @@ -184,6 +162,7 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void) v = g_malloc0(sizeof(*v)); + v->visitor.type = VISITOR_DEALLOC; v->visitor.start_struct = qapi_dealloc_start_struct; v->visitor.end_struct = qapi_dealloc_end_struct; v->visitor.start_alternate = qapi_dealloc_start_alternate; @@ -191,13 +170,13 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void) v->visitor.start_list = qapi_dealloc_start_list; v->visitor.next_list = qapi_dealloc_next_list; v->visitor.end_list = qapi_dealloc_end_list; - v->visitor.type_enum = qapi_dealloc_type_enum; v->visitor.type_int64 = qapi_dealloc_type_int64; v->visitor.type_uint64 = qapi_dealloc_type_uint64; v->visitor.type_bool = qapi_dealloc_type_bool; v->visitor.type_str = qapi_dealloc_type_str; v->visitor.type_number = qapi_dealloc_type_number; v->visitor.type_any = qapi_dealloc_type_anything; + v->visitor.type_null = qapi_dealloc_type_null; QTAILQ_INIT(&v->stack); diff --git a/qapi/qapi-visit-core.c b/qapi/qapi-visit-core.c index fa680c9991..eada4676a2 100644 --- a/qapi/qapi-visit-core.c +++ b/qapi/qapi-visit-core.c @@ -23,23 +23,48 @@ void visit_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { - v->start_struct(v, name, obj, size, errp); + Error *err = NULL; + + if (obj) { + assert(size); + assert(v->type != VISITOR_OUTPUT || *obj); + } + v->start_struct(v, name, obj, size, &err); + if (obj && v->type == VISITOR_INPUT) { + assert(!err != !*obj); + } + error_propagate(errp, err); } -void visit_end_struct(Visitor *v, Error **errp) +void visit_check_struct(Visitor *v, Error **errp) { - v->end_struct(v, errp); + if (v->check_struct) { + v->check_struct(v, errp); + } } -void visit_start_list(Visitor *v, const char *name, Error **errp) +void visit_end_struct(Visitor *v) { - v->start_list(v, name, errp); + v->end_struct(v); } -GenericList *visit_next_list(Visitor *v, GenericList **list, size_t size) +void visit_start_list(Visitor *v, const char *name, GenericList **list, + size_t size, Error **errp) { - assert(list && size >= sizeof(GenericList)); - return v->next_list(v, list, size); + Error *err = NULL; + + assert(!list || size >= sizeof(GenericList)); + v->start_list(v, name, list, size, &err); + if (list && v->type == VISITOR_INPUT) { + assert(!(err && *list)); + } + error_propagate(errp, err); +} + +GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size) +{ + assert(tail && size >= sizeof(GenericList)); + return v->next_list(v, tail, size); } void visit_end_list(Visitor *v) @@ -51,10 +76,17 @@ void visit_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, bool promote_int, Error **errp) { + Error *err = NULL; + assert(obj && size >= sizeof(GenericAlternate)); + assert(v->type != VISITOR_OUTPUT || *obj); if (v->start_alternate) { - v->start_alternate(v, name, obj, size, promote_int, errp); + v->start_alternate(v, name, obj, size, promote_int, &err); } + if (v->type == VISITOR_INPUT) { + assert(v->start_alternate && !err != !*obj); + } + error_propagate(errp, err); } void visit_end_alternate(Visitor *v) @@ -72,14 +104,14 @@ bool visit_optional(Visitor *v, const char *name, bool *present) return *present; } -void visit_type_enum(Visitor *v, const char *name, int *obj, - const char *const strings[], Error **errp) +bool visit_is_input(Visitor *v) { - v->type_enum(v, name, obj, strings, errp); + return v->type == VISITOR_INPUT; } void visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp) { + assert(obj); v->type_int64(v, name, obj, errp); } @@ -127,6 +159,7 @@ void visit_type_uint32(Visitor *v, const char *name, uint32_t *obj, void visit_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { + assert(obj); v->type_uint64(v, name, obj, errp); } @@ -174,12 +207,14 @@ void visit_type_int32(Visitor *v, const char *name, int32_t *obj, void visit_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { + assert(obj); v->type_int64(v, name, obj, errp); } void visit_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { + assert(obj); if (v->type_size) { v->type_size(v, name, obj, errp); } else { @@ -189,33 +224,58 @@ void visit_type_size(Visitor *v, const char *name, uint64_t *obj, void visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { + assert(obj); v->type_bool(v, name, obj, errp); } void visit_type_str(Visitor *v, const char *name, char **obj, Error **errp) { - v->type_str(v, name, obj, errp); + Error *err = NULL; + + assert(obj); + /* TODO: Fix callers to not pass NULL when they mean "", so that we + * can enable: + assert(v->type != VISITOR_OUTPUT || *obj); + */ + v->type_str(v, name, obj, &err); + if (v->type == VISITOR_INPUT) { + assert(!err != !*obj); + } + error_propagate(errp, err); } void visit_type_number(Visitor *v, const char *name, double *obj, Error **errp) { + assert(obj); v->type_number(v, name, obj, errp); } void visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp) { - v->type_any(v, name, obj, errp); + Error *err = NULL; + + assert(obj); + assert(v->type != VISITOR_OUTPUT || *obj); + v->type_any(v, name, obj, &err); + if (v->type == VISITOR_INPUT) { + assert(!err != !*obj); + } + error_propagate(errp, err); +} + +void visit_type_null(Visitor *v, const char *name, Error **errp) +{ + v->type_null(v, name, errp); } -void output_type_enum(Visitor *v, const char *name, int *obj, - const char *const strings[], Error **errp) +static void output_type_enum(Visitor *v, const char *name, int *obj, + const char *const strings[], Error **errp) { int i = 0; int value = *obj; char *enum_str; - assert(strings); while (strings[i++] != NULL); if (value < 0 || value >= i - 1) { error_setg(errp, QERR_INVALID_PARAMETER, name ? name : "null"); @@ -226,15 +286,13 @@ void output_type_enum(Visitor *v, const char *name, int *obj, visit_type_str(v, name, &enum_str, errp); } -void input_type_enum(Visitor *v, const char *name, int *obj, - const char *const strings[], Error **errp) +static void input_type_enum(Visitor *v, const char *name, int *obj, + const char *const strings[], Error **errp) { Error *local_err = NULL; int64_t value = 0; char *enum_str; - assert(strings); - visit_type_str(v, name, &enum_str, &local_err); if (local_err) { error_propagate(errp, local_err); @@ -257,3 +315,14 @@ void input_type_enum(Visitor *v, const char *name, int *obj, g_free(enum_str); *obj = value; } + +void visit_type_enum(Visitor *v, const char *name, int *obj, + const char *const strings[], Error **errp) +{ + assert(obj && strings); + if (v->type == VISITOR_INPUT) { + input_type_enum(v, name, obj, strings, errp); + } else if (v->type == VISITOR_OUTPUT) { + output_type_enum(v, name, obj, strings, errp); + } +} diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c index 510a1aead8..08faf853ac 100644 --- a/qapi/qmp-dispatch.c +++ b/qapi/qmp-dispatch.c @@ -94,17 +94,13 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp) QINCREF(args); } - switch (cmd->type) { - case QCT_NORMAL: - cmd->fn(args, &ret, &local_err); - if (local_err) { - error_propagate(errp, local_err); - } else if (cmd->options & QCO_NO_SUCCESS_RESP) { - g_assert(!ret); - } else if (!ret) { - ret = QOBJECT(qdict_new()); - } - break; + cmd->fn(args, &ret, &local_err); + if (local_err) { + error_propagate(errp, local_err); + } else if (cmd->options & QCO_NO_SUCCESS_RESP) { + g_assert(!ret); + } else if (!ret) { + ret = QOBJECT(qdict_new()); } QDECREF(args); diff --git a/qapi/qmp-input-visitor.c b/qapi/qmp-input-visitor.c index 7cd1b777a0..aea90a1378 100644 --- a/qapi/qmp-input-visitor.c +++ b/qapi/qmp-input-visitor.c @@ -25,16 +25,25 @@ typedef struct StackObject { - QObject *obj; - const QListEntry *entry; - GHashTable *h; + QObject *obj; /* Object being visited */ + + GHashTable *h; /* If obj is dict: unvisited keys */ + const QListEntry *entry; /* If obj is list: unvisited tail */ } StackObject; struct QmpInputVisitor { Visitor visitor; + + /* Root of visit at visitor creation. */ + QObject *root; + + /* Stack of objects being visited (all entries will be either + * QDict or QList). */ StackObject stack[QIV_STACK_SIZE]; int nb_stack; + + /* True to reject parse in visit_end_struct() if unvisited keys remain. */ bool strict; }; @@ -47,20 +56,37 @@ static QObject *qmp_input_get_object(QmpInputVisitor *qiv, const char *name, bool consume) { - QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj; + StackObject *tos; + QObject *qobj; + QObject *ret; - if (qobj) { - if (name && qobject_type(qobj) == QTYPE_QDICT) { - if (qiv->stack[qiv->nb_stack - 1].h && consume) { - g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name); - } - return qdict_get(qobject_to_qdict(qobj), name); - } else if (qiv->stack[qiv->nb_stack - 1].entry) { - return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry); + if (!qiv->nb_stack) { + /* Starting at root, name is ignored. */ + return qiv->root; + } + + /* We are in a container; find the next element. */ + tos = &qiv->stack[qiv->nb_stack - 1]; + qobj = tos->obj; + assert(qobj); + + if (qobject_type(qobj) == QTYPE_QDICT) { + assert(name); + ret = qdict_get(qobject_to_qdict(qobj), name); + if (tos->h && consume && ret) { + bool removed = g_hash_table_remove(tos->h, name); + assert(removed); + } + } else { + assert(qobject_type(qobj) == QTYPE_QLIST); + assert(!name); + ret = qlist_entry_obj(tos->entry); + if (consume) { + tos->entry = qlist_next(tos->entry); } } - return qobj; + return ret; } static void qdict_add_key(const char *key, QObject *obj, void *opaque) @@ -69,35 +95,44 @@ static void qdict_add_key(const char *key, QObject *obj, void *opaque) g_hash_table_insert(h, (gpointer) key, NULL); } -static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp) +static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj, + Error **errp) { GHashTable *h; + StackObject *tos = &qiv->stack[qiv->nb_stack]; + assert(obj); if (qiv->nb_stack >= QIV_STACK_SIZE) { error_setg(errp, "An internal buffer overran"); - return; + return NULL; } - qiv->stack[qiv->nb_stack].obj = obj; - qiv->stack[qiv->nb_stack].entry = NULL; - qiv->stack[qiv->nb_stack].h = NULL; + tos->obj = obj; + assert(!tos->h); + assert(!tos->entry); if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) { h = g_hash_table_new(g_str_hash, g_str_equal); qdict_iter(qobject_to_qdict(obj), qdict_add_key, h); - qiv->stack[qiv->nb_stack].h = h; + tos->h = h; + } else if (qobject_type(obj) == QTYPE_QLIST) { + tos->entry = qlist_first(qobject_to_qlist(obj)); } qiv->nb_stack++; + return tos->entry; } -static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp) +static void qmp_input_check_struct(Visitor *v, Error **errp) { + QmpInputVisitor *qiv = to_qiv(v); + StackObject *tos = &qiv->stack[qiv->nb_stack - 1]; + assert(qiv->nb_stack > 0); if (qiv->strict) { - GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h; + GHashTable *const top_ht = tos->h; if (top_ht) { GHashTableIter iter; const char *key; @@ -106,8 +141,23 @@ static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp) if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) { error_setg(errp, QERR_QMP_EXTRA_MEMBER, key); } + } + } +} + +static void qmp_input_pop(Visitor *v) +{ + QmpInputVisitor *qiv = to_qiv(v); + StackObject *tos = &qiv->stack[qiv->nb_stack - 1]; + + assert(qiv->nb_stack > 0); + + if (qiv->strict) { + GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h; + if (top_ht) { g_hash_table_unref(top_ht); } + tos->h = NULL; } qiv->nb_stack--; @@ -120,6 +170,9 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, QObject *qobj = qmp_input_get_object(qiv, name, true); Error *err = NULL; + if (obj) { + *obj = NULL; + } if (!qobj || qobject_type(qobj) != QTYPE_QDICT) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "QDict"); @@ -137,63 +190,46 @@ static void qmp_input_start_struct(Visitor *v, const char *name, void **obj, } } -static void qmp_input_end_struct(Visitor *v, Error **errp) -{ - QmpInputVisitor *qiv = to_qiv(v); - - qmp_input_pop(qiv, errp); -} -static void qmp_input_start_list(Visitor *v, const char *name, Error **errp) +static void qmp_input_start_list(Visitor *v, const char *name, + GenericList **list, size_t size, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); QObject *qobj = qmp_input_get_object(qiv, name, true); + const QListEntry *entry; if (!qobj || qobject_type(qobj) != QTYPE_QLIST) { + if (list) { + *list = NULL; + } error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "list"); return; } - qmp_input_push(qiv, qobj, errp); + entry = qmp_input_push(qiv, qobj, errp); + if (list) { + if (entry) { + *list = g_malloc0(size); + } else { + *list = NULL; + } + } } -static GenericList *qmp_input_next_list(Visitor *v, GenericList **list, +static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail, size_t size) { QmpInputVisitor *qiv = to_qiv(v); - GenericList *entry; StackObject *so = &qiv->stack[qiv->nb_stack - 1]; - bool first; - if (so->entry == NULL) { - so->entry = qlist_first(qobject_to_qlist(so->obj)); - first = true; - } else { - so->entry = qlist_next(so->entry); - first = false; - } - - if (so->entry == NULL) { + if (!so->entry) { return NULL; } - - entry = g_malloc0(size); - if (first) { - *list = entry; - } else { - (*list)->next = entry; - } - - return entry; + tail->next = g_malloc0(size); + return tail->next; } -static void qmp_input_end_list(Visitor *v) -{ - QmpInputVisitor *qiv = to_qiv(v); - - qmp_input_pop(qiv, &error_abort); -} static void qmp_input_start_alternate(Visitor *v, const char *name, GenericAlternate **obj, size_t size, @@ -267,6 +303,7 @@ static void qmp_input_type_str(Visitor *v, const char *name, char **obj, QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true)); if (!qstr) { + *obj = NULL; error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string"); return; @@ -309,11 +346,22 @@ static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj, *obj = qobj; } -static void qmp_input_optional(Visitor *v, const char *name, bool *present) +static void qmp_input_type_null(Visitor *v, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); QObject *qobj = qmp_input_get_object(qiv, name, true); + if (qobject_type(qobj) != QTYPE_QNULL) { + error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", + "null"); + } +} + +static void qmp_input_optional(Visitor *v, const char *name, bool *present) +{ + QmpInputVisitor *qiv = to_qiv(v); + QObject *qobj = qmp_input_get_object(qiv, name, false); + if (!qobj) { *present = false; return; @@ -329,43 +377,36 @@ Visitor *qmp_input_get_visitor(QmpInputVisitor *v) void qmp_input_visitor_cleanup(QmpInputVisitor *v) { - qobject_decref(v->stack[0].obj); + qobject_decref(v->root); g_free(v); } -QmpInputVisitor *qmp_input_visitor_new(QObject *obj) +QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict) { QmpInputVisitor *v; v = g_malloc0(sizeof(*v)); + v->visitor.type = VISITOR_INPUT; v->visitor.start_struct = qmp_input_start_struct; - v->visitor.end_struct = qmp_input_end_struct; + v->visitor.check_struct = qmp_input_check_struct; + v->visitor.end_struct = qmp_input_pop; v->visitor.start_list = qmp_input_start_list; v->visitor.next_list = qmp_input_next_list; - v->visitor.end_list = qmp_input_end_list; + v->visitor.end_list = qmp_input_pop; v->visitor.start_alternate = qmp_input_start_alternate; - v->visitor.type_enum = input_type_enum; v->visitor.type_int64 = qmp_input_type_int64; v->visitor.type_uint64 = qmp_input_type_uint64; v->visitor.type_bool = qmp_input_type_bool; v->visitor.type_str = qmp_input_type_str; v->visitor.type_number = qmp_input_type_number; v->visitor.type_any = qmp_input_type_any; + v->visitor.type_null = qmp_input_type_null; v->visitor.optional = qmp_input_optional; + v->strict = strict; - qmp_input_push(v, obj, NULL); + v->root = obj; qobject_incref(obj); return v; } - -QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj) -{ - QmpInputVisitor *v; - - v = qmp_input_visitor_new(obj); - v->strict = true; - - return v; -} diff --git a/qapi/qmp-output-visitor.c b/qapi/qmp-output-visitor.c index d44c676317..4d3cf78333 100644 --- a/qapi/qmp-output-visitor.c +++ b/qapi/qmp-output-visitor.c @@ -22,7 +22,6 @@ typedef struct QStackEntry { QObject *value; - bool is_list_head; QTAILQ_ENTRY(QStackEntry) node; } QStackEntry; @@ -52,9 +51,6 @@ static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value) assert(qov->root); assert(value); e->value = value; - if (qobject_type(e->value) == QTYPE_QLIST) { - e->is_list_head = true; - } QTAILQ_INSERT_HEAD(&qov->stack, e, node); } @@ -82,9 +78,8 @@ static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name, QObject *cur = e ? e->value : NULL; if (!cur) { - /* FIXME we should require the user to reset the visitor, rather - * than throwing away the previous root */ - qobject_decref(qov->root); + /* Don't allow reuse of visitor on more than one root */ + assert(!qov->root); qov->root = value; } else { switch (qobject_type(cur)) { @@ -93,6 +88,7 @@ static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name, qdict_put_obj(qobject_to_qdict(cur), name, value); break; case QTYPE_QLIST: + assert(!name); qlist_append_obj(qobject_to_qlist(cur), value); break; default: @@ -111,13 +107,16 @@ static void qmp_output_start_struct(Visitor *v, const char *name, void **obj, qmp_output_push(qov, dict); } -static void qmp_output_end_struct(Visitor *v, Error **errp) +static void qmp_output_end_struct(Visitor *v) { QmpOutputVisitor *qov = to_qov(v); - qmp_output_pop(qov); + QObject *value = qmp_output_pop(qov); + assert(qobject_type(value) == QTYPE_QDICT); } -static void qmp_output_start_list(Visitor *v, const char *name, Error **errp) +static void qmp_output_start_list(Visitor *v, const char *name, + GenericList **listp, size_t size, + Error **errp) { QmpOutputVisitor *qov = to_qov(v); QList *list = qlist_new(); @@ -126,26 +125,17 @@ static void qmp_output_start_list(Visitor *v, const char *name, Error **errp) qmp_output_push(qov, list); } -static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp, +static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail, size_t size) { - GenericList *list = *listp; - QmpOutputVisitor *qov = to_qov(v); - QStackEntry *e = QTAILQ_FIRST(&qov->stack); - - assert(e); - if (e->is_list_head) { - e->is_list_head = false; - return list; - } - - return list ? list->next : NULL; + return tail->next; } static void qmp_output_end_list(Visitor *v) { QmpOutputVisitor *qov = to_qov(v); - qmp_output_pop(qov); + QObject *value = qmp_output_pop(qov); + assert(qobject_type(value) == QTYPE_QLIST); } static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj, @@ -196,18 +186,22 @@ static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj, qmp_output_add_obj(qov, name, *obj); } -/* Finish building, and return the root object. Will not be NULL. */ +static void qmp_output_type_null(Visitor *v, const char *name, Error **errp) +{ + QmpOutputVisitor *qov = to_qov(v); + qmp_output_add_obj(qov, name, qnull()); +} + +/* Finish building, and return the root object. + * The root object is never null. The caller becomes the object's + * owner, and should use qobject_decref() when done with it. */ QObject *qmp_output_get_qobject(QmpOutputVisitor *qov) { - /* FIXME: we should require that a visit occurred, and that it is - * complete (no starts without a matching end) */ - QObject *obj = qov->root; - if (obj) { - qobject_incref(obj); - } else { - obj = qnull(); - } - return obj; + /* A visit must have occurred, with each start paired with end. */ + assert(qov->root && QTAILQ_EMPTY(&qov->stack)); + + qobject_incref(qov->root); + return qov->root; } Visitor *qmp_output_get_visitor(QmpOutputVisitor *v) @@ -234,18 +228,19 @@ QmpOutputVisitor *qmp_output_visitor_new(void) v = g_malloc0(sizeof(*v)); + v->visitor.type = VISITOR_OUTPUT; v->visitor.start_struct = qmp_output_start_struct; v->visitor.end_struct = qmp_output_end_struct; v->visitor.start_list = qmp_output_start_list; v->visitor.next_list = qmp_output_next_list; v->visitor.end_list = qmp_output_end_list; - v->visitor.type_enum = output_type_enum; v->visitor.type_int64 = qmp_output_type_int64; v->visitor.type_uint64 = qmp_output_type_uint64; v->visitor.type_bool = qmp_output_type_bool; v->visitor.type_str = qmp_output_type_str; v->visitor.type_number = qmp_output_type_number; v->visitor.type_any = qmp_output_type_any; + v->visitor.type_null = qmp_output_type_null; QTAILQ_INIT(&v->stack); diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c index 4ebfbccd46..4332a6818d 100644 --- a/qapi/qmp-registry.c +++ b/qapi/qmp-registry.c @@ -25,7 +25,6 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn, QmpCommand *cmd = g_malloc0(sizeof(*cmd)); cmd->name = name; - cmd->type = QCT_NORMAL; cmd->fn = fn; cmd->enabled = true; cmd->options = options; diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c index 5ea2d77b5a..30b58791c9 100644 --- a/qapi/string-input-visitor.c +++ b/qapi/string-input-visitor.c @@ -25,8 +25,6 @@ struct StringInputVisitor { Visitor visitor; - bool head; - GList *ranges; GList *cur_range; int64_t cur; @@ -44,7 +42,7 @@ static void free_range(void *range, void *dummy) g_free(range); } -static void parse_str(StringInputVisitor *siv, Error **errp) +static int parse_str(StringInputVisitor *siv, const char *name, Error **errp) { char *str = (char *) siv->string; long long start, end; @@ -52,7 +50,7 @@ static void parse_str(StringInputVisitor *siv, Error **errp) char *endptr; if (siv->ranges) { - return; + return 0; } do { @@ -117,19 +115,29 @@ static void parse_str(StringInputVisitor *siv, Error **errp) } } while (str); - return; + return 0; error: g_list_foreach(siv->ranges, free_range, NULL); g_list_free(siv->ranges); siv->ranges = NULL; + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null", + "an int64 value or range"); + return -1; } static void -start_list(Visitor *v, const char *name, Error **errp) +start_list(Visitor *v, const char *name, GenericList **list, size_t size, + Error **errp) { StringInputVisitor *siv = to_siv(v); - parse_str(siv, errp); + /* We don't support visits without a list */ + assert(list); + + if (parse_str(siv, name, errp) < 0) { + *list = NULL; + return; + } siv->cur_range = g_list_first(siv->ranges); if (siv->cur_range) { @@ -137,13 +145,15 @@ start_list(Visitor *v, const char *name, Error **errp) if (r) { siv->cur = r->begin; } + *list = g_malloc0(size); + } else { + *list = NULL; } } -static GenericList *next_list(Visitor *v, GenericList **list, size_t size) +static GenericList *next_list(Visitor *v, GenericList *tail, size_t size) { StringInputVisitor *siv = to_siv(v); - GenericList **link; Range *r; if (!siv->ranges || !siv->cur_range) { @@ -167,21 +177,12 @@ static GenericList *next_list(Visitor *v, GenericList **list, size_t size) siv->cur = r->begin; } - if (siv->head) { - link = list; - siv->head = false; - } else { - link = &(*list)->next; - } - - *link = g_malloc0(size); - return *link; + tail->next = g_malloc0(size); + return tail->next; } static void end_list(Visitor *v) { - StringInputVisitor *siv = to_siv(v); - siv->head = true; } static void parse_type_int64(Visitor *v, const char *name, int64_t *obj, @@ -195,7 +196,9 @@ static void parse_type_int64(Visitor *v, const char *name, int64_t *obj, return; } - parse_str(siv, errp); + if (parse_str(siv, name, errp) < 0) { + return; + } if (!siv->ranges) { goto error; @@ -293,6 +296,7 @@ static void parse_type_str(Visitor *v, const char *name, char **obj, if (siv->string) { *obj = g_strdup(siv->string); } else { + *obj = NULL; error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string"); } @@ -348,7 +352,7 @@ StringInputVisitor *string_input_visitor_new(const char *str) v = g_malloc0(sizeof(*v)); - v->visitor.type_enum = input_type_enum; + v->visitor.type = VISITOR_INPUT; v->visitor.type_int64 = parse_type_int64; v->visitor.type_uint64 = parse_type_uint64; v->visitor.type_size = parse_type_size; @@ -361,6 +365,5 @@ StringInputVisitor *string_input_visitor_new(const char *str) v->visitor.optional = parse_optional; v->string = str; - v->head = true; return v; } diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index c2e5c5b92b..d01319628b 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -20,7 +20,7 @@ enum ListMode { LM_NONE, /* not traversing a list of repeated options */ - LM_STARTED, /* start_list() succeeded */ + LM_STARTED, /* next_list() ready to be called */ LM_IN_PROGRESS, /* next_list() has been called. * @@ -48,7 +48,7 @@ enum ListMode { LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */ - LM_END + LM_END, /* next_list() called, about to see last element. */ }; typedef enum ListMode ListMode; @@ -58,7 +58,6 @@ struct StringOutputVisitor Visitor visitor; bool human; GString *string; - bool head; ListMode list_mode; union { int64_t s; @@ -266,39 +265,29 @@ static void print_type_number(Visitor *v, const char *name, double *obj, } static void -start_list(Visitor *v, const char *name, Error **errp) +start_list(Visitor *v, const char *name, GenericList **list, size_t size, + Error **errp) { StringOutputVisitor *sov = to_sov(v); /* we can't traverse a list in a list */ assert(sov->list_mode == LM_NONE); - sov->list_mode = LM_STARTED; - sov->head = true; + /* We don't support visits without a list */ + assert(list); + /* List handling is only needed if there are at least two elements */ + if (*list && (*list)->next) { + sov->list_mode = LM_STARTED; + } } -static GenericList *next_list(Visitor *v, GenericList **list, size_t size) +static GenericList *next_list(Visitor *v, GenericList *tail, size_t size) { StringOutputVisitor *sov = to_sov(v); - GenericList *ret = NULL; - if (*list) { - if (sov->head) { - ret = *list; - } else { - ret = (*list)->next; - } + GenericList *ret = tail->next; - if (sov->head) { - if (ret && ret->next == NULL) { - sov->list_mode = LM_NONE; - } - sov->head = false; - } else { - if (ret && ret->next == NULL) { - sov->list_mode = LM_END; - } - } + if (ret && !ret->next) { + sov->list_mode = LM_END; } - return ret; } @@ -311,8 +300,6 @@ static void end_list(Visitor *v) sov->list_mode == LM_NONE || sov->list_mode == LM_IN_PROGRESS); sov->list_mode = LM_NONE; - sov->head = true; - } char *string_output_get_string(StringOutputVisitor *sov) @@ -351,7 +338,7 @@ StringOutputVisitor *string_output_visitor_new(bool human) v->string = g_string_new(NULL); v->human = human; - v->visitor.type_enum = output_type_enum; + v->visitor.type = VISITOR_OUTPUT; v->visitor.type_int64 = print_type_int64; v->visitor.type_uint64 = print_type_uint64; v->visitor.type_size = print_type_size; |