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