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