X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qapi%2Fopts-visitor.c;h=8f1efab8b9de23fe94999791983a042cffa893de;hb=f13b978cc7ac5548fca8fc0c1d8491596a446ca5;hp=4cf1cf885bdf0efcb5421003bc3d9c25ec9b1fbb;hpb=e4f70d635863cfc3e3fa7d9a6e37b569ae94d82f;p=mirror_qemu.git diff --git a/qapi/opts-visitor.c b/qapi/opts-visitor.c index 4cf1cf885b..8f1efab8b9 100644 --- a/qapi/opts-visitor.c +++ b/qapi/opts-visitor.c @@ -24,7 +24,8 @@ enum ListMode { LM_NONE, /* not traversing a list of repeated options */ - LM_IN_PROGRESS, /* opts_next_list() ready to be 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 @@ -36,7 +37,8 @@ enum ListMode * LM_UNSIGNED_INTERVAL. */ - LM_SIGNED_INTERVAL, /* opts_next_list() has been called. + LM_SIGNED_INTERVAL, /* + * opts_next_list() has been called. * * Generating the next list link will consume the most * recently stored element from the signed interval, @@ -48,7 +50,14 @@ enum ListMode * next element of the signed interval. */ - LM_UNSIGNED_INTERVAL /* Same as above, only for an unsigned interval. */ + LM_UNSIGNED_INTERVAL, /* Same as above, only for an unsigned interval. */ + + LM_TRAVERSED /* + * opts_next_list() has been called. + * + * No more QemuOpt instance in the list. + * The traversal has been completed. + */ }; typedef enum ListMode ListMode; @@ -124,7 +133,7 @@ opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt) } -static void +static bool opts_start_struct(Visitor *v, const char *name, void **obj, size_t size, Error **errp) { @@ -135,7 +144,7 @@ opts_start_struct(Visitor *v, const char *name, void **obj, *obj = g_malloc0(size); } if (ov->depth++ > 0) { - return; + return true; } ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal, @@ -154,18 +163,19 @@ opts_start_struct(Visitor *v, const char *name, void **obj, ov->fake_id_opt->str = g_strdup(ov->opts_root->id); opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt); } + return true; } -static void +static bool opts_check_struct(Visitor *v, Error **errp) { OptsVisitor *ov = to_ov(v); GHashTableIter iter; GQueue *any; - if (ov->depth > 0) { - return; + if (ov->depth > 1) { + return true; } /* we should have processed all (distinct) QemuOpt instances */ @@ -175,12 +185,14 @@ opts_check_struct(Visitor *v, Error **errp) first = g_queue_peek_head(any); error_setg(errp, QERR_INVALID_PARAMETER, first->name); + return false; } + return true; } static void -opts_end_struct(Visitor *v) +opts_end_struct(Visitor *v, void **obj) { OptsVisitor *ov = to_ov(v); @@ -212,7 +224,7 @@ lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp) } -static void +static bool opts_start_list(Visitor *v, const char *name, GenericList **list, size_t size, Error **errp) { @@ -223,12 +235,13 @@ opts_start_list(Visitor *v, const char *name, GenericList **list, size_t size, /* we don't support visits without a list */ assert(list); ov->repeated_opts = lookup_distinct(ov, name, errp); - if (ov->repeated_opts) { - ov->list_mode = LM_IN_PROGRESS; - *list = g_malloc0(size); - } else { + if (!ov->repeated_opts) { *list = NULL; + return false; } + ov->list_mode = LM_IN_PROGRESS; + *list = g_malloc0(size); + return true; } @@ -238,6 +251,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) OptsVisitor *ov = to_ov(v); switch (ov->list_mode) { + case LM_TRAVERSED: + return NULL; case LM_SIGNED_INTERVAL: case LM_UNSIGNED_INTERVAL: if (ov->list_mode == LM_SIGNED_INTERVAL) { @@ -258,6 +273,8 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) opt = g_queue_pop_head(ov->repeated_opts); if (g_queue_is_empty(ov->repeated_opts)) { g_hash_table_remove(ov->unprocessed_opts, opt->name); + ov->repeated_opts = NULL; + ov->list_mode = LM_TRAVERSED; return NULL; } break; @@ -272,14 +289,26 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size) } +static bool +opts_check_list(Visitor *v, Error **errp) +{ + /* + * Unvisited list elements will be reported later when checking + * whether unvisited struct members remain. + */ + return true; +} + + static void -opts_end_list(Visitor *v) +opts_end_list(Visitor *v, void **obj) { OptsVisitor *ov = to_ov(v); assert(ov->list_mode == LM_IN_PROGRESS || ov->list_mode == LM_SIGNED_INTERVAL || - ov->list_mode == LM_UNSIGNED_INTERVAL); + ov->list_mode == LM_UNSIGNED_INTERVAL || + ov->list_mode == LM_TRAVERSED); ov->repeated_opts = NULL; ov->list_mode = LM_NONE; } @@ -296,6 +325,10 @@ lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) list = lookup_distinct(ov, name, errp); return list ? g_queue_peek_tail(list) : NULL; } + if (ov->list_mode == LM_TRAVERSED) { + error_setg(errp, "Fewer list elements than expected"); + return NULL; + } assert(ov->list_mode == LM_IN_PROGRESS); return g_queue_peek_head(ov->repeated_opts); } @@ -313,7 +346,7 @@ processed(OptsVisitor *ov, const char *name) } -static void +static bool opts_type_str(Visitor *v, const char *name, char **obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -322,7 +355,7 @@ opts_type_str(Visitor *v, const char *name, char **obj, Error **errp) opt = lookup_scalar(ov, name, errp); if (!opt) { *obj = NULL; - return; + return false; } *obj = g_strdup(opt->str ? opt->str : ""); /* Note that we consume a string even if this is called as part of @@ -331,11 +364,11 @@ opts_type_str(Visitor *v, const char *name, char **obj, Error **errp) * consumed only matters to visit_end_struct() as the final error * check if there were no other failures during the visit. */ processed(ov, name); + return true; } -/* mimics qemu-option.c::parse_option_bool() */ -static void +static bool opts_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -343,32 +376,22 @@ opts_type_bool(Visitor *v, const char *name, bool *obj, Error **errp) opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } - if (opt->str) { - if (strcmp(opt->str, "on") == 0 || - strcmp(opt->str, "yes") == 0 || - strcmp(opt->str, "y") == 0) { - *obj = true; - } else if (strcmp(opt->str, "off") == 0 || - strcmp(opt->str, "no") == 0 || - strcmp(opt->str, "n") == 0) { - *obj = false; - } else { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, - "on|yes|y|off|no|n"); - return; + if (!qapi_bool_parse(opt->name, opt->str, obj, errp)) { + return false; } } else { *obj = true; } processed(ov, name); + return true; } -static void +static bool opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); @@ -379,12 +402,12 @@ opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) if (ov->list_mode == LM_SIGNED_INTERVAL) { *obj = ov->range_next.s; - return; + return true; } opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } str = opt->str ? opt->str : ""; @@ -397,7 +420,7 @@ opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) if (*endptr == '\0') { *obj = val; processed(ov, name); - return; + return true; } if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) { long long val2; @@ -414,51 +437,52 @@ opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp) /* as if entering on the top */ *obj = ov->range_next.s; - return; + return true; } } } error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, (ov->list_mode == LM_NONE) ? "an int64 value" : "an int64 value or range"); + return false; } -static void +static bool opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); const QemuOpt *opt; const char *str; - unsigned long long val; - char *endptr; + uint64_t val; + const char *endptr; if (ov->list_mode == LM_UNSIGNED_INTERVAL) { *obj = ov->range_next.u; - return; + return true; } opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } str = opt->str; /* we've gotten past lookup_scalar() */ assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS); - if (parse_uint(str, &val, &endptr, 0) == 0 && val <= UINT64_MAX) { + if (parse_uint(str, &endptr, 0, &val) == 0) { if (*endptr == '\0') { *obj = val; processed(ov, name); - return; + return true; } if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) { - unsigned long long val2; + uint64_t val2; str = endptr + 1; - if (parse_uint_full(str, &val2, 0) == 0 && - val2 <= UINT64_MAX && val <= val2 && + if (parse_uint_full(str, 0, &val2) == 0 && + val <= val2 && val2 - val < OPTS_VISITOR_RANGE_MAX) { ov->range_next.u = val; ov->range_limit.u = val2; @@ -466,39 +490,38 @@ opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp) /* as if entering on the top */ *obj = ov->range_next.u; - return; + return true; } } } error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, (ov->list_mode == LM_NONE) ? "a uint64 value" : "a uint64 value or range"); + return false; } -static void +static bool opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp) { OptsVisitor *ov = to_ov(v); const QemuOpt *opt; - int64_t val; - char *endptr; + int err; opt = lookup_scalar(ov, name, errp); if (!opt) { - return; + return false; } - val = qemu_strtosz_suffix(opt->str ? opt->str : "", &endptr, - QEMU_STRTOSZ_DEFSUFFIX_B); - if (val < 0 || *endptr) { + err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj); + if (err < 0) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, - "a size value representible as a non-negative int64"); - return; + "a size value"); + return false; } - *obj = val; processed(ov, name); + return true; } @@ -513,11 +536,25 @@ opts_optional(Visitor *v, const char *name, bool *present) } -OptsVisitor * +static void +opts_free(Visitor *v) +{ + OptsVisitor *ov = to_ov(v); + + if (ov->unprocessed_opts != NULL) { + g_hash_table_destroy(ov->unprocessed_opts); + } + g_free(ov->fake_id_opt); + g_free(ov); +} + + +Visitor * opts_visitor_new(const QemuOpts *opts) { OptsVisitor *ov; + assert(opts); ov = g_malloc0(sizeof *ov); ov->visitor.type = VISITOR_INPUT; @@ -528,6 +565,7 @@ opts_visitor_new(const QemuOpts *opts) ov->visitor.start_list = &opts_start_list; ov->visitor.next_list = &opts_next_list; + ov->visitor.check_list = &opts_check_list; ov->visitor.end_list = &opts_end_list; ov->visitor.type_int64 = &opts_type_int64; @@ -540,26 +578,9 @@ opts_visitor_new(const QemuOpts *opts) * skip some mandatory methods... */ ov->visitor.optional = &opts_optional; + ov->visitor.free = opts_free; ov->opts_root = opts; - return ov; -} - - -void -opts_visitor_cleanup(OptsVisitor *ov) -{ - if (ov->unprocessed_opts != NULL) { - g_hash_table_destroy(ov->unprocessed_opts); - } - g_free(ov->fake_id_opt); - g_free(ov); -} - - -Visitor * -opts_get_visitor(OptsVisitor *ov) -{ return &ov->visitor; }