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