[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v19 06/11] qapi: make string input visitor parse int
From: |
Hu Tao |
Subject: |
[Qemu-devel] [PATCH v19 06/11] qapi: make string input visitor parse int list |
Date: |
Tue, 4 Mar 2014 15:28:20 +0800 |
Cc: Laszlo Ersek <address@hidden>
Signed-off-by: Hu Tao <address@hidden>
---
qapi/string-input-visitor.c | 160 ++++++++++++++++++++++++++++++++++++--
tests/test-string-input-visitor.c | 21 +++++
2 files changed, 175 insertions(+), 6 deletions(-)
diff --git a/qapi/string-input-visitor.c b/qapi/string-input-visitor.c
index 793548a..24aab5e 100644
--- a/qapi/string-input-visitor.c
+++ b/qapi/string-input-visitor.c
@@ -16,30 +16,175 @@
#include "qapi/qmp/qerror.h"
#include "qemu/option.h"
+enum ListMode {
+ LM_NONE, /* not traversing a list of repeated options */
+ LM_STARTED, /* start_list() succeeded */
+
+ LM_IN_PROGRESS, /* next_list() has been called.
+ *
+ * Generating the next list link will consume the most
+ * recently parsed QemuOpt instance of the repeated
+ * option.
+ *
+ * Parsing a value into the list link will examine the
+ * next QemuOpt instance of the repeated option, and
+ * possibly enter LM_SIGNED_INTERVAL or
+ * LM_UNSIGNED_INTERVAL.
+ */
+
+ LM_SIGNED_INTERVAL, /* next_list() has been called.
+ *
+ * Generating the next list link will consume the most
+ * recently stored element from the signed interval,
+ * parsed from the most recent QemuOpt instance of the
+ * repeated option. This may consume QemuOpt itself
+ * and return to LM_IN_PROGRESS.
+ *
+ * Parsing a value into the list link will store the
+ * next element of the signed interval.
+ */
+
+ LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
+
+ LM_END
+};
+
+typedef enum ListMode ListMode;
+
struct StringInputVisitor
{
Visitor visitor;
+
+ ListMode list_mode;
+
+ /* When parsing a list of repeating options as integers, values of the form
+ * "a-b", representing a closed interval, are allowed. Elements in the
+ * range are generated individually.
+ */
+ union {
+ int64_t s;
+ uint64_t u;
+ } range_next, range_limit;
+
const char *string;
};
+static void
+start_list(Visitor *v, const char *name, Error **errp)
+{
+ StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+
+ /* we can't traverse a list in a list */
+ assert(siv->list_mode == LM_NONE);
+ siv->list_mode = LM_STARTED;
+}
+
+static GenericList *
+next_list(Visitor *v, GenericList **list, Error **errp)
+{
+ StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+ GenericList **link;
+
+ switch (siv->list_mode) {
+ case LM_STARTED:
+ siv->list_mode = LM_IN_PROGRESS;
+ link = list;
+ break;
+
+ case LM_SIGNED_INTERVAL:
+ case LM_UNSIGNED_INTERVAL:
+ link = &(*list)->next;
+
+ if (siv->list_mode == LM_SIGNED_INTERVAL) {
+ if (siv->range_next.s < siv->range_limit.s) {
+ ++siv->range_next.s;
+ break;
+ }
+ } else if (siv->range_next.u < siv->range_limit.u) {
+ ++siv->range_next.u;
+ break;
+ }
+ siv->list_mode = LM_END;
+ /* range has been completed, fall through */
+
+ case LM_END:
+ return NULL;
+
+ case LM_IN_PROGRESS:
+ link = &(*list)->next;
+ break;
+
+ default:
+ abort();
+ }
+
+ *link = g_malloc0(sizeof **link);
+ return *link;
+}
+
+static void
+end_list(Visitor *v, Error **errp)
+{
+ StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+
+ assert(siv->list_mode == LM_STARTED ||
+ siv->list_mode == LM_END ||
+ siv->list_mode == LM_IN_PROGRESS ||
+ siv->list_mode == LM_SIGNED_INTERVAL ||
+ siv->list_mode == LM_UNSIGNED_INTERVAL);
+ siv->list_mode = LM_NONE;
+}
+
static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
Error **errp)
{
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
- char *endp = (char *) siv->string;
+ char *str = (char *) siv->string;
long long val;
+ char *endptr;
- errno = 0;
- if (siv->string) {
- val = strtoll(siv->string, &endp, 0);
+ if (siv->list_mode == LM_SIGNED_INTERVAL) {
+ *obj = siv->range_next.s;
+ return;
}
- if (!siv->string || errno || endp == siv->string || *endp) {
+
+ if (!siv->string) {
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"integer");
return;
}
- *obj = val;
+ errno = 0;
+ val = strtoll(siv->string, &endptr, 0);
+
+ if (errno == 0 && endptr > str && INT64_MIN <= val && val <= INT64_MAX) {
+ if (*endptr == '\0') {
+ *obj = val;
+ siv->list_mode = LM_END;
+ return;
+ }
+ if (*endptr == '-' && siv->list_mode == LM_IN_PROGRESS) {
+ long long val2;
+
+ str = endptr + 1;
+ val2 = strtoll(str, &endptr, 0);
+ if (errno == 0 && endptr > str && *endptr == '\0' &&
+ INT64_MIN <= val2 && val2 <= INT64_MAX && val <= val2 &&
+ (val > INT64_MAX - 65536 ||
+ val2 < val + 65536)) {
+ siv->range_next.s = val;
+ siv->range_limit.s = val2;
+ siv->list_mode = LM_SIGNED_INTERVAL;
+
+ /* as if entering on the top */
+ *obj = siv->range_next.s;
+ return;
+ }
+ }
+ }
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, name,
+ (siv->list_mode == LM_NONE) ? "an int64 value" :
+ "an int64 value or range");
}
static void parse_type_size(Visitor *v, uint64_t *obj, const char *name,
@@ -155,6 +300,9 @@ StringInputVisitor *string_input_visitor_new(const char
*str)
v->visitor.type_bool = parse_type_bool;
v->visitor.type_str = parse_type_str;
v->visitor.type_number = parse_type_number;
+ v->visitor.start_list = start_list;
+ v->visitor.next_list = next_list;
+ v->visitor.end_list = end_list;
v->visitor.start_optional = parse_start_optional;
v->string = str;
diff --git a/tests/test-string-input-visitor.c
b/tests/test-string-input-visitor.c
index d406263..31925cb 100644
--- a/tests/test-string-input-visitor.c
+++ b/tests/test-string-input-visitor.c
@@ -64,6 +64,25 @@ static void test_visitor_in_int(TestInputVisitorData *data,
g_assert_cmpint(res, ==, value);
}
+static void test_visitor_in_intList(TestInputVisitorData *data,
+ const void *unused)
+{
+ int64_t value[] = {-2, -1, 0, 1, 2, 3, 4};
+ int16List *res = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+ int i = 0;
+
+ v = visitor_input_test_init(data, "-2-4");
+
+ visit_type_int16List(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ while (res && i < sizeof(value) / sizeof(value[0])) {
+ g_assert_cmpint(res->value, ==, value[i++]);
+ res = res->next;
+ }
+}
+
static void test_visitor_in_bool(TestInputVisitorData *data,
const void *unused)
{
@@ -228,6 +247,8 @@ int main(int argc, char **argv)
input_visitor_test_add("/string-visitor/input/int",
&in_visitor_data, test_visitor_in_int);
+ input_visitor_test_add("/string-visitor/input/intList",
+ &in_visitor_data, test_visitor_in_intList);
input_visitor_test_add("/string-visitor/input/bool",
&in_visitor_data, test_visitor_in_bool);
input_visitor_test_add("/string-visitor/input/number",
--
1.8.5.2.229.g4448466
- [Qemu-devel] [PATCH v19 00/11] Add support for binding guest numa nodes to host numa nodes, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 05/11] numa: add -numa node, memdev= option, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 11/11] hmp: add info memdev, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 02/11] add memdev backend infrastructure, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 01/11] object_add: allow completion handler to get canonical path, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 08/11] Add Linux libnuma detection, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 03/11] pc: pass QEMUMachineInitArgs to pc_memory_init, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 06/11] qapi: make string input visitor parse int list,
Hu Tao <=
- [Qemu-devel] [PATCH v19 09/11] hostmem backend: implement memory policy, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 10/11] qmp: add query-memdev, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 04/11] numa: introduce memory_region_allocate_system_memory, Hu Tao, 2014/03/04
- [Qemu-devel] [PATCH v19 07/11] qapi: make string output visitor parse int list, Hu Tao, 2014/03/04