qobject-input-visitor.c 20.1 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
static void qobject_input_start_alternate(Visitor *v, const char *name,
                                          GenericAlternate **obj, size_t size,
370
                                          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 421
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
422 423
    QNum *qnum;
    int64_t val;
424

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

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

    /* 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");
446 447
}

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

454
    if (!str) {
455 456 457
        return;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

562
    if (!str) {
563 564 565 566 567
        return;
    }

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

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

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

586 587 588 589
    qobject_incref(qobj);
    *obj = qobj;
}

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

595 596 597 598
    if (!qobj) {
        return;
    }

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

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

611
    if (!str) {
612 613 614
        return;
    }

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

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

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

    *present = true;
}

635
static void qobject_input_free(Visitor *v)
E
Eric Blake 已提交
636
{
637
    QObjectInputVisitor *qiv = to_qiv(v);
638

639 640 641 642
    while (!QSLIST_EMPTY(&qiv->stack)) {
        StackObject *tos = QSLIST_FIRST(&qiv->stack);

        QSLIST_REMOVE_HEAD(&qiv->stack, node);
643
        qobject_input_stack_object_free(tos);
644
    }
E
Eric Blake 已提交
645

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

653
static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
M
Michael Roth 已提交
654
{
655
    QObjectInputVisitor *v = g_malloc0(sizeof(*v));
M
Michael Roth 已提交
656

657
    assert(obj);
M
Michael Roth 已提交
658

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

681 682 683 684 685 686 687
    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 已提交
688

689
    return &v->visitor;
M
Michael Roth 已提交
690
}
691 692 693

Visitor *qobject_input_visitor_new_keyval(QObject *obj)
{
694
    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
695 696 697 698

    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;
699
    v->visitor.type_str = qobject_input_type_str_keyval;
700 701 702 703
    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 已提交
704
    v->keyval = true;
705 706 707

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

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