xref: /openbmc/qemu/qapi/string-output-visitor.c (revision 014b99a8)
1a020f980SPaolo Bonzini /*
2a020f980SPaolo Bonzini  * String printing Visitor
3a020f980SPaolo Bonzini  *
408f9541dSEric Blake  * Copyright Red Hat, Inc. 2012-2016
5a020f980SPaolo Bonzini  *
6a020f980SPaolo Bonzini  * Author: Paolo Bonzini <pbonzini@redhat.com>
7a020f980SPaolo Bonzini  *
8a020f980SPaolo Bonzini  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
9a020f980SPaolo Bonzini  * See the COPYING.LIB file in the top-level directory.
10a020f980SPaolo Bonzini  *
11a020f980SPaolo Bonzini  */
12a020f980SPaolo Bonzini 
13cbf21151SPeter Maydell #include "qemu/osdep.h"
1431e40415SPhilippe Mathieu-Daudé #include "qemu/cutils.h"
157b1b5d19SPaolo Bonzini #include "qapi/string-output-visitor.h"
167b1b5d19SPaolo Bonzini #include "qapi/visitor-impl.h"
17e41b509dSPaolo Bonzini #include <math.h>
1869e25563SHu Tao #include "qemu/range.h"
1969e25563SHu Tao 
2069e25563SHu Tao enum ListMode {
2169e25563SHu Tao     LM_NONE,             /* not traversing a list of repeated options */
22d9f62ddeSEric Blake     LM_STARTED,          /* next_list() ready to be called */
2369e25563SHu Tao 
2469e25563SHu Tao     LM_IN_PROGRESS,      /* next_list() has been called.
2569e25563SHu Tao                           *
2669e25563SHu Tao                           * Generating the next list link will consume the most
2769e25563SHu Tao                           * recently parsed QemuOpt instance of the repeated
2869e25563SHu Tao                           * option.
2969e25563SHu Tao                           *
3069e25563SHu Tao                           * Parsing a value into the list link will examine the
3169e25563SHu Tao                           * next QemuOpt instance of the repeated option, and
3269e25563SHu Tao                           * possibly enter LM_SIGNED_INTERVAL or
3369e25563SHu Tao                           * LM_UNSIGNED_INTERVAL.
3469e25563SHu Tao                           */
3569e25563SHu Tao 
3669e25563SHu Tao     LM_SIGNED_INTERVAL,  /* next_list() has been called.
3769e25563SHu Tao                           *
3869e25563SHu Tao                           * Generating the next list link will consume the most
3969e25563SHu Tao                           * recently stored element from the signed interval,
4069e25563SHu Tao                           * parsed from the most recent QemuOpt instance of the
4169e25563SHu Tao                           * repeated option. This may consume QemuOpt itself
4269e25563SHu Tao                           * and return to LM_IN_PROGRESS.
4369e25563SHu Tao                           *
4469e25563SHu Tao                           * Parsing a value into the list link will store the
4569e25563SHu Tao                           * next element of the signed interval.
4669e25563SHu Tao                           */
4769e25563SHu Tao 
4869e25563SHu Tao     LM_UNSIGNED_INTERVAL,/* Same as above, only for an unsigned interval. */
4969e25563SHu Tao 
50d9f62ddeSEric Blake     LM_END,              /* next_list() called, about to see last element. */
5169e25563SHu Tao };
5269e25563SHu Tao 
5369e25563SHu Tao typedef enum ListMode ListMode;
54a020f980SPaolo Bonzini 
55a020f980SPaolo Bonzini struct StringOutputVisitor
56a020f980SPaolo Bonzini {
57a020f980SPaolo Bonzini     Visitor visitor;
580b7593e0SPaolo Bonzini     bool human;
5969e25563SHu Tao     GString *string;
603b098d56SEric Blake     char **result;
6169e25563SHu Tao     ListMode list_mode;
6269e25563SHu Tao     union {
6369e25563SHu Tao         int64_t s;
6469e25563SHu Tao         uint64_t u;
6569e25563SHu Tao     } range_start, range_end;
6669e25563SHu Tao     GList *ranges;
671158bb2aSEric Blake     void *list; /* Only needed for sanity checking the caller */
68*014b99a8SKevin Wolf     unsigned int struct_nesting;
69a020f980SPaolo Bonzini };
70a020f980SPaolo Bonzini 
to_sov(Visitor * v)71d7bea75dSEric Blake static StringOutputVisitor *to_sov(Visitor *v)
72d7bea75dSEric Blake {
73d7bea75dSEric Blake     return container_of(v, StringOutputVisitor, visitor);
74d7bea75dSEric Blake }
75d7bea75dSEric Blake 
string_output_set(StringOutputVisitor * sov,char * string)76a020f980SPaolo Bonzini static void string_output_set(StringOutputVisitor *sov, char *string)
77a020f980SPaolo Bonzini {
78ea7ec158SKevin Wolf     switch (sov->list_mode) {
79ea7ec158SKevin Wolf     case LM_STARTED:
80ea7ec158SKevin Wolf         sov->list_mode = LM_IN_PROGRESS;
81ea7ec158SKevin Wolf         /* fall through */
82ea7ec158SKevin Wolf     case LM_NONE:
8369e25563SHu Tao         if (sov->string) {
8469e25563SHu Tao             g_string_free(sov->string, true);
8569e25563SHu Tao         }
8669e25563SHu Tao         sov->string = g_string_new(string);
8769e25563SHu Tao         g_free(string);
88ea7ec158SKevin Wolf         break;
89ea7ec158SKevin Wolf 
90ea7ec158SKevin Wolf     case LM_IN_PROGRESS:
91ea7ec158SKevin Wolf     case LM_END:
92ea7ec158SKevin Wolf         g_string_append(sov->string, ", ");
93ea7ec158SKevin Wolf         g_string_append(sov->string, string);
94ea7ec158SKevin Wolf         break;
95ea7ec158SKevin Wolf 
96ea7ec158SKevin Wolf     default:
97ea7ec158SKevin Wolf         abort();
98ea7ec158SKevin Wolf     }
9969e25563SHu Tao }
10069e25563SHu Tao 
string_output_append(StringOutputVisitor * sov,int64_t a)10169e25563SHu Tao static void string_output_append(StringOutputVisitor *sov, int64_t a)
10269e25563SHu Tao {
10369e25563SHu Tao     Range *r = g_malloc0(sizeof(*r));
104a0efbf16SMarkus Armbruster 
105a0efbf16SMarkus Armbruster     range_set_bounds(r, a, a);
1067c47959dSEric Blake     sov->ranges = range_list_insert(sov->ranges, r);
10769e25563SHu Tao }
10869e25563SHu Tao 
string_output_append_range(StringOutputVisitor * sov,int64_t s,int64_t e)10969e25563SHu Tao static void string_output_append_range(StringOutputVisitor *sov,
11069e25563SHu Tao                                        int64_t s, int64_t e)
11169e25563SHu Tao {
11269e25563SHu Tao     Range *r = g_malloc0(sizeof(*r));
113a0efbf16SMarkus Armbruster 
114a0efbf16SMarkus Armbruster     range_set_bounds(r, s, e);
1157c47959dSEric Blake     sov->ranges = range_list_insert(sov->ranges, r);
11669e25563SHu Tao }
11769e25563SHu Tao 
format_string(StringOutputVisitor * sov,Range * r,bool next,bool human)11869e25563SHu Tao static void format_string(StringOutputVisitor *sov, Range *r, bool next,
11969e25563SHu Tao                           bool human)
12069e25563SHu Tao {
121a0efbf16SMarkus Armbruster     if (range_lob(r) != range_upb(r)) {
12269e25563SHu Tao         if (human) {
123684531adSHu Tao             g_string_append_printf(sov->string, "0x%" PRIx64 "-0x%" PRIx64,
124a0efbf16SMarkus Armbruster                                    range_lob(r), range_upb(r));
12569e25563SHu Tao 
12669e25563SHu Tao         } else {
12769e25563SHu Tao             g_string_append_printf(sov->string, "%" PRId64 "-%" PRId64,
128a0efbf16SMarkus Armbruster                                    range_lob(r), range_upb(r));
12969e25563SHu Tao         }
13069e25563SHu Tao     } else {
13169e25563SHu Tao         if (human) {
132a0efbf16SMarkus Armbruster             g_string_append_printf(sov->string, "0x%" PRIx64, range_lob(r));
13369e25563SHu Tao         } else {
134a0efbf16SMarkus Armbruster             g_string_append_printf(sov->string, "%" PRId64, range_lob(r));
13569e25563SHu Tao         }
13669e25563SHu Tao     }
13769e25563SHu Tao     if (next) {
13869e25563SHu Tao         g_string_append(sov->string, ",");
13969e25563SHu Tao     }
140a020f980SPaolo Bonzini }
141a020f980SPaolo Bonzini 
print_type_int64(Visitor * v,const char * name,int64_t * obj,Error ** errp)142012d4c96SMarkus Armbruster static bool print_type_int64(Visitor *v, const char *name, int64_t *obj,
143a020f980SPaolo Bonzini                              Error **errp)
144a020f980SPaolo Bonzini {
145d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
14669e25563SHu Tao     GList *l;
14769e25563SHu Tao 
148*014b99a8SKevin Wolf     if (sov->struct_nesting) {
149*014b99a8SKevin Wolf         return true;
150*014b99a8SKevin Wolf     }
151*014b99a8SKevin Wolf 
15269e25563SHu Tao     switch (sov->list_mode) {
15369e25563SHu Tao     case LM_NONE:
15469e25563SHu Tao         string_output_append(sov, *obj);
15569e25563SHu Tao         break;
15669e25563SHu Tao 
15769e25563SHu Tao     case LM_STARTED:
15869e25563SHu Tao         sov->range_start.s = *obj;
15969e25563SHu Tao         sov->range_end.s = *obj;
16069e25563SHu Tao         sov->list_mode = LM_IN_PROGRESS;
161012d4c96SMarkus Armbruster         return true;
16269e25563SHu Tao 
16369e25563SHu Tao     case LM_IN_PROGRESS:
16469e25563SHu Tao         if (sov->range_end.s + 1 == *obj) {
16569e25563SHu Tao             sov->range_end.s++;
16669e25563SHu Tao         } else {
16769e25563SHu Tao             if (sov->range_start.s == sov->range_end.s) {
16869e25563SHu Tao                 string_output_append(sov, sov->range_end.s);
16969e25563SHu Tao             } else {
17069e25563SHu Tao                 assert(sov->range_start.s < sov->range_end.s);
17169e25563SHu Tao                 string_output_append_range(sov, sov->range_start.s,
17269e25563SHu Tao                                            sov->range_end.s);
17369e25563SHu Tao             }
17469e25563SHu Tao 
17569e25563SHu Tao             sov->range_start.s = *obj;
17669e25563SHu Tao             sov->range_end.s = *obj;
17769e25563SHu Tao         }
178012d4c96SMarkus Armbruster         return true;
17969e25563SHu Tao 
18069e25563SHu Tao     case LM_END:
18169e25563SHu Tao         if (sov->range_end.s + 1 == *obj) {
18269e25563SHu Tao             sov->range_end.s++;
18369e25563SHu Tao             assert(sov->range_start.s < sov->range_end.s);
18469e25563SHu Tao             string_output_append_range(sov, sov->range_start.s,
18569e25563SHu Tao                                        sov->range_end.s);
18669e25563SHu Tao         } else {
18769e25563SHu Tao             if (sov->range_start.s == sov->range_end.s) {
18869e25563SHu Tao                 string_output_append(sov, sov->range_end.s);
18969e25563SHu Tao             } else {
19069e25563SHu Tao                 assert(sov->range_start.s < sov->range_end.s);
19169e25563SHu Tao 
19269e25563SHu Tao                 string_output_append_range(sov, sov->range_start.s,
19369e25563SHu Tao                                            sov->range_end.s);
19469e25563SHu Tao             }
19569e25563SHu Tao             string_output_append(sov, *obj);
19669e25563SHu Tao         }
19769e25563SHu Tao         break;
19869e25563SHu Tao 
19969e25563SHu Tao     default:
20069e25563SHu Tao         abort();
20169e25563SHu Tao     }
20269e25563SHu Tao 
20369e25563SHu Tao     l = sov->ranges;
20469e25563SHu Tao     while (l) {
20569e25563SHu Tao         Range *r = l->data;
20669e25563SHu Tao         format_string(sov, r, l->next != NULL, false);
20769e25563SHu Tao         l = l->next;
20869e25563SHu Tao     }
2090b7593e0SPaolo Bonzini 
2100b7593e0SPaolo Bonzini     if (sov->human) {
21169e25563SHu Tao         l = sov->ranges;
21269e25563SHu Tao         g_string_append(sov->string, " (");
21369e25563SHu Tao         while (l) {
21469e25563SHu Tao             Range *r = l->data;
21556fdfb61SMichael S. Tsirkin             format_string(sov, r, l->next != NULL, true);
21669e25563SHu Tao             l = l->next;
2170b7593e0SPaolo Bonzini         }
21869e25563SHu Tao         g_string_append(sov->string, ")");
21969e25563SHu Tao     }
220012d4c96SMarkus Armbruster 
221012d4c96SMarkus Armbruster     return true;
2220b7593e0SPaolo Bonzini }
2230b7593e0SPaolo Bonzini 
print_type_uint64(Visitor * v,const char * name,uint64_t * obj,Error ** errp)224012d4c96SMarkus Armbruster static bool print_type_uint64(Visitor *v, const char *name, uint64_t *obj,
225f755dea7SEric Blake                              Error **errp)
226f755dea7SEric Blake {
227f755dea7SEric Blake     /* FIXME: print_type_int64 mishandles values over INT64_MAX */
228f755dea7SEric Blake     int64_t i = *obj;
229012d4c96SMarkus Armbruster     return print_type_int64(v, name, &i, errp);
230f755dea7SEric Blake }
231f755dea7SEric Blake 
print_type_size(Visitor * v,const char * name,uint64_t * obj,Error ** errp)232012d4c96SMarkus Armbruster static bool print_type_size(Visitor *v, const char *name, uint64_t *obj,
2330b7593e0SPaolo Bonzini                             Error **errp)
2340b7593e0SPaolo Bonzini {
235d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
23622951aaaSPeter Xu     uint64_t val;
23722951aaaSPeter Xu     char *out, *psize;
2380b7593e0SPaolo Bonzini 
239*014b99a8SKevin Wolf     if (sov->struct_nesting) {
240*014b99a8SKevin Wolf         return true;
241*014b99a8SKevin Wolf     }
242*014b99a8SKevin Wolf 
2430b7593e0SPaolo Bonzini     if (!sov->human) {
244e41b509dSPaolo Bonzini         out = g_strdup_printf("%"PRIu64, *obj);
2450b7593e0SPaolo Bonzini         string_output_set(sov, out);
246012d4c96SMarkus Armbruster         return true;
2470b7593e0SPaolo Bonzini     }
2480b7593e0SPaolo Bonzini 
2490b7593e0SPaolo Bonzini     val = *obj;
25022951aaaSPeter Xu     psize = size_to_str(val);
25122951aaaSPeter Xu     out = g_strdup_printf("%"PRIu64" (%s)", val, psize);
2520b7593e0SPaolo Bonzini     string_output_set(sov, out);
25322951aaaSPeter Xu 
25422951aaaSPeter Xu     g_free(psize);
255012d4c96SMarkus Armbruster     return true;
256a020f980SPaolo Bonzini }
257a020f980SPaolo Bonzini 
print_type_bool(Visitor * v,const char * name,bool * obj,Error ** errp)258012d4c96SMarkus Armbruster static bool print_type_bool(Visitor *v, const char *name, bool *obj,
259a020f980SPaolo Bonzini                             Error **errp)
260a020f980SPaolo Bonzini {
261d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
262*014b99a8SKevin Wolf 
263*014b99a8SKevin Wolf     if (sov->struct_nesting) {
264*014b99a8SKevin Wolf         return true;
265*014b99a8SKevin Wolf     }
266*014b99a8SKevin Wolf 
267a020f980SPaolo Bonzini     string_output_set(sov, g_strdup(*obj ? "true" : "false"));
268012d4c96SMarkus Armbruster     return true;
269a020f980SPaolo Bonzini }
270a020f980SPaolo Bonzini 
print_type_str(Visitor * v,const char * name,char ** obj,Error ** errp)271012d4c96SMarkus Armbruster static bool print_type_str(Visitor *v, const char *name, char **obj,
272a020f980SPaolo Bonzini                            Error **errp)
273a020f980SPaolo Bonzini {
274d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
2750b7593e0SPaolo Bonzini     char *out;
2760b7593e0SPaolo Bonzini 
277*014b99a8SKevin Wolf     if (sov->struct_nesting) {
278*014b99a8SKevin Wolf         return true;
279*014b99a8SKevin Wolf     }
280*014b99a8SKevin Wolf 
2810b7593e0SPaolo Bonzini     if (sov->human) {
2820b7593e0SPaolo Bonzini         out = *obj ? g_strdup_printf("\"%s\"", *obj) : g_strdup("<null>");
2830b7593e0SPaolo Bonzini     } else {
2840b7593e0SPaolo Bonzini         out = g_strdup(*obj ? *obj : "");
2850b7593e0SPaolo Bonzini     }
2860b7593e0SPaolo Bonzini     string_output_set(sov, out);
287012d4c96SMarkus Armbruster     return true;
288a020f980SPaolo Bonzini }
289a020f980SPaolo Bonzini 
print_type_number(Visitor * v,const char * name,double * obj,Error ** errp)290012d4c96SMarkus Armbruster static bool print_type_number(Visitor *v, const char *name, double *obj,
291a020f980SPaolo Bonzini                               Error **errp)
292a020f980SPaolo Bonzini {
293d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
294*014b99a8SKevin Wolf 
295*014b99a8SKevin Wolf     if (sov->struct_nesting) {
296*014b99a8SKevin Wolf         return true;
297*014b99a8SKevin Wolf     }
298*014b99a8SKevin Wolf 
29954addb01SMarkus Armbruster     string_output_set(sov, g_strdup_printf("%.17g", *obj));
300012d4c96SMarkus Armbruster     return true;
301a020f980SPaolo Bonzini }
302a020f980SPaolo Bonzini 
print_type_null(Visitor * v,const char * name,QNull ** obj,Error ** errp)303012d4c96SMarkus Armbruster static bool print_type_null(Visitor *v, const char *name, QNull **obj,
304d2f95f4dSMarkus Armbruster                             Error **errp)
305a7333712SGreg Kurz {
306a7333712SGreg Kurz     StringOutputVisitor *sov = to_sov(v);
307a7333712SGreg Kurz     char *out;
308a7333712SGreg Kurz 
309*014b99a8SKevin Wolf     if (sov->struct_nesting) {
310*014b99a8SKevin Wolf         return true;
311*014b99a8SKevin Wolf     }
312*014b99a8SKevin Wolf 
313a7333712SGreg Kurz     if (sov->human) {
314a7333712SGreg Kurz         out = g_strdup("<null>");
315a7333712SGreg Kurz     } else {
316a7333712SGreg Kurz         out = g_strdup("");
317a7333712SGreg Kurz     }
318a7333712SGreg Kurz     string_output_set(sov, out);
319012d4c96SMarkus Armbruster     return true;
320a7333712SGreg Kurz }
321a7333712SGreg Kurz 
start_struct(Visitor * v,const char * name,void ** obj,size_t size,Error ** errp)322ff32bb53SStefan Hajnoczi static bool start_struct(Visitor *v, const char *name, void **obj,
323ff32bb53SStefan Hajnoczi                          size_t size, Error **errp)
324ff32bb53SStefan Hajnoczi {
325*014b99a8SKevin Wolf     StringOutputVisitor *sov = to_sov(v);
326*014b99a8SKevin Wolf 
327*014b99a8SKevin Wolf     sov->struct_nesting++;
328ff32bb53SStefan Hajnoczi     return true;
329ff32bb53SStefan Hajnoczi }
330ff32bb53SStefan Hajnoczi 
end_struct(Visitor * v,void ** obj)331ff32bb53SStefan Hajnoczi static void end_struct(Visitor *v, void **obj)
332ff32bb53SStefan Hajnoczi {
333ff32bb53SStefan Hajnoczi     StringOutputVisitor *sov = to_sov(v);
334ff32bb53SStefan Hajnoczi 
335*014b99a8SKevin Wolf     if (--sov->struct_nesting) {
336*014b99a8SKevin Wolf         return;
337*014b99a8SKevin Wolf     }
338*014b99a8SKevin Wolf 
339ff32bb53SStefan Hajnoczi     /* TODO actually print struct fields */
340ff32bb53SStefan Hajnoczi     string_output_set(sov, g_strdup("<omitted>"));
341ff32bb53SStefan Hajnoczi }
342ff32bb53SStefan Hajnoczi 
343012d4c96SMarkus Armbruster static bool
start_list(Visitor * v,const char * name,GenericList ** list,size_t size,Error ** errp)344d9f62ddeSEric Blake start_list(Visitor *v, const char *name, GenericList **list, size_t size,
345d9f62ddeSEric Blake            Error **errp)
34669e25563SHu Tao {
347d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
34869e25563SHu Tao 
349*014b99a8SKevin Wolf     if (sov->struct_nesting) {
350*014b99a8SKevin Wolf         return true;
351*014b99a8SKevin Wolf     }
352*014b99a8SKevin Wolf 
35369e25563SHu Tao     /* we can't traverse a list in a list */
35469e25563SHu Tao     assert(sov->list_mode == LM_NONE);
355d9f62ddeSEric Blake     /* We don't support visits without a list */
356d9f62ddeSEric Blake     assert(list);
3571158bb2aSEric Blake     sov->list = list;
358d9f62ddeSEric Blake     /* List handling is only needed if there are at least two elements */
359d9f62ddeSEric Blake     if (*list && (*list)->next) {
36069e25563SHu Tao         sov->list_mode = LM_STARTED;
361d9f62ddeSEric Blake     }
362012d4c96SMarkus Armbruster     return true;
36369e25563SHu Tao }
36469e25563SHu Tao 
next_list(Visitor * v,GenericList * tail,size_t size)365d9f62ddeSEric Blake static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
36669e25563SHu Tao {
367d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
368d9f62ddeSEric Blake     GenericList *ret = tail->next;
36969e25563SHu Tao 
370*014b99a8SKevin Wolf     if (sov->struct_nesting) {
371*014b99a8SKevin Wolf         return ret;
372*014b99a8SKevin Wolf     }
373*014b99a8SKevin Wolf 
374d9f62ddeSEric Blake     if (ret && !ret->next) {
37569e25563SHu Tao         sov->list_mode = LM_END;
37669e25563SHu Tao     }
37769e25563SHu Tao     return ret;
37869e25563SHu Tao }
37969e25563SHu Tao 
end_list(Visitor * v,void ** obj)3801158bb2aSEric Blake static void end_list(Visitor *v, void **obj)
38169e25563SHu Tao {
382d7bea75dSEric Blake     StringOutputVisitor *sov = to_sov(v);
38369e25563SHu Tao 
384*014b99a8SKevin Wolf     if (sov->struct_nesting) {
385*014b99a8SKevin Wolf         return;
386*014b99a8SKevin Wolf     }
387*014b99a8SKevin Wolf 
3881158bb2aSEric Blake     assert(sov->list == obj);
38969e25563SHu Tao     assert(sov->list_mode == LM_STARTED ||
39069e25563SHu Tao            sov->list_mode == LM_END ||
39169e25563SHu Tao            sov->list_mode == LM_NONE ||
39269e25563SHu Tao            sov->list_mode == LM_IN_PROGRESS);
39369e25563SHu Tao     sov->list_mode = LM_NONE;
39469e25563SHu Tao }
39569e25563SHu Tao 
string_output_complete(Visitor * v,void * opaque)3963b098d56SEric Blake static void string_output_complete(Visitor *v, void *opaque)
397a020f980SPaolo Bonzini {
3983b098d56SEric Blake     StringOutputVisitor *sov = to_sov(v);
399a020f980SPaolo Bonzini 
4003b098d56SEric Blake     assert(opaque == sov->result);
4013b098d56SEric Blake     *sov->result = g_string_free(sov->string, false);
4023b098d56SEric Blake     sov->string = NULL;
403a020f980SPaolo Bonzini }
404a020f980SPaolo Bonzini 
free_range(void * range,void * dummy)4050d156683SMichael S. Tsirkin static void free_range(void *range, void *dummy)
4060d156683SMichael S. Tsirkin {
4070d156683SMichael S. Tsirkin     g_free(range);
4080d156683SMichael S. Tsirkin }
4090d156683SMichael S. Tsirkin 
string_output_free(Visitor * v)4102c0ef9f4SEric Blake static void string_output_free(Visitor *v)
4112c0ef9f4SEric Blake {
4122c0ef9f4SEric Blake     StringOutputVisitor *sov = to_sov(v);
4132c0ef9f4SEric Blake 
41469e25563SHu Tao     if (sov->string) {
41569e25563SHu Tao         g_string_free(sov->string, true);
41669e25563SHu Tao     }
41769e25563SHu Tao 
4180d156683SMichael S. Tsirkin     g_list_foreach(sov->ranges, free_range, NULL);
4190d156683SMichael S. Tsirkin     g_list_free(sov->ranges);
420a020f980SPaolo Bonzini     g_free(sov);
421a020f980SPaolo Bonzini }
422a020f980SPaolo Bonzini 
string_output_visitor_new(bool human,char ** result)4233b098d56SEric Blake Visitor *string_output_visitor_new(bool human, char **result)
424a020f980SPaolo Bonzini {
425a020f980SPaolo Bonzini     StringOutputVisitor *v;
426a020f980SPaolo Bonzini 
427a020f980SPaolo Bonzini     v = g_malloc0(sizeof(*v));
428a020f980SPaolo Bonzini 
42969e25563SHu Tao     v->string = g_string_new(NULL);
4300b7593e0SPaolo Bonzini     v->human = human;
4313b098d56SEric Blake     v->result = result;
4323b098d56SEric Blake     *result = NULL;
4333b098d56SEric Blake 
434983f52d4SEric Blake     v->visitor.type = VISITOR_OUTPUT;
4354c40314aSEric Blake     v->visitor.type_int64 = print_type_int64;
436f755dea7SEric Blake     v->visitor.type_uint64 = print_type_uint64;
4370b7593e0SPaolo Bonzini     v->visitor.type_size = print_type_size;
438a020f980SPaolo Bonzini     v->visitor.type_bool = print_type_bool;
439a020f980SPaolo Bonzini     v->visitor.type_str = print_type_str;
440a020f980SPaolo Bonzini     v->visitor.type_number = print_type_number;
441a7333712SGreg Kurz     v->visitor.type_null = print_type_null;
442ff32bb53SStefan Hajnoczi     v->visitor.start_struct = start_struct;
443ff32bb53SStefan Hajnoczi     v->visitor.end_struct = end_struct;
44469e25563SHu Tao     v->visitor.start_list = start_list;
44569e25563SHu Tao     v->visitor.next_list = next_list;
44669e25563SHu Tao     v->visitor.end_list = end_list;
4473b098d56SEric Blake     v->visitor.complete = string_output_complete;
4482c0ef9f4SEric Blake     v->visitor.free = string_output_free;
449a020f980SPaolo Bonzini 
4503b098d56SEric Blake     return &v->visitor;
451a020f980SPaolo Bonzini }
452