qobject-input-visitor.c 20.3 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 <math.h>
17
#include "qapi/error.h"
18
#include "qapi/qobject-input-visitor.h"
19
#include "qapi/visitor-impl.h"
20
#include "qemu/queue.h"
M
Michael Roth 已提交
21
#include "qemu-common.h"
22
#include "qapi/qmp/qjson.h"
M
Markus Armbruster 已提交
23
#include "qapi/qmp/qbool.h"
24
#include "qapi/qmp/qdict.h"
25
#include "qapi/qmp/qerror.h"
26
#include "qapi/qmp/qlist.h"
27 28
#include "qapi/qmp/qnull.h"
#include "qapi/qmp/qnum.h"
29
#include "qemu/cutils.h"
30
#include "qemu/option.h"
M
Michael Roth 已提交
31

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

37 38 39
    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 */
40

41
    QSLIST_ENTRY(StackObject) node; /* parent */
M
Michael Roth 已提交
42 43
} StackObject;

44
struct QObjectInputVisitor {
M
Michael Roth 已提交
45
    Visitor visitor;
E
Eric Blake 已提交
46

47 48
    /* Root of visit at visitor creation. */
    QObject *root;
M
Markus Armbruster 已提交
49
    bool keyval;                /* Assume @root made with keyval_parse() */
50 51 52

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

55
    GString *errname;           /* Accumulator for full_name() */
M
Michael Roth 已提交
56 57
};

58
static QObjectInputVisitor *to_qiv(Visitor *v)
M
Michael Roth 已提交
59
{
60
    return container_of(v, QObjectInputVisitor, visitor);
M
Michael Roth 已提交
61 62
}

63 64 65 66 67 68 69 70 71 72 73
/*
 * 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.
 */
74 75
static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
                                 int n)
76 77 78 79 80 81 82 83 84 85 86
{
    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) {
87 88 89 90
        if (n) {
            n--;
        } else if (qobject_type(so->obj) == QTYPE_QDICT) {
            g_string_prepend(qiv->errname, name ?: "<anonymous>");
91 92
            g_string_prepend_c(qiv->errname, '.');
        } else {
M
Markus Armbruster 已提交
93 94 95
            snprintf(buf, sizeof(buf),
                     qiv->keyval ? ".%u" : "[%u]",
                     so->index);
96 97 98 99
            g_string_prepend(qiv->errname, buf);
        }
        name = so->name;
    }
100
    assert(!n);
101 102 103 104 105

    if (name) {
        g_string_prepend(qiv->errname, name);
    } else if (qiv->errname->str[0] == '.') {
        g_string_erase(qiv->errname, 0, 1);
106
    } else if (!qiv->errname->str[0]) {
107 108 109 110 111 112
        return "<anonymous>";
    }

    return qiv->errname->str;
}

113 114 115 116 117
static const char *full_name(QObjectInputVisitor *qiv, const char *name)
{
    return full_name_nth(qiv, name, 0);
}

118 119 120
static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
                                             const char *name,
                                             bool consume)
M
Michael Roth 已提交
121
{
122 123
    StackObject *tos;
    QObject *qobj;
124
    QObject *ret;
E
Eric Blake 已提交
125

126
    if (QSLIST_EMPTY(&qiv->stack)) {
127
        /* Starting at root, name is ignored. */
128
        assert(qiv->root);
129 130 131 132
        return qiv->root;
    }

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

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

160
    return ret;
M
Michael Roth 已提交
161 162
}

163 164 165 166 167 168 169 170 171 172 173 174
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;
}

175 176 177 178 179 180 181 182 183 184 185 186 187 188
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) {
189 190 191 192 193 194 195 196 197 198 199 200
        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;
        }
201 202 203 204 205
    }

    return qstring_get_str(qstr);
}

206 207 208 209 210 211
static void qdict_add_key(const char *key, QObject *obj, void *opaque)
{
    GHashTable *h = opaque;
    g_hash_table_insert(h, (gpointer) key, NULL);
}

212
static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
213
                                            const char *name,
214
                                            QObject *obj, void *qapi)
M
Michael Roth 已提交
215
{
216
    GHashTable *h;
217
    StackObject *tos = g_new0(StackObject, 1);
M
Michael Roth 已提交
218

E
Eric Blake 已提交
219
    assert(obj);
220
    tos->name = name;
E
Eric Blake 已提交
221
    tos->obj = obj;
E
Eric Blake 已提交
222
    tos->qapi = qapi;
223

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

234
    QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
235
    return tos->entry;
M
Michael Roth 已提交
236 237
}

238

239
static void qobject_input_check_struct(Visitor *v, Error **errp)
M
Michael Roth 已提交
240
{
241
    QObjectInputVisitor *qiv = to_qiv(v);
242
    StackObject *tos = QSLIST_FIRST(&qiv->stack);
243 244
    GHashTableIter iter;
    const char *key;
245

246
    assert(tos && !tos->entry);
247 248 249 250 251

    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));
252 253 254
    }
}

