qmp-output-visitor.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * Core Definitions for QAPI/QMP Command Registry
  3. *
  4. * Copyright IBM, Corp. 2011
  5. *
  6. * Authors:
  7. * Anthony Liguori <aliguori@us.ibm.com>
  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. #include "qapi/qmp-output-visitor.h"
  14. #include "qapi/visitor-impl.h"
  15. #include "qemu/queue.h"
  16. #include "qemu-common.h"
  17. #include "qapi/qmp/types.h"
  18. #include "qapi/qmp/qerror.h"
  19. typedef struct QStackEntry
  20. {
  21. QObject *value;
  22. bool is_list_head;
  23. QTAILQ_ENTRY(QStackEntry) node;
  24. } QStackEntry;
  25. typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
  26. struct QmpOutputVisitor
  27. {
  28. Visitor visitor;
  29. QStack stack;
  30. };
  31. #define qmp_output_add(qov, name, value) \
  32. qmp_output_add_obj(qov, name, QOBJECT(value))
  33. #define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
  34. static QmpOutputVisitor *to_qov(Visitor *v)
  35. {
  36. return container_of(v, QmpOutputVisitor, visitor);
  37. }
  38. static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
  39. {
  40. QStackEntry *e = g_malloc0(sizeof(*e));
  41. e->value = value;
  42. if (qobject_type(e->value) == QTYPE_QLIST) {
  43. e->is_list_head = true;
  44. }
  45. QTAILQ_INSERT_HEAD(&qov->stack, e, node);
  46. }
  47. static QObject *qmp_output_pop(QmpOutputVisitor *qov)
  48. {
  49. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  50. QObject *value;
  51. QTAILQ_REMOVE(&qov->stack, e, node);
  52. value = e->value;
  53. g_free(e);
  54. return value;
  55. }
  56. static QObject *qmp_output_first(QmpOutputVisitor *qov)
  57. {
  58. QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
  59. /* FIXME - find a better way to deal with NULL values */
  60. if (!e) {
  61. return NULL;
  62. }
  63. return e->value;
  64. }
  65. static QObject *qmp_output_last(QmpOutputVisitor *qov)
  66. {
  67. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  68. return e->value;
  69. }
  70. static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
  71. QObject *value)
  72. {
  73. QObject *cur;
  74. if (QTAILQ_EMPTY(&qov->stack)) {
  75. qmp_output_push_obj(qov, value);
  76. return;
  77. }
  78. cur = qmp_output_last(qov);
  79. switch (qobject_type(cur)) {
  80. case QTYPE_QDICT:
  81. qdict_put_obj(qobject_to_qdict(cur), name, value);
  82. break;
  83. case QTYPE_QLIST:
  84. qlist_append_obj(qobject_to_qlist(cur), value);
  85. break;
  86. default:
  87. qobject_decref(qmp_output_pop(qov));
  88. qmp_output_push_obj(qov, value);
  89. break;
  90. }
  91. }
  92. static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind,
  93. const char *name, size_t unused,
  94. Error **errp)
  95. {
  96. QmpOutputVisitor *qov = to_qov(v);
  97. QDict *dict = qdict_new();
  98. qmp_output_add(qov, name, dict);
  99. qmp_output_push(qov, dict);
  100. }
  101. static void qmp_output_end_struct(Visitor *v, Error **errp)
  102. {
  103. QmpOutputVisitor *qov = to_qov(v);
  104. qmp_output_pop(qov);
  105. }
  106. static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
  107. {
  108. QmpOutputVisitor *qov = to_qov(v);
  109. QList *list = qlist_new();
  110. qmp_output_add(qov, name, list);
  111. qmp_output_push(qov, list);
  112. }
  113. static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
  114. Error **errp)
  115. {
  116. GenericList *list = *listp;
  117. QmpOutputVisitor *qov = to_qov(v);
  118. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  119. assert(e);
  120. if (e->is_list_head) {
  121. e->is_list_head = false;
  122. return list;
  123. }
  124. return list ? list->next : NULL;
  125. }
  126. static void qmp_output_end_list(Visitor *v, Error **errp)
  127. {
  128. QmpOutputVisitor *qov = to_qov(v);
  129. qmp_output_pop(qov);
  130. }
  131. static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
  132. Error **errp)
  133. {
  134. QmpOutputVisitor *qov = to_qov(v);
  135. qmp_output_add(qov, name, qint_from_int(*obj));
  136. }
  137. static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name,
  138. Error **errp)
  139. {
  140. QmpOutputVisitor *qov = to_qov(v);
  141. qmp_output_add(qov, name, qbool_from_int(*obj));
  142. }
  143. static void qmp_output_type_str(Visitor *v, char **obj, const char *name,
  144. Error **errp)
  145. {
  146. QmpOutputVisitor *qov = to_qov(v);
  147. if (*obj) {
  148. qmp_output_add(qov, name, qstring_from_str(*obj));
  149. } else {
  150. qmp_output_add(qov, name, qstring_from_str(""));
  151. }
  152. }
  153. static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
  154. Error **errp)
  155. {
  156. QmpOutputVisitor *qov = to_qov(v);
  157. qmp_output_add(qov, name, qfloat_from_double(*obj));
  158. }
  159. QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
  160. {
  161. QObject *obj = qmp_output_first(qov);
  162. if (obj) {
  163. qobject_incref(obj);
  164. }
  165. return obj;
  166. }
  167. Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
  168. {
  169. return &v->visitor;
  170. }
  171. void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
  172. {
  173. QStackEntry *e, *tmp;
  174. /* The bottom QStackEntry, if any, owns the root QObject. See the
  175. * qmp_output_push_obj() invocations in qmp_output_add_obj(). */
  176. QObject *root = QTAILQ_EMPTY(&v->stack) ? NULL : qmp_output_first(v);
  177. QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
  178. QTAILQ_REMOVE(&v->stack, e, node);
  179. g_free(e);
  180. }
  181. qobject_decref(root);
  182. g_free(v);
  183. }
  184. QmpOutputVisitor *qmp_output_visitor_new(void)
  185. {
  186. QmpOutputVisitor *v;
  187. v = g_malloc0(sizeof(*v));
  188. v->visitor.start_struct = qmp_output_start_struct;
  189. v->visitor.end_struct = qmp_output_end_struct;
  190. v->visitor.start_list = qmp_output_start_list;
  191. v->visitor.next_list = qmp_output_next_list;
  192. v->visitor.end_list = qmp_output_end_list;
  193. v->visitor.type_enum = output_type_enum;
  194. v->visitor.type_int = qmp_output_type_int;
  195. v->visitor.type_bool = qmp_output_type_bool;
  196. v->visitor.type_str = qmp_output_type_str;
  197. v->visitor.type_number = qmp_output_type_number;
  198. QTAILQ_INIT(&v->stack);
  199. return v;
  200. }