qobject-input-visitor.c 20.0 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"
23 24
#include "qapi/qmp/types.h"
#include "qapi/qmp/qerror.h"
25
#include "qemu/cutils.h"
26
#include "qemu/option.h"
M
Michael Roth 已提交
27

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

33 34 35
    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 */
36

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

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

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

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

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

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

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

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

    return qiv->errname->str;
}

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

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

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

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

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

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

159 160 161 162 163 164 165 166 167 168 169 170
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;
}

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

    return qstring_get_str(qstr);
}

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

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

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

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

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

234

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

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

    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));
248 249 250
    }
}

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

257 258
    g_free(tos);
}
259

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

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

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

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

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

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

295 296 297 298 299 300 301 302 303
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 已提交
304

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

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

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

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

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

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

346 347 348 349 350 351 352 353 354 355 356 357 358
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));
    }
}

359 360 361 362 363 364 365 366
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 已提交
367

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

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

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

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

400 401 402 403
static void qobject_input_type_int64_keyval(Visitor *v, const char *name,
                                            int64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
404
    const char *str = qobject_input_get_keyval(qiv, name, errp);
405

406
    if (!str) {
407 408 409
        return;
    }

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

417 418
static void qobject_input_type_uint64(Visitor *v, const char *name,
                                      uint64_t *obj, Error **errp)
419
{
420
    /* FIXME: qobject_to_qnum mishandles values over INT64_MAX */
421 422
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
423 424
    QNum *qnum;
    int64_t val;
425

426 427 428
    if (!qobj) {
        return;
    }
429 430
    qnum = qobject_to_qnum(qobj);
    if (!qnum || !qnum_get_try_int(qnum, &val)) {
431 432
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "integer");
433
    }
434
    *obj = val;
435 436
}

437 438 439 440
static void qobject_input_type_uint64_keyval(Visitor *v, const char *name,
                                             uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
441
    const char *str = qobject_input_get_keyval(qiv, name, errp);
442

443
    if (!str) {
444 445 446
        return;
    }

447
    if (qemu_strtou64(str, NULL, 0, obj) < 0) {
448 449 450 451 452 453
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "integer");
    }
}

454 455
static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
                                    Error **errp)
M
Michael Roth 已提交
456
{
457 458
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
459
    QBool *qbool;
M
Michael Roth 已提交
460

461 462 463 464
    if (!qobj) {
        return;
    }
    qbool = qobject_to_qbool(qobj);
465
    if (!qbool) {
466 467
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "boolean");
M
Michael Roth 已提交
468 469 470
        return;
    }

471
    *obj = qbool_get_bool(qbool);
M
Michael Roth 已提交
472 473
}

474 475 476 477
static void qobject_input_type_bool_keyval(Visitor *v, const char *name,
                                           bool *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
478
    const char *str = qobject_input_get_keyval(qiv, name, errp);
479

480
    if (!str) {
481 482 483 484 485 486 487 488 489 490 491 492 493
        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'");
    }
}

494 495
static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
                                   Error **errp)
M
Michael Roth 已提交
496
{
497 498
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
499
    QString *qstr;
M
Michael Roth 已提交
500

501 502 503 504 505
    *obj = NULL;
    if (!qobj) {
        return;
    }
    qstr = qobject_to_qstring(qobj);
506
    if (!qstr) {
507 508
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "string");
M
Michael Roth 已提交
509 510 511
        return;
    }

512
    *obj = g_strdup(qstring_get_str(qstr));
M
Michael Roth 已提交
513 514
}

515 516 517 518 519 520 521 522 523
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);
}

524 525
static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
                                      Error **errp)
M
Michael Roth 已提交
526
{
527 528
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
529
    QNum *qnum;
M
Michael Roth 已提交
530

531 532 533
    if (!qobj) {
        return;
    }
534 535
    qnum = qobject_to_qnum(qobj);
    if (!qnum) {
536 537
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "number");
538
        return;
539
    }
