qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

string-output-visitor.c (10477B)


      1 /*
      2  * String printing Visitor
      3  *
      4  * Copyright Red Hat, Inc. 2012-2016
      5  *
      6  * Author: Paolo Bonzini <pbonzini@redhat.com>
      7  *
      8  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
      9  * See the COPYING.LIB file in the top-level directory.
     10  *
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "qemu/cutils.h"
     15 #include "qapi/string-output-visitor.h"
     16 #include "qapi/visitor-impl.h"
     17 #include <math.h>
     18 #include "qemu/range.h"
     19 
     20 enum ListMode {
     21     LM_NONE,             /* not traversing a list of repeated options */
     22     LM_STARTED,          /* next_list() ready to be called */
     23 
     24     LM_IN_PROGRESS,      /* next_list() has been called.
     25                           *
     26                           * Generating the next list link will consume the most
     27                           * recently parsed QemuOpt instance of the repeated
     28                           * option.
     29                           *
     30                           * Parsing a value into the list link will examine the
     31                           * next QemuOpt instance of the repeated option, and
     32                           * possibly enter LM_SIGNED_INTERVAL or
     33                           * LM_UNSIGNED_INTERVAL.
     34                           */
     35 
     36     LM_SIGNED_INTERVAL,  /* next_list() has been called.
     37                           *
     38                           * Generating the next list link will consume the most
     39                           * recently stored element from the signed interval,
     40                           * parsed from the most recent QemuOpt instance of the
     41                           * repeated option. This may consume QemuOpt itself
     42                           * and return to LM_IN_PROGRESS.
     43                           *
     44                           * Parsing a value into the list link will store the
     45                           * next element of the signed interval.
     46                           */
     47 
     48     LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
     49 
     50     LM_END,              /* next_list() called, about to see last element. */
     51 };
     52 
     53 typedef enum ListMode ListMode;
     54 
     55 struct StringOutputVisitor
     56 {
     57     Visitor visitor;
     58     bool human;
     59     GString *string;
     60     char **result;
     61     ListMode list_mode;
     62     union {
     63         int64_t s;
     64         uint64_t u;
     65     } range_start, range_end;
     66     GList *ranges;
     67     void *list; /* Only needed for sanity checking the caller */
     68 };
     69 
     70 static StringOutputVisitor *to_sov(Visitor *v)
     71 {
     72     return container_of(v, StringOutputVisitor, visitor);
     73 }
     74 
     75 static void string_output_set(StringOutputVisitor *sov, char *string)
     76 {
     77     if (sov->string) {
     78         g_string_free(sov->string, true);
     79     }
     80     sov->string = g_string_new(string);
     81     g_free(string);
     82 }
     83 
     84 static void string_output_append(StringOutputVisitor *sov, int64_t a)
     85 {
     86     Range *r = g_malloc0(sizeof(*r));
     87 
     88     range_set_bounds(r, a, a);
     89     sov->ranges = range_list_insert(sov->ranges, r);
     90 }
     91 
     92 static void string_output_append_range(StringOutputVisitor *sov,
     93                                        int64_t s, int64_t e)
     94 {
     95     Range *r = g_malloc0(sizeof(*r));
     96 
     97     range_set_bounds(r, s, e);
     98     sov->ranges = range_list_insert(sov->ranges, r);
     99 }
    100 
    101 static void format_string(StringOutputVisitor *sov, Range *r, bool next,
    102                           bool human)
    103 {
    104     if (range_lob(r) != range_upb(r)) {
    105         if (human) {
    106             g_string_append_printf(sov->string, "0x%" PRIx64 "-0x%" PRIx64,
    107                                    range_lob(r), range_upb(r));
    108 
    109         } else {
    110             g_string_append_printf(sov->string, "%" PRId64 "-%" PRId64,
    111                                    range_lob(r), range_upb(r));
    112         }
    113     } else {
    114         if (human) {
    115             g_string_append_printf(sov->string, "0x%" PRIx64, range_lob(r));
    116         } else {
    117             g_string_append_printf(sov->string, "%" PRId64, range_lob(r));
    118         }
    119     }
    120     if (next) {
    121         g_string_append(sov->string, ",");
    122     }
    123 }
    124 
    125 static bool print_type_int64(Visitor *v, const char *name, int64_t *obj,
    126                              Error **errp)
    127 {
    128     StringOutputVisitor *sov = to_sov(v);
    129     GList *l;
    130 
    131     switch (sov->list_mode) {
    132     case LM_NONE:
    133         string_output_append(sov, *obj);
    134         break;
    135 
    136     case LM_STARTED:
    137         sov->range_start.s = *obj;
    138         sov->range_end.s = *obj;
    139         sov->list_mode = LM_IN_PROGRESS;
    140         return true;
    141 
    142     case LM_IN_PROGRESS:
    143         if (sov->range_end.s + 1 == *obj) {
    144             sov->range_end.s++;
    145         } else {
    146             if (sov->range_start.s == sov->range_end.s) {
    147                 string_output_append(sov, sov->range_end.s);
    148             } else {
    149                 assert(sov->range_start.s < sov->range_end.s);
    150                 string_output_append_range(sov, sov->range_start.s,
    151                                            sov->range_end.s);
    152             }
    153 
    154             sov->range_start.s = *obj;
    155             sov->range_end.s = *obj;
    156         }
    157         return true;
    158 
    159     case LM_END:
    160         if (sov->range_end.s + 1 == *obj) {
    161             sov->range_end.s++;
    162             assert(sov->range_start.s < sov->range_end.s);
    163             string_output_append_range(sov, sov->range_start.s,
    164                                        sov->range_end.s);
    165         } else {
    166             if (sov->range_start.s == sov->range_end.s) {
    167                 string_output_append(sov, sov->range_end.s);
    168             } else {
    169                 assert(sov->range_start.s < sov->range_end.s);
    170 
    171                 string_output_append_range(sov, sov->range_start.s,
    172                                            sov->range_end.s);
    173             }
    174             string_output_append(sov, *obj);
    175         }
    176         break;
    177 
    178     default:
    179         abort();
    180     }
    181 
    182     l = sov->ranges;
    183     while (l) {
    184         Range *r = l->data;
    185         format_string(sov, r, l->next != NULL, false);
    186         l = l->next;
    187     }
    188 
    189     if (sov->human) {
    190         l = sov->ranges;
    191         g_string_append(sov->string, " (");
    192         while (l) {
    193             Range *r = l->data;
    194             format_string(sov, r, l->next != NULL, true);
    195             l = l->next;
    196         }
    197         g_string_append(sov->string, ")");
    198     }
    199 
    200     return true;
    201 }
    202 
    203 static bool print_type_uint64(Visitor *v, const char *name, uint64_t *obj,
    204                              Error **errp)
    205 {
    206     /* FIXME: print_type_int64 mishandles values over INT64_MAX */
    207     int64_t i = *obj;
    208     return print_type_int64(v, name, &i, errp);
    209 }
    210 
    211 static bool print_type_size(Visitor *v, const char *name, uint64_t *obj,
    212                             Error **errp)
    213 {
    214     StringOutputVisitor *sov = to_sov(v);
    215     uint64_t val;
    216     char *out, *psize;
    217 
    218     if (!sov->human) {
    219         out = g_strdup_printf("%"PRIu64, *obj);
    220         string_output_set(sov, out);
    221         return true;
    222     }
    223 
    224     val = *obj;
    225     psize = size_to_str(val);
    226     out = g_strdup_printf("%"PRIu64" (%s)", val, psize);
    227     string_output_set(sov, out);
    228 
    229     g_free(psize);
    230     return true;
    231 }
    232 
    233 static bool print_type_bool(Visitor *v, const char *name, bool *obj,
    234                             Error **errp)
    235 {
    236     StringOutputVisitor *sov = to_sov(v);
    237     string_output_set(sov, g_strdup(*obj ? "true" : "false"));
    238     return true;
    239 }
    240 
    241 static bool print_type_str(Visitor *v, const char *name, char **obj,
    242                            Error **errp)
    243 {
    244     StringOutputVisitor *sov = to_sov(v);
    245     char *out;
    246 
    247     if (sov->human) {
    248         out = *obj ? g_strdup_printf("\"%s\"", *obj) : g_strdup("<null>");
    249     } else {
    250         out = g_strdup(*obj ? *obj : "");
    251     }
    252     string_output_set(sov, out);
    253     return true;
    254 }
    255 
    256 static bool print_type_number(Visitor *v, const char *name, double *obj,
    257                               Error **errp)
    258 {
    259     StringOutputVisitor *sov = to_sov(v);
    260     string_output_set(sov, g_strdup_printf("%.17g", *obj));
    261     return true;
    262 }
    263 
    264 static bool print_type_null(Visitor *v, const char *name, QNull **obj,
    265                             Error **errp)
    266 {
    267     StringOutputVisitor *sov = to_sov(v);
    268     char *out;
    269 
    270     if (sov->human) {
    271         out = g_strdup("<null>");
    272     } else {
    273         out = g_strdup("");
    274     }
    275     string_output_set(sov, out);
    276     return true;
    277 }
    278 
    279 static bool
    280 start_list(Visitor *v, const char *name, GenericList **list, size_t size,
    281            Error **errp)
    282 {
    283     StringOutputVisitor *sov = to_sov(v);
    284 
    285     /* we can't traverse a list in a list */
    286     assert(sov->list_mode == LM_NONE);
    287     /* We don't support visits without a list */
    288     assert(list);
    289     sov->list = list;
    290     /* List handling is only needed if there are at least two elements */
    291     if (*list && (*list)->next) {
    292         sov->list_mode = LM_STARTED;
    293     }
    294     return true;
    295 }
    296 
    297 static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
    298 {
    299     StringOutputVisitor *sov = to_sov(v);
    300     GenericList *ret = tail->next;
    301 
    302     if (ret && !ret->next) {
    303         sov->list_mode = LM_END;
    304     }
    305     return ret;
    306 }
    307 
    308 static void end_list(Visitor *v, void **obj)
    309 {
    310     StringOutputVisitor *sov = to_sov(v);
    311 
    312     assert(sov->list == obj);
    313     assert(sov->list_mode == LM_STARTED ||
    314            sov->list_mode == LM_END ||
    315            sov->list_mode == LM_NONE ||
    316            sov->list_mode == LM_IN_PROGRESS);
    317     sov->list_mode = LM_NONE;
    318 }
    319 
    320 static void string_output_complete(Visitor *v, void *opaque)
    321 {
    322     StringOutputVisitor *sov = to_sov(v);
    323 
    324     assert(opaque == sov->result);
    325     *sov->result = g_string_free(sov->string, false);
    326     sov->string = NULL;
    327 }
    328 
    329 static void free_range(void *range, void *dummy)
    330 {
    331     g_free(range);
    332 }
    333 
    334 static void string_output_free(Visitor *v)
    335 {
    336     StringOutputVisitor *sov = to_sov(v);
    337 
    338     if (sov->string) {
    339         g_string_free(sov->string, true);
    340     }
    341 
    342     g_list_foreach(sov->ranges, free_range, NULL);
    343     g_list_free(sov->ranges);
    344     g_free(sov);
    345 }
    346 
    347 Visitor *string_output_visitor_new(bool human, char **result)
    348 {
    349     StringOutputVisitor *v;
    350 
    351     v = g_malloc0(sizeof(*v));
    352 
    353     v->string = g_string_new(NULL);
    354     v->human = human;
    355     v->result = result;
    356     *result = NULL;
    357 
    358     v->visitor.type = VISITOR_OUTPUT;
    359     v->visitor.type_int64 = print_type_int64;
    360     v->visitor.type_uint64 = print_type_uint64;
    361     v->visitor.type_size = print_type_size;
    362     v->visitor.type_bool = print_type_bool;
    363     v->visitor.type_str = print_type_str;
    364     v->visitor.type_number = print_type_number;
    365     v->visitor.type_null = print_type_null;
    366     v->visitor.start_list = start_list;
    367     v->visitor.next_list = next_list;
    368     v->visitor.end_list = end_list;
    369     v->visitor.complete = string_output_complete;
    370     v->visitor.free = string_output_free;
    371 
    372     return &v->visitor;
    373 }