qobject-input-visitor.c 19.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 "qapi/error.h"
17
#include "qapi/qobject-input-visitor.h"
18
#include "qapi/visitor-impl.h"
19
#include "qemu/queue.h"
M
Michael Roth 已提交
20
#include "qemu-common.h"
21
#include "qapi/qmp/qjson.h"
22 23
#include "qapi/qmp/types.h"
#include "qapi/qmp/qerror.h"
24
#include "qemu/cutils.h"
25
#include "qemu/option.h"
M
Michael Roth 已提交
26

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

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

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

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

42 43 44 45 46
    /* Root of visit at visitor creation. */
    QObject *root;

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

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

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

57 58
static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
                                 int n)
59 60 61 62 63 64 65 66 67 68 69
{
    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) {
70 71 72 73
        if (n) {
            n--;
        } else if (qobject_type(so->obj) == QTYPE_QDICT) {
            g_string_prepend(qiv->errname, name ?: "<anonymous>");
74 75 76 77 78 79 80
            g_string_prepend_c(qiv->errname, '.');
        } else {
            snprintf(buf, sizeof(buf), "[%u]", so->index);
            g_string_prepend(qiv->errname, buf);
        }
        name = so->name;
    }
81
    assert(!n);
82 83 84 85 86

    if (name) {
        g_string_prepend(qiv->errname, name);
    } else if (qiv->errname->str[0] == '.') {
        g_string_erase(qiv->errname, 0, 1);
87
    } else if (!qiv->errname->str[0]) {
88 89 90 91 92 93
        return "<anonymous>";
    }

    return qiv->errname->str;
}

94 95 96 97 98
static const char *full_name(QObjectInputVisitor *qiv, const char *name)
{
    return full_name_nth(qiv, name, 0);
}

99 100 101
static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
                                             const char *name,
                                             bool consume)
M
Michael Roth 已提交
102
{
103 104
    StackObject *tos;
    QObject *qobj;
105
    QObject *ret;
E
Eric Blake 已提交
106

107
    if (QSLIST_EMPTY(&qiv->stack)) {
108
        /* Starting at root, name is ignored. */
109
        assert(qiv->root);
110 111 112 113
        return qiv->root;
    }

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

118 119
    if (qobject_type(qobj) == QTYPE_QDICT) {
        assert(name);
120 121 122 123
        ret = qdict_get(qobject_to_qdict(qobj), name);
        if (tos->h && consume && ret) {
            bool removed = g_hash_table_remove(tos->h, name);
            assert(removed);
124
        }
125
    } else {
E
Eric Blake 已提交
126
        assert(qobject_type(qobj) == QTYPE_QLIST);
127
        assert(!name);
128 129 130 131 132 133 134 135
        if (tos->entry) {
            ret = qlist_entry_obj(tos->entry);
            if (consume) {
                tos->entry = qlist_next(tos->entry);
            }
        } else {
            ret = NULL;
        }
136
        if (consume) {
137
            tos->index++;
138
        }
M
Michael Roth 已提交
139 140
    }

141
    return ret;
M
Michael Roth 已提交
142 143
}

144 145 146 147 148 149 150 151 152 153 154 155
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;
}

156 157 158 159 160 161 162 163 164 165 166 167 168 169
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) {
170 171 172 173 174 175 176 177 178 179 180 181
        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;
        }
182 183 184 185 186
    }

    return qstring_get_str(qstr);
}

187 188 189 190 191 192
static void qdict_add_key(const char *key, QObject *obj, void *opaque)
{
    GHashTable *h = opaque;
    g_hash_table_insert(h, (gpointer) key, NULL);
}

193
static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
194
                                            const char *name,
195
                                            QObject *obj, void *qapi)
