qobject-input-visitor.c 20.2 KB
Newer Older
M
Michael Roth 已提交
1 2 3
/*
 * Input Visitor
 *
4
 * Copyright (C) 2012-2017 Red Hat, Inc.
M
Michael Roth 已提交
5 6 7 8 9 10 11 12 13 14
 * Copyright IBM, Corp. 2011
 *
 * Authors:
 *  Anthony Liguori   <aliguori@us.ibm.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */

P
Peter Maydell 已提交
15
#include "qemu/osdep.h"
16
#include "qapi/error.h"
17
#include "qapi/qobject-input-visitor.h"
18
#include "qapi/visitor-impl.h"
19
#include "qemu/queue.h"
M
Michael Roth 已提交
20
#include "qemu-common.h"
21
#include "qapi/qmp/qjson.h"
22 23
#include "qapi/qmp/types.h"
#include "qapi/qmp/qerror.h"
24
#include "qemu/cutils.h"
25
#include "qemu/option.h"
M
Michael Roth 已提交
26

27 28 29
typedef struct StackObject {
    const char *name;            /* Name of @obj in its parent, if any */
    QObject *obj;                /* QDict or QList being visited */
E
Eric Blake 已提交
30
    void *qapi; /* sanity check that caller uses same pointer */
E
Eric Blake 已提交
31

32 33 34
    GHashTable *h;              /* If @obj is QDict: unvisited keys */
    const QListEntry *entry;    /* If @obj is QList: unvisited tail */
    unsigned index;             /* If @obj is QList: list index of @entry */
35

36
    QSLIST_ENTRY(StackObject) node; /* parent */
M
Michael Roth 已提交
37 38
} StackObject;

39
struct QObjectInputVisitor {
M
Michael Roth 已提交
40
    Visitor visitor;
E
Eric Blake 已提交
41

42 43
    /* Root of visit at visitor creation. */
    QObject *root;
M
Markus Armbruster 已提交
44
    bool keyval;                /* Assume @root made with keyval_parse() */
45 46 47

    /* Stack of objects being visited (all entries will be either
     * QDict or QList). */
48
    QSLIST_HEAD(, StackObject) stack;
E
Eric Blake 已提交
49

50
    GString *errname;           /* Accumulator for full_name() */
M
Michael Roth 已提交
51 52
};

53
static QObjectInputVisitor *to_qiv(Visitor *v)
M
Michael Roth 已提交
54
{
55
    return container_of(v, QObjectInputVisitor, visitor);
M
Michael Roth 已提交
56 57
}

58 59 60 61 62 63 64 65 66 67 68
/*
 * Find the full name of something @qiv is currently visiting.
 * @qiv is visiting something named @name in the stack of containers
 * @qiv->stack.
 * If @n is zero, return its full name.
 * If @n is positive, return the full name of the @n-th container
 * counting from the top.  The stack of containers must have at least
 * @n elements.
 * The returned string is valid until the next full_name_nth(@v) or
 * destruction of @v.
 */
69 70
static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
                                 int n)
71 72 73 74 75 76 77 78 79 80 81
{
    StackObject *so;
    char buf[32];

    if (qiv->errname) {
        g_string_truncate(qiv->errname, 0);
    } else {
        qiv->errname = g_string_new("");
    }

    QSLIST_FOREACH(so , &qiv->stack, node) {
82 83 84 85
        if (n) {
            n--;
        } else if (qobject_type(so->obj) == QTYPE_QDICT) {
            g_string_prepend(qiv->errname, name ?: "<anonymous>");
86 87
            g_string_prepend_c(qiv->errname, '.');
        } else {
M
Markus Armbruster 已提交
88 89 90
            snprintf(buf, sizeof(buf),
                     qiv->keyval ? ".%u" : "[%u]",
                     so->index);
91 92 93 94
            g_string_prepend(qiv->errname, buf);
        }
        name = so->name;
    }
95
    assert(!n);
96 97 98 99 100

    if (name) {
        g_string_prepend(qiv->errname, name);
    } else if (qiv->errname->str[0] == '.') {
        g_string_erase(qiv->errname, 0, 1);
101
    } else if (!qiv->errname->str[0]) {
102 103 104 105 106 107
        return "<anonymous>";
    }

    return qiv->errname->str;
}

