Loading qapi/string-input-visitor.c +187 −8 Original line number Diff line number Diff line Loading @@ -15,31 +15,205 @@ #include "qapi/visitor-impl.h" #include "qapi/qmp/qerror.h" #include "qemu/option.h" #include "qemu/queue.h" #include "qemu/range.h" struct StringInputVisitor { Visitor visitor; bool head; GList *ranges; GList *cur_range; int64_t cur; 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, Error **errp) { 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", "integer"); 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, Loading Loading @@ -140,6 +314,7 @@ Visitor *string_input_get_visitor(StringInputVisitor *v) void string_input_visitor_cleanup(StringInputVisitor *v) { g_list_free_full(v->ranges, g_free); g_free(v); } Loading @@ -155,8 +330,12 @@ 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.optional = parse_optional; v->string = str; v->head = true; return v; } tests/test-string-input-visitor.c +36 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,35 @@ 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[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20}; int16List *res = NULL, *tmp; Error *errp = NULL; Visitor *v; int i = 0; v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8"); visit_type_int16List(v, &res, NULL, &errp); g_assert(errp == NULL); tmp = res; while (i < sizeof(value) / sizeof(value[0])) { g_assert(tmp); g_assert_cmpint(tmp->value, ==, value[i++]); tmp = tmp->next; } g_assert(!tmp); tmp = res; while (tmp) { res = res->next; g_free(tmp); tmp = res; } } static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { Loading Loading @@ -170,6 +199,7 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, const void *unused) { int64_t ires; intList *ilres; bool bres; double nres; char *sres; Loading @@ -195,6 +225,10 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, visit_type_int(v, &ires, NULL, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); visit_type_intList(v, &ilres, NULL, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); visit_type_bool(v, &bres, NULL, NULL); visitor_input_teardown(data, NULL); Loading Loading @@ -231,6 +265,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", Loading Loading
qapi/string-input-visitor.c +187 −8 Original line number Diff line number Diff line Loading @@ -15,31 +15,205 @@ #include "qapi/visitor-impl.h" #include "qapi/qmp/qerror.h" #include "qemu/option.h" #include "qemu/queue.h" #include "qemu/range.h" struct StringInputVisitor { Visitor visitor; bool head; GList *ranges; GList *cur_range; int64_t cur; 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, Error **errp) { 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", "integer"); 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, Loading Loading @@ -140,6 +314,7 @@ Visitor *string_input_get_visitor(StringInputVisitor *v) void string_input_visitor_cleanup(StringInputVisitor *v) { g_list_free_full(v->ranges, g_free); g_free(v); } Loading @@ -155,8 +330,12 @@ 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.optional = parse_optional; v->string = str; v->head = true; return v; }
tests/test-string-input-visitor.c +36 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,35 @@ 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[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20}; int16List *res = NULL, *tmp; Error *errp = NULL; Visitor *v; int i = 0; v = visitor_input_test_init(data, "1,2,0,2-4,20,5-9,1-8"); visit_type_int16List(v, &res, NULL, &errp); g_assert(errp == NULL); tmp = res; while (i < sizeof(value) / sizeof(value[0])) { g_assert(tmp); g_assert_cmpint(tmp->value, ==, value[i++]); tmp = tmp->next; } g_assert(!tmp); tmp = res; while (tmp) { res = res->next; g_free(tmp); tmp = res; } } static void test_visitor_in_bool(TestInputVisitorData *data, const void *unused) { Loading Loading @@ -170,6 +199,7 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, const void *unused) { int64_t ires; intList *ilres; bool bres; double nres; char *sres; Loading @@ -195,6 +225,10 @@ static void test_visitor_in_fuzz(TestInputVisitorData *data, visit_type_int(v, &ires, NULL, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); visit_type_intList(v, &ilres, NULL, NULL); visitor_input_teardown(data, NULL); v = visitor_input_test_init(data, buf); visit_type_bool(v, &bres, NULL, NULL); visitor_input_teardown(data, NULL); Loading Loading @@ -231,6 +265,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", Loading