M
Michael Roth 已提交
196
{
197
    GHashTable *h;
198
    StackObject *tos = g_new0(StackObject, 1);
M
Michael Roth 已提交
199

E
Eric Blake 已提交
200
    assert(obj);
201
    tos->name = name;
E
Eric Blake 已提交
202
    tos->obj = obj;
E
Eric Blake 已提交
203
    tos->qapi = qapi;
204

205
    if (qobject_type(obj) == QTYPE_QDICT) {
206 207
        h = g_hash_table_new(g_str_hash, g_str_equal);
        qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
E
Eric Blake 已提交
208
        tos->h = h;
209 210
    } else {
        assert(qobject_type(obj) == QTYPE_QLIST);
211
        tos->entry = qlist_first(qobject_to_qlist(obj));
212
        tos->index = -1;
213 214
    }

215
    QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
216
    return tos->entry;
M
Michael Roth 已提交
217 218
}

219

220
static void qobject_input_check_struct(Visitor *v, Error **errp)
M
Michael Roth 已提交
221
{
222
    QObjectInputVisitor *qiv = to_qiv(v);
223
    StackObject *tos = QSLIST_FIRST(&qiv->stack);
224 225
    GHashTableIter iter;
    const char *key;
226

227
    assert(tos && !tos->entry);
228 229 230 231 232

    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));
233 234 235
    }
}

236
static void qobject_input_stack_object_free(StackObject *tos)
237
{
238 239 240
    if (tos->h) {
        g_hash_table_unref(tos->h);
    }
241

242 243
    g_free(tos);
}
244

245
static void qobject_input_pop(Visitor *v, void **obj)
246
{
247
    QObjectInputVisitor *qiv = to_qiv(v);
248
    StackObject *tos = QSLIST_FIRST(&qiv->stack);
249

250 251
    assert(tos && tos->qapi == obj);
    QSLIST_REMOVE_HEAD(&qiv->stack, node);
252
    qobject_input_stack_object_free(tos);
M
Michael Roth 已提交
253 254
}

255 256
static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
                                       size_t size, Error **errp)
M
Michael Roth 已提交
257
{
258 259
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
M
Michael Roth 已提交
260

261 262 263
    if (obj) {
        *obj = NULL;
    }
264 265 266 267
    if (!qobj) {
        return;
    }
    if (qobject_type(qobj) != QTYPE_QDICT) {
268 269
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "object");
M
Michael Roth 已提交
270 271 272
        return;
    }

273
    qobject_input_push(qiv, name, qobj, obj);
M
Michael Roth 已提交
274 275

    if (obj) {
276
        *obj = g_malloc0(size);
M
Michael Roth 已提交
277 278 279 280
    }
}


281 282 283
static void qobject_input_start_list(Visitor *v, const char *name,
                                     GenericList **list, size_t size,
                                     Error **errp)
M
Michael Roth 已提交
284
{
285 286
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
287
    const QListEntry *entry;
M
Michael Roth 已提交
288

289 290 291
    if (list) {
        *list = NULL;
    }
292 293 294 295
    if (!qobj) {
        return;
    }
    if (qobject_type(qobj) != QTYPE_QLIST) {
296 297
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "array");
M
Michael Roth 已提交
298 299 300
        return;
    }

301
    entry = qobject_input_push(qiv, name, qobj, list);
302 303
    if (entry && list) {
        *list = g_malloc0(size);
304
    }
M
Michael Roth 已提交
305 306
}

307 308
static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
                                            size_t size)
M
Michael Roth 已提交
309
{
310
    QObjectInputVisitor *qiv = to_qiv(v);
311 312 313
    StackObject *tos = QSLIST_FIRST(&qiv->stack);

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

315
    if (!tos->entry) {
M
Michael Roth 已提交
316 317
        return NULL;
    }
318 319
    tail->next = g_malloc0(size);
    return tail->next;
M
Michael Roth 已提交
320 321
}

322 323 324 325 326 327 328 329 330 331 332 333 334
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));
    }
}

M
Michael Roth 已提交
335

336 337 338
static void qobject_input_start_alternate(Visitor *v, const char *name,
                                          GenericAlternate **obj, size_t size,
                                          bool promote_int, Error **errp)