108 109 110 111 112
static const char *full_name(QObjectInputVisitor *qiv, const char *name)
{
    return full_name_nth(qiv, name, 0);
}

113 114 115
static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
                                             const char *name,
                                             bool consume)
M
Michael Roth 已提交
116
{
117 118
    StackObject *tos;
    QObject *qobj;
119
    QObject *ret;
E
Eric Blake 已提交
120

121
    if (QSLIST_EMPTY(&qiv->stack)) {
122
        /* Starting at root, name is ignored. */
123
        assert(qiv->root);
124 125 126 127
        return qiv->root;
    }

    /* We are in a container; find the next element. */
128
    tos = QSLIST_FIRST(&qiv->stack);
129
    qobj = tos->obj;
E
Eric Blake 已提交
130 131
    assert(qobj);

132 133
    if (qobject_type(qobj) == QTYPE_QDICT) {
        assert(name);
134 135 136 137
        ret = qdict_get(qobject_to_qdict(qobj), name);
        if (tos->h && consume && ret) {
            bool removed = g_hash_table_remove(tos->h, name);
            assert(removed);
138
        }
139
    } else {
E
Eric Blake 已提交
140
        assert(qobject_type(qobj) == QTYPE_QLIST);
141
        assert(!name);
142 143 144 145 146 147 148 149
        if (tos->entry) {
            ret = qlist_entry_obj(tos->entry);
            if (consume) {
                tos->entry = qlist_next(tos->entry);
            }
        } else {
            ret = NULL;
        }
150
        if (consume) {
151
            tos->index++;
152
        }
M
Michael Roth 已提交
153 154
    }

155
    return ret;
M
Michael Roth 已提交
156 157
}

158 159 160 161 162 163 164 165 166 167 168 169
static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
                                         const char *name,
                                         bool consume, Error **errp)
{
    QObject *obj = qobject_input_try_get_object(qiv, name, consume);

    if (!obj) {
        error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name));
    }
    return obj;
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183
static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv,
                                            const char *name,
                                            Error **errp)
{
    QObject *qobj;
    QString *qstr;

    qobj = qobject_input_get_object(qiv, name, true, errp);
    if (!qobj) {
        return NULL;
    }

    qstr = qobject_to_qstring(qobj);
    if (!qstr) {
184 185 186 187 188 189 190 191 192 193 194 195
        switch (qobject_type(qobj)) {
        case QTYPE_QDICT:
        case QTYPE_QLIST:
            error_setg(errp, "Parameters '%s.*' are unexpected",
                       full_name(qiv, name));
            return NULL;
        default:
            /* Non-string scalar (should this be an assertion?) */
            error_setg(errp, "Internal error: parameter %s invalid",
                       full_name(qiv, name));
            return NULL;
        }
196 197 198 199 200
    }

    return qstring_get_str(qstr);
}

201 202 203 204 205 206
static void qdict_add_key(const char *key, QObject *obj, void *opaque)
{
    GHashTable *h = opaque;
    g_hash_table_insert(h, (gpointer) key, NULL);
}

207
static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
208
                                            const char *name,
209
                                            QObject *obj, void *qapi)
M
Michael Roth 已提交
210
{
211
    GHashTable *h;
212
    StackObject *tos = g_new0(StackObject, 1);
M
Michael Roth 已提交
213

E
Eric Blake 已提交
214
    assert(obj);
215
    tos->name = name;
E
Eric Blake 已提交
216
    tos->obj = obj;
E
Eric Blake 已提交
217
    tos->qapi = qapi;
218

219
    if (qobject_type(obj) == QTYPE_QDICT) {
220 221
        h = g_hash_table_new(g_str_hash, g_str_equal);
        qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
E
Eric Blake 已提交
222
        tos->h = h;
223 224
    } else {
        assert(qobject_type(obj) == QTYPE_QLIST);
225
        tos->entry = qlist_first(qobject_to_qlist(obj));
226
        tos->index = -1;
227 228
    }

229
    QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
230
    return tos->entry;
M
Michael Roth 已提交
231 232
}

