1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini * Commandline option parsing functions
3baacf047SPaolo Bonzini *
4baacf047SPaolo Bonzini * Copyright (c) 2003-2008 Fabrice Bellard
5baacf047SPaolo Bonzini * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
6baacf047SPaolo Bonzini *
7baacf047SPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
8baacf047SPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
9baacf047SPaolo Bonzini * in the Software without restriction, including without limitation the rights
10baacf047SPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11baacf047SPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
12baacf047SPaolo Bonzini * furnished to do so, subject to the following conditions:
13baacf047SPaolo Bonzini *
14baacf047SPaolo Bonzini * The above copyright notice and this permission notice shall be included in
15baacf047SPaolo Bonzini * all copies or substantial portions of the Software.
16baacf047SPaolo Bonzini *
17baacf047SPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18baacf047SPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19baacf047SPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20baacf047SPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21baacf047SPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22baacf047SPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23baacf047SPaolo Bonzini * THE SOFTWARE.
24baacf047SPaolo Bonzini */
25baacf047SPaolo Bonzini
26aafd7584SPeter Maydell #include "qemu/osdep.h"
27baacf047SPaolo Bonzini
28da34e65cSMarkus Armbruster #include "qapi/error.h"
29baacf047SPaolo Bonzini #include "qemu/error-report.h"
306b673957SMarkus Armbruster #include "qapi/qmp/qbool.h"
316b673957SMarkus Armbruster #include "qapi/qmp/qdict.h"
3215280c36SMarkus Armbruster #include "qapi/qmp/qnum.h"
336b673957SMarkus Armbruster #include "qapi/qmp/qstring.h"
34baacf047SPaolo Bonzini #include "qapi/qmp/qerror.h"
35baacf047SPaolo Bonzini #include "qemu/option_int.h"
36f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
37f348b6d1SVeronia Bahaa #include "qemu/id.h"
38f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
39baacf047SPaolo Bonzini
40baacf047SPaolo Bonzini /*
41924e9b0dSPaolo Bonzini * Extracts the name of an option from the parameter string (@p points at the
42baacf047SPaolo Bonzini * first byte of the option name)
43baacf047SPaolo Bonzini *
44924e9b0dSPaolo Bonzini * The option name is @len characters long and is copied into @option. The
45924e9b0dSPaolo Bonzini * caller is responsible for free'ing @option when no longer required.
46baacf047SPaolo Bonzini *
47baacf047SPaolo Bonzini * The return value is the position of the delimiter/zero byte after the option
48924e9b0dSPaolo Bonzini * name in @p.
49baacf047SPaolo Bonzini */
get_opt_name(const char * p,char ** option,size_t len)50924e9b0dSPaolo Bonzini static const char *get_opt_name(const char *p, char **option, size_t len)
51baacf047SPaolo Bonzini {
52924e9b0dSPaolo Bonzini *option = g_strndup(p, len);
53924e9b0dSPaolo Bonzini return p + len;
54baacf047SPaolo Bonzini }
55baacf047SPaolo Bonzini
56baacf047SPaolo Bonzini /*
57baacf047SPaolo Bonzini * Extracts the value of an option from the parameter string p (p points at the
58baacf047SPaolo Bonzini * first byte of the option value)
59baacf047SPaolo Bonzini *
60baacf047SPaolo Bonzini * This function is comparable to get_opt_name with the difference that the
61baacf047SPaolo Bonzini * delimiter is fixed to be comma which starts a new option. To specify an
62baacf047SPaolo Bonzini * option value that contains commas, double each comma.
63baacf047SPaolo Bonzini */
get_opt_value(const char * p,char ** value)64950c4e6cSDaniel P. Berrangé const char *get_opt_value(const char *p, char **value)
65baacf047SPaolo Bonzini {
66950c4e6cSDaniel P. Berrangé size_t capacity = 0, length;
67950c4e6cSDaniel P. Berrangé const char *offset;
68baacf047SPaolo Bonzini
69950c4e6cSDaniel P. Berrangé *value = NULL;
70950c4e6cSDaniel P. Berrangé while (1) {
715c99fa37SKeno Fischer offset = qemu_strchrnul(p, ',');
72950c4e6cSDaniel P. Berrangé length = offset - p;
73950c4e6cSDaniel P. Berrangé if (*offset != '\0' && *(offset + 1) == ',') {
74950c4e6cSDaniel P. Berrangé length++;
75950c4e6cSDaniel P. Berrangé }
76950c4e6cSDaniel P. Berrangé *value = g_renew(char, *value, capacity + length + 1);
77950c4e6cSDaniel P. Berrangé strncpy(*value + capacity, p, length);
78950c4e6cSDaniel P. Berrangé (*value)[capacity + length] = '\0';
79950c4e6cSDaniel P. Berrangé capacity += length;
80950c4e6cSDaniel P. Berrangé if (*offset == '\0' ||
81950c4e6cSDaniel P. Berrangé *(offset + 1) != ',') {
82baacf047SPaolo Bonzini break;
83baacf047SPaolo Bonzini }
84baacf047SPaolo Bonzini
85950c4e6cSDaniel P. Berrangé p += (offset - p) + 2;
86950c4e6cSDaniel P. Berrangé }
87950c4e6cSDaniel P. Berrangé
88950c4e6cSDaniel P. Berrangé return offset;
89baacf047SPaolo Bonzini }
90baacf047SPaolo Bonzini
parse_option_number(const char * name,const char * value,uint64_t * ret,Error ** errp)91c75d7f71SMarkus Armbruster static bool parse_option_number(const char *name, const char *value,
92baacf047SPaolo Bonzini uint64_t *ret, Error **errp)
93baacf047SPaolo Bonzini {
94baacf047SPaolo Bonzini uint64_t number;
953403e5ebSMarkus Armbruster int err;
96baacf047SPaolo Bonzini
973403e5ebSMarkus Armbruster err = qemu_strtou64(value, NULL, 0, &number);
983403e5ebSMarkus Armbruster if (err == -ERANGE) {
993403e5ebSMarkus Armbruster error_setg(errp, "Value '%s' is too large for parameter '%s'",
1003403e5ebSMarkus Armbruster value, name);
101c75d7f71SMarkus Armbruster return false;
1023403e5ebSMarkus Armbruster }
1033403e5ebSMarkus Armbruster if (err) {
104c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
105c75d7f71SMarkus Armbruster return false;
106baacf047SPaolo Bonzini }
107baacf047SPaolo Bonzini *ret = number;
108c75d7f71SMarkus Armbruster return true;
109baacf047SPaolo Bonzini }
110baacf047SPaolo Bonzini
find_desc_by_name(const QemuOptDesc * desc,const char * name)1115e89db76SChunyan Liu static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
1125e89db76SChunyan Liu const char *name)
1135e89db76SChunyan Liu {
1145e89db76SChunyan Liu int i;
1155e89db76SChunyan Liu
1165e89db76SChunyan Liu for (i = 0; desc[i].name != NULL; i++) {
1175e89db76SChunyan Liu if (strcmp(desc[i].name, name) == 0) {
1185e89db76SChunyan Liu return &desc[i];
1195e89db76SChunyan Liu }
1205e89db76SChunyan Liu }
1215e89db76SChunyan Liu
1225e89db76SChunyan Liu return NULL;
1235e89db76SChunyan Liu }
1245e89db76SChunyan Liu
find_default_by_name(QemuOpts * opts,const char * name)125f23db652SMarkus Armbruster static const char *find_default_by_name(QemuOpts *opts, const char *name)
126f23db652SMarkus Armbruster {
127f23db652SMarkus Armbruster const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
128f23db652SMarkus Armbruster
129f23db652SMarkus Armbruster return desc ? desc->def_value_str : NULL;
130f23db652SMarkus Armbruster }
131f23db652SMarkus Armbruster
parse_option_size(const char * name,const char * value,uint64_t * ret,Error ** errp)132c75d7f71SMarkus Armbruster bool parse_option_size(const char *name, const char *value,
133baacf047SPaolo Bonzini uint64_t *ret, Error **errp)
134baacf047SPaolo Bonzini {
13575cdcd15SMarkus Armbruster uint64_t size;
13675cdcd15SMarkus Armbruster int err;
137baacf047SPaolo Bonzini
13875cdcd15SMarkus Armbruster err = qemu_strtosz(value, NULL, &size);
13975cdcd15SMarkus Armbruster if (err == -ERANGE) {
1409e19ad4eSMarkus Armbruster error_setg(errp, "Value '%s' is out of range for parameter '%s'",
14175cdcd15SMarkus Armbruster value, name);
142c75d7f71SMarkus Armbruster return false;
14375cdcd15SMarkus Armbruster }
14475cdcd15SMarkus Armbruster if (err) {
14521278992SBo Tu error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
14621278992SBo Tu "a non-negative number below 2^64");
14775cdcd15SMarkus Armbruster error_append_hint(errp, "Optional suffix k, M, G, T, P or E means"
14875cdcd15SMarkus Armbruster " kilo-, mega-, giga-, tera-, peta-\n"
14975cdcd15SMarkus Armbruster "and exabytes, respectively.\n");
150c75d7f71SMarkus Armbruster return false;
15121278992SBo Tu }
15275cdcd15SMarkus Armbruster *ret = size;
153c75d7f71SMarkus Armbruster return true;
154baacf047SPaolo Bonzini }
155baacf047SPaolo Bonzini
opt_type_to_string(enum QemuOptType type)1569cbef9d6SMarc-André Lureau static const char *opt_type_to_string(enum QemuOptType type)
1579cbef9d6SMarc-André Lureau {
1589cbef9d6SMarc-André Lureau switch (type) {
1599cbef9d6SMarc-André Lureau case QEMU_OPT_STRING:
1609cbef9d6SMarc-André Lureau return "str";
1619cbef9d6SMarc-André Lureau case QEMU_OPT_BOOL:
1629cbef9d6SMarc-André Lureau return "bool (on/off)";
1639cbef9d6SMarc-André Lureau case QEMU_OPT_NUMBER:
1649cbef9d6SMarc-André Lureau return "num";
1659cbef9d6SMarc-André Lureau case QEMU_OPT_SIZE:
1669cbef9d6SMarc-André Lureau return "size";
1679cbef9d6SMarc-André Lureau }
1689cbef9d6SMarc-André Lureau
1699cbef9d6SMarc-André Lureau g_assert_not_reached();
1709cbef9d6SMarc-André Lureau }
1719cbef9d6SMarc-André Lureau
17263898712SMax Reitz /**
17363898712SMax Reitz * Print the list of options available in the given list. If
17463898712SMax Reitz * @print_caption is true, a caption (including the list name, if it
17563898712SMax Reitz * exists) is printed. The options itself will be indented, so
17663898712SMax Reitz * @print_caption should only be set to false if the caller prints its
17763898712SMax Reitz * own custom caption (so that the indentation makes sense).
17863898712SMax Reitz */
qemu_opts_print_help(QemuOptsList * list,bool print_caption)17963898712SMax Reitz void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
180504189a9SChunyan Liu {
181504189a9SChunyan Liu QemuOptDesc *desc;
1829cbef9d6SMarc-André Lureau int i;
1839cbef9d6SMarc-André Lureau GPtrArray *array = g_ptr_array_new();
184504189a9SChunyan Liu
185504189a9SChunyan Liu assert(list);
186504189a9SChunyan Liu desc = list->desc;
187504189a9SChunyan Liu while (desc && desc->name) {
1889cbef9d6SMarc-André Lureau GString *str = g_string_new(NULL);
18963898712SMax Reitz g_string_append_printf(str, " %s=<%s>", desc->name,
1909cbef9d6SMarc-André Lureau opt_type_to_string(desc->type));
1919cbef9d6SMarc-André Lureau if (desc->help) {
19263898712SMax Reitz if (str->len < 24) {
19363898712SMax Reitz g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
19463898712SMax Reitz }
1959cbef9d6SMarc-André Lureau g_string_append_printf(str, " - %s", desc->help);
1969cbef9d6SMarc-André Lureau }
1979cbef9d6SMarc-André Lureau g_ptr_array_add(array, g_string_free(str, false));
198504189a9SChunyan Liu desc++;
199504189a9SChunyan Liu }
2009cbef9d6SMarc-André Lureau
2019cbef9d6SMarc-André Lureau g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
20263898712SMax Reitz if (print_caption && array->len > 0) {
20363898712SMax Reitz if (list->name) {
20463898712SMax Reitz printf("%s options:\n", list->name);
20563898712SMax Reitz } else {
20663898712SMax Reitz printf("Options:\n");
20763898712SMax Reitz }
20863898712SMax Reitz } else if (array->len == 0) {
20963898712SMax Reitz if (list->name) {
21063898712SMax Reitz printf("There are no options for %s.\n", list->name);
21163898712SMax Reitz } else {
21263898712SMax Reitz printf("No options available.\n");
21363898712SMax Reitz }
21463898712SMax Reitz }
2159cbef9d6SMarc-André Lureau for (i = 0; i < array->len; i++) {
2169cbef9d6SMarc-André Lureau printf("%s\n", (char *)array->pdata[i]);
2179cbef9d6SMarc-André Lureau }
2189cbef9d6SMarc-André Lureau g_ptr_array_set_free_func(array, g_free);
2199cbef9d6SMarc-André Lureau g_ptr_array_free(array, true);
2209cbef9d6SMarc-André Lureau
221504189a9SChunyan Liu }
222baacf047SPaolo Bonzini /* ------------------------------------------------------------------ */
223baacf047SPaolo Bonzini
qemu_opt_find(QemuOpts * opts,const char * name)22474c3c197SChunyan Liu QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
225baacf047SPaolo Bonzini {
226baacf047SPaolo Bonzini QemuOpt *opt;
227baacf047SPaolo Bonzini
228eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
229baacf047SPaolo Bonzini if (strcmp(opt->name, name) != 0)
230baacf047SPaolo Bonzini continue;
231baacf047SPaolo Bonzini return opt;
232baacf047SPaolo Bonzini }
233baacf047SPaolo Bonzini return NULL;
234baacf047SPaolo Bonzini }
235baacf047SPaolo Bonzini
qemu_opt_del(QemuOpt * opt)236fc345512SChunyan Liu static void qemu_opt_del(QemuOpt *opt)
237fc345512SChunyan Liu {
238fc345512SChunyan Liu QTAILQ_REMOVE(&opt->opts->head, opt, next);
239fc345512SChunyan Liu g_free(opt->name);
240fc345512SChunyan Liu g_free(opt->str);
241fc345512SChunyan Liu g_free(opt);
242fc345512SChunyan Liu }
243fc345512SChunyan Liu
244782730b0SChunyan Liu /* qemu_opt_set allows many settings for the same option.
245782730b0SChunyan Liu * This function deletes all settings for an option.
246782730b0SChunyan Liu */
qemu_opt_del_all(QemuOpts * opts,const char * name)247782730b0SChunyan Liu static void qemu_opt_del_all(QemuOpts *opts, const char *name)
248782730b0SChunyan Liu {
249782730b0SChunyan Liu QemuOpt *opt, *next_opt;
250782730b0SChunyan Liu
251782730b0SChunyan Liu QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next_opt) {
252782730b0SChunyan Liu if (!strcmp(opt->name, name)) {
253782730b0SChunyan Liu qemu_opt_del(opt);
254782730b0SChunyan Liu }
255782730b0SChunyan Liu }
256782730b0SChunyan Liu }
257782730b0SChunyan Liu
qemu_opt_get(QemuOpts * opts,const char * name)258baacf047SPaolo Bonzini const char *qemu_opt_get(QemuOpts *opts, const char *name)
259baacf047SPaolo Bonzini {
260435db4cfSChunyan Liu QemuOpt *opt;
26109722032SChunyan Liu
262435db4cfSChunyan Liu if (opts == NULL) {
263435db4cfSChunyan Liu return NULL;
264435db4cfSChunyan Liu }
265435db4cfSChunyan Liu
266435db4cfSChunyan Liu opt = qemu_opt_find(opts, name);
26709722032SChunyan Liu if (!opt) {
26844b0b7d1SMarkus Armbruster return find_default_by_name(opts, name);
26909722032SChunyan Liu }
27044b0b7d1SMarkus Armbruster
27144b0b7d1SMarkus Armbruster return opt->str;
272baacf047SPaolo Bonzini }
273baacf047SPaolo Bonzini
qemu_opt_iter_init(QemuOptsIter * iter,QemuOpts * opts,const char * name)274e998e209SDaniel P. Berrange void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name)
275e998e209SDaniel P. Berrange {
276e998e209SDaniel P. Berrange iter->opts = opts;
277e998e209SDaniel P. Berrange iter->opt = QTAILQ_FIRST(&opts->head);
278e998e209SDaniel P. Berrange iter->name = name;
279e998e209SDaniel P. Berrange }
280e998e209SDaniel P. Berrange
qemu_opt_iter_next(QemuOptsIter * iter)281e998e209SDaniel P. Berrange const char *qemu_opt_iter_next(QemuOptsIter *iter)
282e998e209SDaniel P. Berrange {
283e998e209SDaniel P. Berrange QemuOpt *ret = iter->opt;
284e998e209SDaniel P. Berrange if (iter->name) {
285e998e209SDaniel P. Berrange while (ret && !g_str_equal(iter->name, ret->name)) {
286e998e209SDaniel P. Berrange ret = QTAILQ_NEXT(ret, next);
287e998e209SDaniel P. Berrange }
288e998e209SDaniel P. Berrange }
289e998e209SDaniel P. Berrange iter->opt = ret ? QTAILQ_NEXT(ret, next) : NULL;
290e998e209SDaniel P. Berrange return ret ? ret->str : NULL;
291e998e209SDaniel P. Berrange }
292e998e209SDaniel P. Berrange
293782730b0SChunyan Liu /* Get a known option (or its default) and remove it from the list
294782730b0SChunyan Liu * all in one action. Return a malloced string of the option value.
295782730b0SChunyan Liu * Result must be freed by caller with g_free().
296782730b0SChunyan Liu */
qemu_opt_get_del(QemuOpts * opts,const char * name)297782730b0SChunyan Liu char *qemu_opt_get_del(QemuOpts *opts, const char *name)
298782730b0SChunyan Liu {
299782730b0SChunyan Liu QemuOpt *opt;
30044b0b7d1SMarkus Armbruster char *str;
301782730b0SChunyan Liu
302782730b0SChunyan Liu if (opts == NULL) {
303782730b0SChunyan Liu return NULL;
304782730b0SChunyan Liu }
305782730b0SChunyan Liu
306782730b0SChunyan Liu opt = qemu_opt_find(opts, name);
307782730b0SChunyan Liu if (!opt) {
30844b0b7d1SMarkus Armbruster return g_strdup(find_default_by_name(opts, name));
309782730b0SChunyan Liu }
310782730b0SChunyan Liu str = opt->str;
311782730b0SChunyan Liu opt->str = NULL;
312782730b0SChunyan Liu qemu_opt_del_all(opts, name);
313782730b0SChunyan Liu return str;
314782730b0SChunyan Liu }
315782730b0SChunyan Liu
qemu_opt_has_help_opt(QemuOpts * opts)316baacf047SPaolo Bonzini bool qemu_opt_has_help_opt(QemuOpts *opts)
317baacf047SPaolo Bonzini {
318baacf047SPaolo Bonzini QemuOpt *opt;
319baacf047SPaolo Bonzini
320eae3eb3eSPaolo Bonzini QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
321baacf047SPaolo Bonzini if (is_help_option(opt->name)) {
322baacf047SPaolo Bonzini return true;
323baacf047SPaolo Bonzini }
324baacf047SPaolo Bonzini }
325baacf047SPaolo Bonzini return false;
326baacf047SPaolo Bonzini }
327baacf047SPaolo Bonzini
qemu_opt_get_bool_helper(QemuOpts * opts,const char * name,bool defval,bool del)328782730b0SChunyan Liu static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name,
329782730b0SChunyan Liu bool defval, bool del)
330baacf047SPaolo Bonzini {
331435db4cfSChunyan Liu QemuOpt *opt;
332f23db652SMarkus Armbruster const char *def_val;
333782730b0SChunyan Liu bool ret = defval;
334baacf047SPaolo Bonzini
335435db4cfSChunyan Liu if (opts == NULL) {
336435db4cfSChunyan Liu return ret;
337435db4cfSChunyan Liu }
338435db4cfSChunyan Liu
339435db4cfSChunyan Liu opt = qemu_opt_find(opts, name);
34009722032SChunyan Liu if (opt == NULL) {
341f23db652SMarkus Armbruster def_val = find_default_by_name(opts, name);
342f23db652SMarkus Armbruster if (def_val) {
343372bcb25SPaolo Bonzini qapi_bool_parse(name, def_val, &ret, &error_abort);
34409722032SChunyan Liu }
345782730b0SChunyan Liu return ret;
34609722032SChunyan Liu }
347baacf047SPaolo Bonzini assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
348782730b0SChunyan Liu ret = opt->value.boolean;
349782730b0SChunyan Liu if (del) {
350782730b0SChunyan Liu qemu_opt_del_all(opts, name);
351782730b0SChunyan Liu }
352782730b0SChunyan Liu return ret;
353782730b0SChunyan Liu }
354782730b0SChunyan Liu
qemu_opt_get_bool(QemuOpts * opts,const char * name,bool defval)355782730b0SChunyan Liu bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
356782730b0SChunyan Liu {
357782730b0SChunyan Liu return qemu_opt_get_bool_helper(opts, name, defval, false);
358782730b0SChunyan Liu }
359782730b0SChunyan Liu
qemu_opt_get_bool_del(QemuOpts * opts,const char * name,bool defval)360782730b0SChunyan Liu bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval)
361782730b0SChunyan Liu {
362782730b0SChunyan Liu return qemu_opt_get_bool_helper(opts, name, defval, true);
363782730b0SChunyan Liu }
364782730b0SChunyan Liu
qemu_opt_get_number_helper(QemuOpts * opts,const char * name,uint64_t defval,bool del)365782730b0SChunyan Liu static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name,
366782730b0SChunyan Liu uint64_t defval, bool del)
367782730b0SChunyan Liu {
368435db4cfSChunyan Liu QemuOpt *opt;
369f23db652SMarkus Armbruster const char *def_val;
370782730b0SChunyan Liu uint64_t ret = defval;
371782730b0SChunyan Liu
372435db4cfSChunyan Liu if (opts == NULL) {
373435db4cfSChunyan Liu return ret;
374435db4cfSChunyan Liu }
375435db4cfSChunyan Liu
376435db4cfSChunyan Liu opt = qemu_opt_find(opts, name);
377782730b0SChunyan Liu if (opt == NULL) {
378f23db652SMarkus Armbruster def_val = find_default_by_name(opts, name);
379f23db652SMarkus Armbruster if (def_val) {
380f23db652SMarkus Armbruster parse_option_number(name, def_val, &ret, &error_abort);
381782730b0SChunyan Liu }
382782730b0SChunyan Liu return ret;
383782730b0SChunyan Liu }
384782730b0SChunyan Liu assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
385782730b0SChunyan Liu ret = opt->value.uint;
386782730b0SChunyan Liu if (del) {
387782730b0SChunyan Liu qemu_opt_del_all(opts, name);
388782730b0SChunyan Liu }
389782730b0SChunyan Liu return ret;
390baacf047SPaolo Bonzini }
391baacf047SPaolo Bonzini
qemu_opt_get_number(QemuOpts * opts,const char * name,uint64_t defval)392baacf047SPaolo Bonzini uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
393baacf047SPaolo Bonzini {
394782730b0SChunyan Liu return qemu_opt_get_number_helper(opts, name, defval, false);
395782730b0SChunyan Liu }
396782730b0SChunyan Liu
qemu_opt_get_number_del(QemuOpts * opts,const char * name,uint64_t defval)397782730b0SChunyan Liu uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name,
398782730b0SChunyan Liu uint64_t defval)
399782730b0SChunyan Liu {
400782730b0SChunyan Liu return qemu_opt_get_number_helper(opts, name, defval, true);
401782730b0SChunyan Liu }
402782730b0SChunyan Liu
qemu_opt_get_size_helper(QemuOpts * opts,const char * name,uint64_t defval,bool del)403782730b0SChunyan Liu static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name,
404782730b0SChunyan Liu uint64_t defval, bool del)
405782730b0SChunyan Liu {
406435db4cfSChunyan Liu QemuOpt *opt;
407f23db652SMarkus Armbruster const char *def_val;
408782730b0SChunyan Liu uint64_t ret = defval;
409baacf047SPaolo Bonzini
410435db4cfSChunyan Liu if (opts == NULL) {
411435db4cfSChunyan Liu return ret;
412435db4cfSChunyan Liu }
413435db4cfSChunyan Liu
414435db4cfSChunyan Liu opt = qemu_opt_find(opts, name);
41509722032SChunyan Liu if (opt == NULL) {
416f23db652SMarkus Armbruster def_val = find_default_by_name(opts, name);
417f23db652SMarkus Armbruster if (def_val) {
418f23db652SMarkus Armbruster parse_option_size(name, def_val, &ret, &error_abort);
41909722032SChunyan Liu }
420782730b0SChunyan Liu return ret;
42109722032SChunyan Liu }
422782730b0SChunyan Liu assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
423782730b0SChunyan Liu ret = opt->value.uint;
424782730b0SChunyan Liu if (del) {
425782730b0SChunyan Liu qemu_opt_del_all(opts, name);
426782730b0SChunyan Liu }
427782730b0SChunyan Liu return ret;
428baacf047SPaolo Bonzini }
429baacf047SPaolo Bonzini
qemu_opt_get_size(QemuOpts * opts,const char * name,uint64_t defval)430baacf047SPaolo Bonzini uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
431baacf047SPaolo Bonzini {
432782730b0SChunyan Liu return qemu_opt_get_size_helper(opts, name, defval, false);
433782730b0SChunyan Liu }
434baacf047SPaolo Bonzini
qemu_opt_get_size_del(QemuOpts * opts,const char * name,uint64_t defval)435782730b0SChunyan Liu uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
436782730b0SChunyan Liu uint64_t defval)
437782730b0SChunyan Liu {
438782730b0SChunyan Liu return qemu_opt_get_size_helper(opts, name, defval, true);
439baacf047SPaolo Bonzini }
440baacf047SPaolo Bonzini
qemu_opt_parse(QemuOpt * opt,Error ** errp)441c75d7f71SMarkus Armbruster static bool qemu_opt_parse(QemuOpt *opt, Error **errp)
442baacf047SPaolo Bonzini {
443baacf047SPaolo Bonzini if (opt->desc == NULL)
444c75d7f71SMarkus Armbruster return true;
445baacf047SPaolo Bonzini
446baacf047SPaolo Bonzini switch (opt->desc->type) {
447baacf047SPaolo Bonzini case QEMU_OPT_STRING:
448baacf047SPaolo Bonzini /* nothing */
449c75d7f71SMarkus Armbruster return true;
450baacf047SPaolo Bonzini case QEMU_OPT_BOOL:
451372bcb25SPaolo Bonzini return qapi_bool_parse(opt->name, opt->str, &opt->value.boolean, errp);
452baacf047SPaolo Bonzini case QEMU_OPT_NUMBER:
453c75d7f71SMarkus Armbruster return parse_option_number(opt->name, opt->str, &opt->value.uint,
454c75d7f71SMarkus Armbruster errp);
455baacf047SPaolo Bonzini case QEMU_OPT_SIZE:
456c75d7f71SMarkus Armbruster return parse_option_size(opt->name, opt->str, &opt->value.uint,
457c75d7f71SMarkus Armbruster errp);
458baacf047SPaolo Bonzini default:
459baacf047SPaolo Bonzini abort();
460baacf047SPaolo Bonzini }
461baacf047SPaolo Bonzini }
462baacf047SPaolo Bonzini
opts_accepts_any(const QemuOptsList * list)46345c53fe6SPaolo Bonzini static bool opts_accepts_any(const QemuOptsList *list)
464baacf047SPaolo Bonzini {
46545c53fe6SPaolo Bonzini return list->desc[0].name == NULL;
466baacf047SPaolo Bonzini }
467baacf047SPaolo Bonzini
qemu_opt_unset(QemuOpts * opts,const char * name)4680dd6c526SKevin Wolf int qemu_opt_unset(QemuOpts *opts, const char *name)
4690dd6c526SKevin Wolf {
4700dd6c526SKevin Wolf QemuOpt *opt = qemu_opt_find(opts, name);
4710dd6c526SKevin Wolf
47245c53fe6SPaolo Bonzini assert(opts_accepts_any(opts->list));
4730dd6c526SKevin Wolf
4740dd6c526SKevin Wolf if (opt == NULL) {
4750dd6c526SKevin Wolf return -1;
4760dd6c526SKevin Wolf } else {
4770dd6c526SKevin Wolf qemu_opt_del(opt);
4780dd6c526SKevin Wolf return 0;
4790dd6c526SKevin Wolf }
4800dd6c526SKevin Wolf }
4810dd6c526SKevin Wolf
opt_create(QemuOpts * opts,const char * name,char * value)482904806c6SPaolo Bonzini static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value)
48381a8a072SMarkus Armbruster {
48481a8a072SMarkus Armbruster QemuOpt *opt = g_malloc0(sizeof(*opt));
48581a8a072SMarkus Armbruster
48681a8a072SMarkus Armbruster opt->name = g_strdup(name);
48781a8a072SMarkus Armbruster opt->str = value;
48881a8a072SMarkus Armbruster opt->opts = opts;
48981a8a072SMarkus Armbruster QTAILQ_INSERT_TAIL(&opts->head, opt, next);
49081a8a072SMarkus Armbruster
49181a8a072SMarkus Armbruster return opt;
49281a8a072SMarkus Armbruster }
49381a8a072SMarkus Armbruster
opt_validate(QemuOpt * opt,Error ** errp)494afd73625SPaolo Bonzini static bool opt_validate(QemuOpt *opt, Error **errp)
495baacf047SPaolo Bonzini {
496baacf047SPaolo Bonzini const QemuOptDesc *desc;
49745c53fe6SPaolo Bonzini const QemuOptsList *list = opt->opts->list;
498baacf047SPaolo Bonzini
49945c53fe6SPaolo Bonzini desc = find_desc_by_name(list->desc, opt->name);
50045c53fe6SPaolo Bonzini if (!desc && !opts_accepts_any(list)) {
501*c6f5d406SPhilippe Mathieu-Daudé error_setg(errp, "Invalid parameter '%s'", opt->name);
50264af7a8bSMarkus Armbruster return false;
503baacf047SPaolo Bonzini }
504baacf047SPaolo Bonzini
505baacf047SPaolo Bonzini opt->desc = desc;
506668f62ecSMarkus Armbruster if (!qemu_opt_parse(opt, errp)) {
50764af7a8bSMarkus Armbruster return false;
508baacf047SPaolo Bonzini }
50964af7a8bSMarkus Armbruster
51064af7a8bSMarkus Armbruster return true;
511baacf047SPaolo Bonzini }
512baacf047SPaolo Bonzini
qemu_opt_set(QemuOpts * opts,const char * name,const char * value,Error ** errp)513c75d7f71SMarkus Armbruster bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
514baacf047SPaolo Bonzini Error **errp)
515baacf047SPaolo Bonzini {
516904806c6SPaolo Bonzini QemuOpt *opt = opt_create(opts, name, g_strdup(value));
51764af7a8bSMarkus Armbruster
518afd73625SPaolo Bonzini if (!opt_validate(opt, errp)) {
51964af7a8bSMarkus Armbruster qemu_opt_del(opt);
520c75d7f71SMarkus Armbruster return false;
52164af7a8bSMarkus Armbruster }
522c75d7f71SMarkus Armbruster return true;
523baacf047SPaolo Bonzini }
524baacf047SPaolo Bonzini
qemu_opt_set_bool(QemuOpts * opts,const char * name,bool val,Error ** errp)525c75d7f71SMarkus Armbruster bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
526cccb7967SMarkus Armbruster Error **errp)
527baacf047SPaolo Bonzini {
528baacf047SPaolo Bonzini QemuOpt *opt;
5299da7197aSMarkus Armbruster const QemuOptDesc *desc;
53045c53fe6SPaolo Bonzini const QemuOptsList *list = opts->list;
531baacf047SPaolo Bonzini
53245c53fe6SPaolo Bonzini desc = find_desc_by_name(list->desc, name);
53345c53fe6SPaolo Bonzini if (!desc && !opts_accepts_any(list)) {
534*c6f5d406SPhilippe Mathieu-Daudé error_setg(errp, "Invalid parameter '%s'", name);
535c75d7f71SMarkus Armbruster return false;
536baacf047SPaolo Bonzini }
537baacf047SPaolo Bonzini
5389da7197aSMarkus Armbruster opt = g_malloc0(sizeof(*opt));
539baacf047SPaolo Bonzini opt->name = g_strdup(name);
540baacf047SPaolo Bonzini opt->opts = opts;
5419da7197aSMarkus Armbruster opt->desc = desc;
542baacf047SPaolo Bonzini opt->value.boolean = !!val;
543baacf047SPaolo Bonzini opt->str = g_strdup(val ? "on" : "off");
544baacf047SPaolo Bonzini QTAILQ_INSERT_TAIL(&opts->head, opt, next);
545c75d7f71SMarkus Armbruster return true;
546baacf047SPaolo Bonzini }
547baacf047SPaolo Bonzini
qemu_opt_set_number(QemuOpts * opts,const char * name,int64_t val,Error ** errp)548c75d7f71SMarkus Armbruster bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
54939101f25SMarkus Armbruster Error **errp)
550baacf047SPaolo Bonzini {
551baacf047SPaolo Bonzini QemuOpt *opt;
5529da7197aSMarkus Armbruster const QemuOptDesc *desc;
55345c53fe6SPaolo Bonzini const QemuOptsList *list = opts->list;
554baacf047SPaolo Bonzini
55545c53fe6SPaolo Bonzini desc = find_desc_by_name(list->desc, name);
55645c53fe6SPaolo Bonzini if (!desc && !opts_accepts_any(list)) {
557*c6f5d406SPhilippe Mathieu-Daudé error_setg(errp, "Invalid parameter '%s'", name);
558c75d7f71SMarkus Armbruster return false;
559baacf047SPaolo Bonzini }
560baacf047SPaolo Bonzini
5619da7197aSMarkus Armbruster opt = g_malloc0(sizeof(*opt));
562baacf047SPaolo Bonzini opt->name = g_strdup(name);
563baacf047SPaolo Bonzini opt->opts = opts;
5649da7197aSMarkus Armbruster opt->desc = desc;
565baacf047SPaolo Bonzini opt->value.uint = val;
566baacf047SPaolo Bonzini opt->str = g_strdup_printf("%" PRId64, val);
567baacf047SPaolo Bonzini QTAILQ_INSERT_TAIL(&opts->head, opt, next);
568c75d7f71SMarkus Armbruster return true;
569baacf047SPaolo Bonzini }
570baacf047SPaolo Bonzini
5711640b200SMarkus Armbruster /**
57271df1d83SMarkus Armbruster * For each member of @opts, call @func(@opaque, name, value, @errp).
57371df1d83SMarkus Armbruster * @func() may store an Error through @errp, but must return non-zero then.
5741640b200SMarkus Armbruster * When @func() returns non-zero, break the loop and return that value.
5751640b200SMarkus Armbruster * Return zero when the loop completes.
5761640b200SMarkus Armbruster */
qemu_opt_foreach(QemuOpts * opts,qemu_opt_loopfunc func,void * opaque,Error ** errp)57771df1d83SMarkus Armbruster int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
57871df1d83SMarkus Armbruster Error **errp)
579baacf047SPaolo Bonzini {
580baacf047SPaolo Bonzini QemuOpt *opt;
5811640b200SMarkus Armbruster int rc;
582baacf047SPaolo Bonzini
583baacf047SPaolo Bonzini QTAILQ_FOREACH(opt, &opts->head, next) {
58471df1d83SMarkus Armbruster rc = func(opaque, opt->name, opt->str, errp);
5851640b200SMarkus Armbruster if (rc) {
586baacf047SPaolo Bonzini return rc;
587baacf047SPaolo Bonzini }
58871df1d83SMarkus Armbruster assert(!errp || !*errp);
5891640b200SMarkus Armbruster }
5901640b200SMarkus Armbruster return 0;
5911640b200SMarkus Armbruster }
592baacf047SPaolo Bonzini
qemu_opts_find(QemuOptsList * list,const char * id)593baacf047SPaolo Bonzini QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
594baacf047SPaolo Bonzini {
595baacf047SPaolo Bonzini QemuOpts *opts;
596baacf047SPaolo Bonzini
597baacf047SPaolo Bonzini QTAILQ_FOREACH(opts, &list->head, next) {
59896bc97ebSMarkus Armbruster if (!opts->id && !id) {
599baacf047SPaolo Bonzini return opts;
600baacf047SPaolo Bonzini }
60196bc97ebSMarkus Armbruster if (opts->id && id && !strcmp(opts->id, id)) {
602baacf047SPaolo Bonzini return opts;
603baacf047SPaolo Bonzini }
60496bc97ebSMarkus Armbruster }
605baacf047SPaolo Bonzini return NULL;
606baacf047SPaolo Bonzini }
607baacf047SPaolo Bonzini
qemu_opts_create(QemuOptsList * list,const char * id,int fail_if_exists,Error ** errp)608baacf047SPaolo Bonzini QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
609baacf047SPaolo Bonzini int fail_if_exists, Error **errp)
610baacf047SPaolo Bonzini {
611baacf047SPaolo Bonzini QemuOpts *opts = NULL;
612baacf047SPaolo Bonzini
61363758d10SPaolo Bonzini if (list->merge_lists) {
614baacf047SPaolo Bonzini if (id) {
615*c6f5d406SPhilippe Mathieu-Daudé error_setg(errp, "Invalid parameter 'id'");
61663758d10SPaolo Bonzini return NULL;
61763758d10SPaolo Bonzini }
61863758d10SPaolo Bonzini opts = qemu_opts_find(list, NULL);
61963758d10SPaolo Bonzini if (opts) {
62063758d10SPaolo Bonzini return opts;
62163758d10SPaolo Bonzini }
62263758d10SPaolo Bonzini } else if (id) {
62363758d10SPaolo Bonzini assert(fail_if_exists);
624f5bebbbbSMarkus Armbruster if (!id_wellformed(id)) {
625c6bd8c70SMarkus Armbruster error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id",
626c6bd8c70SMarkus Armbruster "an identifier");
62750b7b000SEric Blake error_append_hint(errp, "Identifiers consist of letters, digits, "
628543202c0SMarkus Armbruster "'-', '.', '_', starting with a letter.\n");
629baacf047SPaolo Bonzini return NULL;
630baacf047SPaolo Bonzini }
631baacf047SPaolo Bonzini opts = qemu_opts_find(list, id);
632baacf047SPaolo Bonzini if (opts != NULL) {
633f231b88dSCole Robinson error_setg(errp, "Duplicate ID '%s' for %s", id, list->name);
634baacf047SPaolo Bonzini return NULL;
635baacf047SPaolo Bonzini }
636baacf047SPaolo Bonzini }
637baacf047SPaolo Bonzini opts = g_malloc0(sizeof(*opts));
638baacf047SPaolo Bonzini opts->id = g_strdup(id);
639baacf047SPaolo Bonzini opts->list = list;
640baacf047SPaolo Bonzini loc_save(&opts->loc);
641baacf047SPaolo Bonzini QTAILQ_INIT(&opts->head);
642baacf047SPaolo Bonzini QTAILQ_INSERT_TAIL(&list->head, opts, next);
643baacf047SPaolo Bonzini return opts;
644baacf047SPaolo Bonzini }
645baacf047SPaolo Bonzini
qemu_opts_reset(QemuOptsList * list)646baacf047SPaolo Bonzini void qemu_opts_reset(QemuOptsList *list)
647baacf047SPaolo Bonzini {
648baacf047SPaolo Bonzini QemuOpts *opts, *next_opts;
649baacf047SPaolo Bonzini
650baacf047SPaolo Bonzini QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
651baacf047SPaolo Bonzini qemu_opts_del(opts);
652baacf047SPaolo Bonzini }
653baacf047SPaolo Bonzini }
654baacf047SPaolo Bonzini
qemu_opts_loc_restore(QemuOpts * opts)655baacf047SPaolo Bonzini void qemu_opts_loc_restore(QemuOpts *opts)
656baacf047SPaolo Bonzini {
657baacf047SPaolo Bonzini loc_restore(&opts->loc);
658baacf047SPaolo Bonzini }
659baacf047SPaolo Bonzini
qemu_opts_id(QemuOpts * opts)660baacf047SPaolo Bonzini const char *qemu_opts_id(QemuOpts *opts)
661baacf047SPaolo Bonzini {
662baacf047SPaolo Bonzini return opts->id;
663baacf047SPaolo Bonzini }
664baacf047SPaolo Bonzini
665326642bcSKevin Wolf /* The id string will be g_free()d by qemu_opts_del */
qemu_opts_set_id(QemuOpts * opts,char * id)666326642bcSKevin Wolf void qemu_opts_set_id(QemuOpts *opts, char *id)
667326642bcSKevin Wolf {
668326642bcSKevin Wolf opts->id = id;
669326642bcSKevin Wolf }
670326642bcSKevin Wolf
qemu_opts_del(QemuOpts * opts)671baacf047SPaolo Bonzini void qemu_opts_del(QemuOpts *opts)
672baacf047SPaolo Bonzini {
673baacf047SPaolo Bonzini QemuOpt *opt;
674baacf047SPaolo Bonzini
6754782183dSChunyan Liu if (opts == NULL) {
6764782183dSChunyan Liu return;
6774782183dSChunyan Liu }
6784782183dSChunyan Liu
679baacf047SPaolo Bonzini for (;;) {
680baacf047SPaolo Bonzini opt = QTAILQ_FIRST(&opts->head);
681baacf047SPaolo Bonzini if (opt == NULL)
682baacf047SPaolo Bonzini break;
683baacf047SPaolo Bonzini qemu_opt_del(opt);
684baacf047SPaolo Bonzini }
685baacf047SPaolo Bonzini QTAILQ_REMOVE(&opts->list->head, opts, next);
686baacf047SPaolo Bonzini g_free(opts->id);
687baacf047SPaolo Bonzini g_free(opts);
688baacf047SPaolo Bonzini }
689baacf047SPaolo Bonzini
690fe646693SKővágó, Zoltán /* print value, escaping any commas in value */
escaped_print(const char * value)691fe646693SKővágó, Zoltán static void escaped_print(const char *value)
692fe646693SKővágó, Zoltán {
693fe646693SKővágó, Zoltán const char *ptr;
694fe646693SKővágó, Zoltán
695fe646693SKővágó, Zoltán for (ptr = value; *ptr; ++ptr) {
696fe646693SKővágó, Zoltán if (*ptr == ',') {
697fe646693SKővágó, Zoltán putchar(',');
698fe646693SKővágó, Zoltán }
699fe646693SKővágó, Zoltán putchar(*ptr);
700fe646693SKővágó, Zoltán }
701fe646693SKővágó, Zoltán }
702fe646693SKővágó, Zoltán
qemu_opts_print(QemuOpts * opts,const char * separator)703fe646693SKővágó, Zoltán void qemu_opts_print(QemuOpts *opts, const char *separator)
704baacf047SPaolo Bonzini {
705baacf047SPaolo Bonzini QemuOpt *opt;
70609722032SChunyan Liu QemuOptDesc *desc = opts->list->desc;
707fe646693SKővágó, Zoltán const char *sep = "";
708fe646693SKővágó, Zoltán
709fe646693SKővágó, Zoltán if (opts->id) {
710fe646693SKővágó, Zoltán printf("id=%s", opts->id); /* passed id_wellformed -> no commas */
711fe646693SKővágó, Zoltán sep = separator;
712fe646693SKővágó, Zoltán }
713baacf047SPaolo Bonzini
71409722032SChunyan Liu if (desc[0].name == NULL) {
715baacf047SPaolo Bonzini QTAILQ_FOREACH(opt, &opts->head, next) {
716fe646693SKővágó, Zoltán printf("%s%s=", sep, opt->name);
717fe646693SKővágó, Zoltán escaped_print(opt->str);
718fe646693SKővágó, Zoltán sep = separator;
719baacf047SPaolo Bonzini }
72009722032SChunyan Liu return;
72109722032SChunyan Liu }
72209722032SChunyan Liu for (; desc && desc->name; desc++) {
72309722032SChunyan Liu const char *value;
724da78e382SDr. David Alan Gilbert opt = qemu_opt_find(opts, desc->name);
72509722032SChunyan Liu
72609722032SChunyan Liu value = opt ? opt->str : desc->def_value_str;
72709722032SChunyan Liu if (!value) {
72809722032SChunyan Liu continue;
72909722032SChunyan Liu }
73009722032SChunyan Liu if (desc->type == QEMU_OPT_STRING) {
731fe646693SKővágó, Zoltán printf("%s%s=", sep, desc->name);
732fe646693SKővágó, Zoltán escaped_print(value);
73309722032SChunyan Liu } else if ((desc->type == QEMU_OPT_SIZE ||
73409722032SChunyan Liu desc->type == QEMU_OPT_NUMBER) && opt) {
73543c5d8f8SFam Zheng printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint);
73609722032SChunyan Liu } else {
73743c5d8f8SFam Zheng printf("%s%s=%s", sep, desc->name, value);
73809722032SChunyan Liu }
739fe646693SKővágó, Zoltán sep = separator;
74009722032SChunyan Liu }
741baacf047SPaolo Bonzini }
742baacf047SPaolo Bonzini
get_opt_name_value(const char * params,const char * firstname,bool warn_on_flag,bool * help_wanted,char ** name,char ** value)7436129803bSMarkus Armbruster static const char *get_opt_name_value(const char *params,
7446129803bSMarkus Armbruster const char *firstname,
745ccd3b3b8SPaolo Bonzini bool warn_on_flag,
746afd73625SPaolo Bonzini bool *help_wanted,
7476129803bSMarkus Armbruster char **name, char **value)
748baacf047SPaolo Bonzini {
749924e9b0dSPaolo Bonzini const char *p;
750ccd3b3b8SPaolo Bonzini const char *prefix = "";
751924e9b0dSPaolo Bonzini size_t len;
752afd73625SPaolo Bonzini bool is_help = false;
753baacf047SPaolo Bonzini
754924e9b0dSPaolo Bonzini len = strcspn(params, "=,");
755924e9b0dSPaolo Bonzini if (params[len] != '=') {
756baacf047SPaolo Bonzini /* found "foo,more" */
7576129803bSMarkus Armbruster if (firstname) {
758baacf047SPaolo Bonzini /* implicitly named first option */
7596129803bSMarkus Armbruster *name = g_strdup(firstname);
7606129803bSMarkus Armbruster p = get_opt_value(params, value);
761baacf047SPaolo Bonzini } else {
7626129803bSMarkus Armbruster /* option without value, must be a flag */
763924e9b0dSPaolo Bonzini p = get_opt_name(params, name, len);
7646129803bSMarkus Armbruster if (strncmp(*name, "no", 2) == 0) {
7656129803bSMarkus Armbruster memmove(*name, *name + 2, strlen(*name + 2) + 1);
7666129803bSMarkus Armbruster *value = g_strdup("off");
767ccd3b3b8SPaolo Bonzini prefix = "no";
768baacf047SPaolo Bonzini } else {
7696129803bSMarkus Armbruster *value = g_strdup("on");
770afd73625SPaolo Bonzini is_help = is_help_option(*name);
771baacf047SPaolo Bonzini }
772ccd3b3b8SPaolo Bonzini if (!is_help && warn_on_flag) {
773ccd3b3b8SPaolo Bonzini warn_report("short-form boolean option '%s%s' deprecated", prefix, *name);
774fe636424SPaolo Bonzini if (g_str_equal(*name, "delay")) {
775fe636424SPaolo Bonzini error_printf("Please use nodelay=%s instead\n", prefix[0] ? "on" : "off");
776fe636424SPaolo Bonzini } else {
777ccd3b3b8SPaolo Bonzini error_printf("Please use %s=%s instead\n", *name, *value);
778ccd3b3b8SPaolo Bonzini }
779baacf047SPaolo Bonzini }
780fe636424SPaolo Bonzini }
781baacf047SPaolo Bonzini } else {
782baacf047SPaolo Bonzini /* found "foo=bar,more" */
783924e9b0dSPaolo Bonzini p = get_opt_name(params, name, len);
784e652714fSDaniel P. Berrangé assert(*p == '=');
785baacf047SPaolo Bonzini p++;
7866129803bSMarkus Armbruster p = get_opt_value(p, value);
787baacf047SPaolo Bonzini }
788e652714fSDaniel P. Berrangé
7896129803bSMarkus Armbruster assert(!*p || *p == ',');
790afd73625SPaolo Bonzini if (help_wanted && is_help) {
791afd73625SPaolo Bonzini *help_wanted = true;
792afd73625SPaolo Bonzini }
7936129803bSMarkus Armbruster if (*p == ',') {
7946129803bSMarkus Armbruster p++;
7956129803bSMarkus Armbruster }
7966129803bSMarkus Armbruster return p;
7976129803bSMarkus Armbruster }
7986129803bSMarkus Armbruster
opts_do_parse(QemuOpts * opts,const char * params,const char * firstname,bool warn_on_flag,bool * help_wanted,Error ** errp)799c75d7f71SMarkus Armbruster static bool opts_do_parse(QemuOpts *opts, const char *params,
800904806c6SPaolo Bonzini const char *firstname,
801ccd3b3b8SPaolo Bonzini bool warn_on_flag, bool *help_wanted, Error **errp)
8026129803bSMarkus Armbruster {
8036129803bSMarkus Armbruster char *option, *value;
8046129803bSMarkus Armbruster const char *p;
80564af7a8bSMarkus Armbruster QemuOpt *opt;
8066129803bSMarkus Armbruster
8076129803bSMarkus Armbruster for (p = params; *p;) {
808ccd3b3b8SPaolo Bonzini p = get_opt_name_value(p, firstname, warn_on_flag, help_wanted, &option, &value);
809afd73625SPaolo Bonzini if (help_wanted && *help_wanted) {
810afd73625SPaolo Bonzini g_free(option);
811afd73625SPaolo Bonzini g_free(value);
812afd73625SPaolo Bonzini return false;
813afd73625SPaolo Bonzini }
8146129803bSMarkus Armbruster firstname = NULL;
8156129803bSMarkus Armbruster
8166129803bSMarkus Armbruster if (!strcmp(option, "id")) {
817e652714fSDaniel P. Berrangé g_free(option);
818950c4e6cSDaniel P. Berrangé g_free(value);
8196129803bSMarkus Armbruster continue;
8206129803bSMarkus Armbruster }
8216129803bSMarkus Armbruster
822904806c6SPaolo Bonzini opt = opt_create(opts, option, value);
8236129803bSMarkus Armbruster g_free(option);
824afd73625SPaolo Bonzini if (!opt_validate(opt, errp)) {
82564af7a8bSMarkus Armbruster qemu_opt_del(opt);
826c75d7f71SMarkus Armbruster return false;
8276129803bSMarkus Armbruster }
8286129803bSMarkus Armbruster }
829c75d7f71SMarkus Armbruster
830c75d7f71SMarkus Armbruster return true;
831baacf047SPaolo Bonzini }
832baacf047SPaolo Bonzini
opts_parse_id(const char * params)833933d1527SMarkus Armbruster static char *opts_parse_id(const char *params)
834933d1527SMarkus Armbruster {
835933d1527SMarkus Armbruster const char *p;
836933d1527SMarkus Armbruster char *name, *value;
837933d1527SMarkus Armbruster
838933d1527SMarkus Armbruster for (p = params; *p;) {
839ccd3b3b8SPaolo Bonzini p = get_opt_name_value(p, NULL, false, NULL, &name, &value);
840933d1527SMarkus Armbruster if (!strcmp(name, "id")) {
841933d1527SMarkus Armbruster g_free(name);
842933d1527SMarkus Armbruster return value;
843933d1527SMarkus Armbruster }
844933d1527SMarkus Armbruster g_free(name);
845933d1527SMarkus Armbruster g_free(value);
846933d1527SMarkus Armbruster }
847933d1527SMarkus Armbruster
848933d1527SMarkus Armbruster return NULL;
849933d1527SMarkus Armbruster }
850933d1527SMarkus Armbruster
has_help_option(const char * params)85180a94855SMarkus Armbruster bool has_help_option(const char *params)
85280a94855SMarkus Armbruster {
85380a94855SMarkus Armbruster const char *p;
85480a94855SMarkus Armbruster char *name, *value;
855afd73625SPaolo Bonzini bool ret = false;
85680a94855SMarkus Armbruster
85780a94855SMarkus Armbruster for (p = params; *p;) {
858ccd3b3b8SPaolo Bonzini p = get_opt_name_value(p, NULL, false, &ret, &name, &value);
85980a94855SMarkus Armbruster g_free(name);
86080a94855SMarkus Armbruster g_free(value);
86180a94855SMarkus Armbruster if (ret) {
86280a94855SMarkus Armbruster return true;
86380a94855SMarkus Armbruster }
86480a94855SMarkus Armbruster }
86580a94855SMarkus Armbruster
86680a94855SMarkus Armbruster return false;
86780a94855SMarkus Armbruster }
86880a94855SMarkus Armbruster
869dc523cd3SMarkus Armbruster /**
870dc523cd3SMarkus Armbruster * Store options parsed from @params into @opts.
871dc523cd3SMarkus Armbruster * If @firstname is non-null, the first key=value in @params may omit
872dc523cd3SMarkus Armbruster * key=, and is treated as if key was @firstname.
873dc523cd3SMarkus Armbruster * On error, store an error object through @errp if non-null.
874dc523cd3SMarkus Armbruster */
qemu_opts_do_parse(QemuOpts * opts,const char * params,const char * firstname,Error ** errp)875c75d7f71SMarkus Armbruster bool qemu_opts_do_parse(QemuOpts *opts, const char *params,
876dc523cd3SMarkus Armbruster const char *firstname, Error **errp)
877baacf047SPaolo Bonzini {
878904806c6SPaolo Bonzini return opts_do_parse(opts, params, firstname, false, NULL, errp);
879baacf047SPaolo Bonzini }
880baacf047SPaolo Bonzini
opts_parse(QemuOptsList * list,const char * params,bool permit_abbrev,bool warn_on_flag,bool * help_wanted,Error ** errp)881baacf047SPaolo Bonzini static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
882904806c6SPaolo Bonzini bool permit_abbrev,
883ccd3b3b8SPaolo Bonzini bool warn_on_flag, bool *help_wanted, Error **errp)
884baacf047SPaolo Bonzini {
885baacf047SPaolo Bonzini const char *firstname;
886933d1527SMarkus Armbruster char *id = opts_parse_id(params);
887baacf047SPaolo Bonzini QemuOpts *opts;
888baacf047SPaolo Bonzini
889baacf047SPaolo Bonzini assert(!permit_abbrev || list->implied_opt_name);
890baacf047SPaolo Bonzini firstname = permit_abbrev ? list->implied_opt_name : NULL;
891baacf047SPaolo Bonzini
89263758d10SPaolo Bonzini opts = qemu_opts_create(list, id, !list->merge_lists, errp);
893950c4e6cSDaniel P. Berrangé g_free(id);
894baacf047SPaolo Bonzini if (opts == NULL) {
895baacf047SPaolo Bonzini return NULL;
896baacf047SPaolo Bonzini }
897baacf047SPaolo Bonzini
898904806c6SPaolo Bonzini if (!opts_do_parse(opts, params, firstname,
899ccd3b3b8SPaolo Bonzini warn_on_flag, help_wanted, errp)) {
900baacf047SPaolo Bonzini qemu_opts_del(opts);
901baacf047SPaolo Bonzini return NULL;
902baacf047SPaolo Bonzini }
903baacf047SPaolo Bonzini
904baacf047SPaolo Bonzini return opts;
905baacf047SPaolo Bonzini }
906baacf047SPaolo Bonzini
9074f81273dSMarkus Armbruster /**
9084f81273dSMarkus Armbruster * Create a QemuOpts in @list and with options parsed from @params.
9094f81273dSMarkus Armbruster * If @permit_abbrev, the first key=value in @params may omit key=,
9104f81273dSMarkus Armbruster * and is treated as if key was @list->implied_opt_name.
91170b94331SMarkus Armbruster * On error, store an error object through @errp if non-null.
9124f81273dSMarkus Armbruster * Return the new QemuOpts on success, null pointer on error.
9134f81273dSMarkus Armbruster */
qemu_opts_parse(QemuOptsList * list,const char * params,bool permit_abbrev,Error ** errp)914baacf047SPaolo Bonzini QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
91570b94331SMarkus Armbruster bool permit_abbrev, Error **errp)
91670b94331SMarkus Armbruster {
917904806c6SPaolo Bonzini return opts_parse(list, params, permit_abbrev, false, NULL, errp);
91870b94331SMarkus Armbruster }
91970b94331SMarkus Armbruster
92070b94331SMarkus Armbruster /**
92170b94331SMarkus Armbruster * Create a QemuOpts in @list and with options parsed from @params.
92270b94331SMarkus Armbruster * If @permit_abbrev, the first key=value in @params may omit key=,
92370b94331SMarkus Armbruster * and is treated as if key was @list->implied_opt_name.
92470b94331SMarkus Armbruster * Report errors with error_report_err(). This is inappropriate in
92570b94331SMarkus Armbruster * QMP context. Do not use this function there!
92670b94331SMarkus Armbruster * Return the new QemuOpts on success, null pointer on error.
92770b94331SMarkus Armbruster */
qemu_opts_parse_noisily(QemuOptsList * list,const char * params,bool permit_abbrev)92870b94331SMarkus Armbruster QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
92970b94331SMarkus Armbruster bool permit_abbrev)
930baacf047SPaolo Bonzini {
9314f81273dSMarkus Armbruster Error *err = NULL;
9324f81273dSMarkus Armbruster QemuOpts *opts;
93356a9efa1SMarkus Armbruster bool help_wanted = false;
9344f81273dSMarkus Armbruster
935904806c6SPaolo Bonzini opts = opts_parse(list, params, permit_abbrev, true,
936afd73625SPaolo Bonzini opts_accepts_any(list) ? NULL : &help_wanted,
937afd73625SPaolo Bonzini &err);
938afd73625SPaolo Bonzini if (!opts) {
939afd73625SPaolo Bonzini assert(!!err + !!help_wanted == 1);
94056a9efa1SMarkus Armbruster if (help_wanted) {
94163898712SMax Reitz qemu_opts_print_help(list, true);
942e05979d0SMarc-André Lureau } else {
94370b94331SMarkus Armbruster error_report_err(err);
9444f81273dSMarkus Armbruster }
945e05979d0SMarc-André Lureau }
9464f81273dSMarkus Armbruster return opts;
947baacf047SPaolo Bonzini }
948baacf047SPaolo Bonzini
qemu_opts_from_qdict_entry(QemuOpts * opts,const QDictEntry * entry,Error ** errp)949c75d7f71SMarkus Armbruster static bool qemu_opts_from_qdict_entry(QemuOpts *opts,
9502500f6f3SMarkus Armbruster const QDictEntry *entry,
9512500f6f3SMarkus Armbruster Error **errp)
952baacf047SPaolo Bonzini {
9532500f6f3SMarkus Armbruster const char *key = qdict_entry_key(entry);
9542500f6f3SMarkus Armbruster QObject *obj = qdict_entry_value(entry);
955c75d7f71SMarkus Armbruster char buf[32];
956c75d7f71SMarkus Armbruster g_autofree char *tmp = NULL;
957baacf047SPaolo Bonzini const char *value;
958baacf047SPaolo Bonzini
9592500f6f3SMarkus Armbruster if (!strcmp(key, "id")) {
960c75d7f71SMarkus Armbruster return true;
961baacf047SPaolo Bonzini }
962baacf047SPaolo Bonzini
963baacf047SPaolo Bonzini switch (qobject_type(obj)) {
964baacf047SPaolo Bonzini case QTYPE_QSTRING:
9657dc847ebSMax Reitz value = qstring_get_str(qobject_to(QString, obj));
966baacf047SPaolo Bonzini break;
96701b2ffceSMarc-André Lureau case QTYPE_QNUM:
9687dc847ebSMax Reitz tmp = qnum_to_string(qobject_to(QNum, obj));
96901b2ffceSMarc-André Lureau value = tmp;
970baacf047SPaolo Bonzini break;
971baacf047SPaolo Bonzini case QTYPE_QBOOL:
972baacf047SPaolo Bonzini pstrcpy(buf, sizeof(buf),
9737dc847ebSMax Reitz qbool_get_bool(qobject_to(QBool, obj)) ? "on" : "off");
974baacf047SPaolo Bonzini value = buf;
975baacf047SPaolo Bonzini break;
976baacf047SPaolo Bonzini default:
977c75d7f71SMarkus Armbruster return true;
978baacf047SPaolo Bonzini }
979baacf047SPaolo Bonzini
980c75d7f71SMarkus Armbruster return qemu_opt_set(opts, key, value, errp);
981baacf047SPaolo Bonzini }
982baacf047SPaolo Bonzini
983baacf047SPaolo Bonzini /*
984baacf047SPaolo Bonzini * Create QemuOpts from a QDict.
98501b2ffceSMarc-André Lureau * Use value of key "id" as ID if it exists and is a QString. Only
98601b2ffceSMarc-André Lureau * QStrings, QNums and QBools are copied. Entries with other types
98701b2ffceSMarc-André Lureau * are silently ignored.
988baacf047SPaolo Bonzini */
qemu_opts_from_qdict(QemuOptsList * list,const QDict * qdict,Error ** errp)989baacf047SPaolo Bonzini QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
990baacf047SPaolo Bonzini Error **errp)
991baacf047SPaolo Bonzini {
992baacf047SPaolo Bonzini QemuOpts *opts;
9937b1cd1c6SMarkus Armbruster const QDictEntry *entry;
994baacf047SPaolo Bonzini
995c6ecec43SMarkus Armbruster opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, errp);
996c6ecec43SMarkus Armbruster if (!opts) {
997baacf047SPaolo Bonzini return NULL;
998baacf047SPaolo Bonzini }
999baacf047SPaolo Bonzini
10007b1cd1c6SMarkus Armbruster for (entry = qdict_first(qdict);
10017b1cd1c6SMarkus Armbruster entry;
10027b1cd1c6SMarkus Armbruster entry = qdict_next(qdict, entry)) {
1003668f62ecSMarkus Armbruster if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
1004baacf047SPaolo Bonzini qemu_opts_del(opts);
1005baacf047SPaolo Bonzini return NULL;
1006baacf047SPaolo Bonzini }
10072500f6f3SMarkus Armbruster }
1008baacf047SPaolo Bonzini
1009baacf047SPaolo Bonzini return opts;
1010baacf047SPaolo Bonzini }
1011baacf047SPaolo Bonzini
1012baacf047SPaolo Bonzini /*
1013376609ccSKevin Wolf * Adds all QDict entries to the QemuOpts that can be added and removes them
1014376609ccSKevin Wolf * from the QDict. When this function returns, the QDict contains only those
1015376609ccSKevin Wolf * entries that couldn't be added to the QemuOpts.
1016376609ccSKevin Wolf */
qemu_opts_absorb_qdict(QemuOpts * opts,QDict * qdict,Error ** errp)1017c75d7f71SMarkus Armbruster bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
1018376609ccSKevin Wolf {
1019376609ccSKevin Wolf const QDictEntry *entry, *next;
1020376609ccSKevin Wolf
1021376609ccSKevin Wolf entry = qdict_first(qdict);
1022376609ccSKevin Wolf
1023376609ccSKevin Wolf while (entry != NULL) {
1024376609ccSKevin Wolf next = qdict_next(qdict, entry);
1025376609ccSKevin Wolf
1026941a4736SPaolo Bonzini if (opts_accepts_any(opts->list) ||
1027941a4736SPaolo Bonzini find_desc_by_name(opts->list->desc, entry->key)) {
1028668f62ecSMarkus Armbruster if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
1029c75d7f71SMarkus Armbruster return false;
1030376609ccSKevin Wolf }
10312500f6f3SMarkus Armbruster qdict_del(qdict, entry->key);
1032376609ccSKevin Wolf }
1033376609ccSKevin Wolf
1034376609ccSKevin Wolf entry = next;
1035376609ccSKevin Wolf }
1036c75d7f71SMarkus Armbruster
1037c75d7f71SMarkus Armbruster return true;
1038376609ccSKevin Wolf }
1039376609ccSKevin Wolf
1040376609ccSKevin Wolf /*
104172215395SKevin Wolf * Convert from QemuOpts to QDict. The QDict values are of type QString.
104272215395SKevin Wolf *
104372215395SKevin Wolf * If @list is given, only add those options to the QDict that are contained in
104472215395SKevin Wolf * the list. If @del is true, any options added to the QDict are removed from
104572215395SKevin Wolf * the QemuOpts, otherwise they remain there.
104672215395SKevin Wolf *
104772215395SKevin Wolf * If two options in @opts have the same name, they are processed in order
104872215395SKevin Wolf * so that the last one wins (consistent with the reverse iteration in
104972215395SKevin Wolf * qemu_opt_find()), but all of them are deleted if @del is true.
105072215395SKevin Wolf *
1051baacf047SPaolo Bonzini * TODO We'll want to use types appropriate for opt->desc->type, but
1052baacf047SPaolo Bonzini * this is enough for now.
1053baacf047SPaolo Bonzini */
qemu_opts_to_qdict_filtered(QemuOpts * opts,QDict * qdict,QemuOptsList * list,bool del)105472215395SKevin Wolf QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
105572215395SKevin Wolf QemuOptsList *list, bool del)
1056baacf047SPaolo Bonzini {
105772215395SKevin Wolf QemuOpt *opt, *next;
1058baacf047SPaolo Bonzini
1059baacf047SPaolo Bonzini if (!qdict) {
1060baacf047SPaolo Bonzini qdict = qdict_new();
1061baacf047SPaolo Bonzini }
1062baacf047SPaolo Bonzini if (opts->id) {
106346f5ac20SEric Blake qdict_put_str(qdict, "id", opts->id);
1064baacf047SPaolo Bonzini }
106572215395SKevin Wolf QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next) {
106672215395SKevin Wolf if (list) {
106772215395SKevin Wolf QemuOptDesc *desc;
106872215395SKevin Wolf bool found = false;
106972215395SKevin Wolf for (desc = list->desc; desc->name; desc++) {
107072215395SKevin Wolf if (!strcmp(desc->name, opt->name)) {
107172215395SKevin Wolf found = true;
107272215395SKevin Wolf break;
107372215395SKevin Wolf }
107472215395SKevin Wolf }
107572215395SKevin Wolf if (!found) {
107672215395SKevin Wolf continue;
107772215395SKevin Wolf }
107872215395SKevin Wolf }
107928934e0cSEric Blake qdict_put_str(qdict, opt->name, opt->str);
108072215395SKevin Wolf if (del) {
108172215395SKevin Wolf qemu_opt_del(opt);
108272215395SKevin Wolf }
1083baacf047SPaolo Bonzini }
1084baacf047SPaolo Bonzini return qdict;
1085baacf047SPaolo Bonzini }
1086baacf047SPaolo Bonzini
108772215395SKevin Wolf /* Copy all options in a QemuOpts to the given QDict. See
108872215395SKevin Wolf * qemu_opts_to_qdict_filtered() for details. */
qemu_opts_to_qdict(QemuOpts * opts,QDict * qdict)108972215395SKevin Wolf QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
109072215395SKevin Wolf {
109172215395SKevin Wolf return qemu_opts_to_qdict_filtered(opts, qdict, NULL, false);
109272215395SKevin Wolf }
109372215395SKevin Wolf
1094baacf047SPaolo Bonzini /* Validate parsed opts against descriptions where no
1095baacf047SPaolo Bonzini * descriptions were provided in the QemuOptsList.
1096baacf047SPaolo Bonzini */
qemu_opts_validate(QemuOpts * opts,const QemuOptDesc * desc,Error ** errp)1097c75d7f71SMarkus Armbruster bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
1098baacf047SPaolo Bonzini {
1099baacf047SPaolo Bonzini QemuOpt *opt;
1100baacf047SPaolo Bonzini
110145c53fe6SPaolo Bonzini assert(opts_accepts_any(opts->list));
1102baacf047SPaolo Bonzini
1103baacf047SPaolo Bonzini QTAILQ_FOREACH(opt, &opts->head, next) {
1104baacf047SPaolo Bonzini opt->desc = find_desc_by_name(desc, opt->name);
1105baacf047SPaolo Bonzini if (!opt->desc) {
1106*c6f5d406SPhilippe Mathieu-Daudé error_setg(errp, "Invalid parameter '%s'", opt->name);
1107c75d7f71SMarkus Armbruster return false;
1108baacf047SPaolo Bonzini }
1109baacf047SPaolo Bonzini
1110668f62ecSMarkus Armbruster if (!qemu_opt_parse(opt, errp)) {
1111c75d7f71SMarkus Armbruster return false;
1112baacf047SPaolo Bonzini }
1113baacf047SPaolo Bonzini }
1114c75d7f71SMarkus Armbruster
1115c75d7f71SMarkus Armbruster return true;
1116baacf047SPaolo Bonzini }
1117baacf047SPaolo Bonzini
1118a4c7367fSMarkus Armbruster /**
111928d0de7aSMarkus Armbruster * For each member of @list, call @func(@opaque, member, @errp).
1120a4c7367fSMarkus Armbruster * Call it with the current location temporarily set to the member's.
112128d0de7aSMarkus Armbruster * @func() may store an Error through @errp, but must return non-zero then.
1122a4c7367fSMarkus Armbruster * When @func() returns non-zero, break the loop and return that value.
1123a4c7367fSMarkus Armbruster * Return zero when the loop completes.
1124a4c7367fSMarkus Armbruster */
qemu_opts_foreach(QemuOptsList * list,qemu_opts_loopfunc func,void * opaque,Error ** errp)1125a4c7367fSMarkus Armbruster int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
112628d0de7aSMarkus Armbruster void *opaque, Error **errp)
1127baacf047SPaolo Bonzini {
1128baacf047SPaolo Bonzini Location loc;
112930648dd5SKevin Wolf QemuOpts *opts, *next;
113037f32349SMarkus Armbruster int rc = 0;
1131baacf047SPaolo Bonzini
1132baacf047SPaolo Bonzini loc_push_none(&loc);
113330648dd5SKevin Wolf QTAILQ_FOREACH_SAFE(opts, &list->head, next, next) {
1134baacf047SPaolo Bonzini loc_restore(&opts->loc);
113528d0de7aSMarkus Armbruster rc = func(opaque, opts, errp);
1136a4c7367fSMarkus Armbruster if (rc) {
113737f32349SMarkus Armbruster break;
1138a4c7367fSMarkus Armbruster }
113928d0de7aSMarkus Armbruster assert(!errp || !*errp);
1140baacf047SPaolo Bonzini }
1141baacf047SPaolo Bonzini loc_pop(&loc);
114237f32349SMarkus Armbruster return rc;
1143baacf047SPaolo Bonzini }
11448559e45eSChunyan Liu
count_opts_list(QemuOptsList * list)11458559e45eSChunyan Liu static size_t count_opts_list(QemuOptsList *list)
11468559e45eSChunyan Liu {
11478559e45eSChunyan Liu QemuOptDesc *desc = NULL;
11488559e45eSChunyan Liu size_t num_opts = 0;
11498559e45eSChunyan Liu
11508559e45eSChunyan Liu if (!list) {
11518559e45eSChunyan Liu return 0;
11528559e45eSChunyan Liu }
11538559e45eSChunyan Liu
11548559e45eSChunyan Liu desc = list->desc;
11558559e45eSChunyan Liu while (desc && desc->name) {
11568559e45eSChunyan Liu num_opts++;
11578559e45eSChunyan Liu desc++;
11588559e45eSChunyan Liu }
11598559e45eSChunyan Liu
11608559e45eSChunyan Liu return num_opts;
11618559e45eSChunyan Liu }
11628559e45eSChunyan Liu
qemu_opts_free(QemuOptsList * list)11638559e45eSChunyan Liu void qemu_opts_free(QemuOptsList *list)
11648559e45eSChunyan Liu {
11658559e45eSChunyan Liu g_free(list);
11668559e45eSChunyan Liu }
1167a1097a26SChunyan Liu
1168c282e1fdSChunyan Liu /* Realloc dst option list and append options from an option list (list)
1169c282e1fdSChunyan Liu * to it. dst could be NULL or a malloced list.
117098d896d9SChunyan Liu * The lifetime of dst must be shorter than the input list because the
117198d896d9SChunyan Liu * QemuOptDesc->name, ->help, and ->def_value_str strings are shared.
1172a1097a26SChunyan Liu */
qemu_opts_append(QemuOptsList * dst,QemuOptsList * list)1173a1097a26SChunyan Liu QemuOptsList *qemu_opts_append(QemuOptsList *dst,
1174c282e1fdSChunyan Liu QemuOptsList *list)
1175a1097a26SChunyan Liu {
1176a1097a26SChunyan Liu size_t num_opts, num_dst_opts;
1177a1097a26SChunyan Liu QemuOptDesc *desc;
1178a1097a26SChunyan Liu bool need_init = false;
1179a7607150SMichal Privoznik bool need_head_update;
1180a1097a26SChunyan Liu
1181c282e1fdSChunyan Liu if (!list) {
1182a1097a26SChunyan Liu return dst;
1183a1097a26SChunyan Liu }
1184a1097a26SChunyan Liu
1185a1097a26SChunyan Liu /* If dst is NULL, after realloc, some area of dst should be initialized
1186a1097a26SChunyan Liu * before adding options to it.
1187a1097a26SChunyan Liu */
1188a1097a26SChunyan Liu if (!dst) {
1189a1097a26SChunyan Liu need_init = true;
1190a7607150SMichal Privoznik need_head_update = true;
1191a7607150SMichal Privoznik } else {
1192a7607150SMichal Privoznik /* Moreover, even if dst is not NULL, the realloc may move it to a
1193a7607150SMichal Privoznik * different address in which case we may get a stale tail pointer
1194a7607150SMichal Privoznik * in dst->head. */
1195a7607150SMichal Privoznik need_head_update = QTAILQ_EMPTY(&dst->head);
1196a1097a26SChunyan Liu }
1197a1097a26SChunyan Liu
1198a1097a26SChunyan Liu num_opts = count_opts_list(dst);
1199a1097a26SChunyan Liu num_dst_opts = num_opts;
1200a1097a26SChunyan Liu num_opts += count_opts_list(list);
1201a1097a26SChunyan Liu dst = g_realloc(dst, sizeof(QemuOptsList) +
1202a1097a26SChunyan Liu (num_opts + 1) * sizeof(QemuOptDesc));
1203a1097a26SChunyan Liu if (need_init) {
1204a1097a26SChunyan Liu dst->name = NULL;
1205a1097a26SChunyan Liu dst->implied_opt_name = NULL;
1206a1097a26SChunyan Liu dst->merge_lists = false;
1207a1097a26SChunyan Liu }
1208a7607150SMichal Privoznik if (need_head_update) {
1209a7607150SMichal Privoznik QTAILQ_INIT(&dst->head);
1210a7607150SMichal Privoznik }
1211a1097a26SChunyan Liu dst->desc[num_dst_opts].name = NULL;
1212a1097a26SChunyan Liu
1213a1097a26SChunyan Liu /* append list->desc to dst->desc */
1214a1097a26SChunyan Liu if (list) {
1215a1097a26SChunyan Liu desc = list->desc;
1216a1097a26SChunyan Liu while (desc && desc->name) {
1217a1097a26SChunyan Liu if (find_desc_by_name(dst->desc, desc->name) == NULL) {
121898d896d9SChunyan Liu dst->desc[num_dst_opts++] = *desc;
1219a1097a26SChunyan Liu dst->desc[num_dst_opts].name = NULL;
1220a1097a26SChunyan Liu }
1221a1097a26SChunyan Liu desc++;
1222a1097a26SChunyan Liu }
1223a1097a26SChunyan Liu }
1224a1097a26SChunyan Liu
1225a1097a26SChunyan Liu return dst;
1226a1097a26SChunyan Liu }
1227