1eb7ee2cbSLaszlo Ersek /* 2eb7ee2cbSLaszlo Ersek * Options Visitor 3eb7ee2cbSLaszlo Ersek * 4eb7ee2cbSLaszlo Ersek * Copyright Red Hat, Inc. 2012 5eb7ee2cbSLaszlo Ersek * 6eb7ee2cbSLaszlo Ersek * Author: Laszlo Ersek <lersek@redhat.com> 7eb7ee2cbSLaszlo Ersek * 8eb7ee2cbSLaszlo Ersek * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 9eb7ee2cbSLaszlo Ersek * See the COPYING.LIB file in the top-level directory. 10eb7ee2cbSLaszlo Ersek * 11eb7ee2cbSLaszlo Ersek */ 12eb7ee2cbSLaszlo Ersek 13*79ee7df8SPaolo Bonzini #include "qemu-common.h" 14eb7ee2cbSLaszlo Ersek #include "opts-visitor.h" 15eb7ee2cbSLaszlo Ersek #include "qemu-queue.h" 16eb7ee2cbSLaszlo Ersek #include "qemu-option-internal.h" 17eb7ee2cbSLaszlo Ersek #include "qapi-visit-impl.h" 18eb7ee2cbSLaszlo Ersek 19eb7ee2cbSLaszlo Ersek 20eb7ee2cbSLaszlo Ersek struct OptsVisitor 21eb7ee2cbSLaszlo Ersek { 22eb7ee2cbSLaszlo Ersek Visitor visitor; 23eb7ee2cbSLaszlo Ersek 24eb7ee2cbSLaszlo Ersek /* Ownership remains with opts_visitor_new()'s caller. */ 25eb7ee2cbSLaszlo Ersek const QemuOpts *opts_root; 26eb7ee2cbSLaszlo Ersek 27eb7ee2cbSLaszlo Ersek unsigned depth; 28eb7ee2cbSLaszlo Ersek 29eb7ee2cbSLaszlo Ersek /* Non-null iff depth is positive. Each key is a QemuOpt name. Each value 30eb7ee2cbSLaszlo Ersek * is a non-empty GQueue, enumerating all QemuOpt occurrences with that 31eb7ee2cbSLaszlo Ersek * name. */ 32eb7ee2cbSLaszlo Ersek GHashTable *unprocessed_opts; 33eb7ee2cbSLaszlo Ersek 34eb7ee2cbSLaszlo Ersek /* The list currently being traversed with opts_start_list() / 35eb7ee2cbSLaszlo Ersek * opts_next_list(). The list must have a struct element type in the 36eb7ee2cbSLaszlo Ersek * schema, with a single mandatory scalar member. */ 37eb7ee2cbSLaszlo Ersek GQueue *repeated_opts; 38eb7ee2cbSLaszlo Ersek bool repeated_opts_first; 39eb7ee2cbSLaszlo Ersek 40eb7ee2cbSLaszlo Ersek /* If "opts_root->id" is set, reinstantiate it as a fake QemuOpt for 41eb7ee2cbSLaszlo Ersek * uniformity. Only its "name" and "str" fields are set. "fake_id_opt" does 42eb7ee2cbSLaszlo Ersek * not survive or escape the OptsVisitor object. 43eb7ee2cbSLaszlo Ersek */ 44eb7ee2cbSLaszlo Ersek QemuOpt *fake_id_opt; 45eb7ee2cbSLaszlo Ersek }; 46eb7ee2cbSLaszlo Ersek 47eb7ee2cbSLaszlo Ersek 48eb7ee2cbSLaszlo Ersek static void 49eb7ee2cbSLaszlo Ersek destroy_list(gpointer list) 50eb7ee2cbSLaszlo Ersek { 51eb7ee2cbSLaszlo Ersek g_queue_free(list); 52eb7ee2cbSLaszlo Ersek } 53eb7ee2cbSLaszlo Ersek 54eb7ee2cbSLaszlo Ersek 55eb7ee2cbSLaszlo Ersek static void 56eb7ee2cbSLaszlo Ersek opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt) 57eb7ee2cbSLaszlo Ersek { 58eb7ee2cbSLaszlo Ersek GQueue *list; 59eb7ee2cbSLaszlo Ersek 60eb7ee2cbSLaszlo Ersek list = g_hash_table_lookup(unprocessed_opts, opt->name); 61eb7ee2cbSLaszlo Ersek if (list == NULL) { 62eb7ee2cbSLaszlo Ersek list = g_queue_new(); 63eb7ee2cbSLaszlo Ersek 64eb7ee2cbSLaszlo Ersek /* GHashTable will never try to free the keys -- we supply NULL as 65eb7ee2cbSLaszlo Ersek * "key_destroy_func" in opts_start_struct(). Thus cast away key 66eb7ee2cbSLaszlo Ersek * const-ness in order to suppress gcc's warning. 67eb7ee2cbSLaszlo Ersek */ 68eb7ee2cbSLaszlo Ersek g_hash_table_insert(unprocessed_opts, (gpointer)opt->name, list); 69eb7ee2cbSLaszlo Ersek } 70eb7ee2cbSLaszlo Ersek 71eb7ee2cbSLaszlo Ersek /* Similarly, destroy_list() doesn't call g_queue_free_full(). */ 72eb7ee2cbSLaszlo Ersek g_queue_push_tail(list, (gpointer)opt); 73eb7ee2cbSLaszlo Ersek } 74eb7ee2cbSLaszlo Ersek 75eb7ee2cbSLaszlo Ersek 76eb7ee2cbSLaszlo Ersek static void 77eb7ee2cbSLaszlo Ersek opts_start_struct(Visitor *v, void **obj, const char *kind, 78eb7ee2cbSLaszlo Ersek const char *name, size_t size, Error **errp) 79eb7ee2cbSLaszlo Ersek { 80eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 81eb7ee2cbSLaszlo Ersek const QemuOpt *opt; 82eb7ee2cbSLaszlo Ersek 83eb7ee2cbSLaszlo Ersek *obj = g_malloc0(size > 0 ? size : 1); 84eb7ee2cbSLaszlo Ersek if (ov->depth++ > 0) { 85eb7ee2cbSLaszlo Ersek return; 86eb7ee2cbSLaszlo Ersek } 87eb7ee2cbSLaszlo Ersek 88eb7ee2cbSLaszlo Ersek ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal, 89eb7ee2cbSLaszlo Ersek NULL, &destroy_list); 90eb7ee2cbSLaszlo Ersek QTAILQ_FOREACH(opt, &ov->opts_root->head, next) { 91eb7ee2cbSLaszlo Ersek /* ensured by qemu-option.c::opts_do_parse() */ 92eb7ee2cbSLaszlo Ersek assert(strcmp(opt->name, "id") != 0); 93eb7ee2cbSLaszlo Ersek 94eb7ee2cbSLaszlo Ersek opts_visitor_insert(ov->unprocessed_opts, opt); 95eb7ee2cbSLaszlo Ersek } 96eb7ee2cbSLaszlo Ersek 97eb7ee2cbSLaszlo Ersek if (ov->opts_root->id != NULL) { 98eb7ee2cbSLaszlo Ersek ov->fake_id_opt = g_malloc0(sizeof *ov->fake_id_opt); 99eb7ee2cbSLaszlo Ersek 100eb7ee2cbSLaszlo Ersek ov->fake_id_opt->name = "id"; 101eb7ee2cbSLaszlo Ersek ov->fake_id_opt->str = ov->opts_root->id; 102eb7ee2cbSLaszlo Ersek opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt); 103eb7ee2cbSLaszlo Ersek } 104eb7ee2cbSLaszlo Ersek } 105eb7ee2cbSLaszlo Ersek 106eb7ee2cbSLaszlo Ersek 107eb7ee2cbSLaszlo Ersek static gboolean 108eb7ee2cbSLaszlo Ersek ghr_true(gpointer ign_key, gpointer ign_value, gpointer ign_user_data) 109eb7ee2cbSLaszlo Ersek { 110eb7ee2cbSLaszlo Ersek return TRUE; 111eb7ee2cbSLaszlo Ersek } 112eb7ee2cbSLaszlo Ersek 113eb7ee2cbSLaszlo Ersek 114eb7ee2cbSLaszlo Ersek static void 115eb7ee2cbSLaszlo Ersek opts_end_struct(Visitor *v, Error **errp) 116eb7ee2cbSLaszlo Ersek { 117eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 118eb7ee2cbSLaszlo Ersek GQueue *any; 119eb7ee2cbSLaszlo Ersek 120eb7ee2cbSLaszlo Ersek if (--ov->depth > 0) { 121eb7ee2cbSLaszlo Ersek return; 122eb7ee2cbSLaszlo Ersek } 123eb7ee2cbSLaszlo Ersek 124eb7ee2cbSLaszlo Ersek /* we should have processed all (distinct) QemuOpt instances */ 125eb7ee2cbSLaszlo Ersek any = g_hash_table_find(ov->unprocessed_opts, &ghr_true, NULL); 126eb7ee2cbSLaszlo Ersek if (any) { 127eb7ee2cbSLaszlo Ersek const QemuOpt *first; 128eb7ee2cbSLaszlo Ersek 129eb7ee2cbSLaszlo Ersek first = g_queue_peek_head(any); 130eb7ee2cbSLaszlo Ersek error_set(errp, QERR_INVALID_PARAMETER, first->name); 131eb7ee2cbSLaszlo Ersek } 132eb7ee2cbSLaszlo Ersek g_hash_table_destroy(ov->unprocessed_opts); 133eb7ee2cbSLaszlo Ersek ov->unprocessed_opts = NULL; 134eb7ee2cbSLaszlo Ersek g_free(ov->fake_id_opt); 135eb7ee2cbSLaszlo Ersek ov->fake_id_opt = NULL; 136eb7ee2cbSLaszlo Ersek } 137eb7ee2cbSLaszlo Ersek 138eb7ee2cbSLaszlo Ersek 139eb7ee2cbSLaszlo Ersek static GQueue * 140eb7ee2cbSLaszlo Ersek lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp) 141eb7ee2cbSLaszlo Ersek { 142eb7ee2cbSLaszlo Ersek GQueue *list; 143eb7ee2cbSLaszlo Ersek 144eb7ee2cbSLaszlo Ersek list = g_hash_table_lookup(ov->unprocessed_opts, name); 145eb7ee2cbSLaszlo Ersek if (!list) { 146eb7ee2cbSLaszlo Ersek error_set(errp, QERR_MISSING_PARAMETER, name); 147eb7ee2cbSLaszlo Ersek } 148eb7ee2cbSLaszlo Ersek return list; 149eb7ee2cbSLaszlo Ersek } 150eb7ee2cbSLaszlo Ersek 151eb7ee2cbSLaszlo Ersek 152eb7ee2cbSLaszlo Ersek static void 153eb7ee2cbSLaszlo Ersek opts_start_list(Visitor *v, const char *name, Error **errp) 154eb7ee2cbSLaszlo Ersek { 155eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 156eb7ee2cbSLaszlo Ersek 157eb7ee2cbSLaszlo Ersek /* we can't traverse a list in a list */ 158eb7ee2cbSLaszlo Ersek assert(ov->repeated_opts == NULL); 159eb7ee2cbSLaszlo Ersek ov->repeated_opts = lookup_distinct(ov, name, errp); 160eb7ee2cbSLaszlo Ersek ov->repeated_opts_first = (ov->repeated_opts != NULL); 161eb7ee2cbSLaszlo Ersek } 162eb7ee2cbSLaszlo Ersek 163eb7ee2cbSLaszlo Ersek 164eb7ee2cbSLaszlo Ersek static GenericList * 165eb7ee2cbSLaszlo Ersek opts_next_list(Visitor *v, GenericList **list, Error **errp) 166eb7ee2cbSLaszlo Ersek { 167eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 168eb7ee2cbSLaszlo Ersek GenericList **link; 169eb7ee2cbSLaszlo Ersek 170eb7ee2cbSLaszlo Ersek if (ov->repeated_opts_first) { 171eb7ee2cbSLaszlo Ersek ov->repeated_opts_first = false; 172eb7ee2cbSLaszlo Ersek link = list; 173eb7ee2cbSLaszlo Ersek } else { 174eb7ee2cbSLaszlo Ersek const QemuOpt *opt; 175eb7ee2cbSLaszlo Ersek 176eb7ee2cbSLaszlo Ersek opt = g_queue_pop_head(ov->repeated_opts); 177eb7ee2cbSLaszlo Ersek if (g_queue_is_empty(ov->repeated_opts)) { 178eb7ee2cbSLaszlo Ersek g_hash_table_remove(ov->unprocessed_opts, opt->name); 179eb7ee2cbSLaszlo Ersek return NULL; 180eb7ee2cbSLaszlo Ersek } 181eb7ee2cbSLaszlo Ersek link = &(*list)->next; 182eb7ee2cbSLaszlo Ersek } 183eb7ee2cbSLaszlo Ersek 184eb7ee2cbSLaszlo Ersek *link = g_malloc0(sizeof **link); 185eb7ee2cbSLaszlo Ersek return *link; 186eb7ee2cbSLaszlo Ersek } 187eb7ee2cbSLaszlo Ersek 188eb7ee2cbSLaszlo Ersek 189eb7ee2cbSLaszlo Ersek static void 190eb7ee2cbSLaszlo Ersek opts_end_list(Visitor *v, Error **errp) 191eb7ee2cbSLaszlo Ersek { 192eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 193eb7ee2cbSLaszlo Ersek 194eb7ee2cbSLaszlo Ersek ov->repeated_opts = NULL; 195eb7ee2cbSLaszlo Ersek } 196eb7ee2cbSLaszlo Ersek 197eb7ee2cbSLaszlo Ersek 198eb7ee2cbSLaszlo Ersek static const QemuOpt * 199eb7ee2cbSLaszlo Ersek lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) 200eb7ee2cbSLaszlo Ersek { 201eb7ee2cbSLaszlo Ersek if (ov->repeated_opts == NULL) { 202eb7ee2cbSLaszlo Ersek GQueue *list; 203eb7ee2cbSLaszlo Ersek 204eb7ee2cbSLaszlo Ersek /* the last occurrence of any QemuOpt takes effect when queried by name 205eb7ee2cbSLaszlo Ersek */ 206eb7ee2cbSLaszlo Ersek list = lookup_distinct(ov, name, errp); 207eb7ee2cbSLaszlo Ersek return list ? g_queue_peek_tail(list) : NULL; 208eb7ee2cbSLaszlo Ersek } 209eb7ee2cbSLaszlo Ersek return g_queue_peek_head(ov->repeated_opts); 210eb7ee2cbSLaszlo Ersek } 211eb7ee2cbSLaszlo Ersek 212eb7ee2cbSLaszlo Ersek 213eb7ee2cbSLaszlo Ersek static void 214eb7ee2cbSLaszlo Ersek processed(OptsVisitor *ov, const char *name) 215eb7ee2cbSLaszlo Ersek { 216eb7ee2cbSLaszlo Ersek if (ov->repeated_opts == NULL) { 217eb7ee2cbSLaszlo Ersek g_hash_table_remove(ov->unprocessed_opts, name); 218eb7ee2cbSLaszlo Ersek } 219eb7ee2cbSLaszlo Ersek } 220eb7ee2cbSLaszlo Ersek 221eb7ee2cbSLaszlo Ersek 222eb7ee2cbSLaszlo Ersek static void 223eb7ee2cbSLaszlo Ersek opts_type_str(Visitor *v, char **obj, const char *name, Error **errp) 224eb7ee2cbSLaszlo Ersek { 225eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 226eb7ee2cbSLaszlo Ersek const QemuOpt *opt; 227eb7ee2cbSLaszlo Ersek 228eb7ee2cbSLaszlo Ersek opt = lookup_scalar(ov, name, errp); 229eb7ee2cbSLaszlo Ersek if (!opt) { 230eb7ee2cbSLaszlo Ersek return; 231eb7ee2cbSLaszlo Ersek } 232eb7ee2cbSLaszlo Ersek *obj = g_strdup(opt->str ? opt->str : ""); 233eb7ee2cbSLaszlo Ersek processed(ov, name); 234eb7ee2cbSLaszlo Ersek } 235eb7ee2cbSLaszlo Ersek 236eb7ee2cbSLaszlo Ersek 237eb7ee2cbSLaszlo Ersek /* mimics qemu-option.c::parse_option_bool() */ 238eb7ee2cbSLaszlo Ersek static void 239eb7ee2cbSLaszlo Ersek opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) 240eb7ee2cbSLaszlo Ersek { 241eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 242eb7ee2cbSLaszlo Ersek const QemuOpt *opt; 243eb7ee2cbSLaszlo Ersek 244eb7ee2cbSLaszlo Ersek opt = lookup_scalar(ov, name, errp); 245eb7ee2cbSLaszlo Ersek if (!opt) { 246eb7ee2cbSLaszlo Ersek return; 247eb7ee2cbSLaszlo Ersek } 248eb7ee2cbSLaszlo Ersek 249eb7ee2cbSLaszlo Ersek if (opt->str) { 250eb7ee2cbSLaszlo Ersek if (strcmp(opt->str, "on") == 0 || 251eb7ee2cbSLaszlo Ersek strcmp(opt->str, "yes") == 0 || 252eb7ee2cbSLaszlo Ersek strcmp(opt->str, "y") == 0) { 253eb7ee2cbSLaszlo Ersek *obj = true; 254eb7ee2cbSLaszlo Ersek } else if (strcmp(opt->str, "off") == 0 || 255eb7ee2cbSLaszlo Ersek strcmp(opt->str, "no") == 0 || 256eb7ee2cbSLaszlo Ersek strcmp(opt->str, "n") == 0) { 257eb7ee2cbSLaszlo Ersek *obj = false; 258eb7ee2cbSLaszlo Ersek } else { 259eb7ee2cbSLaszlo Ersek error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, 260eb7ee2cbSLaszlo Ersek "on|yes|y|off|no|n"); 261eb7ee2cbSLaszlo Ersek return; 262eb7ee2cbSLaszlo Ersek } 263eb7ee2cbSLaszlo Ersek } else { 264eb7ee2cbSLaszlo Ersek *obj = true; 265eb7ee2cbSLaszlo Ersek } 266eb7ee2cbSLaszlo Ersek 267eb7ee2cbSLaszlo Ersek processed(ov, name); 268eb7ee2cbSLaszlo Ersek } 269eb7ee2cbSLaszlo Ersek 270eb7ee2cbSLaszlo Ersek 271eb7ee2cbSLaszlo Ersek static void 272eb7ee2cbSLaszlo Ersek opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) 273eb7ee2cbSLaszlo Ersek { 274eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 275eb7ee2cbSLaszlo Ersek const QemuOpt *opt; 276eb7ee2cbSLaszlo Ersek const char *str; 277eb7ee2cbSLaszlo Ersek long long val; 278eb7ee2cbSLaszlo Ersek char *endptr; 279eb7ee2cbSLaszlo Ersek 280eb7ee2cbSLaszlo Ersek opt = lookup_scalar(ov, name, errp); 281eb7ee2cbSLaszlo Ersek if (!opt) { 282eb7ee2cbSLaszlo Ersek return; 283eb7ee2cbSLaszlo Ersek } 284eb7ee2cbSLaszlo Ersek str = opt->str ? opt->str : ""; 285eb7ee2cbSLaszlo Ersek 286eb7ee2cbSLaszlo Ersek errno = 0; 287eb7ee2cbSLaszlo Ersek val = strtoll(str, &endptr, 0); 288eb7ee2cbSLaszlo Ersek if (*str != '\0' && *endptr == '\0' && errno == 0 && INT64_MIN <= val && 289eb7ee2cbSLaszlo Ersek val <= INT64_MAX) { 290eb7ee2cbSLaszlo Ersek *obj = val; 291eb7ee2cbSLaszlo Ersek processed(ov, name); 292eb7ee2cbSLaszlo Ersek return; 293eb7ee2cbSLaszlo Ersek } 294eb7ee2cbSLaszlo Ersek error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "an int64 value"); 295eb7ee2cbSLaszlo Ersek } 296eb7ee2cbSLaszlo Ersek 297eb7ee2cbSLaszlo Ersek 298eb7ee2cbSLaszlo Ersek static void 299eb7ee2cbSLaszlo Ersek opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) 300eb7ee2cbSLaszlo Ersek { 301eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 302eb7ee2cbSLaszlo Ersek const QemuOpt *opt; 303eb7ee2cbSLaszlo Ersek const char *str; 304eb7ee2cbSLaszlo Ersek 305eb7ee2cbSLaszlo Ersek opt = lookup_scalar(ov, name, errp); 306eb7ee2cbSLaszlo Ersek if (!opt) { 307eb7ee2cbSLaszlo Ersek return; 308eb7ee2cbSLaszlo Ersek } 309eb7ee2cbSLaszlo Ersek 310eb7ee2cbSLaszlo Ersek str = opt->str; 311eb7ee2cbSLaszlo Ersek if (str != NULL) { 312eb7ee2cbSLaszlo Ersek while (isspace((unsigned char)*str)) { 313eb7ee2cbSLaszlo Ersek ++str; 314eb7ee2cbSLaszlo Ersek } 315eb7ee2cbSLaszlo Ersek 316eb7ee2cbSLaszlo Ersek if (*str != '-' && *str != '\0') { 317eb7ee2cbSLaszlo Ersek unsigned long long val; 318eb7ee2cbSLaszlo Ersek char *endptr; 319eb7ee2cbSLaszlo Ersek 320eb7ee2cbSLaszlo Ersek /* non-empty, non-negative subject sequence */ 321eb7ee2cbSLaszlo Ersek errno = 0; 322eb7ee2cbSLaszlo Ersek val = strtoull(str, &endptr, 0); 323eb7ee2cbSLaszlo Ersek if (*endptr == '\0' && errno == 0 && val <= UINT64_MAX) { 324eb7ee2cbSLaszlo Ersek *obj = val; 325eb7ee2cbSLaszlo Ersek processed(ov, name); 326eb7ee2cbSLaszlo Ersek return; 327eb7ee2cbSLaszlo Ersek } 328eb7ee2cbSLaszlo Ersek } 329eb7ee2cbSLaszlo Ersek } 330eb7ee2cbSLaszlo Ersek error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, 331eb7ee2cbSLaszlo Ersek "an uint64 value"); 332eb7ee2cbSLaszlo Ersek } 333eb7ee2cbSLaszlo Ersek 334eb7ee2cbSLaszlo Ersek 335eb7ee2cbSLaszlo Ersek static void 336eb7ee2cbSLaszlo Ersek opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) 337eb7ee2cbSLaszlo Ersek { 338eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 339eb7ee2cbSLaszlo Ersek const QemuOpt *opt; 340eb7ee2cbSLaszlo Ersek int64_t val; 341eb7ee2cbSLaszlo Ersek char *endptr; 342eb7ee2cbSLaszlo Ersek 343eb7ee2cbSLaszlo Ersek opt = lookup_scalar(ov, name, errp); 344eb7ee2cbSLaszlo Ersek if (!opt) { 345eb7ee2cbSLaszlo Ersek return; 346eb7ee2cbSLaszlo Ersek } 347eb7ee2cbSLaszlo Ersek 348eb7ee2cbSLaszlo Ersek val = strtosz_suffix(opt->str ? opt->str : "", &endptr, 349eb7ee2cbSLaszlo Ersek STRTOSZ_DEFSUFFIX_B); 350eb7ee2cbSLaszlo Ersek if (val != -1 && *endptr == '\0') { 351eb7ee2cbSLaszlo Ersek *obj = val; 352eb7ee2cbSLaszlo Ersek processed(ov, name); 353eb7ee2cbSLaszlo Ersek return; 354eb7ee2cbSLaszlo Ersek } 355eb7ee2cbSLaszlo Ersek error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, 356eb7ee2cbSLaszlo Ersek "a size value representible as a non-negative int64"); 357eb7ee2cbSLaszlo Ersek } 358eb7ee2cbSLaszlo Ersek 359eb7ee2cbSLaszlo Ersek 360eb7ee2cbSLaszlo Ersek static void 361eb7ee2cbSLaszlo Ersek opts_start_optional(Visitor *v, bool *present, const char *name, 362eb7ee2cbSLaszlo Ersek Error **errp) 363eb7ee2cbSLaszlo Ersek { 364eb7ee2cbSLaszlo Ersek OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); 365eb7ee2cbSLaszlo Ersek 366eb7ee2cbSLaszlo Ersek /* we only support a single mandatory scalar field in a list node */ 367eb7ee2cbSLaszlo Ersek assert(ov->repeated_opts == NULL); 368eb7ee2cbSLaszlo Ersek *present = (lookup_distinct(ov, name, NULL) != NULL); 369eb7ee2cbSLaszlo Ersek } 370eb7ee2cbSLaszlo Ersek 371eb7ee2cbSLaszlo Ersek 372eb7ee2cbSLaszlo Ersek OptsVisitor * 373eb7ee2cbSLaszlo Ersek opts_visitor_new(const QemuOpts *opts) 374eb7ee2cbSLaszlo Ersek { 375eb7ee2cbSLaszlo Ersek OptsVisitor *ov; 376eb7ee2cbSLaszlo Ersek 377eb7ee2cbSLaszlo Ersek ov = g_malloc0(sizeof *ov); 378eb7ee2cbSLaszlo Ersek 379eb7ee2cbSLaszlo Ersek ov->visitor.start_struct = &opts_start_struct; 380eb7ee2cbSLaszlo Ersek ov->visitor.end_struct = &opts_end_struct; 381eb7ee2cbSLaszlo Ersek 382eb7ee2cbSLaszlo Ersek ov->visitor.start_list = &opts_start_list; 383eb7ee2cbSLaszlo Ersek ov->visitor.next_list = &opts_next_list; 384eb7ee2cbSLaszlo Ersek ov->visitor.end_list = &opts_end_list; 385eb7ee2cbSLaszlo Ersek 386eb7ee2cbSLaszlo Ersek /* input_type_enum() covers both "normal" enums and union discriminators. 387eb7ee2cbSLaszlo Ersek * The union discriminator field is always generated as "type"; it should 388eb7ee2cbSLaszlo Ersek * match the "type" QemuOpt child of any QemuOpts. 389eb7ee2cbSLaszlo Ersek * 390eb7ee2cbSLaszlo Ersek * input_type_enum() will remove the looked-up key from the 391eb7ee2cbSLaszlo Ersek * "unprocessed_opts" hash even if the lookup fails, because the removal is 392eb7ee2cbSLaszlo Ersek * done earlier in opts_type_str(). This should be harmless. 393eb7ee2cbSLaszlo Ersek */ 394eb7ee2cbSLaszlo Ersek ov->visitor.type_enum = &input_type_enum; 395eb7ee2cbSLaszlo Ersek 396eb7ee2cbSLaszlo Ersek ov->visitor.type_int = &opts_type_int; 397eb7ee2cbSLaszlo Ersek ov->visitor.type_uint64 = &opts_type_uint64; 398eb7ee2cbSLaszlo Ersek ov->visitor.type_size = &opts_type_size; 399eb7ee2cbSLaszlo Ersek ov->visitor.type_bool = &opts_type_bool; 400eb7ee2cbSLaszlo Ersek ov->visitor.type_str = &opts_type_str; 401eb7ee2cbSLaszlo Ersek 402eb7ee2cbSLaszlo Ersek /* type_number() is not filled in, but this is not the first visitor to 403eb7ee2cbSLaszlo Ersek * skip some mandatory methods... */ 404eb7ee2cbSLaszlo Ersek 405eb7ee2cbSLaszlo Ersek ov->visitor.start_optional = &opts_start_optional; 406eb7ee2cbSLaszlo Ersek 407eb7ee2cbSLaszlo Ersek ov->opts_root = opts; 408eb7ee2cbSLaszlo Ersek 409eb7ee2cbSLaszlo Ersek return ov; 410eb7ee2cbSLaszlo Ersek } 411eb7ee2cbSLaszlo Ersek 412eb7ee2cbSLaszlo Ersek 413eb7ee2cbSLaszlo Ersek void 414eb7ee2cbSLaszlo Ersek opts_visitor_cleanup(OptsVisitor *ov) 415eb7ee2cbSLaszlo Ersek { 416eb7ee2cbSLaszlo Ersek if (ov->unprocessed_opts != NULL) { 417eb7ee2cbSLaszlo Ersek g_hash_table_destroy(ov->unprocessed_opts); 418eb7ee2cbSLaszlo Ersek } 419eb7ee2cbSLaszlo Ersek g_free(ov->fake_id_opt); 420e36c8766SStefan Weil g_free(ov); 421eb7ee2cbSLaszlo Ersek } 422eb7ee2cbSLaszlo Ersek 423eb7ee2cbSLaszlo Ersek 424eb7ee2cbSLaszlo Ersek Visitor * 425eb7ee2cbSLaszlo Ersek opts_get_visitor(OptsVisitor *ov) 426eb7ee2cbSLaszlo Ersek { 427eb7ee2cbSLaszlo Ersek return &ov->visitor; 428eb7ee2cbSLaszlo Ersek } 429