Am 18.05.2021 um 17:40 hat Paolo Bonzini geschrieben: > Change the parser to put the values into a QDict and pass them > to a callback. qemu_config_parse's QemuOpts creation is > itself turned into a callback function. > > This is useful for -readconfig to support keyval-based options; > getting a QDict from the parser removes a roundtrip from > QDict to QemuOpts and then back to QDict. > > Cc: Kevin Wolf <kw...@redhat.com> > Cc: Markus Armbruster <arm...@redhat.com> > Cc: qemu-sta...@nongnu.org > Signed-off-by: Paolo Bonzini <pbonz...@redhat.com>
> diff --git a/util/qemu-config.c b/util/qemu-config.c > index 34974c4b47..7bca153c6c 100644 > --- a/util/qemu-config.c > +++ b/util/qemu-config.c > @@ -351,19 +351,19 @@ void qemu_config_write(FILE *fp) > } > > /* Returns number of config groups on success, -errno on error */ > -int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, > Error **errp) > +static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, > + const char *fname, Error **errp) > { > - char line[1024], group[64], id[64], arg[64], value[1024]; > + char line[1024], prev_group[64], group[64], arg[64], value[1024]; > Location loc; > - QemuOptsList *list = NULL; > Error *local_err = NULL; > - QemuOpts *opts = NULL; > + QDict *qdict = NULL; > int res = -EINVAL, lno = 0; > int count = 0; > > loc_push_none(&loc); > while (fgets(line, sizeof(line), fp) != NULL) { > - loc_set_file(fname, ++lno); > + ++lno; > if (line[0] == '\n') { > /* skip empty lines */ > continue; > @@ -372,39 +372,39 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, > const char *fname, Error * > /* comment */ > continue; > } > - if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { > - /* group with id */ > - list = find_list(lists, group, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - goto out; > + if (line[0] == '[') { > + QDict *prev = qdict; > + if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) { > + qdict = qdict_new(); > + qdict_put_str(qdict, "id", value); > + count++; > + } else if (sscanf(line, "[%63[^]]]", group) == 1) { > + qdict = qdict_new(); > + count++; > } > - opts = qemu_opts_create(list, id, 1, NULL); > - count++; > - continue; > - } > - if (sscanf(line, "[%63[^]]]", group) == 1) { > - /* group without id */ > - list = find_list(lists, group, &local_err); > - if (local_err) { > - error_propagate(errp, local_err); > - goto out; > + if (qdict != prev) { > + if (prev) { > + cb(prev_group, prev, opaque, &local_err); > + qobject_unref(prev); > + if (local_err) { > + error_propagate(errp, local_err); > + goto out; > + } > + } > + strcpy(prev_group, group); > + continue; > } > - opts = qemu_opts_create(list, NULL, 0, &error_abort); > - count++; > - continue; > } > + loc_set_file(fname, lno); Error reporting is going to suffer quite a bit from this delayed parsing, reporting the last line of a group for most cases now. I think it's acceptable for an option that we want to get rid of in the long term anyway, but worth noting. > value[0] = '\0'; > if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 || > sscanf(line, " %63s = \"\"", arg) == 1) { > /* arg = value */ > - if (opts == NULL) { > + if (qdict == NULL) { > error_setg(errp, "no group defined"); > goto out; > } > - if (!qemu_opt_set(opts, arg, value, errp)) { > - goto out; > - } > + qdict_put_str(qdict, arg, value); > continue; > } > error_setg(errp, "parse error"); > @@ -418,10 +418,41 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, > const char *fname, Error * > res = count; > out: > loc_pop(&loc); > + if (qdict) { > + cb(group, qdict, opaque, errp); > + qobject_unref(qdict); > + } > return res; > } > > -int qemu_read_config_file(const char *filename, Error **errp) > +void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, > Error **errp) > +{ > + QemuOptsList **lists = opaque; > + const char *id = qdict_get_try_str(qdict, "id"); > + QemuOptsList *list; > + QemuOpts *opts; > + > + list = find_list(lists, group, errp); > + if (!list) { > + return; > + } > + > + opts = qemu_opts_create(list, id, 1, errp); > + if (!opts) { > + return; > + } > + if (id) { > + qdict_del(qdict, "id"); > + } > + qemu_opts_absorb_qdict(opts, qdict, errp); Shouldn't we check that qdict is empty now and return an error if there are any options that the QemuOptsList doesn't accept? Kevin