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