|
@@ -15,31 +15,205 @@
|
|
#include "qapi/visitor-impl.h"
|
|
#include "qapi/visitor-impl.h"
|
|
#include "qapi/qmp/qerror.h"
|
|
#include "qapi/qmp/qerror.h"
|
|
#include "qemu/option.h"
|
|
#include "qemu/option.h"
|
|
|
|
+#include "qemu/queue.h"
|
|
|
|
+#include "qemu/range.h"
|
|
|
|
+
|
|
|
|
|
|
struct StringInputVisitor
|
|
struct StringInputVisitor
|
|
{
|
|
{
|
|
Visitor visitor;
|
|
Visitor visitor;
|
|
|
|
+
|
|
|
|
+ bool head;
|
|
|
|
+
|
|
|
|
+ GList *ranges;
|
|
|
|
+ GList *cur_range;
|
|
|
|
+ int64_t cur;
|
|
|
|
+
|
|
const char *string;
|
|
const char *string;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static void parse_str(StringInputVisitor *siv, Error **errp)
|
|
|
|
+{
|
|
|
|
+ char *str = (char *) siv->string;
|
|
|
|
+ long long start, end;
|
|
|
|
+ Range *cur;
|
|
|
|
+ char *endptr;
|
|
|
|
+
|
|
|
|
+ if (siv->ranges) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ errno = 0;
|
|
|
|
+ do {
|
|
|
|
+ start = strtoll(str, &endptr, 0);
|
|
|
|
+ if (errno == 0 && endptr > str && INT64_MIN <= start &&
|
|
|
|
+ start <= INT64_MAX) {
|
|
|
|
+ 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);
|
|
|
|
+ cur = NULL;
|
|
|
|
+ str = NULL;
|
|
|
|
+ } else if (*endptr == '-') {
|
|
|
|
+ str = endptr + 1;
|
|
|
|
+ end = strtoll(str, &endptr, 0);
|
|
|
|
+ if (errno == 0 && endptr > str &&
|
|
|
|
+ INT64_MIN <= end && end <= INT64_MAX && start <= end &&
|
|
|
|
+ (start > INT64_MAX - 65536 ||
|
|
|
|
+ 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);
|
|
|
|
+ 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);
|
|
|
|
+ cur = NULL;
|
|
|
|
+ } else {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+ } 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);
|
|
|
|
+ cur = NULL;
|
|
|
|
+ } else {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+ } while (str);
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
+error:
|
|
|
|
+ g_list_free_full(siv->ranges, g_free);
|
|
|
|
+ assert(siv->ranges == NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+start_list(Visitor *v, const char *name, Error **errp)
|
|
|
|
+{
|
|
|
|
+ StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
|
|
|
+
|
|
|
|
+ parse_str(siv, errp);
|
|
|
|
+
|
|
|
|
+ siv->cur_range = g_list_first(siv->ranges);
|
|
|
|
+ if (siv->cur_range) {
|
|
|
|
+ Range *r = siv->cur_range->data;
|
|
|
|
+ if (r) {
|
|
|
|
+ siv->cur = r->begin;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static GenericList *
|
|
|
|
+next_list(Visitor *v, GenericList **list, Error **errp)
|
|
|
|
+{
|
|
|
|
+ StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
|
|
|
+ GenericList **link;
|
|
|
|
+ Range *r;
|
|
|
|
+
|
|
|
|
+ if (!siv->ranges || !siv->cur_range) {
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ r = siv->cur_range->data;
|
|
|
|
+ if (!r) {
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (siv->cur < r->begin || siv->cur >= r->end) {
|
|
|
|
+ siv->cur_range = g_list_next(siv->cur_range);
|
|
|
|
+ if (!siv->cur_range) {
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ r = siv->cur_range->data;
|
|
|
|
+ if (!r) {
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ siv->cur = r->begin;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (siv->head) {
|
|
|
|
+ link = list;
|
|
|
|
+ siv->head = false;
|
|
|
|
+ } else {
|
|
|
|
+ link = &(*list)->next;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *link = g_malloc0(sizeof **link);
|
|
|
|
+ return *link;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+end_list(Visitor *v, Error **errp)
|
|
|
|
+{
|
|
|
|
+ StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
|
|
|
+ siv->head = true;
|
|
|
|
+}
|
|
|
|
+
|
|
static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
|
|
static void parse_type_int(Visitor *v, int64_t *obj, const char *name,
|
|
Error **errp)
|
|
Error **errp)
|
|
{
|
|
{
|
|
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
|
StringInputVisitor *siv = DO_UPCAST(StringInputVisitor, visitor, v);
|
|
- char *endp = (char *) siv->string;
|
|
|
|
- long long val;
|
|
|
|
|
|
|
|
- errno = 0;
|
|
|
|
- if (siv->string) {
|
|
|
|
- val = strtoll(siv->string, &endp, 0);
|
|
|
|
- }
|
|
|
|
- if (!siv->string || errno || endp == siv->string || *endp) {
|
|
|
|
|
|
+ if (!siv->string) {
|
|
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
|
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
|
"integer");
|
|
"integer");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- *obj = val;
|
|
|
|
|
|
+ parse_str(siv, errp);
|
|
|
|
+
|
|
|
|
+ if (!siv->ranges) {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!siv->cur_range) {
|
|
|
|
+ Range *r;
|
|
|
|
+
|
|
|
|
+ siv->cur_range = g_list_first(siv->ranges);
|
|
|
|
+ if (!siv->cur_range) {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ r = siv->cur_range->data;
|
|
|
|
+ if (!r) {
|
|
|
|
+ goto error;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ siv->cur = r->begin;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *obj = siv->cur;
|
|
|
|
+ siv->cur++;
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+error:
|
|
|
|
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, name,
|
|
|
|
+ "an int64 value or range");
|
|
}
|
|
}
|
|
|
|
|
|
static void parse_type_size(Visitor *v, uint64_t *obj, const char *name,
|
|
static void parse_type_size(Visitor *v, uint64_t *obj, const char *name,
|
|
@@ -140,6 +314,7 @@ Visitor *string_input_get_visitor(StringInputVisitor *v)
|
|
|
|
|
|
void string_input_visitor_cleanup(StringInputVisitor *v)
|
|
void string_input_visitor_cleanup(StringInputVisitor *v)
|
|
{
|
|
{
|
|
|
|
+ g_list_free_full(v->ranges, g_free);
|
|
g_free(v);
|
|
g_free(v);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -155,8 +330,12 @@ StringInputVisitor *string_input_visitor_new(const char *str)
|
|
v->visitor.type_bool = parse_type_bool;
|
|
v->visitor.type_bool = parse_type_bool;
|
|
v->visitor.type_str = parse_type_str;
|
|
v->visitor.type_str = parse_type_str;
|
|
v->visitor.type_number = parse_type_number;
|
|
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.optional = parse_optional;
|
|
v->visitor.optional = parse_optional;
|
|
|
|
|
|
v->string = str;
|
|
v->string = str;
|
|
|
|
+ v->head = true;
|
|
return v;
|
|
return v;
|
|
}
|
|
}
|