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