/*
* String parsing visitor
*
- * Copyright Red Hat, Inc. 2012
+ * Copyright Red Hat, Inc. 2012-2016
*
*
*
*/
+#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "qemu-common.h"
#include "qapi/string-input-visitor.h"
#include "qapi/visitor-impl.h"
{
Visitor visitor;
- bool head;
-
GList *ranges;
GList *cur_range;
int64_t cur;
const char *string;
+ void *list; /* Only needed for sanity checking the caller */
};
+static StringInputVisitor *to_siv(Visitor *v)
+{
+ return container_of(v, StringInputVisitor, visitor);
+}
+
static void free_range(void *range, void *dummy)
{
g_free(range);
}
-static void parse_str(StringInputVisitor *siv, Error **errp)
+static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
{
char *str = (char *) siv->string;
long long start, end;
char *endptr;
if (siv->ranges) {
- return;
+ return 0;
+ }
+
+ if (!*str) {
+ return 0;
}
do {
if (errno == 0 && endptr > str) {
if (*endptr == '\0') {
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = start + 1;
- siv->ranges = g_list_insert_sorted_merged(siv->ranges, cur,
- range_compare);
+ range_set_bounds(cur, start, start);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
str = NULL;
} else if (*endptr == '-') {
end < start + 65536)) {
if (*endptr == '\0') {
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = end + 1;
- siv->ranges =
- g_list_insert_sorted_merged(siv->ranges,
- cur,
- range_compare);
+ range_set_bounds(cur, start, end);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
str = NULL;
} else if (*endptr == ',') {
str = endptr + 1;
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = end + 1;
- siv->ranges =
- g_list_insert_sorted_merged(siv->ranges,
- cur,
- range_compare);
+ range_set_bounds(cur, start, end);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
} else {
goto error;
} else if (*endptr == ',') {
str = endptr + 1;
cur = g_malloc0(sizeof(*cur));
- cur->begin = start;
- cur->end = start + 1;
- siv->ranges = g_list_insert_sorted_merged(siv->ranges,
- cur,
- range_compare);
+ range_set_bounds(cur, start, start);
+ siv->ranges = range_list_insert(siv->ranges, cur);
cur = NULL;
} else {
goto error;
}
} while (str);
- return;
+ return 0;
error:
g_list_foreach(siv->ranges, free_range, NULL);
g_list_free(siv->ranges);
siv->ranges = NULL;
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
+ "an int64 value or range");
+ return -1;
}
static void
-start_list(Visitor *v, const char *name, Error **errp)
+start_list(Visitor *v, const char *name, GenericList **list, size_t size,
+ Error **errp)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+ StringInputVisitor *siv = to_siv(v);
- parse_str(siv, errp);
+ /* We don't support visits without a list */
+ assert(list);
+ siv->list = list;
+
+ if (parse_str(siv, name, errp) < 0) {
+ *list = NULL;
+ return;
+ }
siv->cur_range = g_list_first(siv->ranges);
if (siv->cur_range) {
Range *r = siv->cur_range->data;
if (r) {
- siv->cur = r->begin;
+ siv->cur = range_lob(r);
}
+ *list = g_malloc0(size);
+ } else {
+ *list = NULL;
}
}
-static GenericList *
-next_list(Visitor *v, GenericList **list, Error **errp)
+static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
- GenericList **link;
+ StringInputVisitor *siv = to_siv(v);
Range *r;
if (!siv->ranges || !siv->cur_range) {
return NULL;
}
- if (siv->cur < r->begin || siv->cur >= r->end) {
+ if (!range_contains(r, siv->cur)) {
siv->cur_range = g_list_next(siv->cur_range);
if (!siv->cur_range) {
return NULL;
if (!r) {
return NULL;
}
- siv->cur = r->begin;
+ siv->cur = range_lob(r);
}
- if (siv->head) {
- link = list;
- siv->head = false;
- } else {
- link = &(*list)->next;
+ tail->next = g_malloc0(size);
+ return tail->next;
+}
+
+static void check_list(Visitor *v, Error **errp)
+{
+ const StringInputVisitor *siv = to_siv(v);
+ Range *r;
+ GList *cur_range;
+
+ if (!siv->ranges || !siv->cur_range) {
+ return;
+ }
+
+ r = siv->cur_range->data;
+ if (!r) {
+ return;
+ }
+
+ if (!range_contains(r, siv->cur)) {
+ cur_range = g_list_next(siv->cur_range);
+ if (!cur_range) {
+ return;
+ }
+ r = cur_range->data;
+ if (!r) {
+ return;
+ }
}
- *link = g_malloc0(sizeof **link);
- return *link;
+ error_setg(errp, "Range contains too many values");
}
-static void
-end_list(Visitor *v, Error **errp)
+static void end_list(Visitor *v, void **obj)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
- siv->head = true;
+ StringInputVisitor *siv = to_siv(v);
+
+ assert(siv->list == obj);
}
-static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
- Error **errp)
+static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
+ Error **errp)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+ StringInputVisitor *siv = to_siv(v);
- if (!siv->string) {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
- "integer");
+ if (parse_str(siv, name, errp) < 0) {
return;
}
- parse_str(siv, errp);
-
if (!siv->ranges) {
goto error;
}
goto error;
}
- siv->cur = r->begin;
+ siv->cur = range_lob(r);
}
*obj = siv->cur;
return;
error:
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
"an int64 value or range");
}
-static void parse_type_size(Visitor *v, uint64_t *obj, const char *name,
+static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
+ Error **errp)
+{
+ /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
+ int64_t i;
+ Error *err = NULL;
+ parse_type_int64(v, name, &i, &err);
+ if (err) {
+ error_propagate(errp, err);
+ } else {
+ *obj = i;
+ }
+}
+
+static void parse_type_size(Visitor *v, const char *name, uint64_t *obj,
Error **errp)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+ StringInputVisitor *siv = to_siv(v);
Error *err = NULL;
uint64_t val;
- if (siv->string) {
- parse_option_size(name, siv->string, &val, &err);
- } else {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
- "size");
- return;
- }
+ parse_option_size(name, siv->string, &val, &err);
if (err) {
error_propagate(errp, err);
return;
*obj = val;
}
-static void parse_type_bool(Visitor *v, bool *obj, const char *name,
+static void parse_type_bool(Visitor *v, const char *name, bool *obj,
Error **errp)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+ StringInputVisitor *siv = to_siv(v);
- if (siv->string) {
- if (!strcasecmp(siv->string, "on") ||
- !strcasecmp(siv->string, "yes") ||
- !strcasecmp(siv->string, "true")) {
- *obj = true;
- return;
- }
- if (!strcasecmp(siv->string, "off") ||
- !strcasecmp(siv->string, "no") ||
- !strcasecmp(siv->string, "false")) {
- *obj = false;
- return;
- }
+ if (!strcasecmp(siv->string, "on") ||
+ !strcasecmp(siv->string, "yes") ||
+ !strcasecmp(siv->string, "true")) {
+ *obj = true;
+ return;
+ }
+ if (!strcasecmp(siv->string, "off") ||
+ !strcasecmp(siv->string, "no") ||
+ !strcasecmp(siv->string, "false")) {
+ *obj = false;
+ return;
}
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"boolean");
}
-static void parse_type_str(Visitor *v, char **obj, const char *name,
+static void parse_type_str(Visitor *v, const char *name, char **obj,
Error **errp)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
- if (siv->string) {
- *obj = g_strdup(siv->string);
- } else {
- error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
- "string");
- }
+ StringInputVisitor *siv = to_siv(v);
+
+ *obj = g_strdup(siv->string);
}
-static void parse_type_number(Visitor *v, double *obj, const char *name,
+static void parse_type_number(Visitor *v, const char *name, double *obj,
Error **errp)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+ StringInputVisitor *siv = to_siv(v);
char *endp = (char *) siv->string;
double val;
errno = 0;
- if (siv->string) {
- val = strtod(siv->string, &endp);
- }
- if (!siv->string || errno || endp == siv->string || *endp) {
+ val = strtod(siv->string, &endp);
+ if (errno || endp == siv->string || *endp) {
error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
"number");
return;
*obj = val;
}
-static void parse_optional(Visitor *v, bool *present, const char *name,
- Error **errp)
+static void parse_type_null(Visitor *v, const char *name, Error **errp)
{
- StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
+ StringInputVisitor *siv = to_siv(v);
- if (!siv->string) {
- *present = false;
- return;
+ if (!siv->string || siv->string[0]) {
+ error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
+ "null");
}
-
- *present = true;
}
-Visitor *string_input_get_visitor(StringInputVisitor *v)
+static void string_input_free(Visitor *v)
{
- return &v->visitor;
-}
+ StringInputVisitor *siv = to_siv(v);
-void string_input_visitor_cleanup(StringInputVisitor *v)
-{
- g_list_foreach(v->ranges, free_range, NULL);
- g_list_free(v->ranges);
- g_free(v);
+ g_list_foreach(siv->ranges, free_range, NULL);
+ g_list_free(siv->ranges);
+ g_free(siv);
}
-StringInputVisitor *string_input_visitor_new(const char *str)
+Visitor *string_input_visitor_new(const char *str)
{
StringInputVisitor *v;
+ assert(str);
v = g_malloc0(sizeof(*v));
- v->visitor.type_enum = input_type_enum;
- v->visitor.type_int = parse_type_int;
+ v->visitor.type = VISITOR_INPUT;
+ v->visitor.type_int64 = parse_type_int64;
+ v->visitor.type_uint64 = parse_type_uint64;
v->visitor.type_size = parse_type_size;
v->visitor.type_bool = parse_type_bool;
v->visitor.type_str = parse_type_str;
v->visitor.type_number = parse_type_number;
+ v->visitor.type_null = parse_type_null;
v->visitor.start_list = start_list;
v->visitor.next_list = next_list;
+ v->visitor.check_list = check_list;
v->visitor.end_list = end_list;
- v->visitor.optional = parse_optional;
+ v->visitor.free = string_input_free;
v->string = str;
- v->head = true;
- return v;
+ return &v->visitor;
}