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