qmp-output-visitor.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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 "qemu-queue.h"
  15. #include "qemu-common.h"
  16. #include "qemu-objects.h"
  17. #include "qerror.h"
  18. typedef struct QStackEntry
  19. {
  20. QObject *value;
  21. bool is_list_head;
  22. QTAILQ_ENTRY(QStackEntry) node;
  23. } QStackEntry;
  24. typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
  25. struct QmpOutputVisitor
  26. {
  27. Visitor visitor;
  28. QStack stack;
  29. };
  30. #define qmp_output_add(qov, name, value) \
  31. qmp_output_add_obj(qov, name, QOBJECT(value))
  32. #define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
  33. static QmpOutputVisitor *to_qov(Visitor *v)
  34. {
  35. return container_of(v, QmpOutputVisitor, visitor);
  36. }
  37. static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
  38. {
  39. QStackEntry *e = g_malloc0(sizeof(*e));
  40. e->value = value;
  41. if (qobject_type(e->value) == QTYPE_QLIST) {
  42. e->is_list_head = true;
  43. }
  44. QTAILQ_INSERT_HEAD(&qov->stack, e, node);
  45. }
  46. static QObject *qmp_output_pop(QmpOutputVisitor *qov)
  47. {
  48. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  49. QObject *value;
  50. QTAILQ_REMOVE(&qov->stack, e, node);
  51. value = e->value;
  52. g_free(e);
  53. return value;
  54. }
  55. static QObject *qmp_output_first(QmpOutputVisitor *qov)
  56. {
  57. QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
  58. return e->value;
  59. }
  60. static QObject *qmp_output_last(QmpOutputVisitor *qov)
  61. {
  62. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  63. return e->value;
  64. }
  65. static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
  66. QObject *value)
  67. {
  68. QObject *cur;
  69. if (QTAILQ_EMPTY(&qov->stack)) {
  70. qmp_output_push_obj(qov, value);
  71. return;
  72. }
  73. cur = qmp_output_last(qov);
  74. switch (qobject_type(cur)) {
  75. case QTYPE_QDICT:
  76. qdict_put_obj(qobject_to_qdict(cur), name, value);
  77. break;
  78. case QTYPE_QLIST:
  79. qlist_append_obj(qobject_to_qlist(cur), value);
  80. break;
  81. default:
  82. qobject_decref(qmp_output_pop(qov));
  83. qmp_output_push_obj(qov, value);
  84. break;
  85. }
  86. }
  87. static void qmp_output_start_struct(Visitor *v, void **obj, const char *kind,
  88. const char *name, size_t unused,
  89. Error **errp)
  90. {
  91. QmpOutputVisitor *qov = to_qov(v);
  92. QDict *dict = qdict_new();
  93. qmp_output_add(qov, name, dict);
  94. qmp_output_push(qov, dict);
  95. }
  96. static void qmp_output_end_struct(Visitor *v, Error **errp)
  97. {
  98. QmpOutputVisitor *qov = to_qov(v);
  99. qmp_output_pop(qov);
  100. }
  101. static void qmp_output_start_list(Visitor *v, const char *name, Error **errp)
  102. {
  103. QmpOutputVisitor *qov = to_qov(v);
  104. QList *list = qlist_new();
  105. qmp_output_add(qov, name, list);
  106. qmp_output_push(qov, list);
  107. }
  108. static GenericList *qmp_output_next_list(Visitor *v, GenericList **listp,
  109. Error **errp)
  110. {
  111. GenericList *list = *listp;
  112. QmpOutputVisitor *qov = to_qov(v);
  113. QStackEntry *e = QTAILQ_FIRST(&qov->stack);
  114. assert(e);
  115. if (e->is_list_head) {
  116. e->is_list_head = false;
  117. return list;
  118. }
  119. return list ? list->next : NULL;
  120. }
  121. static void qmp_output_end_list(Visitor *v, Error **errp)
  122. {
  123. QmpOutputVisitor *qov = to_qov(v);
  124. qmp_output_pop(qov);
  125. }
  126. static void qmp_output_type_int(Visitor *v, int64_t *obj, const char *name,
  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_bool(Visitor *v, bool *obj, const char *name,
  133. Error **errp)
  134. {
  135. QmpOutputVisitor *qov = to_qov(v);
  136. qmp_output_add(qov, name, qbool_from_int(*obj));
  137. }
  138. static void qmp_output_type_str(Visitor *v, char **obj, const char *name,
  139. Error **errp)
  140. {
  141. QmpOutputVisitor *qov = to_qov(v);
  142. if (*obj) {
  143. qmp_output_add(qov, name, qstring_from_str(*obj));
  144. } else {
  145. qmp_output_add(qov, name, qstring_from_str(""));
  146. }
  147. }
  148. static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
  149. Error **errp)
  150. {
  151. QmpOutputVisitor *qov = to_qov(v);
  152. qmp_output_add(qov, name, qfloat_from_double(*obj));
  153. }
  154. static void qmp_output_type_enum(Visitor *v, int *obj, const char *strings[],
  155. const char *kind, const char *name,
  156. Error **errp)
  157. {
  158. int i = 0;
  159. int value = *obj;
  160. char *enum_str;
  161. assert(strings);
  162. while (strings[i++] != NULL);
  163. if (value < 0 || value >= i - 1) {
  164. error_set(errp, QERR_INVALID_PARAMETER, name ? name : "null");
  165. return;
  166. }
  167. enum_str = (char *)strings[value];
  168. qmp_output_type_str(v, &enum_str, name, errp);
  169. }
  170. QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
  171. {
  172. QObject *obj = qmp_output_first(qov);
  173. if (obj) {
  174. qobject_incref(obj);
  175. }
  176. return obj;
  177. }
  178. Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
  179. {
  180. return &v->visitor;
  181. }
  182. void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
  183. {
  184. QStackEntry *e, *tmp;
  185. QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
  186. QTAILQ_REMOVE(&v->stack, e, node);
  187. if (e->value) {
  188. qobject_decref(e->value);
  189. }
  190. g_free(e);
  191. }
  192. g_free(v);
  193. }
  194. QmpOutputVisitor *qmp_output_visitor_new(void)
  195. {
  196. QmpOutputVisitor *v;
  197. v = g_malloc0(sizeof(*v));
  198. v->visitor.start_struct = qmp_output_start_struct;
  199. v->visitor.end_struct = qmp_output_end_struct;
  200. v->visitor.start_list = qmp_output_start_list;
  201. v->visitor.next_list = qmp_output_next_list;
  202. v->visitor.end_list = qmp_output_end_list;
  203. v->visitor.type_enum = qmp_output_type_enum;
  204. v->visitor.type_int = qmp_output_type_int;
  205. v->visitor.type_bool = qmp_output_type_bool;
  206. v->visitor.type_str = qmp_output_type_str;
  207. v->visitor.type_number = qmp_output_type_number;
  208. QTAILQ_INIT(&v->stack);
  209. return v;
  210. }