qobject-output-visitor.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. #include "qemu/osdep.h"
  15. #include "qapi/qobject-output-visitor.h"
  16. #include "qapi/visitor-impl.h"
  17. #include "qemu/queue.h"
  18. #include "qemu-common.h"
  19. #include "qapi/qmp/types.h"
  20. typedef struct QStackEntry
  21. {
  22. QObject *value;
  23. void *qapi; /* sanity check that caller uses same pointer */
  24. QSLIST_ENTRY(QStackEntry) node;
  25. } QStackEntry;
  26. struct QmpOutputVisitor
  27. {
  28. Visitor visitor;
  29. QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */
  30. QObject *root; /* Root of the output visit */
  31. QObject **result; /* User's storage location for result */
  32. };
  33. #define qmp_output_add(qov, name, value) \
  34. qmp_output_add_obj(qov, name, QOBJECT(value))
  35. #define qmp_output_push(qov, value, qapi) \
  36. qmp_output_push_obj(qov, QOBJECT(value), qapi)
  37. static QmpOutputVisitor *to_qov(Visitor *v)
  38. {
  39. return container_of(v, QmpOutputVisitor, visitor);
  40. }
  41. /* Push @value onto the stack of current QObjects being built */
  42. static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value,
  43. void *qapi)
  44. {
  45. QStackEntry *e = g_malloc0(sizeof(*e));
  46. assert(qov->root);
  47. assert(value);
  48. e->value = value;
  49. e->qapi = qapi;
  50. QSLIST_INSERT_HEAD(&qov->stack, e, node);
  51. }
  52. /* Pop a value off the stack of QObjects being built, and return it. */
  53. static QObject *qmp_output_pop(QmpOutputVisitor *qov, void *qapi)
  54. {
  55. QStackEntry *e = QSLIST_FIRST(&qov->stack);
  56. QObject *value;
  57. assert(e);
  58. assert(e->qapi == qapi);
  59. QSLIST_REMOVE_HEAD(&qov->stack, node);
  60. value = e->value;
  61. assert(value);
  62. g_free(e);
  63. return value;
  64. }
  65. /* Add @value to the current QObject being built.
  66. * If the stack is visiting a dictionary or list, @value is now owned
  67. * by that container. Otherwise, @value is now the root. */
  68. static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
  69. QObject *value)
  70. {
  71. QStackEntry *e = QSLIST_FIRST(&qov->stack);
  72. QObject *cur = e ? e->value : NULL;
  73. if (!cur) {
  74. /* Don't allow reuse of visitor on more than one root */
  75. assert(!qov->root);
  76. qov->root = value;
  77. } else {
  78. switch (qobject_type(cur)) {
  79. case QTYPE_QDICT:
  80. assert(name);
  81. qdict_put_obj(qobject_to_qdict(cur), name, value);
  82. break;
  83. case QTYPE_QLIST:
  84. assert(!name);
  85. qlist_append_obj(qobject_to_qlist(cur), value);
  86. break;
  87. default:
  88. g_assert_not_reached();
  89. }
  90. }
  91. }
  92. static void qmp_output_start_struct(Visitor *v, const char *name, void **obj,
  93. size_t unused, Error **errp)
  94. {
  95. QmpOutputVisitor *qov = to_qov(v);
  96. QDict *dict = qdict_new();
  97. qmp_output_add(qov, name, dict);
  98. qmp_output_push(qov, dict, obj);
  99. }
  100. static void qmp_output_end_struct(Visitor *v, void **obj)
  101. {
  102. QmpOutputVisitor *qov = to_qov(v);
  103. QObject *value = qmp_output_pop(qov, obj);
  104. assert(qobject_type(value) == QTYPE_QDICT);
  105. }
  106. static void qmp_output_start_list(Visitor *v, const char *name,
  107. GenericList **listp, size_t size,
  108. Error **errp)
  109. {
  110. QmpOutputVisitor *qov = to_qov(v);
  111. QList *list = qlist_new();
  112. qmp_output_add(qov, name, list);
  113. qmp_output_push(qov, list, listp);
  114. }
  115. static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail,
  116. size_t size)
  117. {
  118. return tail->next;
  119. }
  120. static void qmp_output_end_list(Visitor *v, void **obj)
  121. {
  122. QmpOutputVisitor *qov = to_qov(v);
  123. QObject *value = qmp_output_pop(qov, obj);
  124. assert(qobject_type(value) == QTYPE_QLIST);
  125. }
  126. static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj,
  127. Error **errp)
  128. {
  129. QmpOutputVisitor *qov = to_qov(v);
  130. qmp_output_add(qov, name, qint_from_int(*obj));
  131. }
  132. static void qmp_output_type_uint64(Visitor *v, const char *name, uint64_t *obj,
  133. Error **errp)
  134. {
  135. /* FIXME values larger than INT64_MAX become negative */
  136. QmpOutputVisitor *qov = to_qov(v);
  137. qmp_output_add(qov, name, qint_from_int(*obj));
  138. }
  139. static void qmp_output_type_bool(Visitor *v, const char *name, bool *obj,
  140. Error **errp)
  141. {
  142. QmpOutputVisitor *qov = to_qov(v);
  143. qmp_output_add(qov, name, qbool_from_bool(*obj));
  144. }
  145. static void qmp_output_type_str(Visitor *v, const char *name, char **obj,
  146. Error **errp)
  147. {
  148. QmpOutputVisitor *qov = to_qov(v);
  149. if (*obj) {
  150. qmp_output_add(qov, name, qstring_from_str(*obj));
  151. } else {
  152. qmp_output_add(qov, name, qstring_from_str(""));
  153. }
  154. }
  155. static void qmp_output_type_number(Visitor *v, const char *name, double *obj,
  156. Error **errp)
  157. {
  158. QmpOutputVisitor *qov = to_qov(v);
  159. qmp_output_add(qov, name, qfloat_from_double(*obj));
  160. }
  161. static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj,
  162. Error **errp)
  163. {
  164. QmpOutputVisitor *qov = to_qov(v);
  165. qobject_incref(*obj);
  166. qmp_output_add_obj(qov, name, *obj);
  167. }
  168. static void qmp_output_type_null(Visitor *v, const char *name, Error **errp)
  169. {
  170. QmpOutputVisitor *qov = to_qov(v);
  171. qmp_output_add_obj(qov, name, qnull());
  172. }
  173. /* Finish building, and return the root object.
  174. * The root object is never null. The caller becomes the object's
  175. * owner, and should use qobject_decref() when done with it. */
  176. static void qmp_output_complete(Visitor *v, void *opaque)
  177. {
  178. QmpOutputVisitor *qov = to_qov(v);
  179. /* A visit must have occurred, with each start paired with end. */
  180. assert(qov->root && QSLIST_EMPTY(&qov->stack));
  181. assert(opaque == qov->result);
  182. qobject_incref(qov->root);
  183. *qov->result = qov->root;
  184. qov->result = NULL;
  185. }
  186. static void qmp_output_free(Visitor *v)
  187. {
  188. QmpOutputVisitor *qov = to_qov(v);
  189. QStackEntry *e;
  190. while (!QSLIST_EMPTY(&qov->stack)) {
  191. e = QSLIST_FIRST(&qov->stack);
  192. QSLIST_REMOVE_HEAD(&qov->stack, node);
  193. g_free(e);
  194. }
  195. qobject_decref(qov->root);
  196. g_free(qov);
  197. }
  198. Visitor *qmp_output_visitor_new(QObject **result)
  199. {
  200. QmpOutputVisitor *v;
  201. v = g_malloc0(sizeof(*v));
  202. v->visitor.type = VISITOR_OUTPUT;
  203. v->visitor.start_struct = qmp_output_start_struct;
  204. v->visitor.end_struct = qmp_output_end_struct;
  205. v->visitor.start_list = qmp_output_start_list;
  206. v->visitor.next_list = qmp_output_next_list;
  207. v->visitor.end_list = qmp_output_end_list;
  208. v->visitor.type_int64 = qmp_output_type_int64;
  209. v->visitor.type_uint64 = qmp_output_type_uint64;
  210. v->visitor.type_bool = qmp_output_type_bool;
  211. v->visitor.type_str = qmp_output_type_str;
  212. v->visitor.type_number = qmp_output_type_number;
  213. v->visitor.type_any = qmp_output_type_any;
  214. v->visitor.type_null = qmp_output_type_null;
  215. v->visitor.complete = qmp_output_complete;
  216. v->visitor.free = qmp_output_free;
  217. *result = NULL;
  218. v->result = result;
  219. return &v->visitor;
  220. }