]> git.proxmox.com Git - mirror_qemu.git/blobdiff - qapi/opts-visitor.c
Merge tag 'pull-maintainer-may24-160524-2' of https://gitlab.com/stsquad/qemu into...
[mirror_qemu.git] / qapi / opts-visitor.c
index 026d25b76779a5657cf92008b44d413387cc9a2e..3d1a28b4191895d456ccf421ca8ae565c471ca12 100644 (file)
@@ -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 */
@@ -174,8 +184,10 @@ opts_check_struct(Visitor *v, Error **errp)
         const QemuOpt *first;
 
         first = g_queue_peek_head(any);
-        error_setg(errp, QERR_INVALID_PARAMETER, first->name);
+        error_setg(errp, "Invalid parameter '%s'", first->name);
+        return false;
     }
+    return true;
 }
 
 
@@ -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,13 +289,14 @@ opts_next_list(Visitor *v, GenericList *tail, size_t size)
 }
 
 
-static void
+static bool
 opts_check_list(Visitor *v, Error **errp)
 {
     /*
-     * FIXME should set error when unvisited elements remain.  Mostly
-     * harmless, as the generated visits always visit all elements.
+     * Unvisited list elements will be reported later when checking
+     * whether unvisited struct members remain.
      */
+    return true;
 }
 
 
@@ -289,7 +307,8 @@ opts_end_list(Visitor *v, void **obj)
 
     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;
 }
@@ -306,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);
 }
@@ -323,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);
@@ -332,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
@@ -341,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);
@@ -353,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);
@@ -389,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 : "";
 
@@ -407,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;
@@ -424,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;
@@ -476,17 +490,18 @@ 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);
@@ -495,17 +510,18 @@ opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp)
 
     opt = lookup_scalar(ov, name, errp);
     if (!opt) {
-        return;
+        return false;
     }
 
     err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj);
     if (err < 0) {
         error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
                    "a size value");
-        return;
+        return false;
     }
 
     processed(ov, name);
+    return true;
 }