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 <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/qerror.h"
25 26
#include "qapi/qmp/qnull.h"
#include "qapi/qmp/qnum.h"
27
#include "qemu/cutils.h"
28
#include "qemu/option.h"
M
Michael Roth 已提交
29

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

35 36 37
    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 */
38

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

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

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

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

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

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

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

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

    return qiv->errname->str;
}

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

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

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

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

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

158
    return ret;
M
Michael Roth 已提交
159 160
}

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

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

    return qstring_get_str(qstr);
}

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

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

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

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

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

236

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

244
    assert(tos && !tos->entry);
245 246 247 248 249

    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));
250 251 252
    }
}

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

259 260
    g_free(tos);
}
261

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if (!qobj) {
378
        *obj = NULL;
K
Kevin Wolf 已提交
379 380
        return;
    }
381 382
    *obj = g_malloc0(size);
    (*obj)->type = qobject_type(qobj);
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
    QNum *qnum;
M
Michael Roth 已提交
391

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

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

408
    if (!str) {
409 410 411
        return;
    }

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

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

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

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

    /* 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");
448 449
}

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

456
    if (!str) {
457 458 459
        return;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

564
    if (!str) {
565 566 567 568 569
        return;
    }

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

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

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

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

592 593
static void qobject_input_type_null(Visitor *v, const char *name,
                                    QNull **obj, 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
    *obj = NULL;
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
        return;
607
    }
608
    *obj = qnull();
E
Eric Blake 已提交
609 610
}

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

617
    if (!str) {
618 619 620
        return;
    }

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

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

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

    *present = true;
}

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

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

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

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

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

663
    assert(obj);
M
Michael Roth 已提交
664

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

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

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

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

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

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

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