Currently the qemu_opts_parse and qemu_opts_parse_noisily functions
are called in one two ways:

1) qemu_opts_parse|_noisily(&some_group_list, ...)
2) qemu_opts_parse|_noisily(qemu_find_opts("some_opt"), ...)

The second form is problematic. Having the result of qemu_find_opts()
going directly into the first argument makes it difficult to handle a
possible NULL pointer retuned by it.

Next patches will change qemu_opts_parse() and
qemu_opts_parse_noisily() to receive the option name and call
qemu_find_opts() in their body so the return of the function can be
handled properly.

Add a new qemu_opts_parse_list() and change all callsites that pass
the list directly to use it. In the next patches this new _list
version will become the inner function, but at this point, simply make
it defer to qemu_opts_parse() to make the refactoring easier.

Signed-off-by: Fabiano Rosas <[email protected]>
---
 include/qemu/option.h       |   2 +
 tests/unit/test-qemu-opts.c | 169 +++++++++++++++++++-----------------
 util/qemu-option.c          |  13 +++
 util/qemu-sockets.c         |   2 +-
 4 files changed, 104 insertions(+), 82 deletions(-)

diff --git a/include/qemu/option.h b/include/qemu/option.h
index 9a00ac0a35..f96d9fae42 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -132,6 +132,8 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const 
char *params,
                                   bool permit_abbrev);
 QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
                           bool permit_abbrev, Error **errp);
+QemuOpts *qemu_opts_parse_list(QemuOptsList *list, const char *params,
+                               bool permit_abbrev, Error **errp);
 QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
                                Error **errp);
 QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
diff --git a/tests/unit/test-qemu-opts.c b/tests/unit/test-qemu-opts.c
index 8d03a69f7c..1257ef750b 100644
--- a/tests/unit/test-qemu-opts.c
+++ b/tests/unit/test-qemu-opts.c
@@ -349,7 +349,7 @@ static void test_qemu_opt_unset(void)
     int ret;
 
     /* dynamically initialized (parsed) opts */
-    opts = qemu_opts_parse(&opts_list_03, "key=value", false, NULL);
+    opts = qemu_opts_parse_list(&opts_list_03, "key=value", false, NULL);
     g_assert(opts != NULL);
 
     /* check default/parsed value */
@@ -431,95 +431,96 @@ static void test_opts_parse(void)
     QemuOpts *opts;
 
     /* Nothing */
-    opts = qemu_opts_parse(&opts_list_03, "", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "", false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 0);
 
     /* Empty key */
-    opts = qemu_opts_parse(&opts_list_03, "=val", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "=val", false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
 
     /* Multiple keys, last one wins */
-    opts = qemu_opts_parse(&opts_list_03, "a=1,b=2,,x,a=3",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "a=1,b=2,,x,a=3",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 3);
     g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "3");
     g_assert_cmpstr(qemu_opt_get(opts, "b"), ==, "2,x");
 
     /* Except when it doesn't */
-    opts = qemu_opts_parse(&opts_list_03, "id=foo,id=bar",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "id=foo,id=bar",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 0);
     g_assert_cmpstr(qemu_opts_id(opts), ==, "foo");
 
     /* TODO Cover low-level access to repeated keys */
 
     /* Trailing comma is ignored */
-    opts = qemu_opts_parse(&opts_list_03, "x=y,", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "x=y,", false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, "y");
 
     /* Except when it isn't */
-    opts = qemu_opts_parse(&opts_list_03, ",", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, ",", false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "on");
 
     /* Duplicate ID */
