|
|
1.1 root 1: /*
2: * Input Visitor
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-input-visitor.h"
1.1.1.3 ! root 15: #include "qapi/qapi-visit-impl.h"
1.1 root 16: #include "qemu-queue.h"
17: #include "qemu-common.h"
18: #include "qemu-objects.h"
19: #include "qerror.h"
20:
21: #define QIV_STACK_SIZE 1024
22:
23: typedef struct StackObject
24: {
1.1.1.3 ! root 25: QObject *obj;
! 26: const QListEntry *entry;
! 27: GHashTable *h;
1.1 root 28: } StackObject;
29:
30: struct QmpInputVisitor
31: {
32: Visitor visitor;
33: StackObject stack[QIV_STACK_SIZE];
34: int nb_stack;
1.1.1.3 ! root 35: bool strict;
1.1 root 36: };
37:
38: static QmpInputVisitor *to_qiv(Visitor *v)
39: {
40: return container_of(v, QmpInputVisitor, visitor);
41: }
42:
1.1.1.3 ! root 43: static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
! 44: const char *name)
1.1 root 45: {
1.1.1.3 ! root 46: QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj;
1.1 root 47:
1.1.1.3 ! root 48: if (qobj) {
! 49: if (name && qobject_type(qobj) == QTYPE_QDICT) {
! 50: if (qiv->stack[qiv->nb_stack - 1].h) {
! 51: g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name);
! 52: }
! 53: return qdict_get(qobject_to_qdict(qobj), name);
! 54: } else if (qiv->stack[qiv->nb_stack - 1].entry) {
! 55: return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
! 56: }
1.1 root 57: }
58:
59: return qobj;
60: }
61:
1.1.1.3 ! root 62: static void qdict_add_key(const char *key, QObject *obj, void *opaque)
1.1 root 63: {
1.1.1.3 ! root 64: GHashTable *h = opaque;
! 65: g_hash_table_insert(h, (gpointer) key, NULL);
! 66: }
! 67:
! 68: static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
! 69: {
! 70: GHashTable *h;
1.1 root 71:
72: if (qiv->nb_stack >= QIV_STACK_SIZE) {
73: error_set(errp, QERR_BUFFER_OVERRUN);
74: return;
75: }
1.1.1.3 ! root 76:
! 77: qiv->stack[qiv->nb_stack].obj = obj;
! 78: qiv->stack[qiv->nb_stack].entry = NULL;
! 79: qiv->stack[qiv->nb_stack].h = NULL;
! 80:
! 81: if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
! 82: h = g_hash_table_new(g_str_hash, g_str_equal);
! 83: qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
! 84: qiv->stack[qiv->nb_stack].h = h;
! 85: }
! 86:
! 87: qiv->nb_stack++;
! 88: }
! 89:
! 90: /** Only for qmp_input_pop. */
! 91: static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
! 92: {
! 93: *(const char **)user_pkey = (const char *)key;
! 94: return TRUE;
1.1 root 95: }
96:
97: static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
98: {
1.1.1.3 ! root 99: assert(qiv->nb_stack > 0);
! 100:
! 101: if (qiv->strict) {
! 102: GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
! 103: if (top_ht) {
! 104: if (g_hash_table_size(top_ht)) {
! 105: const char *key;
! 106: g_hash_table_find(top_ht, always_true, &key);
! 107: error_set(errp, QERR_QMP_EXTRA_MEMBER, key);
! 108: }
! 109: g_hash_table_unref(top_ht);
! 110: }
1.1 root 111: }
1.1.1.3 ! root 112:
! 113: qiv->nb_stack--;
1.1 root 114: }
115:
116: static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
117: const char *name, size_t size, Error **errp)
118: {
119: QmpInputVisitor *qiv = to_qiv(v);
1.1.1.3 ! root 120: QObject *qobj = qmp_input_get_object(qiv, name);
! 121: Error *err = NULL;
1.1 root 122:
123: if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
124: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
125: "QDict");
126: return;
127: }
128:
1.1.1.3 ! root 129: qmp_input_push(qiv, qobj, &err);
! 130: if (err) {
! 131: error_propagate(errp, err);
1.1 root 132: return;
133: }
134:
135: if (obj) {
1.1.1.2 root 136: *obj = g_malloc0(size);
1.1 root 137: }
138: }
139:
140: static void qmp_input_end_struct(Visitor *v, Error **errp)
141: {
142: QmpInputVisitor *qiv = to_qiv(v);
143:
144: qmp_input_pop(qiv, errp);
145: }
146:
147: static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
148: {
149: QmpInputVisitor *qiv = to_qiv(v);
1.1.1.3 ! root 150: QObject *qobj = qmp_input_get_object(qiv, name);
1.1 root 151:
152: if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
153: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
154: "list");
155: return;
156: }
157:
158: qmp_input_push(qiv, qobj, errp);
159: }
160:
161: static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
162: Error **errp)
163: {
164: QmpInputVisitor *qiv = to_qiv(v);
165: GenericList *entry;
166: StackObject *so = &qiv->stack[qiv->nb_stack - 1];
1.1.1.3 ! root 167: bool first;
! 168:
! 169: if (so->entry == NULL) {
! 170: so->entry = qlist_first(qobject_to_qlist(so->obj));
! 171: first = true;
! 172: } else {
! 173: so->entry = qlist_next(so->entry);
! 174: first = false;
! 175: }
1.1 root 176:
177: if (so->entry == NULL) {
178: return NULL;
179: }
180:
1.1.1.2 root 181: entry = g_malloc0(sizeof(*entry));
1.1.1.3 ! root 182: if (first) {
! 183: *list = entry;
! 184: } else {
1.1 root 185: (*list)->next = entry;
186: }
187:
188: return entry;
189: }
190:
191: static void qmp_input_end_list(Visitor *v, Error **errp)
192: {
193: QmpInputVisitor *qiv = to_qiv(v);
194:
195: qmp_input_pop(qiv, errp);
196: }
197:
198: static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
199: Error **errp)
200: {
201: QmpInputVisitor *qiv = to_qiv(v);
1.1.1.3 ! root 202: QObject *qobj = qmp_input_get_object(qiv, name);
1.1 root 203:
204: if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
205: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
206: "integer");
207: return;
208: }
209:
210: *obj = qint_get_int(qobject_to_qint(qobj));
211: }
212:
213: static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
214: Error **errp)
215: {
216: QmpInputVisitor *qiv = to_qiv(v);
1.1.1.3 ! root 217: QObject *qobj = qmp_input_get_object(qiv, name);
1.1 root 218:
219: if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
220: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
221: "boolean");
222: return;
223: }
224:
225: *obj = qbool_get_int(qobject_to_qbool(qobj));
226: }
227:
228: static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
229: Error **errp)
230: {
231: QmpInputVisitor *qiv = to_qiv(v);
1.1.1.3 ! root 232: QObject *qobj = qmp_input_get_object(qiv, name);
1.1 root 233:
234: if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
235: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
236: "string");
237: return;
238: }
239:
1.1.1.2 root 240: *obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj)));
1.1 root 241: }
242:
243: static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
244: Error **errp)
245: {
246: QmpInputVisitor *qiv = to_qiv(v);
1.1.1.3 ! root 247: QObject *qobj = qmp_input_get_object(qiv, name);
1.1 root 248:
1.1.1.3 ! root 249: if (!qobj || (qobject_type(qobj) != QTYPE_QFLOAT &&
! 250: qobject_type(qobj) != QTYPE_QINT)) {
1.1 root 251: error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
1.1.1.3 ! root 252: "number");
1.1 root 253: return;
254: }
255:
1.1.1.3 ! root 256: if (qobject_type(qobj) == QTYPE_QINT) {
! 257: *obj = qint_get_int(qobject_to_qint(qobj));
! 258: } else {
! 259: *obj = qfloat_get_double(qobject_to_qfloat(qobj));
1.1 root 260: }
261: }
262:
263: static void qmp_input_start_optional(Visitor *v, bool *present,
264: const char *name, Error **errp)
265: {
266: QmpInputVisitor *qiv = to_qiv(v);
1.1.1.3 ! root 267: QObject *qobj = qmp_input_get_object(qiv, name);
1.1 root 268:
269: if (!qobj) {
270: *present = false;
271: return;
272: }
273:
274: *present = true;
275: }
276:
277: Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
278: {
279: return &v->visitor;
280: }
281:
282: void qmp_input_visitor_cleanup(QmpInputVisitor *v)
283: {
1.1.1.3 ! root 284: qobject_decref(v->stack[0].obj);
1.1.1.2 root 285: g_free(v);
1.1 root 286: }
287:
288: QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
289: {
290: QmpInputVisitor *v;
291:
1.1.1.2 root 292: v = g_malloc0(sizeof(*v));
1.1 root 293:
294: v->visitor.start_struct = qmp_input_start_struct;
295: v->visitor.end_struct = qmp_input_end_struct;
296: v->visitor.start_list = qmp_input_start_list;
297: v->visitor.next_list = qmp_input_next_list;
298: v->visitor.end_list = qmp_input_end_list;
1.1.1.3 ! root 299: v->visitor.type_enum = input_type_enum;
1.1 root 300: v->visitor.type_int = qmp_input_type_int;
301: v->visitor.type_bool = qmp_input_type_bool;
302: v->visitor.type_str = qmp_input_type_str;
303: v->visitor.type_number = qmp_input_type_number;
304: v->visitor.start_optional = qmp_input_start_optional;
305:
1.1.1.3 ! root 306: qmp_input_push(v, obj, NULL);
! 307: qobject_incref(obj);
! 308:
! 309: return v;
! 310: }
! 311:
! 312: QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj)
! 313: {
! 314: QmpInputVisitor *v;
! 315:
! 316: v = qmp_input_visitor_new(obj);
! 317: v->strict = true;
1.1 root 318:
319: return v;
320: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.