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"
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 381 382
    *obj = g_malloc0(size);
    (*obj)->type = qobject_type(qobj);
    if (promote_int && (*obj)->type == QTYPE_QINT) {
        (*obj)->type = QTYPE_QFLOAT;
383
    }
K
Kevin Wolf 已提交
384 385
}

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

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

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

406 407 408 409 410

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

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

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

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

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

    *obj = qint_get_int(qint);
}

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

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

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

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

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

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

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

488
    if (!str) {
489 490 491 492 493 494 495 496 497 498 499 500 501
        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'");
    }
}

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

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

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

523 524 525 526 527 528 529 530 531
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);
}

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

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

549
    qfloat = qobject_to_qfloat(qobj);
550 551 552
    if (!qfloat) {
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "number");
553
        return;
554
    }
555

556
    *obj = qfloat_get_double(qobject_to_qfloat(qobj));
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
static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
E
Eric Blake 已提交
595
{
596 597
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
598

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

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

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

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

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

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

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

    *present = true;
}

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

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

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

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

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

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

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

685 686 687 688 689 690 691
    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 已提交
692

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

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

    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;
703
    v->visitor.type_str = qobject_input_type_str_keyval;
704 705 706 707
    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 已提交
708
    v->keyval = true;
709 710 711

    return &v->visitor;
}
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 745

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