-    opts = qemu_opts_parse(&opts_list_03, "x=y,id=foo", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_03, "x=y,id=foo", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
     /* TODO Cover .merge_lists = true */
 
     /* Buggy ID recognition (fixed) */
-    opts = qemu_opts_parse(&opts_list_03, "x=,,id=bar", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "x=,,id=bar", false,
+                                &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert(!qemu_opts_id(opts));
     g_assert_cmpstr(qemu_opt_get(opts, "x"), ==, ",id=bar");
 
     /* Anti-social ID */
-    opts = qemu_opts_parse(&opts_list_01, "id=666", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "id=666", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
     /* Implied value (qemu_opts_parse warns but accepts it) */
-    opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "an,noaus,noaus=",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 3);
     g_assert_cmpstr(qemu_opt_get(opts, "an"), ==, "on");
     g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
     g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
 
     /* Implied value, negated empty key */
-    opts = qemu_opts_parse(&opts_list_03, "no", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "no", false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "off");
 
     /* Implied key */
-    opts = qemu_opts_parse(&opts_list_03, "an,noaus,noaus=", true,
-                           &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "an,noaus,noaus=", true,
+                                &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 3);
     g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "an");
     g_assert_cmpstr(qemu_opt_get(opts, "aus"), ==, "off");
     g_assert_cmpstr(qemu_opt_get(opts, "noaus"), ==, "");
 
     /* Implied key with empty value */
-    opts = qemu_opts_parse(&opts_list_03, ",", true, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, ",", true, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, "");
 
     /* Implied key with comma value */
-    opts = qemu_opts_parse(&opts_list_03, ",,,a=1", true, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, ",,,a=1", true, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 2);
     g_assert_cmpstr(qemu_opt_get(opts, "implied"), ==, ",");
     g_assert_cmpstr(qemu_opt_get(opts, "a"), ==, "1");
 
     /* Empty key is not an implied key */
-    opts = qemu_opts_parse(&opts_list_03, "=val", true, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "=val", true, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpstr(qemu_opt_get(opts, ""), ==, "val");
 
     /* Unknown key */
-    opts = qemu_opts_parse(&opts_list_01, "nonexistent=", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "nonexistent=", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
@@ -532,13 +533,13 @@ static void test_opts_parse_bool(void)
     Error *err = NULL;
     QemuOpts *opts;
 
-    opts = qemu_opts_parse(&opts_list_02, "bool1=on,bool2=off",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_02, "bool1=on,bool2=off",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 2);
     g_assert(qemu_opt_get_bool(opts, "bool1", false));
     g_assert(!qemu_opt_get_bool(opts, "bool2", true));
 
-    opts = qemu_opts_parse(&opts_list_02, "bool1=offer", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_02, "bool1=offer", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
@@ -551,59 +552,60 @@ static void test_opts_parse_number(void)
     QemuOpts *opts;
 
     /* Lower limit zero */
-    opts = qemu_opts_parse(&opts_list_01, "number1=0", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=0", false,
+                                &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 0);
 
     /* Upper limit 2^64-1 */
-    opts = qemu_opts_parse(&opts_list_01,
-                           "number1=18446744073709551615,number2=-1",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_01,
+                                "number1=18446744073709551615,number2=-1",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 2);
     g_assert_cmphex(qemu_opt_get_number(opts, "number1", 1), ==, UINT64_MAX);
     g_assert_cmphex(qemu_opt_get_number(opts, "number2", 0), ==, UINT64_MAX);
 
     /* Above upper limit */
-    opts = qemu_opts_parse(&opts_list_01, "number1=18446744073709551616",
-                           false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=18446744073709551616",
+                                false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
     /* Below lower limit */
-    opts = qemu_opts_parse(&opts_list_01, "number1=-18446744073709551616",
-                           false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=-18446744073709551616",
+                                false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
     /* Hex and octal */
-    opts = qemu_opts_parse(&opts_list_01, "number1=0x2a,number2=052",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=0x2a,number2=052",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 2);
     g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
     g_assert_cmpuint(qemu_opt_get_number(opts, "number2", 0), ==, 42);
 
     /* Invalid */
-    opts = qemu_opts_parse(&opts_list_01, "number1=", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
-    opts = qemu_opts_parse(&opts_list_01, "number1=eins", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=eins", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
     /* Leading whitespace */
-    opts = qemu_opts_parse(&opts_list_01, "number1= \t42",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1= \t42",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpuint(qemu_opt_get_number(opts, "number1", 1), ==, 42);
 
     /* Trailing crap */
-    opts = qemu_opts_parse(&opts_list_01, "number1=3.14", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=3.14", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
-    opts = qemu_opts_parse(&opts_list_01, "number1=08", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=08", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
-    opts = qemu_opts_parse(&opts_list_01, "number1=0 ", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_01, "number1=0 ", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
@@ -616,18 +618,18 @@ static void test_opts_parse_size(void)
     QemuOpts *opts;
 
     /* Lower limit zero */
-    opts = qemu_opts_parse(&opts_list_02, "size1=0", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_02, "size1=0", false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmpuint(qemu_opt_get_size(opts, "size1", 1), ==, 0);
 
     /* Note: full 64 bits of precision */
 
     /* Around double limit of precision: 2^53-1, 2^53, 2^53+1 */
-    opts = qemu_opts_parse(&opts_list_02,
-                           "size1=9007199254740991,"
-                           "size2=9007199254740992,"
-                           "size3=9007199254740993",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_02,
+                                "size1=9007199254740991,"
+                                "size2=9007199254740992,"
+                                "size3=9007199254740993",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 3);
     g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
                      ==, 0x1fffffffffffff);
@@ -637,11 +639,12 @@ static void test_opts_parse_size(void)
                      ==, 0x20000000000001);
 
     /* Close to signed int limit: 2^63-1, 2^63, 2^63+1 */
-    opts = qemu_opts_parse(&opts_list_02,
-                           "size1=9223372036854775807," /* 7fffffffffffffff */
-                           "size2=9223372036854775808," /* 8000000000000000 */
-                           "size3=9223372036854775809", /* 8000000000000001 */
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(
+        &opts_list_02,
+        "size1=9223372036854775807," /* 7fffffffffffffff */
+        "size2=9223372036854775808," /* 8000000000000000 */
+        "size3=9223372036854775809", /* 8000000000000001 */
+        false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 3);
     g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
                      ==, 0x7fffffffffffffff);
@@ -651,10 +654,11 @@ static void test_opts_parse_size(void)
                      ==, 0x8000000000000001);
 
     /* Close to actual upper limit 0xfffffffffffff800 (53 msbs set) */
-    opts = qemu_opts_parse(&opts_list_02,
-                           "size1=18446744073709549568," /* fffffffffffff800 */
-                           "size2=18446744073709550591", /* fffffffffffffbff */
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(
+        &opts_list_02,
+        "size1=18446744073709549568," /* fffffffffffff800 */
+        "size2=18446744073709550591", /* fffffffffffffbff */
+        false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 2);
     g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
                      ==, 0xfffffffffffff800);
@@ -662,47 +666,48 @@ static void test_opts_parse_size(void)
                      ==, 0xfffffffffffffbff);
 
     /* Actual limit, 2^64-1 */
-    opts = qemu_opts_parse(&opts_list_02,
-                           "size1=18446744073709551615", /* ffffffffffffffff */
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(
+        &opts_list_02,
+        "size1=18446744073709551615", /* ffffffffffffffff */
+        false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 1);
     g_assert_cmphex(qemu_opt_get_size(opts, "size1", 1),
                      ==, 0xffffffffffffffff);
 
     /* Beyond limits */
-    opts = qemu_opts_parse(&opts_list_02, "size1=-1", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_02, "size1=-1", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
-    opts = qemu_opts_parse(&opts_list_02,
-                           "size1=18446744073709551616", /* 2^64 */
-                           false, &err);
+    opts = qemu_opts_parse_list(&opts_list_02,
+                                "size1=18446744073709551616", /* 2^64 */
+                                false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
     /* Suffixes */
-    opts = qemu_opts_parse(&opts_list_02, "size1=8b,size2=1.5k,size3=2M",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_02, "size1=8b,size2=1.5k,size3=2M",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 3);
     g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, 8);
     g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 1536);
     g_assert_cmphex(qemu_opt_get_size(opts, "size3", 0), ==, 2 * MiB);
-    opts = qemu_opts_parse(&opts_list_02, "size1=0.1G,size2=16777215T",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_02, "size1=0.1G,size2=16777215T",
+                                false, &error_abort);
     g_assert_cmpuint(opts_count(opts), ==, 2);
     g_assert_cmphex(qemu_opt_get_size(opts, "size1", 0), ==, GiB / 10);
     g_assert_cmphex(qemu_opt_get_size(opts, "size2", 0), ==, 16777215ULL * 
TiB);
 
     /* Beyond limit with suffix */
-    opts = qemu_opts_parse(&opts_list_02, "size1=16777216T",
-                           false, &err);
+    opts = qemu_opts_parse_list(&opts_list_02, "size1=16777216T",
+                                false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
     /* Trailing crap */
-    opts = qemu_opts_parse(&opts_list_02, "size1=16E", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_02, "size1=16E", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
-    opts = qemu_opts_parse(&opts_list_02, "size1=16Gi", false, &err);
+    opts = qemu_opts_parse_list(&opts_list_02, "size1=16Gi", false, &err);
     error_free_or_abort(&err);
     g_assert(!opts);
 
@@ -737,13 +742,13 @@ static void test_has_help_option(void)
     for (i = 0; i < ARRAY_SIZE(test); i++) {
         g_assert_cmpint(has_help_option(test[i].params),
                         ==, test[i].expect);
-        opts = qemu_opts_parse(&opts_list_03, test[i].params, false,
-                               &error_abort);
+        opts = qemu_opts_parse_list(&opts_list_03, test[i].params, false,
+                                    &error_abort);
         g_assert_cmpint(qemu_opt_has_help_opt(opts),
                         ==, test[i].expect);
         qemu_opts_del(opts);
-        opts = qemu_opts_parse(&opts_list_03, test[i].params, true,
-                               &error_abort);
+        opts = qemu_opts_parse_list(&opts_list_03, test[i].params, true,
+                                    &error_abort);
         g_assert_cmpint(qemu_opt_has_help_opt(opts),
                         ==, test[i].expect_implied);
         qemu_opts_del(opts);
@@ -877,8 +882,9 @@ static void test_opts_to_qdict_basic(void)
     QemuOpts *opts;
     QDict *dict;
 
-    opts = qemu_opts_parse(&opts_list_01, "str1=foo,str2=,str3=bar,number1=42",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_01,
+                                "str1=foo,str2=,str3=bar,number1=42",
+                                false, &error_abort);
     g_assert(opts != NULL);
 
     dict = qemu_opts_to_qdict(opts, NULL);
@@ -903,9 +909,9 @@ static void test_opts_to_qdict_filtered(void)
     first = qemu_opts_append(NULL, &opts_list_02);
     merged = qemu_opts_append(first, &opts_list_01);
 
-    opts = qemu_opts_parse(merged,
-                           "str1=foo,str2=,str3=bar,bool1=off,number1=42",
-                           false, &error_abort);
+    opts = qemu_opts_parse_list(
+        merged, "str1=foo,str2=,str3=bar,bool1=off,number1=42",
+        false, &error_abort);
     g_assert(opts != NULL);
 
     /* Convert to QDict without deleting from opts */
@@ -962,7 +968,8 @@ static void test_opts_to_qdict_duplicates(void)
     QemuOpt *opt;
     QDict *dict;
 
-    opts = qemu_opts_parse(&opts_list_03, "foo=a,foo=b", false, &error_abort);
+    opts = qemu_opts_parse_list(&opts_list_03, "foo=a,foo=b", false,
+                                &error_abort);
     g_assert(opts != NULL);
 
     /* Verify that opts has two options with the same name */
diff --git a/util/qemu-option.c b/util/qemu-option.c
index e115e1acef..aa879b78f8 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -922,6 +922,19 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char 
*params,
     return opts_parse(list, params, permit_abbrev, false, NULL, errp);
 }
 
+/**
+ * Create a QemuOpts from @list with options parsed from @params.  If
+ * @permit_abbrev, the first key=value in @params may omit key= and is
+ * treated as if key was @list->implied_opt_name.  On error, store an
+ * error object through @errp if non-null.  Return the new QemuOpts on
+ * success, null pointer on error.
+ */
+QemuOpts *qemu_opts_parse_list(QemuOptsList *list, const char *params,
+                               bool permit_abbrev, Error **errp)
+{
+    return qemu_opts_parse(list, params, permit_abbrev, errp);
+}
+
 /**
  * Create a QemuOpts in @list and with options parsed from @params.
  * If @permit_abbrev, the first key=value in @params may omit key=,
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 4773755fd5..30226671a9 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -704,7 +704,7 @@ static QemuOptsList inet_opts = {
 
 int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
 {
-    QemuOpts *opts = qemu_opts_parse(&inet_opts, str, true, errp);
+    QemuOpts *opts = qemu_opts_parse_list(&inet_opts, str, true, errp);
     if (!opts) {
         return -1;
     }
-- 
2.53.0


Reply via email to