K
Kevin Wolf 已提交
339
{
340 341
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
K
Kevin Wolf 已提交
342 343

    if (!qobj) {
344
        *obj = NULL;
K
Kevin Wolf 已提交
345 346
        return;
    }
347 348 349 350
    *obj = g_malloc0(size);
    (*obj)->type = qobject_type(qobj);
    if (promote_int && (*obj)->type == QTYPE_QINT) {
        (*obj)->type = QTYPE_QFLOAT;
351
    }
K
Kevin Wolf 已提交
352 353
}

354 355
static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
                                     Error **errp)
M
Michael Roth 已提交
356
{
357 358
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
359
    QInt *qint;
M
Michael Roth 已提交
360

361 362 363 364
    if (!qobj) {
        return;
    }
    qint = qobject_to_qint(qobj);
365
    if (!qint) {
366 367
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "integer");
M
Michael Roth 已提交
368 369 370
        return;
    }

371
    *obj = qint_get_int(qint);
M
Michael Roth 已提交
372 373
}

374 375 376 377 378

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

381
    if (!str) {
382 383 384
        return;
    }

385
    if (qemu_strtoi64(str, NULL, 0, obj) < 0) {
386 387 388 389 390 391
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "integer");
    }
}

392 393
static void qobject_input_type_uint64(Visitor *v, const char *name,
                                      uint64_t *obj, Error **errp)
394 395
{
    /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
396 397
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
398
    QInt *qint;
399

400 401 402 403
    if (!qobj) {
        return;
    }
    qint = qobject_to_qint(qobj);
404
    if (!qint) {
405 406
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "integer");
407 408 409 410 411 412
        return;
    }

    *obj = qint_get_int(qint);
}

413 414 415 416
static void qobject_input_type_uint64_keyval(Visitor *v, const char *name,
                                             uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
417
    const char *str = qobject_input_get_keyval(qiv, name, errp);
418

419
    if (!str) {
420 421 422
        return;
    }

423
    if (qemu_strtou64(str, NULL, 0, obj) < 0) {
424 425 426 427 428 429
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "integer");
    }
}

430 431
static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
                                    Error **errp)
M
Michael Roth 已提交
432
{
433 434
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
435
    QBool *qbool;
M
Michael Roth 已提交
436

437 438 439 440
    if (!qobj) {
        return;
    }
    qbool = qobject_to_qbool(qobj);
441
    if (!qbool) {
442 443
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "boolean");
M
Michael Roth 已提交
444 445 446
        return;
    }

447
    *obj = qbool_get_bool(qbool);
M
Michael Roth 已提交
448 449
}

450 451 452 453
static void qobject_input_type_bool_keyval(Visitor *v, const char *name,
                                           bool *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 460 461 462 463 464 465 466 467 468 469
        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'");
    }
}

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

477 478 479 480 481
    *obj = NULL;
    if (!qobj) {
        return;
    }
    qstr = qobject_to_qstring(qobj);
482
    if (!qstr) {
483 484
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "string");
M
Michael Roth 已提交
485 486 487
        return;
    }

488
    *obj = g_strdup(qstring_get_str(qstr));
M
Michael Roth 已提交
489 490
}

491 492 493 494 495 496 497 498 499
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);
}

500 501
static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
                                      Error **errp)
M
Michael Roth 已提交
502
{
503 504
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
505 506
    QInt *qint;
    QFloat *qfloat;
M
Michael Roth 已提交
507

508 509 510
    if (!qobj) {
        return;
    }
511 512 513
    qint = qobject_to_qint(qobj);
    if (qint) {
        *obj = qint_get_int(qobject_to_qint(qobj));
M
Michael Roth 已提交
514 515 516
        return;
    }

517 518
    qfloat = qobject_to_qfloat(qobj);
    if (qfloat) {
519
        *obj = qfloat_get_double(qobject_to_qfloat(qobj));
520
        return;
521
    }
522

523 524
    error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
               full_name(qiv, name), "number");
M
Michael Roth 已提交
525 526
}