255
static void qobject_input_stack_object_free(StackObject *tos)
256
{
257 258 259
    if (tos->h) {
        g_hash_table_unref(tos->h);
    }
260

261 262
    g_free(tos);
}
263

264
static void qobject_input_pop(Visitor *v, void **obj)
265
{
266
    QObjectInputVisitor *qiv = to_qiv(v);
267
    StackObject *tos = QSLIST_FIRST(&qiv->stack);
268

269 270
    assert(tos && tos->qapi == obj);
    QSLIST_REMOVE_HEAD(&qiv->stack, node);
271
    qobject_input_stack_object_free(tos);
M
Michael Roth 已提交
272 273
}

274 275
static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
                                       size_t size, Error **errp)
M
Michael Roth 已提交
276
{
277 278
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
M
Michael Roth 已提交
279

280 281 282
    if (obj) {
        *obj = NULL;
    }
283 284 285 286
    if (!qobj) {
        return;
    }
    if (qobject_type(qobj) != QTYPE_QDICT) {
287 288
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "object");
M
Michael Roth 已提交
289 290 291
        return;
    }

292
    qobject_input_push(qiv, name, qobj, obj);
M
Michael Roth 已提交
293 294

    if (obj) {
295
        *obj = g_malloc0(size);
M
Michael Roth 已提交
296 297 298
    }
}

299 300 301 302 303 304 305 306 307
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 已提交
308

309 310 311
static void qobject_input_start_list(Visitor *v, const char *name,
                                     GenericList **list, size_t size,
                                     Error **errp)
M
Michael Roth 已提交
312
{
313 314
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
315
    const QListEntry *entry;
M
Michael Roth 已提交
316

317 318 319
    if (list) {
        *list = NULL;
    }
320 321 322 323
    if (!qobj) {
        return;
    }
    if (qobject_type(qobj) != QTYPE_QLIST) {
324 325
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "array");
M
Michael Roth 已提交
326 327 328
        return;
    }

329
    entry = qobject_input_push(qiv, name, qobj, list);
330 331
    if (entry && list) {
        *list = g_malloc0(size);
332
    }
M
Michael Roth 已提交
333 334
}

335 336
static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
                                            size_t size)
M
Michael Roth 已提交
337
{
338
    QObjectInputVisitor *qiv = to_qiv(v);
339 340 341
    StackObject *tos = QSLIST_FIRST(&qiv->stack);

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

343
    if (!tos->entry) {
M
Michael Roth 已提交
344 345
        return NULL;
    }
346 347
    tail->next = g_malloc0(size);
    return tail->next;
M
Michael Roth 已提交
348 349
}

350 351 352 353 354 355 356 357 358 359 360 361 362
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));
    }
}

363 364 365 366 367 368 369 370
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 已提交
371

372 373
static void qobject_input_start_alternate(Visitor *v, const char *name,
                                          GenericAlternate **obj, size_t size,
374
                                          Error **errp)
K
Kevin Wolf 已提交
375
{
376 377
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
K
Kevin Wolf 已提交
378 379

    if (!qobj) {
380
        *obj = NULL;
K
Kevin Wolf 已提交
381 382
        return;
    }
383 384
    *obj = g_malloc0(size);
    (*obj)->type = qobject_type(qobj);
K
Kevin Wolf 已提交
385 386
}

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

394 395 396
    if (!qobj) {
        return;
    }
397 398
    qnum = qobject_to_qnum(qobj);
    if (!qnum || !qnum_get_try_int(qnum, obj)) {
399 400
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "integer");
M
Michael Roth 已提交
401 402 403
    }
}

404 405 406 407
static void qobject_input_type_int64_keyval(Visitor *v, const char *name,
                                            int64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
408
    const char *str = qobject_input_get_keyval(qiv, name, errp);
409

410
    if (!str) {
411 412 413
        return;
    }

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

421 422
static void qobject_input_type_uint64(Visitor *v, const char *name,
                                      uint64_t *obj, Error **errp)
423
{
424 425
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
426 427
    QNum *qnum;
    int64_t val;
428

429 430 431
    if (!qobj) {
        return;
    }
432
    qnum = qobject_to_qnum(qobj);
433 434 435 436 437 438
    if (!qnum) {
        goto err;
    }

    if (qnum_get_try_uint(qnum, obj)) {
        return;
439
    }
440 441 442 443 444 445 446 447 448 449

    /* Need to accept negative values for backward compatibility */
    if (qnum_get_try_int(qnum, &val)) {
        *obj = val;
        return;
    }

err:
    error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
               full_name(qiv, name), "uint64");
450 451
}

452 453 454 455
static void qobject_input_type_uint64_keyval(Visitor *v, const char *name,
                                             uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
456
    const char *str = qobject_input_get_keyval(qiv, name, errp);
457

458
    if (!str) {
459 460 461
        return;
    }

462
    if (qemu_strtou64(str, NULL, 0, obj) < 0) {
463 464 465 466 467 468
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "integer");
    }
}

469 470
static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
                                    Error **errp)
