2
0

qmp-output-visitor.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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 "qmp-output-visitor.h"
  14. #include "qapi/qapi-visit-impl.h"
  15. #include "qemu-queue.h"
  16. #include "qemu-common.h"
  17. #include "qemu-objects.h"
  18. #include "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. return e->value;
  60. }
  61. static QObject *qmp_output_last(QmpOutputVisitor *qov)
  62. {
  63. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  64. return e->value;
  65. }
  66. static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
  67. QObject *value)
  68. {
  69. QObject *cur;
  70. if (QTAILQ_EMPTY(&qov->stack)) {
  71. qmp_output_push_obj(qov, value);
  72. return;
  73. }
  74. cur = qmp_output_last(qov);
  75. switch (qobject_type(cur)) {
  76. case QTYPE_QDICT:
  77. qdict_put_obj(qobject_to_qdict(cur), name, value);
  78. break;
  79. case QTYPE_QLIST:
  80. qlist_append_obj(qobject_to_qlist(cur), value);
  81. break;
  82. default:
  83. qobject_decref(qmp_output_pop(qov));
  84. qmp_output_push_obj(qov, value);
  85. break;
  86. }
  87. }
  88. static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind,
  89. const char *name, size_t unused,
  90. Error **errp)
  91. {
  92. QmpOutputVisitor *qov = to_qov(v);
  93. QDict *dict = qdict_new();
  94. qmp_output_add(qov, name, dict);
  95. qmp_output_push(qov, dict);
  96. }
  97. static void qmp_output_end_struct(Visitor *v, Error **errp)
  98. {
  99. QmpOutputVisitor *qov = to_qov(v);
  100. qmp_output_pop(qov);
  101. }
  102. static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
  103. {
  104. QmpOutputVisitor *qov = to_qov(v);
  105. QList *list = qlist_new();
  106. qmp_output_add(qov, name, list);
  107. qmp_output_push(qov, list);
  108. }
  109. static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
  110. Error **errp)
  111. {
  112. GenericList *list = *listp;
  113. QmpOutputVisitor *qov = to_qov(v);
  114. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  115. assert(e);
  116. if (e->is_list_head) {
  117. e->is_list_head = false;
  118. return list;
  119. }
  120. return list ? list->next : NULL;
  121. }
  122. static void qmp_output_end_list(Visitor *v, Error **errp)
  123. {
  124. QmpOutputVisitor *qov = to_qov(v);
  125. qmp_output_pop(qov);
  126. }
  127. static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
  128. Error **errp)
  129. {
  130. QmpOutputVisitor *qov = to_qov(v);
  131. qmp_output_add(qov, name, qint_from_int(*obj));
  132. }
  133. static void qmp_output_type_bool(Visitor *v, bool *obj, const char *name,
  134. Error **errp)
  135. {
  136. QmpOutputVisitor *qov = to_qov(v);
  137. qmp_output_add(qov, name, qbool_from_int(*obj));
  138. }
  139. static void qmp_output_type_str(Visitor *v, char **obj, const char *name,
  140. Error **errp)
  141. {
  142. QmpOutputVisitor *qov = to_qov(v);
  143. if (*obj) {
  144. qmp_output_add(qov, name, qstring_from_str(*obj));
  145. } else {
  146. qmp_output_add(qov, name, qstring_from_str(""));
  147. }
  148. }
  149. static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
  150. Error **errp)
  151. {
  152. QmpOutputVisitor *qov = to_qov(v);
  153. qmp_output_add(qov, name, qfloat_from_double(*obj));
  154. }
  155. QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
  156. {
  157. QObject *obj = qmp_output_first(qov);
  158. if (obj) {
  159. qobject_incref(obj);
  160. }
  161. return obj;
  162. }
  163. Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
  164. {
  165. return &v->visitor;
  166. }
  167. void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
  168. {
  169. QStackEntry *e, *tmp;
  170. /* The bottom QStackEntry, if any, owns the root QObject. See the
  171. * qmp_output_push_obj() invocations in qmp_output_add_obj(). */
  172. QObject *root = QTAILQ_EMPTY(&v->stack) ? NULL : qmp_output_first(v);
  173. QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
  174. QTAILQ_REMOVE(&v->stack, e, node);
  175. g_free(e);
  176. }
  177. qobject_decref(root);
  178. g_free(v);
  179. }
  180. QmpOutputVisitor *qmp_output_visitor_new(void)
  181. {
  182. QmpOutputVisitor *v;
  183. v = g_malloc0(sizeof(*v));
  184. v->visitor.start_struct = qmp_output_start_struct;
  185. v->visitor.end_struct = qmp_output_end_struct;
  186. v->visitor.start_list = qmp_output_start_list;
  187. v->visitor.next_list = qmp_output_next_list;
  188. v->visitor.end_list = qmp_output_end_list;
  189. v->visitor.type_enum = output_type_enum;
  190. v->visitor.type_int = qmp_output_type_int;
  191. v->visitor.type_bool = qmp_output_type_bool;
  192. v->visitor.type_str = qmp_output_type_str;
  193. v->visitor.type_number = qmp_output_type_number;
  194. QTAILQ_INIT(&v->stack);
  195. return v;
  196. }