qemu/qapi/qobject-input-visitor.c
<<
>>
Prefs
   1/*
   2 * Input Visitor
   3 *
   4 * Copyright (C) 2012-2017 Red Hat, Inc.
   5 * Copyright IBM, Corp. 2011
   6 *
   7 * Authors:
   8 *  Anthony Liguori   <aliguori@us.ibm.com>
   9 *
  10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  11 * See the COPYING.LIB file in the top-level directory.
  12 *
  13 */
  14
  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"
  21#include "qapi/qmp/qjson.h"
  22#include "qapi/qmp/qbool.h"
  23#include "qapi/qmp/qdict.h"
  24#include "qapi/qmp/qerror.h"
  25#include "qapi/qmp/qlist.h"
  26#include "qapi/qmp/qnull.h"
  27#include "qapi/qmp/qnum.h"
  28#include "qapi/qmp/qstring.h"
  29#include "qemu/cutils.h"
  30#include "qemu/option.h"
  31
  32typedef struct StackObject {
  33    const char *name;            /* Name of @obj in its parent, if any */
  34    QObject *obj;                /* QDict or QList being visited */
  35    void *qapi; /* sanity check that caller uses same pointer */
  36
  37    GHashTable *h;              /* If @obj is QDict: unvisited keys */
  38    const QListEntry *entry;    /* If @obj is QList: unvisited tail */
  39    unsigned index;             /* If @obj is QList: list index of @entry */
  40
  41    QSLIST_ENTRY(StackObject) node; /* parent */
  42} StackObject;
  43
  44struct QObjectInputVisitor {
  45    Visitor visitor;
  46
  47    /* Root of visit at visitor creation. */
  48    QObject *root;
  49    bool keyval;                /* Assume @root made with keyval_parse() */
  50
  51    /* Stack of objects being visited (all entries will be either
  52     * QDict or QList). */
  53    QSLIST_HEAD(, StackObject) stack;
  54
  55    GString *errname;           /* Accumulator for full_name() */
  56};
  57
  58static QObjectInputVisitor *to_qiv(Visitor *v)
  59{
  60    return container_of(v, QObjectInputVisitor, visitor);
  61}
  62
  63/*
  64 * Find the full name of something @qiv is currently visiting.
  65 * @qiv is visiting something named @name in the stack of containers
  66 * @qiv->stack.
  67 * If @n is zero, return its full name.
  68 * If @n is positive, return the full name of the @n-th container
  69 * counting from the top.  The stack of containers must have at least
  70 * @n elements.
  71 * The returned string is valid until the next full_name_nth(@v) or
  72 * destruction of @v.
  73 */
  74static const char *full_name_nth(QObjectInputVisitor *qiv, const char *name,
  75                                 int n)
  76{
  77    StackObject *so;
  78    char buf[32];
  79
  80    if (qiv->errname) {
  81        g_string_truncate(qiv->errname, 0);
  82    } else {
  83        qiv->errname = g_string_new("");
  84    }
  85
  86    QSLIST_FOREACH(so , &qiv->stack, node) {
  87        if (n) {
  88            n--;
  89        } else if (qobject_type(so->obj) == QTYPE_QDICT) {
  90            g_string_prepend(qiv->errname, name ?: "<anonymous>");
  91            g_string_prepend_c(qiv->errname, '.');
  92        } else {
  93            snprintf(buf, sizeof(buf),
  94                     qiv->keyval ? ".%u" : "[%u]",
  95                     so->index);
  96            g_string_prepend(qiv->errname, buf);
  97        }
  98        name = so->name;
  99    }
 100    assert(!n);
 101
 102    if (name) {
 103        g_string_prepend(qiv->errname, name);
 104    } else if (qiv->errname->str[0] == '.') {
 105        g_string_erase(qiv->errname, 0, 1);
 106    } else if (!qiv->errname->str[0]) {
 107        return "<anonymous>";
 108    }
 109
 110    return qiv->errname->str;
 111}
 112
 113static const char *full_name(QObjectInputVisitor *qiv, const char *name)
 114{
 115    return full_name_nth(qiv, name, 0);
 116}
 117
 118static QObject *qobject_input_try_get_object(QObjectInputVisitor *qiv,
 119                                             const char *name,
 120                                             bool consume)
 121{
 122    StackObject *tos;
 123    QObject *qobj;
 124    QObject *ret;
 125
 126    if (QSLIST_EMPTY(&qiv->stack)) {
 127        /* Starting at root, name is ignored. */
 128        assert(qiv->root);
 129        return qiv->root;
 130    }
 131
 132    /* We are in a container; find the next element. */
 133    tos = QSLIST_FIRST(&qiv->stack);
 134    qobj = tos->obj;
 135    assert(qobj);
 136
 137    if (qobject_type(qobj) == QTYPE_QDICT) {
 138        assert(name);
 139        ret = qdict_get(qobject_to(QDict, qobj), name);
 140        if (tos->h && consume && ret) {
 141            bool removed = g_hash_table_remove(tos->h, name);
 142            assert(removed);
 143        }
 144    } else {
 145        assert(qobject_type(qobj) == QTYPE_QLIST);
 146        assert(!name);
 147        if (tos->entry) {
 148            ret = qlist_entry_obj(tos->entry);
 149            if (consume) {
 150                tos->entry = qlist_next(tos->entry);
 151            }
 152        } else {
 153            ret = NULL;
 154        }
 155        if (consume) {
 156            tos->index++;
 157        }
 158    }
 159
 160    return ret;
 161}
 162
 163static QObject *qobject_input_get_object(QObjectInputVisitor *qiv,
 164                                         const char *name,
 165                                         bool consume, Error **errp)
 166{
 167    QObject *obj = qobject_input_try_get_object(qiv, name, consume);
 168
 169    if (!obj) {
 170        error_setg(errp, QERR_MISSING_PARAMETER, full_name(qiv, name));
 171    }
 172    return obj;
 173}
 174
 175static const char *qobject_input_get_keyval(QObjectInputVisitor *qiv,
 176                                            const char *name,
 177                                            Error **errp)
 178{
 179    QObject *qobj;
 180    QString *qstr;
 181
 182    qobj = qobject_input_get_object(qiv, name, true, errp);
 183    if (!qobj) {
 184        return NULL;
 185    }
 186
 187    qstr = qobject_to(QString, qobj);
 188    if (!qstr) {
 189        switch (qobject_type(qobj)) {
 190        case QTYPE_QDICT:
 191        case QTYPE_QLIST:
 192            error_setg(errp, "Parameters '%s.*' are unexpected",
 193                       full_name(qiv, name));
 194            return NULL;
 195        default:
 196            /* Non-string scalar (should this be an assertion?) */
 197            error_setg(errp, "Internal error: parameter %s invalid",
 198                       full_name(qiv, name));
 199            return NULL;
 200        }
 201    }
 202
 203    return qstring_get_str(qstr);
 204}
 205
 206static void qdict_add_key(const char *key, QObject *obj, void *opaque)
 207{
 208    GHashTable *h = opaque;
 209    g_hash_table_insert(h, (gpointer) key, NULL);
 210}
 211
 212static const QListEntry *qobject_input_push(QObjectInputVisitor *qiv,
 213                                            const char *name,
 214                                            QObject *obj, void *qapi)
 215{
 216    GHashTable *h;
 217    StackObject *tos = g_new0(StackObject, 1);
 218
 219    assert(obj);
 220    tos->name = name;
 221    tos->obj = obj;
 222    tos->qapi = qapi;
 223
 224    if (qobject_type(obj) == QTYPE_QDICT) {
 225        h = g_hash_table_new(g_str_hash, g_str_equal);
 226        qdict_iter(qobject_to(QDict, obj), qdict_add_key, h);
 227        tos->h = h;
 228    } else {
 229        assert(qobject_type(obj) == QTYPE_QLIST);
 230        tos->entry = qlist_first(qobject_to(QList, obj));
 231        tos->index = -1;
 232    }
 233
 234    QSLIST_INSERT_HEAD(&qiv->stack, tos, node);
 235    return tos->entry;
 236}
 237
 238
 239static void qobject_input_check_struct(Visitor *v, Error **errp)
 240{
 241    QObjectInputVisitor *qiv = to_qiv(v);
 242    StackObject *tos = QSLIST_FIRST(&qiv->stack);
 243    GHashTableIter iter;
 244    const char *key;
 245
 246    assert(tos && !tos->entry);
 247
 248    g_hash_table_iter_init(&iter, tos->h);
 249    if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
 250        error_setg(errp, "Parameter '%s' is unexpected",
 251                   full_name(qiv, key));
 252    }
 253}
 254
 255static void qobject_input_stack_object_free(StackObject *tos)
 256{
 257    if (tos->h) {
 258        g_hash_table_unref(tos->h);
 259    }
 260
 261    g_free(tos);
 262}
 263
 264static void qobject_input_pop(Visitor *v, void **obj)
 265{
 266    QObjectInputVisitor *qiv = to_qiv(v);
 267    StackObject *tos = QSLIST_FIRST(&qiv->stack);
 268
 269    assert(tos && tos->qapi == obj);
 270    QSLIST_REMOVE_HEAD(&qiv->stack, node);
 271    qobject_input_stack_object_free(tos);
 272}
 273
 274static void qobject_input_start_struct(Visitor *v, const char *name, void **obj,
 275                                       size_t size, Error **errp)
 276{
 277    QObjectInputVisitor *qiv = to_qiv(v);
 278    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 279
 280    if (obj) {
 281        *obj = NULL;
 282    }
 283    if (!qobj) {
 284        return;
 285    }
 286    if (qobject_type(qobj) != QTYPE_QDICT) {
 287        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 288                   full_name(qiv, name), "object");
 289        return;
 290    }
 291
 292    qobject_input_push(qiv, name, qobj, obj);
 293
 294    if (obj) {
 295        *obj = g_malloc0(size);
 296    }
 297}
 298
 299static void qobject_input_end_struct(Visitor *v, void **obj)
 300{
 301    QObjectInputVisitor *qiv = to_qiv(v);
 302    StackObject *tos = QSLIST_FIRST(&qiv->stack);
 303
 304    assert(qobject_type(tos->obj) == QTYPE_QDICT && tos->h);
 305    qobject_input_pop(v, obj);
 306}
 307
 308
 309static void qobject_input_start_list(Visitor *v, const char *name,
 310                                     GenericList **list, size_t size,
 311                                     Error **errp)
 312{
 313    QObjectInputVisitor *qiv = to_qiv(v);
 314    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 315    const QListEntry *entry;
 316
 317    if (list) {
 318        *list = NULL;
 319    }
 320    if (!qobj) {
 321        return;
 322    }
 323    if (qobject_type(qobj) != QTYPE_QLIST) {
 324        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 325                   full_name(qiv, name), "array");
 326        return;
 327    }
 328
 329    entry = qobject_input_push(qiv, name, qobj, list);
 330    if (entry && list) {
 331        *list = g_malloc0(size);
 332    }
 333}
 334
 335static GenericList *qobject_input_next_list(Visitor *v, GenericList *tail,
 336                                            size_t size)
 337{
 338    QObjectInputVisitor *qiv = to_qiv(v);
 339    StackObject *tos = QSLIST_FIRST(&qiv->stack);
 340
 341    assert(tos && qobject_to(QList, tos->obj));
 342
 343    if (!tos->entry) {
 344        return NULL;
 345    }
 346    tail->next = g_malloc0(size);
 347    return tail->next;
 348}
 349
 350static void qobject_input_check_list(Visitor *v, Error **errp)
 351{
 352    QObjectInputVisitor *qiv = to_qiv(v);
 353    StackObject *tos = QSLIST_FIRST(&qiv->stack);
 354
 355    assert(tos && qobject_to(QList, tos->obj));
 356
 357    if (tos->entry) {
 358        error_setg(errp, "Only %u list elements expected in %s",
 359                   tos->index + 1, full_name_nth(qiv, NULL, 1));
 360    }
 361}
 362
 363static void qobject_input_end_list(Visitor *v, void **obj)
 364{
 365    QObjectInputVisitor *qiv = to_qiv(v);
 366    StackObject *tos = QSLIST_FIRST(&qiv->stack);
 367
 368    assert(qobject_type(tos->obj) == QTYPE_QLIST && !tos->h);
 369    qobject_input_pop(v, obj);
 370}
 371
 372static void qobject_input_start_alternate(Visitor *v, const char *name,
 373                                          GenericAlternate **obj, size_t size,
 374                                          Error **errp)
 375{
 376    QObjectInputVisitor *qiv = to_qiv(v);
 377    QObject *qobj = qobject_input_get_object(qiv, name, false, errp);
 378
 379    if (!qobj) {
 380        *obj = NULL;
 381        return;
 382    }
 383    *obj = g_malloc0(size);
 384    (*obj)->type = qobject_type(qobj);
 385}
 386
 387static void qobject_input_type_int64(Visitor *v, const char *name, int64_t *obj,
 388                                     Error **errp)
 389{
 390    QObjectInputVisitor *qiv = to_qiv(v);
 391    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 392    QNum *qnum;
 393
 394    if (!qobj) {
 395        return;
 396    }
 397    qnum = qobject_to(QNum, qobj);
 398    if (!qnum || !qnum_get_try_int(qnum, obj)) {
 399        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 400                   full_name(qiv, name), "integer");
 401    }
 402}
 403
 404static void qobject_input_type_int64_keyval(Visitor *v, const char *name,
 405                                            int64_t *obj, Error **errp)
 406{
 407    QObjectInputVisitor *qiv = to_qiv(v);
 408    const char *str = qobject_input_get_keyval(qiv, name, errp);
 409
 410    if (!str) {
 411        return;
 412    }
 413
 414    if (qemu_strtoi64(str, NULL, 0, obj) < 0) {
 415        /* TODO report -ERANGE more nicely */
 416        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 417                   full_name(qiv, name), "integer");
 418    }
 419}
 420
 421static void qobject_input_type_uint64(Visitor *v, const char *name,
 422                                      uint64_t *obj, Error **errp)
 423{
 424    QObjectInputVisitor *qiv = to_qiv(v);
 425    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 426    QNum *qnum;
 427    int64_t val;
 428
 429    if (!qobj) {
 430        return;
 431    }
 432    qnum = qobject_to(QNum, qobj);
 433    if (!qnum) {
 434        goto err;
 435    }
 436
 437    if (qnum_get_try_uint(qnum, obj)) {
 438        return;
 439    }
 440
 441    /* Need to accept negative values for backward compatibility */
 442    if (qnum_get_try_int(qnum, &val)) {
 443        *obj = val;
 444        return;
 445    }
 446
 447err:
 448    error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 449               full_name(qiv, name), "uint64");
 450}
 451
 452static void qobject_input_type_uint64_keyval(Visitor *v, const char *name,
 453                                             uint64_t *obj, Error **errp)
 454{
 455    QObjectInputVisitor *qiv = to_qiv(v);
 456    const char *str = qobject_input_get_keyval(qiv, name, errp);
 457
 458    if (!str) {
 459        return;
 460    }
 461
 462    if (qemu_strtou64(str, NULL, 0, obj) < 0) {
 463        /* TODO report -ERANGE more nicely */
 464        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 465                   full_name(qiv, name), "integer");
 466    }
 467}
 468
 469static void qobject_input_type_bool(Visitor *v, const char *name, bool *obj,
 470                                    Error **errp)
 471{
 472    QObjectInputVisitor *qiv = to_qiv(v);
 473    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 474    QBool *qbool;
 475
 476    if (!qobj) {
 477        return;
 478    }
 479    qbool = qobject_to(QBool, qobj);
 480    if (!qbool) {
 481        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 482                   full_name(qiv, name), "boolean");
 483        return;
 484    }
 485
 486    *obj = qbool_get_bool(qbool);
 487}
 488
 489static void qobject_input_type_bool_keyval(Visitor *v, const char *name,
 490                                           bool *obj, Error **errp)
 491{
 492    QObjectInputVisitor *qiv = to_qiv(v);
 493    const char *str = qobject_input_get_keyval(qiv, name, errp);
 494
 495    if (!str) {
 496        return;
 497    }
 498
 499    if (!strcmp(str, "on")) {
 500        *obj = true;
 501    } else if (!strcmp(str, "off")) {
 502        *obj = false;
 503    } else {
 504        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 505                   full_name(qiv, name), "'on' or 'off'");
 506    }
 507}
 508
 509static void qobject_input_type_str(Visitor *v, const char *name, char **obj,
 510                                   Error **errp)
 511{
 512    QObjectInputVisitor *qiv = to_qiv(v);
 513    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 514    QString *qstr;
 515
 516    *obj = NULL;
 517    if (!qobj) {
 518        return;
 519    }
 520    qstr = qobject_to(QString, qobj);
 521    if (!qstr) {
 522        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 523                   full_name(qiv, name), "string");
 524        return;
 525    }
 526
 527    *obj = g_strdup(qstring_get_str(qstr));
 528}
 529
 530static void qobject_input_type_str_keyval(Visitor *v, const char *name,
 531                                          char **obj, Error **errp)
 532{
 533    QObjectInputVisitor *qiv = to_qiv(v);
 534    const char *str = qobject_input_get_keyval(qiv, name, errp);
 535
 536    *obj = g_strdup(str);
 537}
 538
 539static void qobject_input_type_number(Visitor *v, const char *name, double *obj,
 540                                      Error **errp)
 541{
 542    QObjectInputVisitor *qiv = to_qiv(v);
 543    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 544    QNum *qnum;
 545
 546    if (!qobj) {
 547        return;
 548    }
 549    qnum = qobject_to(QNum, qobj);
 550    if (!qnum) {
 551        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 552                   full_name(qiv, name), "number");
 553        return;
 554    }
 555
 556    *obj = qnum_get_double(qnum);
 557}
 558
 559static void qobject_input_type_number_keyval(Visitor *v, const char *name,
 560                                             double *obj, Error **errp)
 561{
 562    QObjectInputVisitor *qiv = to_qiv(v);
 563    const char *str = qobject_input_get_keyval(qiv, name, errp);
 564    double val;
 565
 566    if (!str) {
 567        return;
 568    }
 569
 570    if (qemu_strtod_finite(str, NULL, &val)) {
 571        /* TODO report -ERANGE more nicely */
 572        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 573                   full_name(qiv, name), "number");
 574        return;
 575    }
 576
 577    *obj = val;
 578}
 579
 580static void qobject_input_type_any(Visitor *v, const char *name, QObject **obj,
 581                                   Error **errp)
 582{
 583    QObjectInputVisitor *qiv = to_qiv(v);
 584    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 585
 586    *obj = NULL;
 587    if (!qobj) {
 588        return;
 589    }
 590
 591    *obj = qobject_ref(qobj);
 592}
 593
 594static void qobject_input_type_null(Visitor *v, const char *name,
 595                                    QNull **obj, Error **errp)
 596{
 597    QObjectInputVisitor *qiv = to_qiv(v);
 598    QObject *qobj = qobject_input_get_object(qiv, name, true, errp);
 599
 600    *obj = NULL;
 601    if (!qobj) {
 602        return;
 603    }
 604
 605    if (qobject_type(qobj) != QTYPE_QNULL) {
 606        error_setg(errp, QERR_INVALID_PARAMETER_TYPE,
 607                   full_name(qiv, name), "null");
 608        return;
 609    }
 610    *obj = qnull();
 611}
 612
 613static void qobject_input_type_size_keyval(Visitor *v, const char *name,
 614                                           uint64_t *obj, Error **errp)
 615{
 616    QObjectInputVisitor *qiv = to_qiv(v);
 617    const char *str = qobject_input_get_keyval(qiv, name, errp);
 618
 619    if (!str) {
 620        return;
 621    }
 622
 623    if (qemu_strtosz(str, NULL, obj) < 0) {
 624        /* TODO report -ERANGE more nicely */
 625        error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
 626                   full_name(qiv, name), "size");
 627    }
 628}
 629
 630static void qobject_input_optional(Visitor *v, const char *name, bool *present)
 631{
 632    QObjectInputVisitor *qiv = to_qiv(v);
 633    QObject *qobj = qobject_input_try_get_object(qiv, name, false);
 634
 635    if (!qobj) {
 636        *present = false;
 637        return;
 638    }
 639
 640    *present = true;
 641}
 642
 643static void qobject_input_free(Visitor *v)
 644{
 645    QObjectInputVisitor *qiv = to_qiv(v);
 646
 647    while (!QSLIST_EMPTY(&qiv->stack)) {
 648        StackObject *tos = QSLIST_FIRST(&qiv->stack);
 649
 650        QSLIST_REMOVE_HEAD(&qiv->stack, node);
 651        qobject_input_stack_object_free(tos);
 652    }
 653
 654    qobject_unref(qiv->root);
 655    if (qiv->errname) {
 656        g_string_free(qiv->errname, TRUE);
 657    }
 658    g_free(qiv);
 659}
 660
 661static QObjectInputVisitor *qobject_input_visitor_base_new(QObject *obj)
 662{
 663    QObjectInputVisitor *v = g_malloc0(sizeof(*v));
 664
 665    assert(obj);
 666
 667    v->visitor.type = VISITOR_INPUT;
 668    v->visitor.start_struct = qobject_input_start_struct;
 669    v->visitor.check_struct = qobject_input_check_struct;
 670    v->visitor.end_struct = qobject_input_end_struct;
 671    v->visitor.start_list = qobject_input_start_list;
 672    v->visitor.next_list = qobject_input_next_list;
 673    v->visitor.check_list = qobject_input_check_list;
 674    v->visitor.end_list = qobject_input_end_list;
 675    v->visitor.start_alternate = qobject_input_start_alternate;
 676    v->visitor.optional = qobject_input_optional;
 677    v->visitor.free = qobject_input_free;
 678
 679    v->root = qobject_ref(obj);
 680
 681    return v;
 682}
 683
 684Visitor *qobject_input_visitor_new(QObject *obj)
 685{
 686    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
 687
 688    v->visitor.type_int64 = qobject_input_type_int64;
 689    v->visitor.type_uint64 = qobject_input_type_uint64;
 690    v->visitor.type_bool = qobject_input_type_bool;
 691    v->visitor.type_str = qobject_input_type_str;
 692    v->visitor.type_number = qobject_input_type_number;
 693    v->visitor.type_any = qobject_input_type_any;
 694    v->visitor.type_null = qobject_input_type_null;
 695
 696    return &v->visitor;
 697}
 698
 699Visitor *qobject_input_visitor_new_keyval(QObject *obj)
 700{
 701    QObjectInputVisitor *v = qobject_input_visitor_base_new(obj);
 702
 703    v->visitor.type_int64 = qobject_input_type_int64_keyval;
 704    v->visitor.type_uint64 = qobject_input_type_uint64_keyval;
 705    v->visitor.type_bool = qobject_input_type_bool_keyval;
 706    v->visitor.type_str = qobject_input_type_str_keyval;
 707    v->visitor.type_number = qobject_input_type_number_keyval;
 708    v->visitor.type_any = qobject_input_type_any;
 709    v->visitor.type_null = qobject_input_type_null;
 710    v->visitor.type_size = qobject_input_type_size_keyval;
 711    v->keyval = true;
 712
 713    return &v->visitor;
 714}
 715
 716Visitor *qobject_input_visitor_new_str(const char *str,
 717                                       const char *implied_key,
 718                                       Error **errp)
 719{
 720    bool is_json = str[0] == '{';
 721    QObject *obj;
 722    QDict *args;
 723    Visitor *v;
 724
 725    if (is_json) {
 726        obj = qobject_from_json(str, errp);
 727        if (!obj) {
 728            return NULL;
 729        }
 730        args = qobject_to(QDict, obj);
 731        assert(args);
 732        v = qobject_input_visitor_new(QOBJECT(args));
 733    } else {
 734        args = keyval_parse(str, implied_key, errp);
 735        if (!args) {
 736            return NULL;
 737        }
 738        v = qobject_input_visitor_new_keyval(QOBJECT(args));
 739    }
 740    qobject_unref(args);
 741
 742    return v;
 743}
 744