M
Michael Roth 已提交
471
{
472 473
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
474
    QBool *qbool;
M
Michael Roth 已提交
475

476 477 478 479
    if (!qobj) {
        return;
    }
    qbool = qobject_to_qbool(qobj);
480
    if (!qbool) {
481 482
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "boolean");
M
Michael Roth 已提交
483 484 485
        return;
    }

486
    *obj = qbool_get_bool(qbool);
M
Michael Roth 已提交
487 488
}

489 490 491 492
static void qobject_input_type_bool_keyval(Visitor *v, const char *name,
                                           bool *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
493
    const char *str = qobject_input_get_keyval(qiv, name, errp);
494

495
    if (!str) {
496 497 498 499 500 501 502 503 504 505 506 507 508
        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'");
    }
}

509 510
static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
                                   Error **errp)
M
Michael Roth 已提交
511
{
512 513
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
514
    QString *qstr;
M
Michael Roth 已提交
515

516 517 518 519 520
    *obj = NULL;
    if (!qobj) {
        return;
    }
    qstr = qobject_to_qstring(qobj);
521
    if (!qstr) {
522 523
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "string");
M
Michael Roth 已提交
524 525 526
        return;
    }

527
    *obj = g_strdup(qstring_get_str(qstr));
M
Michael Roth 已提交
528 529
}

530 531 532 533 534 535 536 537 538
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);
}

539 540
static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
                                      Error **errp)
M
Michael Roth 已提交
541
{
542 543
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
544
    QNum *qnum;
M
Michael Roth 已提交
545

546 547 548
    if (!qobj) {
        return;
    }
549 550
    qnum = qobject_to_qnum(qobj);
    if (!qnum) {
551 552
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "number");
553
        return;
554
    }
555

556
    *obj = qnum_get_double(qnum);
M
Michael Roth 已提交
557 558
}

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

566
    if (!str) {
567 568 569 570 571
        return;
    }

    errno = 0;
    *obj = strtod(str, &endp);
572
    if (errno || endp == str || *endp || !isfinite(*obj)) {
573 574 575 576 577 578
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "number");
    }
}

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

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

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

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

600
    *obj = NULL;
601 602 603 604
    if (!qobj) {
        return;
    }

605
    if (qobject_type(qobj) != QTYPE_QNULL) {
606 607
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "null");
608
        return;
609
    }
610
    *obj = qnull();
E
Eric Blake 已提交
611 612
}

613 614 615 616
static void qobject_input_type_size_keyval(Visitor *v, const char *name,
                                           uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
617
    const char *str = qobject_input_get_keyval(qiv, name, errp);
618

619
    if (!str) {
620 621 622
        return;
    }

623
    if (qemu_strtosz(str, NULL, obj) < 0) {
624 625 626 627 628 629
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "size");
    }
}

630
static void qobject_input_optional(Visitor *v, const char *name, bool *present)
M
Michael Roth 已提交
631
{
632
    QObjectInputVisitor *qiv = to_qiv(v);
633
    QObject *qobj = qobject_input_try_get_object(qiv, name, false);
M
Michael Roth 已提交
634 635 636 637 638 639 640 641 642

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

    *present = true;
}

643
static void qobject_input_free(Visitor *v)
E
Eric Blake 已提交
644
{
645
    QObjectInputVisitor *qiv = to_qiv(v);
646

647 648 649 650
    while (!QSLIST_EMPTY(&qiv->stack)) {
        StackObject *tos = QSLIST_FIRST(&qiv->stack);

        QSLIST_REMOVE_HEAD(&qiv->stack, node);
651
        qobject_input_stack_object_free(tos);
652
    }
E
Eric Blake 已提交
653

654
    qobject_decref(qiv->root);
655 656 657
    if (qiv->errname) {
        g_string_free(qiv->errname, TRUE);
    }
658
    g_free(qiv);
E
Eric Blake 已提交
659 660
}

661
static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
M
Michael Roth 已提交
662
{
663
    QObjectInputVisitor *v = g_malloc0(sizeof(*v));
M
Michael Roth 已提交
664

665
    assert(obj);
M
Michael Roth 已提交
666

667
    v->visitor.type = VISITOR_INPUT;
668 669
    v->visitor.start_struct = qobject_input_start_struct;
    v->visitor.check_struct = qobject_input_check_struct;
670
    v->visitor.end_struct = qobject_input_end_struct;
671 672
    v->visitor.start_list = qobject_input_start_list;
    v->visitor.next_list = qobject_input_next_list;
673
    v->visitor.check_list = qobject_input_check_list;
674
    v->visitor.end_list = qobject_input_end_list;
675
    v->visitor.start_alternate = qobject_input_start_alternate;
676 677 678 679 680 681 682 683 684 685 686 687 688
    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);

689 690 691 692 693 694 695
    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 已提交
696

697
    return &v->visitor;
M
Michael Roth 已提交
698
}
699 700 701

Visitor *qobject_input_visitor_new_keyval(QObject *obj)
{
702
    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
703 704 705 706

    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;
707
    v->visitor.type_str = qobject_input_type_str_keyval;
708 709 710 711
    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 已提交
712
    v->keyval = true;
713 714 715

    return &v->visitor;
}
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 745 746 747 748 749

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;
}