527 528 529 530
static void qobject_input_type_number_keyval(Visitor *v, const char *name,
                                             double *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
531
    const char *str = qobject_input_get_keyval(qiv, name, errp);
532 533
    char *endp;

534
    if (!str) {
535 536 537 538 539 540 541 542 543 544 545 546
        return;
    }

    errno = 0;
    *obj = strtod(str, &endp);
    if (errno || endp == str || *endp) {
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "number");
    }
}

547 548
static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
                                   Error **errp)
549
{
550 551
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
552

553
    *obj = NULL;
554 555 556 557
    if (!qobj) {
        return;
    }

558 559 560 561
    qobject_incref(qobj);
    *obj = qobj;
}

562
static void qobject_input_type_null(Visitor *v, const char *name, Error **errp)
E
Eric Blake 已提交
563
{
564 565
    QObjectInputVisitor *qiv = to_qiv(v);
    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
566

567 568 569 570
    if (!qobj) {
        return;
    }

571
    if (qobject_type(qobj) != QTYPE_QNULL) {
572 573
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
                   full_name(qiv, name), "null");
574
    }
E
Eric Blake 已提交
575 576
}

577 578 579 580
static void qobject_input_type_size_keyval(Visitor *v, const char *name,
                                           uint64_t *obj, Error **errp)
{
    QObjectInputVisitor *qiv = to_qiv(v);
581
    const char *str = qobject_input_get_keyval(qiv, name, errp);
582

583
    if (!str) {
584 585 586
        return;
    }

587
    if (qemu_strtosz(str, NULL, obj) < 0) {
588 589 590 591 592 593
        /* TODO report -ERANGE more nicely */
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                   full_name(qiv, name), "size");
    }
}

594
static void qobject_input_optional(Visitor *v, const char *name, bool *present)
M
Michael Roth 已提交
595
{
596
    QObjectInputVisitor *qiv = to_qiv(v);
597
    QObject *qobj = qobject_input_try_get_object(qiv, name, false);
M
Michael Roth 已提交
598 599 600 601 602 603 604 605 606

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

    *present = true;
}

607
static void qobject_input_free(Visitor *v)
E
Eric Blake 已提交
608
{
609
    QObjectInputVisitor *qiv = to_qiv(v);
610

611 612 613 614
    while (!QSLIST_EMPTY(&qiv->stack)) {
        StackObject *tos = QSLIST_FIRST(&qiv->stack);

        QSLIST_REMOVE_HEAD(&qiv->stack, node);
615
        qobject_input_stack_object_free(tos);
616
    }
E
Eric Blake 已提交
617

618
    qobject_decref(qiv->root);
619 620 621
    if (qiv->errname) {
        g_string_free(qiv->errname, TRUE);
    }
622
    g_free(qiv);
E
Eric Blake 已提交
623 624
}

625
static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
M
Michael Roth 已提交
626
{
627
    QObjectInputVisitor *v = g_malloc0(sizeof(*v));
M
Michael Roth 已提交
628

629
    assert(obj);
M
Michael Roth 已提交
630

631
    v->visitor.type = VISITOR_INPUT;
632 633 634 635 636
    v->visitor.start_struct = qobject_input_start_struct;
    v->visitor.check_struct = qobject_input_check_struct;
    v->visitor.end_struct = qobject_input_pop;
    v->visitor.start_list = qobject_input_start_list;
    v->visitor.next_list = qobject_input_next_list;
637
    v->visitor.check_list = qobject_input_check_list;
638 639
    v->visitor.end_list = qobject_input_pop;
    v->visitor.start_alternate = qobject_input_start_alternate;
640 641 642 643 644 645 646 647 648 649 650 651 652
    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);

653 654 655 656 657 658 659
    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 已提交
660

661
    return &v->visitor;
M
Michael Roth 已提交
662
}
663 664 665

Visitor *qobject_input_visitor_new_keyval(QObject *obj)
{
666
    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
667 668 669 670

    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;
671
    v->visitor.type_str = qobject_input_type_str_keyval;
672 673 674 675 676 677 678
    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;

    return &v->visitor;
}
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712

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