1 /* 2 * Core Definitions for QAPI/QMP Command Registry 3 * 4 * Copyright (C) 2012-2016 Red Hat, Inc. 5 * Copyright IBM, Corp. 2011 6 * 7 * Authors: 8 * Anthony Liguori <aliguori@us.ibm.com> 9 * 10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. 11 * See the COPYING.LIB file in the top-level directory. 12 * 13 */ 14 15 #include "qemu/osdep.h" 16 #include "qapi/qobject-output-visitor.h" 17 #include "qapi/visitor-impl.h" 18 #include "qemu/queue.h" 19 #include "qapi/qmp/qbool.h" 20 #include "qapi/qmp/qdict.h" 21 #include "qapi/qmp/qlist.h" 22 #include "qapi/qmp/qnull.h" 23 #include "qapi/qmp/qnum.h" 24 #include "qapi/qmp/qstring.h" 25 26 typedef struct QStackEntry { 27 QObject *value; 28 void *qapi; /* sanity check that caller uses same pointer */ 29 QSLIST_ENTRY(QStackEntry) node; 30 } QStackEntry; 31 32 struct QObjectOutputVisitor { 33 Visitor visitor; 34 QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */ 35 QObject *root; /* Root of the output visit */ 36 QObject **result; /* User's storage location for result */ 37 }; 38 39 #define qobject_output_add(qov, name, value) \ 40 qobject_output_add_obj(qov, name, QOBJECT(value)) 41 #define qobject_output_push(qov, value, qapi) \ 42 qobject_output_push_obj(qov, QOBJECT(value), qapi) 43 44 static QObjectOutputVisitor *to_qov(Visitor *v) 45 { 46 return container_of(v, QObjectOutputVisitor, visitor); 47 } 48 49 /* Push @value onto the stack of current QObjects being built */ 50 static void qobject_output_push_obj(QObjectOutputVisitor *qov, QObject *value, 51 void *qapi) 52 { 53 QStackEntry *e = g_malloc0(sizeof(*e)); 54 55 assert(qov->root); 56 assert(value); 57 e->value = value; 58 e->qapi = qapi; 59 QSLIST_INSERT_HEAD(&qov->stack, e, node); 60 } 61 62 /* Pop a value off the stack of QObjects being built, and return it. */ 63 static QObject *qobject_output_pop(QObjectOutputVisitor *qov, void *qapi) 64 { 65 QStackEntry *e = QSLIST_FIRST(&qov->stack); 66 QObject *value; 67 68 assert(e); 69 assert(e->qapi == qapi); 70 QSLIST_REMOVE_HEAD(&qov->stack, node); 71 value = e->value; 72 assert(value); 73 g_free(e); 74 return value; 75 } 76 77 /* Add @value to the current QObject being built. 78 * If the stack is visiting a dictionary or list, @value is now owned 79 * by that container. Otherwise, @value is now the root. */ 80 static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name, 81 QObject *value) 82 { 83 QStackEntry *e = QSLIST_FIRST(&qov->stack); 84 QObject *cur = e ? e->value : NULL; 85 86 if (!cur) { 87 /* Don't allow reuse of visitor on more than one root */ 88 assert(!qov->root); 89 qov->root = value; 90 } else { 91 switch (qobject_type(cur)) { 92 case QTYPE_QDICT: 93 assert(name); 94 qdict_put_obj(qobject_to(QDict, cur), name, value); 95 break; 96 case QTYPE_QLIST: 97 assert(!name); 98 qlist_append_obj(qobject_to(QList, cur), value); 99 break; 100 default: 101 g_assert_not_reached(); 102 } 103 } 104 } 105 106 static void qobject_output_start_struct(Visitor *v, const char *name, 107 void **obj, size_t unused, Error **errp) 108 { 109 QObjectOutputVisitor *qov = to_qov(v); 110 QDict *dict = qdict_new(); 111 112 qobject_output_add(qov, name, dict); 113 qobject_output_push(qov, dict, obj); 114 } 115 116 static void qobject_output_end_struct(Visitor *v, void **obj) 117 { 118 QObjectOutputVisitor *qov = to_qov(v); 119 QObject *value = qobject_output_pop(qov, obj); 120 assert(qobject_type(value) == QTYPE_QDICT); 121 } 122 123 static void qobject_output_start_list(Visitor *v, const char *name, 124 GenericList **listp, size_t size, 125 Error **errp) 126 { 127 QObjectOutputVisitor *qov = to_qov(v); 128 QList *list = qlist_new(); 129 130 qobject_output_add(qov, name, list); 131 qobject_output_push(qov, list, listp); 132 } 133 134 static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail, 135 size_t size) 136 { 137 return tail->next; 138 } 139 140 static void qobject_output_end_list(Visitor *v, void **obj) 141 { 142 QObjectOutputVisitor *qov = to_qov(v); 143 QObject *value = qobject_output_pop(qov, obj); 144 assert(qobject_type(value) == QTYPE_QLIST); 145 } 146 147 static void qobject_output_type_int64(Visitor *v, const char *name, 148 int64_t *obj, Error **errp) 149 { 150 QObjectOutputVisitor *qov = to_qov(v); 151 qobject_output_add(qov, name, qnum_from_int(*obj)); 152 } 153 154 static void qobject_output_type_uint64(Visitor *v, const char *name, 155 uint64_t *obj, Error **errp) 156 { 157 QObjectOutputVisitor *qov = to_qov(v); 158 qobject_output_add(qov, name, qnum_from_uint(*obj)); 159 } 160 161 static void qobject_output_type_bool(Visitor *v, const char *name, bool *obj, 162 Error **errp) 163 { 164 QObjectOutputVisitor *qov = to_qov(v); 165 qobject_output_add(qov, name, qbool_from_bool(*obj)); 166 } 167 168 static void qobject_output_type_str(Visitor *v, const char *name, char **obj, 169 Error **errp) 170 { 171 QObjectOutputVisitor *qov = to_qov(v); 172 if (*obj) { 173 qobject_output_add(qov, name, qstring_from_str(*obj)); 174 } else { 175 qobject_output_add(qov, name, qstring_from_str("")); 176 } 177 } 178 179 static void qobject_output_type_number(Visitor *v, const char *name, 180 double *obj, Error **errp) 181 { 182 QObjectOutputVisitor *qov = to_qov(v); 183 qobject_output_add(qov, name, qnum_from_double(*obj)); 184 } 185 186 static void qobject_output_type_any(Visitor *v, const char *name, 187 QObject **obj, Error **errp) 188 { 189 QObjectOutputVisitor *qov = to_qov(v); 190 191 qobject_output_add_obj(qov, name, qobject_ref(*obj)); 192 } 193 194 static void qobject_output_type_null(Visitor *v, const char *name, 195 QNull **obj, Error **errp) 196 { 197 QObjectOutputVisitor *qov = to_qov(v); 198 qobject_output_add(qov, name, qnull()); 199 } 200 201 /* Finish building, and return the root object. 202 * The root object is never null. The caller becomes the object's 203 * owner, and should use qobject_unref() when done with it. */ 204 static void qobject_output_complete(Visitor *v, void *opaque) 205 { 206 QObjectOutputVisitor *qov = to_qov(v); 207 208 /* A visit must have occurred, with each start paired with end. */ 209 assert(qov->root && QSLIST_EMPTY(&qov->stack)); 210 assert(opaque == qov->result); 211 212 *qov->result = qobject_ref(qov->root); 213 qov->result = NULL; 214 } 215 216 static void qobject_output_free(Visitor *v) 217 { 218 QObjectOutputVisitor *qov = to_qov(v); 219 QStackEntry *e; 220 221 while (!QSLIST_EMPTY(&qov->stack)) { 222 e = QSLIST_FIRST(&qov->stack); 223 QSLIST_REMOVE_HEAD(&qov->stack, node); 224 g_free(e); 225 } 226 227 qobject_unref(qov->root); 228 g_free(qov); 229 } 230 231 Visitor *qobject_output_visitor_new(QObject **result) 232 { 233 QObjectOutputVisitor *v; 234 235 v = g_malloc0(sizeof(*v)); 236 237 v->visitor.type = VISITOR_OUTPUT; 238 v->visitor.start_struct = qobject_output_start_struct; 239 v->visitor.end_struct = qobject_output_end_struct; 240 v->visitor.start_list = qobject_output_start_list; 241 v->visitor.next_list = qobject_output_next_list; 242 v->visitor.end_list = qobject_output_end_list; 243 v->visitor.type_int64 = qobject_output_type_int64; 244 v->visitor.type_uint64 = qobject_output_type_uint64; 245 v->visitor.type_bool = qobject_output_type_bool; 246 v->visitor.type_str = qobject_output_type_str; 247 v->visitor.type_number = qobject_output_type_number; 248 v->visitor.type_any = qobject_output_type_any; 249 v->visitor.type_null = qobject_output_type_null; 250 v->visitor.complete = qobject_output_complete; 251 v->visitor.free = qobject_output_free; 252 253 *result = NULL; 254 v->result = result; 255 256 return &v->visitor; 257 } 258