233

234
static void qobject_input_check_struct(Visitor *v, Error **errp)
M
Michael Roth 已提交
235
{
236
    QObjectInputVisitor *qiv = to_qiv(v);
237
    StackObject *tos = QSLIST_FIRST(&qiv->stack);
238 239
    GHashTableIter iter;
    const char *key;
240

241
    assert(tos && !tos->entry);
242 243 244 245 246

    g_hash_table_iter_init(&iter, tos->h);
    if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
        error_setg(errp, "Parameter '%s' is unexpected",
                   full_name(qiv, key));
247 248 249
    }
}

250
static void qobject_input_stack_object_free(StackObject *tos)
251
{
252 253 254
    if (tos->h) {
        g_hash_table_unref(tos->h);
    }
255

256 257
    g_free(tos);
}
258

259
static void qobject_input_pop(Visitor *v, void **obj)
260
{
261
    QObjectInputVisitor *qiv = to_qiv(v);
262
    StackObject *tos = QSLIST_FIRST(&qiv->stack);
263

264 265
    assert(tos && tos->qapi == obj);
    QSLIST_REMOVE_HEAD(&qiv->stack, node);
266
    qobject_input_stack_object_free(tos);
M
Michael Roth 已提交
267 268
}

269 270
static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
                                       size_t size, Error **errp)
M
Michael Roth 已提交
271
{
272 273
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
M
Michael Roth 已提交
274

275 276 277
    if (obj) {
        *obj = NULL;
    }
278 279 280 281
    if (!qobj) {
        return;
    }
    if (qobject_type(qobj) != QTYPE_QDICT) {
282 283
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "object");
M
Michael Roth 已提交
284 285 286
        return;
    }

287
    qobject_input_push(qiv, name, qobj, obj);
M
Michael Roth 已提交
288 289

    if (obj) {
290
        *obj = g_malloc0(size);
M
Michael Roth 已提交
291 292 293
    }
}

294 295 296 297 298 299 300 301 302
static void qobject_input_end_struct(Visitor *v, void **obj)
{
    QObjectInputVisitor *qiv = to_qiv(v);
    StackObject *tos = QSLIST_FIRST(&qiv->stack);

    assert(qobject_type(tos->obj) == QTYPE_QDICT && tos->h);
    qobject_input_pop(v, obj);
}

M
Michael Roth 已提交
303

304 305 306
static void qobject_input_start_list(Visitor *v, const char *name,
                                     GenericList **list, size_t size,
                                     Error **errp)
M
Michael Roth 已提交
307
{
308 309
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
310
    const QListEntry *entry;
M
Michael Roth 已提交
311

312 313 314
    if (list) {
        *list = NULL;
    }
315 316 317 318
    if (!qobj) {
        return;
    }
    if (qobject_type(qobj) != QTYPE_QLIST) {
319 320
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "array");
M
Michael Roth 已提交
321 322 323
        return;
    }

324
    entry = qobject_input_push(qiv, name, qobj, list);
325 326
    if (entry && list) {
        *list = g_malloc0(size);
327
    }
M
Michael Roth 已提交
328 329
}

330 331
static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
                                            size_t size)
M
Michael Roth 已提交
332
{
333
    QObjectInputVisitor *qiv = to_qiv(v);
334 335 336
    StackObject *tos = QSLIST_FIRST(&qiv->stack);

    assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST);
M
Michael Roth 已提交
337

338
    if (!tos->entry) {
M
Michael Roth 已提交
339 340
        return NULL;
    }
