Add qemu 2.4.0
[kvmfornfv.git] / qemu / qapi / qmp-output-visitor.c
1 /*
2  * Core Definitions for QAPI/QMP Command Registry
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10  * See the COPYING.LIB file in the top-level directory.
11  *
12  */
13
14 #include "qapi/qmp-output-visitor.h"
15 #include "qapi/visitor-impl.h"
16 #include "qemu/queue.h"
17 #include "qemu-common.h"
18 #include "qapi/qmp/types.h"
19
20 typedef struct QStackEntry
21 {
22     QObject *value;
23     bool is_list_head;
24     QTAILQ_ENTRY(QStackEntry) node;
25 } QStackEntry;
26
27 typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
28
29 struct QmpOutputVisitor
30 {
31     Visitor visitor;
32     QStack stack;
33 };
34
35 #define qmp_output_add(qov, name, value) \
36     qmp_output_add_obj(qov, name, QOBJECT(value))
37 #define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
38
39 static QmpOutputVisitor *to_qov(Visitor *v)
40 {
41     return container_of(v, QmpOutputVisitor, visitor);
42 }
43
44 static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
45 {
46     QStackEntry *e = g_malloc0(sizeof(*e));
47
48     e->value = value;
49     if (qobject_type(e->value) == QTYPE_QLIST) {
50         e->is_list_head = true;
51     }
52     QTAILQ_INSERT_HEAD(&qov->stack, e, node);
53 }
54
55 static QObject *qmp_output_pop(QmpOutputVisitor *qov)
56 {
57     QStackEntry *e = QTAILQ_FIRST(&qov->stack);
58     QObject *value;
59     QTAILQ_REMOVE(&qov->stack, e, node);
60     value = e->value;
61     g_free(e);
62     return value;
63 }
64
65 static QObject *qmp_output_first(QmpOutputVisitor *qov)
66 {
67     QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
68
69     /* FIXME - find a better way to deal with NULL values */
70     if (!e) {
71         return NULL;
72     }
73
74     return e->value;
75 }
76
77 static QObject *qmp_output_last(QmpOutputVisitor *qov)
78 {
79     QStackEntry *e = QTAILQ_FIRST(&qov->stack);
80     return e->value;
81 }
82
83 static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
84                                QObject *value)
85 {
86     QObject *cur;
87
88     if (QTAILQ_EMPTY(&qov->stack)) {
89         qmp_output_push_obj(qov, value);
90         return;
91     }
92
93     cur = qmp_output_last(qov);
94
95     switch (qobject_type(cur)) {
96     case QTYPE_QDICT:
97         qdict_put_obj(qobject_to_qdict(cur), name, value);
98         break;
99     case QTYPE_QLIST:
100         qlist_append_obj(qobject_to_qlist(cur), value);
101         break;
102     default:
103         qobject_decref(qmp_output_pop(qov));
104         qmp_output_push_obj(qov, value);
105         break;
106     }
107 }
108
109 static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind,
110                                     const char *name, size_t unused,
111                                     Error **errp)
112 {
113     QmpOutputVisitor *qov = to_qov(v);
114     QDict *dict = qdict_new();
115
116     qmp_output_add(qov, name, dict);
117     qmp_output_push(qov, dict);
118 }
119
120 static void qmp_output_end_struct(Visitor *v, Error **errp)
121 {
122     QmpOutputVisitor *qov = to_qov(v);
123     qmp_output_pop(qov);
124 }
125
126 static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
127 {
128     QmpOutputVisitor *qov = to_qov(v);
129     QList *list = qlist_new();
130
131     qmp_output_add(qov, name, list);
132     qmp_output_push(qov, list);
133 }
134
135 static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
136                                          Error **errp)
137 {
138     GenericList *list = *listp;
139     QmpOutputVisitor *qov = to_qov(v);
140     QStackEntry *e = QTAILQ_FIRST(&qov->stack);
141
142     assert(e);
143     if (e->is_list_head) {
144         e->is_list_head = false;
145         return list;
146     }
147
148     return list ? list->next : NULL;
149 }
150
151 static void qmp_output_end_list(Visitor *v, Error **errp)
152 {
153     QmpOutputVisitor *qov = to_qov(v);
154     qmp_output_pop(qov);
155 }
156
157 static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
158                                 Error **errp)
159 {
160     QmpOutputVisitor *qov = to_qov(v);
161     qmp_output_add(qov, name, qint_from_int(*obj));
162 }
163
164 static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name,
165                                  Error **errp)
166 {
167     QmpOutputVisitor *qov = to_qov(v);
168     qmp_output_add(qov, name, qbool_from_bool(*obj));
169 }
170
171 static void qmp_output_type_str(Visitor *v, char **obj, const char *name,
172                                 Error **errp)
173 {
174     QmpOutputVisitor *qov = to_qov(v);
175     if (*obj) {
176         qmp_output_add(qov, name, qstring_from_str(*obj));
177     } else {
178         qmp_output_add(qov, name, qstring_from_str(""));
179     }
180 }
181
182 static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
183                                    Error **errp)
184 {
185     QmpOutputVisitor *qov = to_qov(v);
186     qmp_output_add(qov, name, qfloat_from_double(*obj));
187 }
188
189 QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
190 {
191     QObject *obj = qmp_output_first(qov);
192     if (obj) {
193         qobject_incref(obj);
194     }
195     return obj;
196 }
197
198 Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
199 {
200     return &v->visitor;
201 }
202
203 void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
204 {
205     QStackEntry *e, *tmp;
206
207     /* The bottom QStackEntry, if any, owns the root QObject. See the
208      * qmp_output_push_obj() invocations in qmp_output_add_obj(). */
209     QObject *root = QTAILQ_EMPTY(&v->stack) ? NULL : qmp_output_first(v);
210
211     QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
212         QTAILQ_REMOVE(&v->stack, e, node);
213         g_free(e);
214     }
215
216     qobject_decref(root);
217     g_free(v);
218 }
219
220 QmpOutputVisitor *qmp_output_visitor_new(void)
221 {
222     QmpOutputVisitor *v;
223
224     v = g_malloc0(sizeof(*v));
225
226     v->visitor.start_struct = qmp_output_start_struct;
227     v->visitor.end_struct = qmp_output_end_struct;
228     v->visitor.start_list = qmp_output_start_list;
229     v->visitor.next_list = qmp_output_next_list;
230     v->visitor.end_list = qmp_output_end_list;
231     v->visitor.type_enum = output_type_enum;
232     v->visitor.type_int = qmp_output_type_int;
233     v->visitor.type_bool = qmp_output_type_bool;
234     v->visitor.type_str = qmp_output_type_str;
235     v->visitor.type_number = qmp_output_type_number;
236
237     QTAILQ_INIT(&v->stack);
238
239     return v;
240 }