xref: /openbmc/qemu/util/qemu-option.c (revision 39101f25)
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 
26baacf047SPaolo Bonzini #include <stdio.h>
27baacf047SPaolo Bonzini #include <string.h>
28baacf047SPaolo Bonzini 
29baacf047SPaolo Bonzini #include "qemu-common.h"
30baacf047SPaolo Bonzini #include "qemu/error-report.h"
31baacf047SPaolo Bonzini #include "qapi/qmp/types.h"
32baacf047SPaolo Bonzini #include "qapi/error.h"
33baacf047SPaolo Bonzini #include "qapi/qmp/qerror.h"
34baacf047SPaolo Bonzini #include "qemu/option_int.h"
35baacf047SPaolo Bonzini 
36baacf047SPaolo Bonzini /*
37baacf047SPaolo Bonzini  * Extracts the name of an option from the parameter string (p points at the
38baacf047SPaolo Bonzini  * first byte of the option name)
39baacf047SPaolo Bonzini  *
40baacf047SPaolo Bonzini  * The option name is delimited by delim (usually , or =) or the string end
41baacf047SPaolo Bonzini  * and is copied into buf. If the option name is longer than buf_size, it is
42baacf047SPaolo Bonzini  * truncated. buf is always zero terminated.
43baacf047SPaolo Bonzini  *
44baacf047SPaolo Bonzini  * The return value is the position of the delimiter/zero byte after the option
45baacf047SPaolo Bonzini  * name in p.
46baacf047SPaolo Bonzini  */
47baacf047SPaolo Bonzini const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
48baacf047SPaolo Bonzini {
49baacf047SPaolo Bonzini     char *q;
50baacf047SPaolo Bonzini 
51baacf047SPaolo Bonzini     q = buf;
52baacf047SPaolo Bonzini     while (*p != '\0' && *p != delim) {
53baacf047SPaolo Bonzini         if (q && (q - buf) < buf_size - 1)
54baacf047SPaolo Bonzini             *q++ = *p;
55baacf047SPaolo Bonzini         p++;
56baacf047SPaolo Bonzini     }
57baacf047SPaolo Bonzini     if (q)
58baacf047SPaolo Bonzini         *q = '\0';
59baacf047SPaolo Bonzini 
60baacf047SPaolo Bonzini     return p;
61baacf047SPaolo Bonzini }
62baacf047SPaolo Bonzini 
63baacf047SPaolo Bonzini /*
64baacf047SPaolo Bonzini  * Extracts the value of an option from the parameter string p (p points at the
65baacf047SPaolo Bonzini  * first byte of the option value)
66baacf047SPaolo Bonzini  *
67baacf047SPaolo Bonzini  * This function is comparable to get_opt_name with the difference that the
68baacf047SPaolo Bonzini  * delimiter is fixed to be comma which starts a new option. To specify an
69baacf047SPaolo Bonzini  * option value that contains commas, double each comma.
70baacf047SPaolo Bonzini  */
71baacf047SPaolo Bonzini const char *get_opt_value(char *buf, int buf_size, const char *p)
72baacf047SPaolo Bonzini {
73baacf047SPaolo Bonzini     char *q;
74baacf047SPaolo Bonzini 
75baacf047SPaolo Bonzini     q = buf;
76baacf047SPaolo Bonzini     while (*p != '\0') {
77baacf047SPaolo Bonzini         if (*p == ',') {
78baacf047SPaolo Bonzini             if (*(p + 1) != ',')
79baacf047SPaolo Bonzini                 break;
80baacf047SPaolo Bonzini             p++;
81baacf047SPaolo Bonzini         }
82baacf047SPaolo Bonzini         if (q && (q - buf) < buf_size - 1)
83baacf047SPaolo Bonzini             *q++ = *p;
84baacf047SPaolo Bonzini         p++;
85baacf047SPaolo Bonzini     }
86baacf047SPaolo Bonzini     if (q)
87baacf047SPaolo Bonzini         *q = '\0';
88baacf047SPaolo Bonzini 
89baacf047SPaolo Bonzini     return p;
90baacf047SPaolo Bonzini }
91baacf047SPaolo Bonzini 
92baacf047SPaolo Bonzini int get_next_param_value(char *buf, int buf_size,
93baacf047SPaolo Bonzini                          const char *tag, const char **pstr)
94baacf047SPaolo Bonzini {
95baacf047SPaolo Bonzini     const char *p;
96baacf047SPaolo Bonzini     char option[128];
97baacf047SPaolo Bonzini 
98baacf047SPaolo Bonzini     p = *pstr;
99baacf047SPaolo Bonzini     for(;;) {
100baacf047SPaolo Bonzini         p = get_opt_name(option, sizeof(option), p, '=');
101baacf047SPaolo Bonzini         if (*p != '=')
102baacf047SPaolo Bonzini             break;
103baacf047SPaolo Bonzini         p++;
104baacf047SPaolo Bonzini         if (!strcmp(tag, option)) {
105baacf047SPaolo Bonzini             *pstr = get_opt_value(buf, buf_size, p);
106baacf047SPaolo Bonzini             if (**pstr == ',') {
107baacf047SPaolo Bonzini                 (*pstr)++;
108baacf047SPaolo Bonzini             }
109baacf047SPaolo Bonzini             return strlen(buf);
110baacf047SPaolo Bonzini         } else {
111baacf047SPaolo Bonzini             p = get_opt_value(NULL, 0, p);
112baacf047SPaolo Bonzini         }
113baacf047SPaolo Bonzini         if (*p != ',')
114baacf047SPaolo Bonzini             break;
115baacf047SPaolo Bonzini         p++;
116baacf047SPaolo Bonzini     }
117baacf047SPaolo Bonzini     return 0;
118baacf047SPaolo Bonzini }
119baacf047SPaolo Bonzini 
120baacf047SPaolo Bonzini int get_param_value(char *buf, int buf_size,
121baacf047SPaolo Bonzini                     const char *tag, const char *str)
122baacf047SPaolo Bonzini {
123baacf047SPaolo Bonzini     return get_next_param_value(buf, buf_size, tag, &str);
124baacf047SPaolo Bonzini }
125baacf047SPaolo Bonzini 
126baacf047SPaolo Bonzini static void parse_option_bool(const char *name, const char *value, bool *ret,
127baacf047SPaolo Bonzini                               Error **errp)
128baacf047SPaolo Bonzini {
129baacf047SPaolo Bonzini     if (value != NULL) {
130baacf047SPaolo Bonzini         if (!strcmp(value, "on")) {
131baacf047SPaolo Bonzini             *ret = 1;
132baacf047SPaolo Bonzini         } else if (!strcmp(value, "off")) {
133baacf047SPaolo Bonzini             *ret = 0;
134baacf047SPaolo Bonzini         } else {
135baacf047SPaolo Bonzini             error_set(errp,QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'");
136baacf047SPaolo Bonzini         }
137baacf047SPaolo Bonzini     } else {
138baacf047SPaolo Bonzini         *ret = 1;
139baacf047SPaolo Bonzini     }
140baacf047SPaolo Bonzini }
141baacf047SPaolo Bonzini 
142baacf047SPaolo Bonzini static void parse_option_number(const char *name, const char *value,
143baacf047SPaolo Bonzini                                 uint64_t *ret, Error **errp)
144baacf047SPaolo Bonzini {
145baacf047SPaolo Bonzini     char *postfix;
146baacf047SPaolo Bonzini     uint64_t number;
147baacf047SPaolo Bonzini 
148baacf047SPaolo Bonzini     if (value != NULL) {
149baacf047SPaolo Bonzini         number = strtoull(value, &postfix, 0);
150baacf047SPaolo Bonzini         if (*postfix != '\0') {
151baacf047SPaolo Bonzini             error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
152baacf047SPaolo Bonzini             return;
153baacf047SPaolo Bonzini         }
154baacf047SPaolo Bonzini         *ret = number;
155baacf047SPaolo Bonzini     } else {
156baacf047SPaolo Bonzini         error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
157baacf047SPaolo Bonzini     }
158baacf047SPaolo Bonzini }
159baacf047SPaolo Bonzini 
1605e89db76SChunyan Liu static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
1615e89db76SChunyan Liu                                             const char *name)
1625e89db76SChunyan Liu {
1635e89db76SChunyan Liu     int i;
1645e89db76SChunyan Liu 
1655e89db76SChunyan Liu     for (i = 0; desc[i].name != NULL; i++) {
1665e89db76SChunyan Liu         if (strcmp(desc[i].name, name) == 0) {
1675e89db76SChunyan Liu             return &desc[i];
1685e89db76SChunyan Liu         }
1695e89db76SChunyan Liu     }
1705e89db76SChunyan Liu 
1715e89db76SChunyan Liu     return NULL;
1725e89db76SChunyan Liu }
1735e89db76SChunyan Liu 
174e8cd45c7SVasilis Liaskovitis void parse_option_size(const char *name, const char *value,
175baacf047SPaolo Bonzini                        uint64_t *ret, Error **errp)
176baacf047SPaolo Bonzini {
177baacf047SPaolo Bonzini     char *postfix;
178baacf047SPaolo Bonzini     double sizef;
179baacf047SPaolo Bonzini 
180baacf047SPaolo Bonzini     if (value != NULL) {
181baacf047SPaolo Bonzini         sizef = strtod(value, &postfix);
182baacf047SPaolo Bonzini         switch (*postfix) {
183baacf047SPaolo Bonzini         case 'T':
184baacf047SPaolo Bonzini             sizef *= 1024;
185baacf047SPaolo Bonzini             /* fall through */
186baacf047SPaolo Bonzini         case 'G':
187baacf047SPaolo Bonzini             sizef *= 1024;
188baacf047SPaolo Bonzini             /* fall through */
189baacf047SPaolo Bonzini         case 'M':
190baacf047SPaolo Bonzini             sizef *= 1024;
191baacf047SPaolo Bonzini             /* fall through */
192baacf047SPaolo Bonzini         case 'K':
193baacf047SPaolo Bonzini         case 'k':
194baacf047SPaolo Bonzini             sizef *= 1024;
195baacf047SPaolo Bonzini             /* fall through */
196baacf047SPaolo Bonzini         case 'b':
197baacf047SPaolo Bonzini         case '\0':
198baacf047SPaolo Bonzini             *ret = (uint64_t) sizef;
199baacf047SPaolo Bonzini             break;
200baacf047SPaolo Bonzini         default:
201baacf047SPaolo Bonzini             error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
2027216ae3dSMarkus Armbruster #if 0 /* conversion from qerror_report() to error_set() broke this: */
203baacf047SPaolo Bonzini             error_printf_unless_qmp("You may use k, M, G or T suffixes for "
204baacf047SPaolo Bonzini                     "kilobytes, megabytes, gigabytes and terabytes.\n");
2057216ae3dSMarkus Armbruster #endif
206baacf047SPaolo Bonzini             return;
207baacf047SPaolo Bonzini         }
208baacf047SPaolo Bonzini     } else {
209baacf047SPaolo Bonzini         error_set(errp, QERR_INVALID_PARAMETER_VALUE, name, "a size");
210baacf047SPaolo Bonzini     }
211baacf047SPaolo Bonzini }
212baacf047SPaolo Bonzini 
2137cc07ab8SKevin Wolf bool has_help_option(const char *param)
2147cc07ab8SKevin Wolf {
2157cc07ab8SKevin Wolf     size_t buflen = strlen(param) + 1;
21696c044afSMarkus Armbruster     char *buf = g_malloc(buflen);
2177cc07ab8SKevin Wolf     const char *p = param;
2187cc07ab8SKevin Wolf     bool result = false;
2197cc07ab8SKevin Wolf 
2207cc07ab8SKevin Wolf     while (*p) {
2217cc07ab8SKevin Wolf         p = get_opt_value(buf, buflen, p);
2227cc07ab8SKevin Wolf         if (*p) {
2237cc07ab8SKevin Wolf             p++;
2247cc07ab8SKevin Wolf         }
2257cc07ab8SKevin Wolf 
2267cc07ab8SKevin Wolf         if (is_help_option(buf)) {
2277cc07ab8SKevin Wolf             result = true;
2287cc07ab8SKevin Wolf             goto out;
2297cc07ab8SKevin Wolf         }
2307cc07ab8SKevin Wolf     }
2317cc07ab8SKevin Wolf 
2327cc07ab8SKevin Wolf out:
233c0462f6dSMarkus Armbruster     g_free(buf);
2347cc07ab8SKevin Wolf     return result;
2357cc07ab8SKevin Wolf }
2367cc07ab8SKevin Wolf 
2377cc07ab8SKevin Wolf bool is_valid_option_list(const char *param)
2387cc07ab8SKevin Wolf {
2397cc07ab8SKevin Wolf     size_t buflen = strlen(param) + 1;
24096c044afSMarkus Armbruster     char *buf = g_malloc(buflen);
2417cc07ab8SKevin Wolf     const char *p = param;
2427cc07ab8SKevin Wolf     bool result = true;
2437cc07ab8SKevin Wolf 
2447cc07ab8SKevin Wolf     while (*p) {
2457cc07ab8SKevin Wolf         p = get_opt_value(buf, buflen, p);
2467cc07ab8SKevin Wolf         if (*p && !*++p) {
2477cc07ab8SKevin Wolf             result = false;
2487cc07ab8SKevin Wolf             goto out;
2497cc07ab8SKevin Wolf         }
2507cc07ab8SKevin Wolf 
2517cc07ab8SKevin Wolf         if (!*buf || *buf == ',') {
2527cc07ab8SKevin Wolf             result = false;
2537cc07ab8SKevin Wolf             goto out;
2547cc07ab8SKevin Wolf         }
2557cc07ab8SKevin Wolf     }
2567cc07ab8SKevin Wolf 
2577cc07ab8SKevin Wolf out:
258c0462f6dSMarkus Armbruster     g_free(buf);
2597cc07ab8SKevin Wolf     return result;
2607cc07ab8SKevin Wolf }
2617cc07ab8SKevin Wolf 
262504189a9SChunyan Liu void qemu_opts_print_help(QemuOptsList *list)
263504189a9SChunyan Liu {
264504189a9SChunyan Liu     QemuOptDesc *desc;
265504189a9SChunyan Liu 
266504189a9SChunyan Liu     assert(list);
267504189a9SChunyan Liu     desc = list->desc;
268504189a9SChunyan Liu     printf("Supported options:\n");
269504189a9SChunyan Liu     while (desc && desc->name) {
270504189a9SChunyan Liu         printf("%-16s %s\n", desc->name,
271504189a9SChunyan Liu                desc->help ? desc->help : "No description available");
272504189a9SChunyan Liu         desc++;
273504189a9SChunyan Liu     }
274504189a9SChunyan Liu }
275baacf047SPaolo Bonzini /* ------------------------------------------------------------------ */
276baacf047SPaolo Bonzini 
27774c3c197SChunyan Liu QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
278baacf047SPaolo Bonzini {
279baacf047SPaolo Bonzini     QemuOpt *opt;
280baacf047SPaolo Bonzini 
281baacf047SPaolo Bonzini     QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
282baacf047SPaolo Bonzini         if (strcmp(opt->name, name) != 0)
283baacf047SPaolo Bonzini             continue;
284baacf047SPaolo Bonzini         return opt;
285baacf047SPaolo Bonzini     }
286baacf047SPaolo Bonzini     return NULL;
287baacf047SPaolo Bonzini }
288baacf047SPaolo Bonzini 
289fc345512SChunyan Liu static void qemu_opt_del(QemuOpt *opt)
290fc345512SChunyan Liu {
291fc345512SChunyan Liu     QTAILQ_REMOVE(&opt->opts->head, opt, next);
292fc345512SChunyan Liu     g_free(opt->name);
293fc345512SChunyan Liu     g_free(opt->str);
294fc345512SChunyan Liu     g_free(opt);
295fc345512SChunyan Liu }
296fc345512SChunyan Liu 
297782730b0SChunyan Liu /* qemu_opt_set allows many settings for the same option.
298782730b0SChunyan Liu  * This function deletes all settings for an option.
299782730b0SChunyan Liu  */
300782730b0SChunyan Liu static void qemu_opt_del_all(QemuOpts *opts, const char *name)
301782730b0SChunyan Liu {
302782730b0SChunyan Liu     QemuOpt *opt, *next_opt;
303782730b0SChunyan Liu 
304782730b0SChunyan Liu     QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next_opt) {
305782730b0SChunyan Liu         if (!strcmp(opt->name, name)) {
306782730b0SChunyan Liu             qemu_opt_del(opt);
307782730b0SChunyan Liu         }
308782730b0SChunyan Liu     }
309782730b0SChunyan Liu }
310782730b0SChunyan Liu 
311baacf047SPaolo Bonzini const char *qemu_opt_get(QemuOpts *opts, const char *name)
312baacf047SPaolo Bonzini {
313435db4cfSChunyan Liu     QemuOpt *opt;
31409722032SChunyan Liu 
315435db4cfSChunyan Liu     if (opts == NULL) {
316435db4cfSChunyan Liu         return NULL;
317435db4cfSChunyan Liu     }
318435db4cfSChunyan Liu 
319435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
32009722032SChunyan Liu     if (!opt) {
32109722032SChunyan Liu         const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
32209722032SChunyan Liu         if (desc && desc->def_value_str) {
32309722032SChunyan Liu             return desc->def_value_str;
32409722032SChunyan Liu         }
32509722032SChunyan Liu     }
326baacf047SPaolo Bonzini     return opt ? opt->str : NULL;
327baacf047SPaolo Bonzini }
328baacf047SPaolo Bonzini 
329782730b0SChunyan Liu /* Get a known option (or its default) and remove it from the list
330782730b0SChunyan Liu  * all in one action. Return a malloced string of the option value.
331782730b0SChunyan Liu  * Result must be freed by caller with g_free().
332782730b0SChunyan Liu  */
333782730b0SChunyan Liu char *qemu_opt_get_del(QemuOpts *opts, const char *name)
334782730b0SChunyan Liu {
335782730b0SChunyan Liu     QemuOpt *opt;
336782730b0SChunyan Liu     const QemuOptDesc *desc;
337782730b0SChunyan Liu     char *str = NULL;
338782730b0SChunyan Liu 
339782730b0SChunyan Liu     if (opts == NULL) {
340782730b0SChunyan Liu         return NULL;
341782730b0SChunyan Liu     }
342782730b0SChunyan Liu 
343782730b0SChunyan Liu     opt = qemu_opt_find(opts, name);
344782730b0SChunyan Liu     if (!opt) {
345782730b0SChunyan Liu         desc = find_desc_by_name(opts->list->desc, name);
346782730b0SChunyan Liu         if (desc && desc->def_value_str) {
347782730b0SChunyan Liu             str = g_strdup(desc->def_value_str);
348782730b0SChunyan Liu         }
349782730b0SChunyan Liu         return str;
350782730b0SChunyan Liu     }
351782730b0SChunyan Liu     str = opt->str;
352782730b0SChunyan Liu     opt->str = NULL;
353782730b0SChunyan Liu     qemu_opt_del_all(opts, name);
354782730b0SChunyan Liu     return str;
355782730b0SChunyan Liu }
356782730b0SChunyan Liu 
357baacf047SPaolo Bonzini bool qemu_opt_has_help_opt(QemuOpts *opts)
358baacf047SPaolo Bonzini {
359baacf047SPaolo Bonzini     QemuOpt *opt;
360baacf047SPaolo Bonzini 
361baacf047SPaolo Bonzini     QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
362baacf047SPaolo Bonzini         if (is_help_option(opt->name)) {
363baacf047SPaolo Bonzini             return true;
364baacf047SPaolo Bonzini         }
365baacf047SPaolo Bonzini     }
366baacf047SPaolo Bonzini     return false;
367baacf047SPaolo Bonzini }
368baacf047SPaolo Bonzini 
369782730b0SChunyan Liu static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name,
370782730b0SChunyan Liu                                      bool defval, bool del)
371baacf047SPaolo Bonzini {
372435db4cfSChunyan Liu     QemuOpt *opt;
373782730b0SChunyan Liu     bool ret = defval;
374baacf047SPaolo Bonzini 
375435db4cfSChunyan Liu     if (opts == NULL) {
376435db4cfSChunyan Liu         return ret;
377435db4cfSChunyan Liu     }
378435db4cfSChunyan Liu 
379435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
38009722032SChunyan Liu     if (opt == NULL) {
38109722032SChunyan Liu         const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
38209722032SChunyan Liu         if (desc && desc->def_value_str) {
383782730b0SChunyan Liu             parse_option_bool(name, desc->def_value_str, &ret, &error_abort);
38409722032SChunyan Liu         }
385782730b0SChunyan Liu         return ret;
38609722032SChunyan Liu     }
387baacf047SPaolo Bonzini     assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
388782730b0SChunyan Liu     ret = opt->value.boolean;
389782730b0SChunyan Liu     if (del) {
390782730b0SChunyan Liu         qemu_opt_del_all(opts, name);
391782730b0SChunyan Liu     }
392782730b0SChunyan Liu     return ret;
393782730b0SChunyan Liu }
394782730b0SChunyan Liu 
395782730b0SChunyan Liu bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
396782730b0SChunyan Liu {
397782730b0SChunyan Liu     return qemu_opt_get_bool_helper(opts, name, defval, false);
398782730b0SChunyan Liu }
399782730b0SChunyan Liu 
400782730b0SChunyan Liu bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval)
401782730b0SChunyan Liu {
402782730b0SChunyan Liu     return qemu_opt_get_bool_helper(opts, name, defval, true);
403782730b0SChunyan Liu }
404782730b0SChunyan Liu 
405782730b0SChunyan Liu static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name,
406782730b0SChunyan Liu                                            uint64_t defval, bool del)
407782730b0SChunyan Liu {
408435db4cfSChunyan Liu     QemuOpt *opt;
409782730b0SChunyan Liu     uint64_t ret = defval;
410782730b0SChunyan Liu 
411435db4cfSChunyan Liu     if (opts == NULL) {
412435db4cfSChunyan Liu         return ret;
413435db4cfSChunyan Liu     }
414435db4cfSChunyan Liu 
415435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
416782730b0SChunyan Liu     if (opt == NULL) {
417782730b0SChunyan Liu         const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
418782730b0SChunyan Liu         if (desc && desc->def_value_str) {
419782730b0SChunyan Liu             parse_option_number(name, desc->def_value_str, &ret, &error_abort);
420782730b0SChunyan Liu         }
421782730b0SChunyan Liu         return ret;
422782730b0SChunyan Liu     }
423782730b0SChunyan Liu     assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
424782730b0SChunyan Liu     ret = opt->value.uint;
425782730b0SChunyan Liu     if (del) {
426782730b0SChunyan Liu         qemu_opt_del_all(opts, name);
427782730b0SChunyan Liu     }
428782730b0SChunyan Liu     return ret;
429baacf047SPaolo Bonzini }
430baacf047SPaolo Bonzini 
431baacf047SPaolo Bonzini uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
432baacf047SPaolo Bonzini {
433782730b0SChunyan Liu     return qemu_opt_get_number_helper(opts, name, defval, false);
434782730b0SChunyan Liu }
435782730b0SChunyan Liu 
436782730b0SChunyan Liu uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name,
437782730b0SChunyan Liu                                  uint64_t defval)
438782730b0SChunyan Liu {
439782730b0SChunyan Liu     return qemu_opt_get_number_helper(opts, name, defval, true);
440782730b0SChunyan Liu }
441782730b0SChunyan Liu 
442782730b0SChunyan Liu static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name,
443782730b0SChunyan Liu                                          uint64_t defval, bool del)
444782730b0SChunyan Liu {
445435db4cfSChunyan Liu     QemuOpt *opt;
446782730b0SChunyan Liu     uint64_t ret = defval;
447baacf047SPaolo Bonzini 
448435db4cfSChunyan Liu     if (opts == NULL) {
449435db4cfSChunyan Liu         return ret;
450435db4cfSChunyan Liu     }
451435db4cfSChunyan Liu 
452435db4cfSChunyan Liu     opt = qemu_opt_find(opts, name);
45309722032SChunyan Liu     if (opt == NULL) {
45409722032SChunyan Liu         const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
45509722032SChunyan Liu         if (desc && desc->def_value_str) {
456782730b0SChunyan Liu             parse_option_size(name, desc->def_value_str, &ret, &error_abort);
45709722032SChunyan Liu         }
458782730b0SChunyan Liu         return ret;
45909722032SChunyan Liu     }
460782730b0SChunyan Liu     assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
461782730b0SChunyan Liu     ret = opt->value.uint;
462782730b0SChunyan Liu     if (del) {
463782730b0SChunyan Liu         qemu_opt_del_all(opts, name);
464782730b0SChunyan Liu     }
465782730b0SChunyan Liu     return ret;
466baacf047SPaolo Bonzini }
467baacf047SPaolo Bonzini 
468baacf047SPaolo Bonzini uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
469baacf047SPaolo Bonzini {
470782730b0SChunyan Liu     return qemu_opt_get_size_helper(opts, name, defval, false);
471782730b0SChunyan Liu }
472baacf047SPaolo Bonzini 
473782730b0SChunyan Liu uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
474782730b0SChunyan Liu                                uint64_t defval)
475782730b0SChunyan Liu {
476782730b0SChunyan Liu     return qemu_opt_get_size_helper(opts, name, defval, true);
477baacf047SPaolo Bonzini }
478baacf047SPaolo Bonzini 
479baacf047SPaolo Bonzini static void qemu_opt_parse(QemuOpt *opt, Error **errp)
480baacf047SPaolo Bonzini {
481baacf047SPaolo Bonzini     if (opt->desc == NULL)
482baacf047SPaolo Bonzini         return;
483baacf047SPaolo Bonzini 
484baacf047SPaolo Bonzini     switch (opt->desc->type) {
485baacf047SPaolo Bonzini     case QEMU_OPT_STRING:
486baacf047SPaolo Bonzini         /* nothing */
487baacf047SPaolo Bonzini         return;
488baacf047SPaolo Bonzini     case QEMU_OPT_BOOL:
489baacf047SPaolo Bonzini         parse_option_bool(opt->name, opt->str, &opt->value.boolean, errp);
490baacf047SPaolo Bonzini         break;
491baacf047SPaolo Bonzini     case QEMU_OPT_NUMBER:
492baacf047SPaolo Bonzini         parse_option_number(opt->name, opt->str, &opt->value.uint, errp);
493baacf047SPaolo Bonzini         break;
494baacf047SPaolo Bonzini     case QEMU_OPT_SIZE:
495baacf047SPaolo Bonzini         parse_option_size(opt->name, opt->str, &opt->value.uint, errp);
496baacf047SPaolo Bonzini         break;
497baacf047SPaolo Bonzini     default:
498baacf047SPaolo Bonzini         abort();
499baacf047SPaolo Bonzini     }
500baacf047SPaolo Bonzini }
501baacf047SPaolo Bonzini 
502baacf047SPaolo Bonzini static bool opts_accepts_any(const QemuOpts *opts)
503baacf047SPaolo Bonzini {
504baacf047SPaolo Bonzini     return opts->list->desc[0].name == NULL;
505baacf047SPaolo Bonzini }
506baacf047SPaolo Bonzini 
5070dd6c526SKevin Wolf int qemu_opt_unset(QemuOpts *opts, const char *name)
5080dd6c526SKevin Wolf {
5090dd6c526SKevin Wolf     QemuOpt *opt = qemu_opt_find(opts, name);
5100dd6c526SKevin Wolf 
5110dd6c526SKevin Wolf     assert(opts_accepts_any(opts));
5120dd6c526SKevin Wolf 
5130dd6c526SKevin Wolf     if (opt == NULL) {
5140dd6c526SKevin Wolf         return -1;
5150dd6c526SKevin Wolf     } else {
5160dd6c526SKevin Wolf         qemu_opt_del(opt);
5170dd6c526SKevin Wolf         return 0;
5180dd6c526SKevin Wolf     }
5190dd6c526SKevin Wolf }
5200dd6c526SKevin Wolf 
521baacf047SPaolo Bonzini static void opt_set(QemuOpts *opts, const char *name, const char *value,
522baacf047SPaolo Bonzini                     bool prepend, Error **errp)
523baacf047SPaolo Bonzini {
524baacf047SPaolo Bonzini     QemuOpt *opt;
525baacf047SPaolo Bonzini     const QemuOptDesc *desc;
526baacf047SPaolo Bonzini     Error *local_err = NULL;
527baacf047SPaolo Bonzini 
528baacf047SPaolo Bonzini     desc = find_desc_by_name(opts->list->desc, name);
529baacf047SPaolo Bonzini     if (!desc && !opts_accepts_any(opts)) {
530baacf047SPaolo Bonzini         error_set(errp, QERR_INVALID_PARAMETER, name);
531baacf047SPaolo Bonzini         return;
532baacf047SPaolo Bonzini     }
533baacf047SPaolo Bonzini 
534baacf047SPaolo Bonzini     opt = g_malloc0(sizeof(*opt));
535baacf047SPaolo Bonzini     opt->name = g_strdup(name);
536baacf047SPaolo Bonzini     opt->opts = opts;
537baacf047SPaolo Bonzini     if (prepend) {
538baacf047SPaolo Bonzini         QTAILQ_INSERT_HEAD(&opts->head, opt, next);
539baacf047SPaolo Bonzini     } else {
540baacf047SPaolo Bonzini         QTAILQ_INSERT_TAIL(&opts->head, opt, next);
541baacf047SPaolo Bonzini     }
542baacf047SPaolo Bonzini     opt->desc = desc;
543baacf047SPaolo Bonzini     opt->str = g_strdup(value);
544baacf047SPaolo Bonzini     qemu_opt_parse(opt, &local_err);
54584d18f06SMarkus Armbruster     if (local_err) {
546baacf047SPaolo Bonzini         error_propagate(errp, local_err);
547baacf047SPaolo Bonzini         qemu_opt_del(opt);
548baacf047SPaolo Bonzini     }
549baacf047SPaolo Bonzini }
550baacf047SPaolo Bonzini 
551baacf047SPaolo Bonzini int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
552baacf047SPaolo Bonzini {
553baacf047SPaolo Bonzini     Error *local_err = NULL;
554baacf047SPaolo Bonzini 
555baacf047SPaolo Bonzini     opt_set(opts, name, value, false, &local_err);
55684d18f06SMarkus Armbruster     if (local_err) {
557baacf047SPaolo Bonzini         qerror_report_err(local_err);
558baacf047SPaolo Bonzini         error_free(local_err);
559baacf047SPaolo Bonzini         return -1;
560baacf047SPaolo Bonzini     }
561baacf047SPaolo Bonzini 
562baacf047SPaolo Bonzini     return 0;
563baacf047SPaolo Bonzini }
564baacf047SPaolo Bonzini 
565baacf047SPaolo Bonzini void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value,
566baacf047SPaolo Bonzini                       Error **errp)
567baacf047SPaolo Bonzini {
568baacf047SPaolo Bonzini     opt_set(opts, name, value, false, errp);
569baacf047SPaolo Bonzini }
570baacf047SPaolo Bonzini 
571cccb7967SMarkus Armbruster void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
572cccb7967SMarkus Armbruster                        Error **errp)
573baacf047SPaolo Bonzini {
574baacf047SPaolo Bonzini     QemuOpt *opt;
575baacf047SPaolo Bonzini     const QemuOptDesc *desc = opts->list->desc;
576baacf047SPaolo Bonzini 
577baacf047SPaolo Bonzini     opt = g_malloc0(sizeof(*opt));
578baacf047SPaolo Bonzini     opt->desc = find_desc_by_name(desc, name);
579baacf047SPaolo Bonzini     if (!opt->desc && !opts_accepts_any(opts)) {
580cccb7967SMarkus Armbruster         error_set(errp, QERR_INVALID_PARAMETER, name);
581baacf047SPaolo Bonzini         g_free(opt);
582cccb7967SMarkus Armbruster         return;
583baacf047SPaolo Bonzini     }
584baacf047SPaolo Bonzini 
585baacf047SPaolo Bonzini     opt->name = g_strdup(name);
586baacf047SPaolo Bonzini     opt->opts = opts;
587baacf047SPaolo Bonzini     opt->value.boolean = !!val;
588baacf047SPaolo Bonzini     opt->str = g_strdup(val ? "on" : "off");
589baacf047SPaolo Bonzini     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
590baacf047SPaolo Bonzini }
591baacf047SPaolo Bonzini 
592*39101f25SMarkus Armbruster void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
593*39101f25SMarkus Armbruster                          Error **errp)
594baacf047SPaolo Bonzini {
595baacf047SPaolo Bonzini     QemuOpt *opt;
596baacf047SPaolo Bonzini     const QemuOptDesc *desc = opts->list->desc;
597baacf047SPaolo Bonzini 
598baacf047SPaolo Bonzini     opt = g_malloc0(sizeof(*opt));
599baacf047SPaolo Bonzini     opt->desc = find_desc_by_name(desc, name);
600baacf047SPaolo Bonzini     if (!opt->desc && !opts_accepts_any(opts)) {
601*39101f25SMarkus Armbruster         error_set(errp, QERR_INVALID_PARAMETER, name);
602baacf047SPaolo Bonzini         g_free(opt);
603*39101f25SMarkus Armbruster         return;
604baacf047SPaolo Bonzini     }
605baacf047SPaolo Bonzini 
606baacf047SPaolo Bonzini     opt->name = g_strdup(name);
607baacf047SPaolo Bonzini     opt->opts = opts;
608baacf047SPaolo Bonzini     opt->value.uint = val;
609baacf047SPaolo Bonzini     opt->str = g_strdup_printf("%" PRId64, val);
610baacf047SPaolo Bonzini     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
611baacf047SPaolo Bonzini }
612baacf047SPaolo Bonzini 
613baacf047SPaolo Bonzini int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
614baacf047SPaolo Bonzini                      int abort_on_failure)
615baacf047SPaolo Bonzini {
616baacf047SPaolo Bonzini     QemuOpt *opt;
617baacf047SPaolo Bonzini     int rc = 0;
618baacf047SPaolo Bonzini 
619baacf047SPaolo Bonzini     QTAILQ_FOREACH(opt, &opts->head, next) {
620baacf047SPaolo Bonzini         rc = func(opt->name, opt->str, opaque);
621baacf047SPaolo Bonzini         if (abort_on_failure  &&  rc != 0)
622baacf047SPaolo Bonzini             break;
623baacf047SPaolo Bonzini     }
624baacf047SPaolo Bonzini     return rc;
625baacf047SPaolo Bonzini }
626baacf047SPaolo Bonzini 
627baacf047SPaolo Bonzini QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
628baacf047SPaolo Bonzini {
629baacf047SPaolo Bonzini     QemuOpts *opts;
630baacf047SPaolo Bonzini 
631baacf047SPaolo Bonzini     QTAILQ_FOREACH(opts, &list->head, next) {
63296bc97ebSMarkus Armbruster         if (!opts->id && !id) {
633baacf047SPaolo Bonzini             return opts;
634baacf047SPaolo Bonzini         }
63596bc97ebSMarkus Armbruster         if (opts->id && id && !strcmp(opts->id, id)) {
636baacf047SPaolo Bonzini             return opts;
637baacf047SPaolo Bonzini         }
63896bc97ebSMarkus Armbruster     }
639baacf047SPaolo Bonzini     return NULL;
640baacf047SPaolo Bonzini }
641baacf047SPaolo Bonzini 
642baacf047SPaolo Bonzini QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
643baacf047SPaolo Bonzini                            int fail_if_exists, Error **errp)
644baacf047SPaolo Bonzini {
645baacf047SPaolo Bonzini     QemuOpts *opts = NULL;
646baacf047SPaolo Bonzini 
647baacf047SPaolo Bonzini     if (id) {
648f5bebbbbSMarkus Armbruster         if (!id_wellformed(id)) {
649baacf047SPaolo Bonzini             error_set(errp,QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
6507216ae3dSMarkus Armbruster #if 0 /* conversion from qerror_report() to error_set() broke this: */
651baacf047SPaolo Bonzini             error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n");
6527216ae3dSMarkus Armbruster #endif
653baacf047SPaolo Bonzini             return NULL;
654baacf047SPaolo Bonzini         }
655baacf047SPaolo Bonzini         opts = qemu_opts_find(list, id);
656baacf047SPaolo Bonzini         if (opts != NULL) {
657baacf047SPaolo Bonzini             if (fail_if_exists && !list->merge_lists) {
658f231b88dSCole Robinson                 error_setg(errp, "Duplicate ID '%s' for %s", id, list->name);
659baacf047SPaolo Bonzini                 return NULL;
660baacf047SPaolo Bonzini             } else {
661baacf047SPaolo Bonzini                 return opts;
662baacf047SPaolo Bonzini             }
663baacf047SPaolo Bonzini         }
664baacf047SPaolo Bonzini     } else if (list->merge_lists) {
665baacf047SPaolo Bonzini         opts = qemu_opts_find(list, NULL);
666baacf047SPaolo Bonzini         if (opts) {
667baacf047SPaolo Bonzini             return opts;
668baacf047SPaolo Bonzini         }
669baacf047SPaolo Bonzini     }
670baacf047SPaolo Bonzini     opts = g_malloc0(sizeof(*opts));
671baacf047SPaolo Bonzini     opts->id = g_strdup(id);
672baacf047SPaolo Bonzini     opts->list = list;
673baacf047SPaolo Bonzini     loc_save(&opts->loc);
674baacf047SPaolo Bonzini     QTAILQ_INIT(&opts->head);
675baacf047SPaolo Bonzini     QTAILQ_INSERT_TAIL(&list->head, opts, next);
676baacf047SPaolo Bonzini     return opts;
677baacf047SPaolo Bonzini }
678baacf047SPaolo Bonzini 
679baacf047SPaolo Bonzini void qemu_opts_reset(QemuOptsList *list)
680baacf047SPaolo Bonzini {
681baacf047SPaolo Bonzini     QemuOpts *opts, *next_opts;
682baacf047SPaolo Bonzini 
683baacf047SPaolo Bonzini     QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
684baacf047SPaolo Bonzini         qemu_opts_del(opts);
685baacf047SPaolo Bonzini     }
686baacf047SPaolo Bonzini }
687baacf047SPaolo Bonzini 
688baacf047SPaolo Bonzini void qemu_opts_loc_restore(QemuOpts *opts)
689baacf047SPaolo Bonzini {
690baacf047SPaolo Bonzini     loc_restore(&opts->loc);
691baacf047SPaolo Bonzini }
692baacf047SPaolo Bonzini 
693baacf047SPaolo Bonzini int qemu_opts_set(QemuOptsList *list, const char *id,
694baacf047SPaolo Bonzini                   const char *name, const char *value)
695baacf047SPaolo Bonzini {
696baacf047SPaolo Bonzini     QemuOpts *opts;
697baacf047SPaolo Bonzini     Error *local_err = NULL;
698baacf047SPaolo Bonzini 
699baacf047SPaolo Bonzini     opts = qemu_opts_create(list, id, 1, &local_err);
70084d18f06SMarkus Armbruster     if (local_err) {
701baacf047SPaolo Bonzini         qerror_report_err(local_err);
702baacf047SPaolo Bonzini         error_free(local_err);
703baacf047SPaolo Bonzini         return -1;
704baacf047SPaolo Bonzini     }
705baacf047SPaolo Bonzini     return qemu_opt_set(opts, name, value);
706baacf047SPaolo Bonzini }
707baacf047SPaolo Bonzini 
708baacf047SPaolo Bonzini const char *qemu_opts_id(QemuOpts *opts)
709baacf047SPaolo Bonzini {
710baacf047SPaolo Bonzini     return opts->id;
711baacf047SPaolo Bonzini }
712baacf047SPaolo Bonzini 
713326642bcSKevin Wolf /* The id string will be g_free()d by qemu_opts_del */
714326642bcSKevin Wolf void qemu_opts_set_id(QemuOpts *opts, char *id)
715326642bcSKevin Wolf {
716326642bcSKevin Wolf     opts->id = id;
717326642bcSKevin Wolf }
718326642bcSKevin Wolf 
719baacf047SPaolo Bonzini void qemu_opts_del(QemuOpts *opts)
720baacf047SPaolo Bonzini {
721baacf047SPaolo Bonzini     QemuOpt *opt;
722baacf047SPaolo Bonzini 
7234782183dSChunyan Liu     if (opts == NULL) {
7244782183dSChunyan Liu         return;
7254782183dSChunyan Liu     }
7264782183dSChunyan Liu 
727baacf047SPaolo Bonzini     for (;;) {
728baacf047SPaolo Bonzini         opt = QTAILQ_FIRST(&opts->head);
729baacf047SPaolo Bonzini         if (opt == NULL)
730baacf047SPaolo Bonzini             break;
731baacf047SPaolo Bonzini         qemu_opt_del(opt);
732baacf047SPaolo Bonzini     }
733baacf047SPaolo Bonzini     QTAILQ_REMOVE(&opts->list->head, opts, next);
734baacf047SPaolo Bonzini     g_free(opts->id);
735baacf047SPaolo Bonzini     g_free(opts);
736baacf047SPaolo Bonzini }
737baacf047SPaolo Bonzini 
73843c5d8f8SFam Zheng void qemu_opts_print(QemuOpts *opts, const char *sep)
739baacf047SPaolo Bonzini {
740baacf047SPaolo Bonzini     QemuOpt *opt;
74109722032SChunyan Liu     QemuOptDesc *desc = opts->list->desc;
742baacf047SPaolo Bonzini 
74309722032SChunyan Liu     if (desc[0].name == NULL) {
744baacf047SPaolo Bonzini         QTAILQ_FOREACH(opt, &opts->head, next) {
74543c5d8f8SFam Zheng             printf("%s%s=\"%s\"", sep, opt->name, opt->str);
746baacf047SPaolo Bonzini         }
74709722032SChunyan Liu         return;
74809722032SChunyan Liu     }
74909722032SChunyan Liu     for (; desc && desc->name; desc++) {
75009722032SChunyan Liu         const char *value;
75109722032SChunyan Liu         QemuOpt *opt = qemu_opt_find(opts, desc->name);
75209722032SChunyan Liu 
75309722032SChunyan Liu         value = opt ? opt->str : desc->def_value_str;
75409722032SChunyan Liu         if (!value) {
75509722032SChunyan Liu             continue;
75609722032SChunyan Liu         }
75709722032SChunyan Liu         if (desc->type == QEMU_OPT_STRING) {
75843c5d8f8SFam Zheng             printf("%s%s='%s'", sep, desc->name, value);
75909722032SChunyan Liu         } else if ((desc->type == QEMU_OPT_SIZE ||
76009722032SChunyan Liu                     desc->type == QEMU_OPT_NUMBER) && opt) {
76143c5d8f8SFam Zheng             printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint);
76209722032SChunyan Liu         } else {
76343c5d8f8SFam Zheng             printf("%s%s=%s", sep, desc->name, value);
76409722032SChunyan Liu         }
76509722032SChunyan Liu     }
766baacf047SPaolo Bonzini }
767baacf047SPaolo Bonzini 
768baacf047SPaolo Bonzini static int opts_do_parse(QemuOpts *opts, const char *params,
769baacf047SPaolo Bonzini                          const char *firstname, bool prepend)
770baacf047SPaolo Bonzini {
771baacf047SPaolo Bonzini     char option[128], value[1024];
772baacf047SPaolo Bonzini     const char *p,*pe,*pc;
773baacf047SPaolo Bonzini     Error *local_err = NULL;
774baacf047SPaolo Bonzini 
775baacf047SPaolo Bonzini     for (p = params; *p != '\0'; p++) {
776baacf047SPaolo Bonzini         pe = strchr(p, '=');
777baacf047SPaolo Bonzini         pc = strchr(p, ',');
778baacf047SPaolo Bonzini         if (!pe || (pc && pc < pe)) {
779baacf047SPaolo Bonzini             /* found "foo,more" */
780baacf047SPaolo Bonzini             if (p == params && firstname) {
781baacf047SPaolo Bonzini                 /* implicitly named first option */
782baacf047SPaolo Bonzini                 pstrcpy(option, sizeof(option), firstname);
783baacf047SPaolo Bonzini                 p = get_opt_value(value, sizeof(value), p);
784baacf047SPaolo Bonzini             } else {
785baacf047SPaolo Bonzini                 /* option without value, probably a flag */
786baacf047SPaolo Bonzini                 p = get_opt_name(option, sizeof(option), p, ',');
787baacf047SPaolo Bonzini                 if (strncmp(option, "no", 2) == 0) {
788baacf047SPaolo Bonzini                     memmove(option, option+2, strlen(option+2)+1);
789baacf047SPaolo Bonzini                     pstrcpy(value, sizeof(value), "off");
790baacf047SPaolo Bonzini                 } else {
791baacf047SPaolo Bonzini                     pstrcpy(value, sizeof(value), "on");
792baacf047SPaolo Bonzini                 }
793baacf047SPaolo Bonzini             }
794baacf047SPaolo Bonzini         } else {
795baacf047SPaolo Bonzini             /* found "foo=bar,more" */
796baacf047SPaolo Bonzini             p = get_opt_name(option, sizeof(option), p, '=');
797baacf047SPaolo Bonzini             if (*p != '=') {
798baacf047SPaolo Bonzini                 break;
799baacf047SPaolo Bonzini             }
800baacf047SPaolo Bonzini             p++;
801baacf047SPaolo Bonzini             p = get_opt_value(value, sizeof(value), p);
802baacf047SPaolo Bonzini         }
803baacf047SPaolo Bonzini         if (strcmp(option, "id") != 0) {
804baacf047SPaolo Bonzini             /* store and parse */
805baacf047SPaolo Bonzini             opt_set(opts, option, value, prepend, &local_err);
80684d18f06SMarkus Armbruster             if (local_err) {
807baacf047SPaolo Bonzini                 qerror_report_err(local_err);
808baacf047SPaolo Bonzini                 error_free(local_err);
809baacf047SPaolo Bonzini                 return -1;
810baacf047SPaolo Bonzini             }
811baacf047SPaolo Bonzini         }
812baacf047SPaolo Bonzini         if (*p != ',') {
813baacf047SPaolo Bonzini             break;
814baacf047SPaolo Bonzini         }
815baacf047SPaolo Bonzini     }
816baacf047SPaolo Bonzini     return 0;
817baacf047SPaolo Bonzini }
818baacf047SPaolo Bonzini 
819baacf047SPaolo Bonzini int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
820baacf047SPaolo Bonzini {
821baacf047SPaolo Bonzini     return opts_do_parse(opts, params, firstname, false);
822baacf047SPaolo Bonzini }
823baacf047SPaolo Bonzini 
824baacf047SPaolo Bonzini static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
825baacf047SPaolo Bonzini                             int permit_abbrev, bool defaults)
826baacf047SPaolo Bonzini {
827baacf047SPaolo Bonzini     const char *firstname;
828baacf047SPaolo Bonzini     char value[1024], *id = NULL;
829baacf047SPaolo Bonzini     const char *p;
830baacf047SPaolo Bonzini     QemuOpts *opts;
831baacf047SPaolo Bonzini     Error *local_err = NULL;
832baacf047SPaolo Bonzini 
833baacf047SPaolo Bonzini     assert(!permit_abbrev || list->implied_opt_name);
834baacf047SPaolo Bonzini     firstname = permit_abbrev ? list->implied_opt_name : NULL;
835baacf047SPaolo Bonzini 
836baacf047SPaolo Bonzini     if (strncmp(params, "id=", 3) == 0) {
837baacf047SPaolo Bonzini         get_opt_value(value, sizeof(value), params+3);
838baacf047SPaolo Bonzini         id = value;
839baacf047SPaolo Bonzini     } else if ((p = strstr(params, ",id=")) != NULL) {
840baacf047SPaolo Bonzini         get_opt_value(value, sizeof(value), p+4);
841baacf047SPaolo Bonzini         id = value;
842baacf047SPaolo Bonzini     }
843cb77d192SMarkus Armbruster 
844cb77d192SMarkus Armbruster     /*
845cb77d192SMarkus Armbruster      * This code doesn't work for defaults && !list->merge_lists: when
846cb77d192SMarkus Armbruster      * params has no id=, and list has an element with !opts->id, it
847cb77d192SMarkus Armbruster      * appends a new element instead of returning the existing opts.
848cb77d192SMarkus Armbruster      * However, we got no use for this case.  Guard against possible
849cb77d192SMarkus Armbruster      * (if unlikely) future misuse:
850cb77d192SMarkus Armbruster      */
851cb77d192SMarkus Armbruster     assert(!defaults || list->merge_lists);
8526d4cd408SMarkus Armbruster     opts = qemu_opts_create(list, id, !defaults, &local_err);
853baacf047SPaolo Bonzini     if (opts == NULL) {
85484d18f06SMarkus Armbruster         if (local_err) {
855baacf047SPaolo Bonzini             qerror_report_err(local_err);
856baacf047SPaolo Bonzini             error_free(local_err);
857baacf047SPaolo Bonzini         }
858baacf047SPaolo Bonzini         return NULL;
859baacf047SPaolo Bonzini     }
860baacf047SPaolo Bonzini 
861baacf047SPaolo Bonzini     if (opts_do_parse(opts, params, firstname, defaults) != 0) {
862baacf047SPaolo Bonzini         qemu_opts_del(opts);
863baacf047SPaolo Bonzini         return NULL;
864baacf047SPaolo Bonzini     }
865baacf047SPaolo Bonzini 
866baacf047SPaolo Bonzini     return opts;
867baacf047SPaolo Bonzini }
868baacf047SPaolo Bonzini 
869baacf047SPaolo Bonzini QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
870baacf047SPaolo Bonzini                           int permit_abbrev)
871baacf047SPaolo Bonzini {
872baacf047SPaolo Bonzini     return opts_parse(list, params, permit_abbrev, false);
873baacf047SPaolo Bonzini }
874baacf047SPaolo Bonzini 
875baacf047SPaolo Bonzini void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
876baacf047SPaolo Bonzini                             int permit_abbrev)
877baacf047SPaolo Bonzini {
878baacf047SPaolo Bonzini     QemuOpts *opts;
879baacf047SPaolo Bonzini 
880baacf047SPaolo Bonzini     opts = opts_parse(list, params, permit_abbrev, true);
881baacf047SPaolo Bonzini     assert(opts);
882baacf047SPaolo Bonzini }
883baacf047SPaolo Bonzini 
884baacf047SPaolo Bonzini typedef struct OptsFromQDictState {
885baacf047SPaolo Bonzini     QemuOpts *opts;
886baacf047SPaolo Bonzini     Error **errp;
887baacf047SPaolo Bonzini } OptsFromQDictState;
888baacf047SPaolo Bonzini 
889baacf047SPaolo Bonzini static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
890baacf047SPaolo Bonzini {
891baacf047SPaolo Bonzini     OptsFromQDictState *state = opaque;
892baacf047SPaolo Bonzini     char buf[32];
893baacf047SPaolo Bonzini     const char *value;
894baacf047SPaolo Bonzini     int n;
895baacf047SPaolo Bonzini 
8962767ceecSMarkus Armbruster     if (!strcmp(key, "id") || *state->errp) {
897baacf047SPaolo Bonzini         return;
898baacf047SPaolo Bonzini     }
899baacf047SPaolo Bonzini 
900baacf047SPaolo Bonzini     switch (qobject_type(obj)) {
901baacf047SPaolo Bonzini     case QTYPE_QSTRING:
902baacf047SPaolo Bonzini         value = qstring_get_str(qobject_to_qstring(obj));
903baacf047SPaolo Bonzini         break;
904baacf047SPaolo Bonzini     case QTYPE_QINT:
905baacf047SPaolo Bonzini         n = snprintf(buf, sizeof(buf), "%" PRId64,
906baacf047SPaolo Bonzini                      qint_get_int(qobject_to_qint(obj)));
907baacf047SPaolo Bonzini         assert(n < sizeof(buf));
908baacf047SPaolo Bonzini         value = buf;
909baacf047SPaolo Bonzini         break;
910baacf047SPaolo Bonzini     case QTYPE_QFLOAT:
911baacf047SPaolo Bonzini         n = snprintf(buf, sizeof(buf), "%.17g",
912baacf047SPaolo Bonzini                      qfloat_get_double(qobject_to_qfloat(obj)));
913baacf047SPaolo Bonzini         assert(n < sizeof(buf));
914baacf047SPaolo Bonzini         value = buf;
915baacf047SPaolo Bonzini         break;
916baacf047SPaolo Bonzini     case QTYPE_QBOOL:
917baacf047SPaolo Bonzini         pstrcpy(buf, sizeof(buf),
918baacf047SPaolo Bonzini                 qbool_get_int(qobject_to_qbool(obj)) ? "on" : "off");
919baacf047SPaolo Bonzini         value = buf;
920baacf047SPaolo Bonzini         break;
921baacf047SPaolo Bonzini     default:
922baacf047SPaolo Bonzini         return;
923baacf047SPaolo Bonzini     }
924baacf047SPaolo Bonzini 
925baacf047SPaolo Bonzini     qemu_opt_set_err(state->opts, key, value, state->errp);
926baacf047SPaolo Bonzini }
927baacf047SPaolo Bonzini 
928baacf047SPaolo Bonzini /*
929baacf047SPaolo Bonzini  * Create QemuOpts from a QDict.
930baacf047SPaolo Bonzini  * Use value of key "id" as ID if it exists and is a QString.
931baacf047SPaolo Bonzini  * Only QStrings, QInts, QFloats and QBools are copied.  Entries with
932baacf047SPaolo Bonzini  * other types are silently ignored.
933baacf047SPaolo Bonzini  */
934baacf047SPaolo Bonzini QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
935baacf047SPaolo Bonzini                                Error **errp)
936baacf047SPaolo Bonzini {
937baacf047SPaolo Bonzini     OptsFromQDictState state;
938baacf047SPaolo Bonzini     Error *local_err = NULL;
939baacf047SPaolo Bonzini     QemuOpts *opts;
940baacf047SPaolo Bonzini 
941baacf047SPaolo Bonzini     opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1,
942baacf047SPaolo Bonzini                             &local_err);
94384d18f06SMarkus Armbruster     if (local_err) {
944baacf047SPaolo Bonzini         error_propagate(errp, local_err);
945baacf047SPaolo Bonzini         return NULL;
946baacf047SPaolo Bonzini     }
947baacf047SPaolo Bonzini 
948baacf047SPaolo Bonzini     assert(opts != NULL);
949baacf047SPaolo Bonzini 
950baacf047SPaolo Bonzini     state.errp = &local_err;
951baacf047SPaolo Bonzini     state.opts = opts;
952baacf047SPaolo Bonzini     qdict_iter(qdict, qemu_opts_from_qdict_1, &state);
95384d18f06SMarkus Armbruster     if (local_err) {
954baacf047SPaolo Bonzini         error_propagate(errp, local_err);
955baacf047SPaolo Bonzini         qemu_opts_del(opts);
956baacf047SPaolo Bonzini         return NULL;
957baacf047SPaolo Bonzini     }
958baacf047SPaolo Bonzini 
959baacf047SPaolo Bonzini     return opts;
960baacf047SPaolo Bonzini }
961baacf047SPaolo Bonzini 
962baacf047SPaolo Bonzini /*
963376609ccSKevin Wolf  * Adds all QDict entries to the QemuOpts that can be added and removes them
964376609ccSKevin Wolf  * from the QDict. When this function returns, the QDict contains only those
965376609ccSKevin Wolf  * entries that couldn't be added to the QemuOpts.
966376609ccSKevin Wolf  */
967376609ccSKevin Wolf void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
968376609ccSKevin Wolf {
969376609ccSKevin Wolf     const QDictEntry *entry, *next;
970376609ccSKevin Wolf 
971376609ccSKevin Wolf     entry = qdict_first(qdict);
972376609ccSKevin Wolf 
973376609ccSKevin Wolf     while (entry != NULL) {
974376609ccSKevin Wolf         Error *local_err = NULL;
975376609ccSKevin Wolf         OptsFromQDictState state = {
976376609ccSKevin Wolf             .errp = &local_err,
977376609ccSKevin Wolf             .opts = opts,
978376609ccSKevin Wolf         };
979376609ccSKevin Wolf 
980376609ccSKevin Wolf         next = qdict_next(qdict, entry);
981376609ccSKevin Wolf 
982376609ccSKevin Wolf         if (find_desc_by_name(opts->list->desc, entry->key)) {
983376609ccSKevin Wolf             qemu_opts_from_qdict_1(entry->key, entry->value, &state);
98484d18f06SMarkus Armbruster             if (local_err) {
985376609ccSKevin Wolf                 error_propagate(errp, local_err);
986376609ccSKevin Wolf                 return;
987376609ccSKevin Wolf             } else {
988376609ccSKevin Wolf                 qdict_del(qdict, entry->key);
989376609ccSKevin Wolf             }
990376609ccSKevin Wolf         }
991376609ccSKevin Wolf 
992376609ccSKevin Wolf         entry = next;
993376609ccSKevin Wolf     }
994376609ccSKevin Wolf }
995376609ccSKevin Wolf 
996376609ccSKevin Wolf /*
997baacf047SPaolo Bonzini  * Convert from QemuOpts to QDict.
998baacf047SPaolo Bonzini  * The QDict values are of type QString.
999baacf047SPaolo Bonzini  * TODO We'll want to use types appropriate for opt->desc->type, but
1000baacf047SPaolo Bonzini  * this is enough for now.
1001baacf047SPaolo Bonzini  */
1002baacf047SPaolo Bonzini QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
1003baacf047SPaolo Bonzini {
1004baacf047SPaolo Bonzini     QemuOpt *opt;
1005baacf047SPaolo Bonzini     QObject *val;
1006baacf047SPaolo Bonzini 
1007baacf047SPaolo Bonzini     if (!qdict) {
1008baacf047SPaolo Bonzini         qdict = qdict_new();
1009baacf047SPaolo Bonzini     }
1010baacf047SPaolo Bonzini     if (opts->id) {
1011baacf047SPaolo Bonzini         qdict_put(qdict, "id", qstring_from_str(opts->id));
1012baacf047SPaolo Bonzini     }
1013baacf047SPaolo Bonzini     QTAILQ_FOREACH(opt, &opts->head, next) {
1014baacf047SPaolo Bonzini         val = QOBJECT(qstring_from_str(opt->str));
1015baacf047SPaolo Bonzini         qdict_put_obj(qdict, opt->name, val);
1016baacf047SPaolo Bonzini     }
1017baacf047SPaolo Bonzini     return qdict;
1018baacf047SPaolo Bonzini }
1019baacf047SPaolo Bonzini 
1020baacf047SPaolo Bonzini /* Validate parsed opts against descriptions where no
1021baacf047SPaolo Bonzini  * descriptions were provided in the QemuOptsList.
1022baacf047SPaolo Bonzini  */
1023baacf047SPaolo Bonzini void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
1024baacf047SPaolo Bonzini {
1025baacf047SPaolo Bonzini     QemuOpt *opt;
1026baacf047SPaolo Bonzini     Error *local_err = NULL;
1027baacf047SPaolo Bonzini 
1028baacf047SPaolo Bonzini     assert(opts_accepts_any(opts));
1029baacf047SPaolo Bonzini 
1030baacf047SPaolo Bonzini     QTAILQ_FOREACH(opt, &opts->head, next) {
1031baacf047SPaolo Bonzini         opt->desc = find_desc_by_name(desc, opt->name);
1032baacf047SPaolo Bonzini         if (!opt->desc) {
1033baacf047SPaolo Bonzini             error_set(errp, QERR_INVALID_PARAMETER, opt->name);
1034baacf047SPaolo Bonzini             return;
1035baacf047SPaolo Bonzini         }
1036baacf047SPaolo Bonzini 
1037baacf047SPaolo Bonzini         qemu_opt_parse(opt, &local_err);
103884d18f06SMarkus Armbruster         if (local_err) {
1039baacf047SPaolo Bonzini             error_propagate(errp, local_err);
1040baacf047SPaolo Bonzini             return;
1041baacf047SPaolo Bonzini         }
1042baacf047SPaolo Bonzini     }
1043baacf047SPaolo Bonzini }
1044baacf047SPaolo Bonzini 
1045baacf047SPaolo Bonzini int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque,
1046baacf047SPaolo Bonzini                       int abort_on_failure)
1047baacf047SPaolo Bonzini {
1048baacf047SPaolo Bonzini     Location loc;
1049baacf047SPaolo Bonzini     QemuOpts *opts;
1050baacf047SPaolo Bonzini     int rc = 0;
1051baacf047SPaolo Bonzini 
1052baacf047SPaolo Bonzini     loc_push_none(&loc);
1053baacf047SPaolo Bonzini     QTAILQ_FOREACH(opts, &list->head, next) {
1054baacf047SPaolo Bonzini         loc_restore(&opts->loc);
1055baacf047SPaolo Bonzini         rc |= func(opts, opaque);
1056baacf047SPaolo Bonzini         if (abort_on_failure  &&  rc != 0)
1057baacf047SPaolo Bonzini             break;
1058baacf047SPaolo Bonzini     }
1059baacf047SPaolo Bonzini     loc_pop(&loc);
1060baacf047SPaolo Bonzini     return rc;
1061baacf047SPaolo Bonzini }
10628559e45eSChunyan Liu 
10638559e45eSChunyan Liu static size_t count_opts_list(QemuOptsList *list)
10648559e45eSChunyan Liu {
10658559e45eSChunyan Liu     QemuOptDesc *desc = NULL;
10668559e45eSChunyan Liu     size_t num_opts = 0;
10678559e45eSChunyan Liu 
10688559e45eSChunyan Liu     if (!list) {
10698559e45eSChunyan Liu         return 0;
10708559e45eSChunyan Liu     }
10718559e45eSChunyan Liu 
10728559e45eSChunyan Liu     desc = list->desc;
10738559e45eSChunyan Liu     while (desc && desc->name) {
10748559e45eSChunyan Liu         num_opts++;
10758559e45eSChunyan Liu         desc++;
10768559e45eSChunyan Liu     }
10778559e45eSChunyan Liu 
10788559e45eSChunyan Liu     return num_opts;
10798559e45eSChunyan Liu }
10808559e45eSChunyan Liu 
10818559e45eSChunyan Liu void qemu_opts_free(QemuOptsList *list)
10828559e45eSChunyan Liu {
10838559e45eSChunyan Liu     g_free(list);
10848559e45eSChunyan Liu }
1085a1097a26SChunyan Liu 
1086c282e1fdSChunyan Liu /* Realloc dst option list and append options from an option list (list)
1087c282e1fdSChunyan Liu  * to it. dst could be NULL or a malloced list.
108898d896d9SChunyan Liu  * The lifetime of dst must be shorter than the input list because the
108998d896d9SChunyan Liu  * QemuOptDesc->name, ->help, and ->def_value_str strings are shared.
1090a1097a26SChunyan Liu  */
1091a1097a26SChunyan Liu QemuOptsList *qemu_opts_append(QemuOptsList *dst,
1092c282e1fdSChunyan Liu                                QemuOptsList *list)
1093a1097a26SChunyan Liu {
1094a1097a26SChunyan Liu     size_t num_opts, num_dst_opts;
1095a1097a26SChunyan Liu     QemuOptDesc *desc;
1096a1097a26SChunyan Liu     bool need_init = false;
1097a7607150SMichal Privoznik     bool need_head_update;
1098a1097a26SChunyan Liu 
1099c282e1fdSChunyan Liu     if (!list) {
1100a1097a26SChunyan Liu         return dst;
1101a1097a26SChunyan Liu     }
1102a1097a26SChunyan Liu 
1103a1097a26SChunyan Liu     /* If dst is NULL, after realloc, some area of dst should be initialized
1104a1097a26SChunyan Liu      * before adding options to it.
1105a1097a26SChunyan Liu      */
1106a1097a26SChunyan Liu     if (!dst) {
1107a1097a26SChunyan Liu         need_init = true;
1108a7607150SMichal Privoznik         need_head_update = true;
1109a7607150SMichal Privoznik     } else {
1110a7607150SMichal Privoznik         /* Moreover, even if dst is not NULL, the realloc may move it to a
1111a7607150SMichal Privoznik          * different address in which case we may get a stale tail pointer
1112a7607150SMichal Privoznik          * in dst->head. */
1113a7607150SMichal Privoznik         need_head_update = QTAILQ_EMPTY(&dst->head);
1114a1097a26SChunyan Liu     }
1115a1097a26SChunyan Liu 
1116a1097a26SChunyan Liu     num_opts = count_opts_list(dst);
1117a1097a26SChunyan Liu     num_dst_opts = num_opts;
1118a1097a26SChunyan Liu     num_opts += count_opts_list(list);
1119a1097a26SChunyan Liu     dst = g_realloc(dst, sizeof(QemuOptsList) +
1120a1097a26SChunyan Liu                     (num_opts + 1) * sizeof(QemuOptDesc));
1121a1097a26SChunyan Liu     if (need_init) {
1122a1097a26SChunyan Liu         dst->name = NULL;
1123a1097a26SChunyan Liu         dst->implied_opt_name = NULL;
1124a1097a26SChunyan Liu         dst->merge_lists = false;
1125a1097a26SChunyan Liu     }
1126a7607150SMichal Privoznik     if (need_head_update) {
1127a7607150SMichal Privoznik         QTAILQ_INIT(&dst->head);
1128a7607150SMichal Privoznik     }
1129a1097a26SChunyan Liu     dst->desc[num_dst_opts].name = NULL;
1130a1097a26SChunyan Liu 
1131a1097a26SChunyan Liu     /* append list->desc to dst->desc */
1132a1097a26SChunyan Liu     if (list) {
1133a1097a26SChunyan Liu         desc = list->desc;
1134a1097a26SChunyan Liu         while (desc && desc->name) {
1135a1097a26SChunyan Liu             if (find_desc_by_name(dst->desc, desc->name) == NULL) {
113698d896d9SChunyan Liu                 dst->desc[num_dst_opts++] = *desc;
1137a1097a26SChunyan Liu                 dst->desc[num_dst_opts].name = NULL;
1138a1097a26SChunyan Liu             }
1139a1097a26SChunyan Liu             desc++;
1140a1097a26SChunyan Liu         }
1141a1097a26SChunyan Liu     }
1142a1097a26SChunyan Liu 
1143a1097a26SChunyan Liu     return dst;
1144a1097a26SChunyan Liu }
1145