From: Hu Tao <hu.t...@gmail.com> Signed-off-by: Hu Tao <hu...@cn.fujitsu.com> --- qapi/string-output-visitor.c | 156 +++++++++++++++++++++++++++++++++++-- tests/test-string-output-visitor.c | 26 +++++++ 2 files changed, 177 insertions(+), 5 deletions(-)
diff --git a/qapi/string-output-visitor.c b/qapi/string-output-visitor.c index fb1d2e8..bc9bb36 100644 --- a/qapi/string-output-visitor.c +++ b/qapi/string-output-visitor.c @@ -17,11 +17,57 @@ #include "qemu/host-utils.h" #include <math.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 StringOutputVisitor { Visitor visitor; bool human; + bool head; char *string; + 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_start, range_end; + }; static void string_output_set(StringOutputVisitor *sov, char *string) @@ -34,13 +80,60 @@ static void print_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) { StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); - char *out; + char *out = NULL; - if (sov->human) { - out = g_strdup_printf("%lld (%#llx)", (long long) *obj, (long long) *obj); - } else { - out = g_strdup_printf("%lld", (long long) *obj); + switch (sov->list_mode) { + case LM_NONE: + if (sov->human) { + out = g_strdup_printf("%lld (%#llx)", (long long) *obj, + (long long) *obj); + } else { + out = g_strdup_printf("%lld", (long long) *obj); + } + sov->list_mode = LM_END; + break; + + case LM_STARTED: + sov->range_start.s = *obj; + sov->range_end.s = *obj; + sov->list_mode = LM_IN_PROGRESS; + break; + + case LM_IN_PROGRESS: + assert(sov->range_end.s + 1 == *obj); + sov->range_end.s++; + break; + + case LM_END: + assert(sov->range_end.s + 1 == *obj); + sov->range_end.s++; + if (sov->range_end.s == sov->range_start.s) { + if (sov->human) { + out = g_strdup_printf("%lld (%#llx)", + (long long)sov->range_start.s, + (long long)sov->range_start.s); + } else { + out = g_strdup_printf("%lld", (long long)sov->range_start.s); + } + } else { + if (sov->human) { + out = g_strdup_printf("%lld(%#llx)-%lld(%#llx)", + (long long) sov->range_start.s, + (long long) sov->range_start.s, + (long long) sov->range_end.s, + (long long) sov->range_end.s); + } else { + out = g_strdup_printf("%lld-%lld", + (long long) sov->range_start.s, + (long long) sov->range_end.s); + } + } + break; + + default: + abort(); } + string_output_set(sov, out); } @@ -103,6 +196,56 @@ static void print_type_number(Visitor *v, double *obj, const char *name, string_output_set(sov, g_strdup_printf("%f", *obj)); } +static void +start_list(Visitor *v, const char *name, Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + + /* we can't traverse a list in a list */ + assert(sov->list_mode == LM_NONE); + sov->list_mode = LM_STARTED; + sov->head = true; +} + +static GenericList * +next_list(Visitor *v, GenericList **list, Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + GenericList *ret = NULL; + if (*list) { + if (sov->head) { + ret = *list; + } else { + ret = (*list)->next; + } + + if (sov->head) { + if (ret && ret->next == NULL) { + sov->list_mode = LM_NONE; + } + sov->head = false; + } else { + if (ret && ret->next == NULL) { + sov->list_mode = LM_END; + } + } + } + + return ret; +} + +static void +end_list(Visitor *v, Error **errp) +{ + StringOutputVisitor *sov = DO_UPCAST(StringOutputVisitor, visitor, v); + + assert(sov->list_mode == LM_STARTED || + sov->list_mode == LM_END || + sov->list_mode == LM_IN_PROGRESS); + sov->list_mode = LM_NONE; + sov->head = true; +} + char *string_output_get_string(StringOutputVisitor *sov) { char *string = sov->string; @@ -134,6 +277,9 @@ StringOutputVisitor *string_output_visitor_new(bool human) v->visitor.type_bool = print_type_bool; v->visitor.type_str = print_type_str; v->visitor.type_number = print_type_number; + v->visitor.start_list = start_list; + v->visitor.next_list = next_list; + v->visitor.end_list = end_list; return v; } diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c index 22363d1..511ef14 100644 --- a/tests/test-string-output-visitor.c +++ b/tests/test-string-output-visitor.c @@ -57,6 +57,30 @@ static void test_visitor_out_int(TestOutputVisitorData *data, g_free(str); } +static void test_visitor_out_intList(TestOutputVisitorData *data, + const void *unused) +{ + int64_t value[] = {-2, -1, 0, 1, 2, 3, 4}; + intList *list = NULL, **tmp = &list; + int i; + Error *errp = NULL; + char *str; + + for (i = 0; i < sizeof(value) / sizeof(value[0]); i++) { + *tmp = g_malloc0(sizeof(**tmp)); + (*tmp)->value = value[i]; + tmp = &(*tmp)->next; + } + + visit_type_intList(data->ov, &list, NULL, &errp); + g_assert(error_is_set(&errp) == 0); + + str = string_output_get_string(data->sov); + g_assert(str != NULL); + g_assert_cmpstr(str, ==, "-2-4"); + g_free(str); +} + static void test_visitor_out_bool(TestOutputVisitorData *data, const void *unused) { @@ -182,6 +206,8 @@ int main(int argc, char **argv) &out_visitor_data, test_visitor_out_enum); output_visitor_test_add("/string-visitor/output/enum-errors", &out_visitor_data, test_visitor_out_enum_errors); + output_visitor_test_add("/string-visitor/output/intList", + &out_visitor_data, test_visitor_out_intList); g_test_run(); -- 1.8.5.2.229.g4448466