341 342
    tail->next = g_malloc0(size);
    return tail->next;
M
Michael Roth 已提交
343 344
}

345 346 347 348 349 350 351 352 353 354 355 356 357
static void qobject_input_check_list(Visitor *v, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
    StackObject *tos = QSLIST_FIRST(&qiv->stack);

    assert(tos && tos->obj && qobject_type(tos->obj) == QTYPE_QLIST);

    if (tos->entry) {
        error_setg(errp, "Only %u list elements expected in %s",
                   tos->index + 1, full_name_nth(qiv, NULL, 1));
    }
}

358 359 360 361 362 363 364 365
static void qobject_input_end_list(Visitor *v, void **obj)
{
    QObjectInputVisitor *qiv = to_qiv(v);
    StackObject *tos = QSLIST_FIRST(&qiv->stack);

    assert(qobject_type(tos->obj) == QTYPE_QLIST && !tos->h);
    qobject_input_pop(v, obj);
}
M
Michael Roth 已提交
366

367 368 369
static void qobject_input_start_alternate(Visitor *v, const char *name,
                                          GenericAlternate **obj, size_t size,
                                          bool promote_int, Error **errp)
K
Kevin Wolf 已提交
370
{
371 372
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
K
Kevin Wolf 已提交
373 374

    if (!qobj) {
375
        *obj = NULL;
K
Kevin Wolf 已提交
376 377
        return;
    }
378 379 380 381
    *obj = g_malloc0(size);
    (*obj)->type = qobject_type(qobj);
    if (promote_int && (*obj)->type == QTYPE_QINT) {
        (*obj)->type = QTYPE_QFLOAT;
382
    }
K
Kevin Wolf 已提交
383 384
}

385 386
static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
                                     Error **errp)
M
Michael Roth 已提交
387
{
388 389
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
390
    QInt *qint;
M
Michael Roth 已提交
391

392 393 394 395
    if (!qobj) {
        return;
    }
    qint = qobject_to_qint(qobj);
396
    if (!qint) {
397 398
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "integer");
M
Michael Roth 已提交
399 400 401
        return;
    }

402
    *obj = qint_get_int(qint);
M
Michael Roth 已提交
403 404
}

405 406 407 408 409

static void qobject_input_type_int64_keyval(Visitor *v, const char *name,
                                            int64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
410
    const char *str = qobject_input_get_keyval(qiv, name, errp);
411

412
    if (!str) {
413 414 415
        return;
    }

416
    if (qemu_strtoi64(str, NULL, 0, obj) < 0) {
417 418 419 420 421 422
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "integer");
    }
}

423 424
static void qobject_input_type_uint64(Visitor *v, const char *name,
                                      uint64_t *obj, Error **errp)
425 426
{
    /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
427 428
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
429
    QInt *qint;
430

431 432 433 434
    if (!qobj) {
        return;
    }
    qint = qobject_to_qint(qobj);
435
    if (!qint) {
436 437
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "integer");
438 439 440 441 442 443
        return;
    }

    *obj = qint_get_int(qint);
}

444 445 446 447
static void qobject_input_type_uint64_keyval(Visitor *v, const char *name,
                                             uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
448
    const char *str = qobject_input_get_keyval(qiv, name, errp);
449

450
    if (!str) {
451 452 453
        return;
    }

454
    if (qemu_strtou64(str, NULL, 0, obj) < 0) {
455 456 457 458 459 460
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "integer");
    }
}

461 462
static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
                                    Error **errp)
M
Michael Roth 已提交
463
{
464 465
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
466
    QBool *qbool;
M
Michael Roth 已提交
467

468 469 470 471
    if (!qobj) {
        return;
    }
    qbool = qobject_to_qbool(qobj);
472
    if (!qbool) {
473 474
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "boolean");
M
Michael Roth 已提交
475 476 477
        return;
    }

478
    *obj = qbool_get_bool(qbool);
M
Michael Roth 已提交
479 480
}