540

541
    *obj = qnum_get_double(qnum);
M
Michael Roth 已提交
542 543
}

544 545 546 547
static void qobject_input_type_number_keyval(Visitor *v, const char *name,
                                             double *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
548
    const char *str = qobject_input_get_keyval(qiv, name, errp);
549 550
    char *endp;

551
    if (!str) {
552 553 554 555 556
        return;
    }

    errno = 0;
    *obj = strtod(str, &endp);
557
    if (errno || endp == str || *endp || !isfinite(*obj)) {
558 559 560 561 562 563
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "number");
    }
}

564 565
static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
                                   Error **errp)
566
{
567 568
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
569

570
    *obj = NULL;
571 572 573 574
    if (!qobj) {
        return;
    }

575 576 577 578
    qobject_incref(qobj);
    *obj = qobj;
}

579
static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
E
Eric Blake 已提交
580
{
581 582
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
583

584 585 586 587
    if (!qobj) {
        return;
    }

588
    if (qobject_type(qobj) != QTYPE_QNULL) {
589 590
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "null");
591
    }
E
Eric Blake 已提交
592 593
}

594 595 596 597
static void qobject_input_type_size_keyval(Visitor *v, const char *name,
                                           uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
598
    const char *str = qobject_input_get_keyval(qiv, name, errp);
599

600
    if (!str) {
601 602 603
        return;
    }

604
    if (qemu_strtosz(str, NULL, obj) < 0) {
605 606 607 608 609 610
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "size");
    }
}

611
static void qobject_input_optional(Visitor *v, const char *name, bool *present)
M
Michael Roth 已提交
612
{
613
    QObjectInputVisitor *qiv = to_qiv(v);
614
    QObject *qobj = qobject_input_try_get_object(qiv, name, false);
M
Michael Roth 已提交
615 616 617 618 619 620 621 622 623

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

    *present = true;
}

624
static void qobject_input_free(Visitor *v)
E
Eric Blake 已提交
625
{
626
    QObjectInputVisitor *qiv = to_qiv(v);
627

628 629 630 631
    while (!QSLIST_EMPTY(&qiv->stack)) {
        StackObject *tos = QSLIST_FIRST(&qiv->stack);

        QSLIST_REMOVE_HEAD(&qiv->stack, node);
632
        qobject_input_stack_object_free(tos);
633
    }
E
Eric Blake 已提交
634

635
    qobject_decref(qiv->root);
636 637 638
    if (qiv->errname) {
        g_string_free(qiv->errname, TRUE);
    }
639
    g_free(qiv);
E
Eric Blake 已提交
640 641
}

642
static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
M
Michael Roth 已提交
643
{
644
    QObjectInputVisitor *v = g_malloc0(sizeof(*v));
M
Michael Roth 已提交
645

646
    assert(obj);
M
Michael Roth 已提交
647

648
    v->visitor.type = VISITOR_INPUT;
649 650
    v->visitor.start_struct = qobject_input_start_struct;
    v->visitor.check_struct = qobject_input_check_struct;
651
    v->visitor.end_struct = qobject_input_end_struct;
652 653
    v->visitor.start_list = qobject_input_start_list;
    v->visitor.next_list = qobject_input_next_list;
654
    v->visitor.check_list = qobject_input_check_list;
655
    v->visitor.end_list = qobject_input_end_list;
656
    v->visitor.start_alternate = qobject_input_start_alternate;
657 658 659 660 661 662 663 664 665 666 667 668 669
    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);

670 671 672 673 674 675 676
    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 已提交
677

678
    return &v->visitor;
M
Michael Roth 已提交
679
}
680 681 682

Visitor *qobject_input_visitor_new_keyval(QObject *obj)
{
683
    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
684 685 686 687

    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;
688
    v->visitor.type_str = qobject_input_type_str_keyval;
689 690 691 692
    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 已提交
693
    v->keyval = true;
694 695 696

    return &v->visitor;
}
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730

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