481 482 483 484
static void qobject_input_type_bool_keyval(Visitor *v, const char *name,
                                           bool *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
485
    const char *str = qobject_input_get_keyval(qiv, name, errp);
486

487
    if (!str) {
488 489 490 491 492 493 494 495 496 497 498 499 500
        return;
    }

    if (!strcmp(str, "on")) {
        *obj = true;
    } else if (!strcmp(str, "off")) {
        *obj = false;
    } else {
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "'on' or 'off'");
    }
}

501 502
static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
                                   Error **errp)
M
Michael Roth 已提交
503
{
504 505
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
506
    QString *qstr;
M
Michael Roth 已提交
507

508 509 510 511 512
    *obj = NULL;
    if (!qobj) {
        return;
    }
    qstr = qobject_to_qstring(qobj);
513
    if (!qstr) {
514 515
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "string");
M
Michael Roth 已提交
516 517 518
        return;
    }

519
    *obj = g_strdup(qstring_get_str(qstr));
M
Michael Roth 已提交
520 521
}

522 523 524 525 526 527 528 529 530
static void qobject_input_type_str_keyval(Visitor *v, const char *name,
                                          char **obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
    const char *str = qobject_input_get_keyval(qiv, name, errp);

    *obj = g_strdup(str);
}

531 532
static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
                                      Error **errp)
M
Michael Roth 已提交
533
{
534 535
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
536 537
    QInt *qint;
    QFloat *qfloat;
M
Michael Roth 已提交
538

539 540 541
    if (!qobj) {
        return;
    }
542 543 544
    qint = qobject_to_qint(qobj);
    if (qint) {
        *obj = qint_get_int(qobject_to_qint(qobj));
M
Michael Roth 已提交
545 546 547
        return;
    }

548 549
    qfloat = qobject_to_qfloat(qobj);
    if (qfloat) {
550
        *obj = qfloat_get_double(qobject_to_qfloat(qobj));
551
        return;
552
    }
553

554 555
    error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
               full_name(qiv, name), "number");
M
Michael Roth 已提交
556 557
}

558 559 560 561
static void qobject_input_type_number_keyval(Visitor *v, const char *name,
                                             double *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
562
    const char *str = qobject_input_get_keyval(qiv, name, errp);
563 564
    char *endp;

565
    if (!str) {
566 567 568 569 570 571 572 573 574 575 576 577
        return;
    }

    errno = 0;
    *obj = strtod(str, &endp);
    if (errno || endp == str || *endp) {
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "number");
    }
}

578 579
static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
                                   Error **errp)
580
{
581 582
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
583

584
    *obj = NULL;
585 586 587 588
    if (!qobj) {
        return;
    }

589 590 591 592
    qobject_incref(qobj);
    *obj = qobj;
}

593
static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
E
Eric Blake 已提交
594
{
595 596
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
597

598 599 600 601
    if (!qobj) {
        return;
    }

602
    if (qobject_type(qobj) != QTYPE_QNULL) {
603 604
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "null");
605
    }
E
Eric Blake 已提交
606 607
}

608 609 610 611
static void qobject_input_type_size_keyval(Visitor *v, const char *name,
                                           uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
612
    const char *str = qobject_input_get_keyval(qiv, name, errp);
613

614
    if (!str) {
615 616 617
        return;
    }

618
    if (qemu_strtosz(str, NULL, obj) < 0) {
619 620 621 622 623 624
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "size");
    }
}

625
static void qobject_input_optional(Visitor *v, const char *name, bool *present)
M
Michael Roth 已提交
626
{
627
    QObjectInputVisitor *qiv = to_qiv(v);
628
    QObject *qobj = qobject_input_try_get_object(qiv, name, false);
M
Michael Roth 已提交
629 630 631 632 633 634 635 636 637

    if (!qobj) {
        *present = false;
        return;
    }

    *present = true;
}

638
static void qobject_input_free(Visitor *v)
E
Eric Blake 已提交
639
{
640
    QObjectInputVisitor *qiv = to_qiv(v);
641

642 643 644 645
    while (!QSLIST_EMPTY(&qiv->stack)) {
        StackObject *tos = QSLIST_FIRST(&qiv->stack);

        QSLIST_REMOVE_HEAD(&qiv->stack, node);
646
        qobject_input_stack_object_free(tos);
647
    }
E
Eric Blake 已提交
648

649
    qobject_decref(qiv->root);
650 651 652
    if (qiv->errname) {
        g_string_free(qiv->errname, TRUE);
    }
653
    g_free(qiv);
E
Eric Blake 已提交
654 655
}

656
static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
M
Michael Roth 已提交
657
{
658
    QObjectInputVisitor *v = g_malloc0(sizeof(*v));
M
Michael Roth 已提交
659

660
    assert(obj);
M
Michael Roth 已提交
661

662
    v->visitor.type = VISITOR_INPUT;
663 664
    v->visitor.start_struct = qobject_input_start_struct;
    v->visitor.check_struct = qobject_input_check_struct;
665
    v->visitor.end_struct = qobject_input_end_struct;
666 667
    v->visitor.start_list = qobject_input_start_list;
    v->visitor.next_list = qobject_input_next_list;
668
    v->visitor.check_list = qobject_input_check_list;
669
    v->visitor.end_list = qobject_input_end_list;
670
    v->visitor.start_alternate = qobject_input_start_alternate;
671 672 673 674 675 676 677 678 679 680 681 682 683
    v->visitor.optional = qobject_input_optional;
    v->visitor.free = qobject_input_free;

    v->root = obj;
    qobject_incref(obj);

    return v;
}

Visitor *qobject_input_visitor_new(QObject *obj)
{
    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);

684 685 686 687 688 689 690
    v->visitor.type_int64 = qobject_input_type_int64;
    v->visitor.type_uint64 = qobject_input_type_uint64;
    v->visitor.type_bool = qobject_input_type_bool;
    v->visitor.type_str = qobject_input_type_str;
    v->visitor.type_number = qobject_input_type_number;
    v->visitor.type_any = qobject_input_type_any;
    v->visitor.type_null = qobject_input_type_null;
M
Michael Roth 已提交
691

692
    return &v->visitor;
M
Michael Roth 已提交
693
}
694 695 696

Visitor *qobject_input_visitor_new_keyval(QObject *obj)
{
697
    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
698 699 700 701

    v->visitor.type_int64 = qobject_input_type_int64_keyval;
    v->visitor.type_uint64 = qobject_input_type_uint64_keyval;
    v->visitor.type_bool = qobject_input_type_bool_keyval;
702
    v->visitor.type_str = qobject_input_type_str_keyval;
703 704 705 706
    v->visitor.type_number = qobject_input_type_number_keyval;
    v->visitor.type_any = qobject_input_type_any;
    v->visitor.type_null = qobject_input_type_null;
    v->visitor.type_size = qobject_input_type_size_keyval;
M
Markus Armbruster 已提交
707
    v->keyval = true;
708 709 710

    return &v->visitor;
}
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744

Visitor *qobject_input_visitor_new_str(const char *str,
                                       const char *implied_key,
                                       Error **errp)
{
    bool is_json = str[0] == '{';
    QObject *obj;
    QDict *args;
    Visitor *v;

    if (is_json) {
        obj = qobject_from_json(str, errp);
        if (!obj) {
            /* Work around qobject_from_json() lossage TODO fix that */
            if (errp && !*errp) {
                error_setg(errp, "JSON parse error");
                return NULL;
            }
            return NULL;
        }
        args = qobject_to_qdict(obj);
        assert(args);
        v = qobject_input_visitor_new(QOBJECT(args));
    } else {
        args = keyval_parse(str, implied_key, errp);
        if (!args) {
            return NULL;
        }
        v = qobject_input_visitor_new_keyval(QOBJECT(args));
    }
    QDECREF(args);

    return v;
}