root / qemu-option.c @ 2966b390
History | View | Annotate | Download (20.6 kB)
1 | d3f24367 | Kevin Wolf | /*
|
---|---|---|---|
2 | d3f24367 | Kevin Wolf | * Commandline option parsing functions
|
3 | d3f24367 | Kevin Wolf | *
|
4 | d3f24367 | Kevin Wolf | * Copyright (c) 2003-2008 Fabrice Bellard
|
5 | d3f24367 | Kevin Wolf | * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
|
6 | d3f24367 | Kevin Wolf | *
|
7 | d3f24367 | Kevin Wolf | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 | d3f24367 | Kevin Wolf | * of this software and associated documentation files (the "Software"), to deal
|
9 | d3f24367 | Kevin Wolf | * in the Software without restriction, including without limitation the rights
|
10 | d3f24367 | Kevin Wolf | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 | d3f24367 | Kevin Wolf | * copies of the Software, and to permit persons to whom the Software is
|
12 | d3f24367 | Kevin Wolf | * furnished to do so, subject to the following conditions:
|
13 | d3f24367 | Kevin Wolf | *
|
14 | d3f24367 | Kevin Wolf | * The above copyright notice and this permission notice shall be included in
|
15 | d3f24367 | Kevin Wolf | * all copies or substantial portions of the Software.
|
16 | d3f24367 | Kevin Wolf | *
|
17 | d3f24367 | Kevin Wolf | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 | d3f24367 | Kevin Wolf | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 | d3f24367 | Kevin Wolf | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
20 | d3f24367 | Kevin Wolf | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 | d3f24367 | Kevin Wolf | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 | d3f24367 | Kevin Wolf | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 | d3f24367 | Kevin Wolf | * THE SOFTWARE.
|
24 | d3f24367 | Kevin Wolf | */
|
25 | d3f24367 | Kevin Wolf | |
26 | d3f24367 | Kevin Wolf | #include <stdio.h> |
27 | d3f24367 | Kevin Wolf | #include <string.h> |
28 | d3f24367 | Kevin Wolf | |
29 | d3f24367 | Kevin Wolf | #include "qemu-common.h" |
30 | d3f24367 | Kevin Wolf | #include "qemu-option.h" |
31 | d3f24367 | Kevin Wolf | |
32 | d3f24367 | Kevin Wolf | /*
|
33 | d3f24367 | Kevin Wolf | * Extracts the name of an option from the parameter string (p points at the
|
34 | d3f24367 | Kevin Wolf | * first byte of the option name)
|
35 | d3f24367 | Kevin Wolf | *
|
36 | d3f24367 | Kevin Wolf | * The option name is delimited by delim (usually , or =) or the string end
|
37 | d3f24367 | Kevin Wolf | * and is copied into buf. If the option name is longer than buf_size, it is
|
38 | d3f24367 | Kevin Wolf | * truncated. buf is always zero terminated.
|
39 | d3f24367 | Kevin Wolf | *
|
40 | d3f24367 | Kevin Wolf | * The return value is the position of the delimiter/zero byte after the option
|
41 | d3f24367 | Kevin Wolf | * name in p.
|
42 | d3f24367 | Kevin Wolf | */
|
43 | d3f24367 | Kevin Wolf | const char *get_opt_name(char *buf, int buf_size, const char *p, char delim) |
44 | d3f24367 | Kevin Wolf | { |
45 | d3f24367 | Kevin Wolf | char *q;
|
46 | d3f24367 | Kevin Wolf | |
47 | d3f24367 | Kevin Wolf | q = buf; |
48 | d3f24367 | Kevin Wolf | while (*p != '\0' && *p != delim) { |
49 | d3f24367 | Kevin Wolf | if (q && (q - buf) < buf_size - 1) |
50 | d3f24367 | Kevin Wolf | *q++ = *p; |
51 | d3f24367 | Kevin Wolf | p++; |
52 | d3f24367 | Kevin Wolf | } |
53 | d3f24367 | Kevin Wolf | if (q)
|
54 | d3f24367 | Kevin Wolf | *q = '\0';
|
55 | d3f24367 | Kevin Wolf | |
56 | d3f24367 | Kevin Wolf | return p;
|
57 | d3f24367 | Kevin Wolf | } |
58 | d3f24367 | Kevin Wolf | |
59 | d3f24367 | Kevin Wolf | /*
|
60 | d3f24367 | Kevin Wolf | * Extracts the value of an option from the parameter string p (p points at the
|
61 | d3f24367 | Kevin Wolf | * first byte of the option value)
|
62 | d3f24367 | Kevin Wolf | *
|
63 | d3f24367 | Kevin Wolf | * This function is comparable to get_opt_name with the difference that the
|
64 | d3f24367 | Kevin Wolf | * delimiter is fixed to be comma which starts a new option. To specify an
|
65 | d3f24367 | Kevin Wolf | * option value that contains commas, double each comma.
|
66 | d3f24367 | Kevin Wolf | */
|
67 | d3f24367 | Kevin Wolf | const char *get_opt_value(char *buf, int buf_size, const char *p) |
68 | d3f24367 | Kevin Wolf | { |
69 | d3f24367 | Kevin Wolf | char *q;
|
70 | d3f24367 | Kevin Wolf | |
71 | d3f24367 | Kevin Wolf | q = buf; |
72 | d3f24367 | Kevin Wolf | while (*p != '\0') { |
73 | d3f24367 | Kevin Wolf | if (*p == ',') { |
74 | d3f24367 | Kevin Wolf | if (*(p + 1) != ',') |
75 | d3f24367 | Kevin Wolf | break;
|
76 | d3f24367 | Kevin Wolf | p++; |
77 | d3f24367 | Kevin Wolf | } |
78 | d3f24367 | Kevin Wolf | if (q && (q - buf) < buf_size - 1) |
79 | d3f24367 | Kevin Wolf | *q++ = *p; |
80 | d3f24367 | Kevin Wolf | p++; |
81 | d3f24367 | Kevin Wolf | } |
82 | d3f24367 | Kevin Wolf | if (q)
|
83 | d3f24367 | Kevin Wolf | *q = '\0';
|
84 | d3f24367 | Kevin Wolf | |
85 | d3f24367 | Kevin Wolf | return p;
|
86 | d3f24367 | Kevin Wolf | } |
87 | d3f24367 | Kevin Wolf | |
88 | 62c5802e | Gerd Hoffmann | int get_next_param_value(char *buf, int buf_size, |
89 | 62c5802e | Gerd Hoffmann | const char *tag, const char **pstr) |
90 | 62c5802e | Gerd Hoffmann | { |
91 | 62c5802e | Gerd Hoffmann | const char *p; |
92 | 62c5802e | Gerd Hoffmann | char option[128]; |
93 | 62c5802e | Gerd Hoffmann | |
94 | 62c5802e | Gerd Hoffmann | p = *pstr; |
95 | 62c5802e | Gerd Hoffmann | for(;;) {
|
96 | 62c5802e | Gerd Hoffmann | p = get_opt_name(option, sizeof(option), p, '='); |
97 | 62c5802e | Gerd Hoffmann | if (*p != '=') |
98 | 62c5802e | Gerd Hoffmann | break;
|
99 | 62c5802e | Gerd Hoffmann | p++; |
100 | 62c5802e | Gerd Hoffmann | if (!strcmp(tag, option)) {
|
101 | 62c5802e | Gerd Hoffmann | *pstr = get_opt_value(buf, buf_size, p); |
102 | 62c5802e | Gerd Hoffmann | if (**pstr == ',') { |
103 | 62c5802e | Gerd Hoffmann | (*pstr)++; |
104 | 62c5802e | Gerd Hoffmann | } |
105 | 62c5802e | Gerd Hoffmann | return strlen(buf);
|
106 | 62c5802e | Gerd Hoffmann | } else {
|
107 | 62c5802e | Gerd Hoffmann | p = get_opt_value(NULL, 0, p); |
108 | 62c5802e | Gerd Hoffmann | } |
109 | 62c5802e | Gerd Hoffmann | if (*p != ',') |
110 | 62c5802e | Gerd Hoffmann | break;
|
111 | 62c5802e | Gerd Hoffmann | p++; |
112 | 62c5802e | Gerd Hoffmann | } |
113 | 62c5802e | Gerd Hoffmann | return 0; |
114 | 62c5802e | Gerd Hoffmann | } |
115 | 62c5802e | Gerd Hoffmann | |
116 | 62c5802e | Gerd Hoffmann | int get_param_value(char *buf, int buf_size, |
117 | 62c5802e | Gerd Hoffmann | const char *tag, const char *str) |
118 | 62c5802e | Gerd Hoffmann | { |
119 | 62c5802e | Gerd Hoffmann | return get_next_param_value(buf, buf_size, tag, &str);
|
120 | 62c5802e | Gerd Hoffmann | } |
121 | 62c5802e | Gerd Hoffmann | |
122 | 62c5802e | Gerd Hoffmann | int check_params(char *buf, int buf_size, |
123 | 62c5802e | Gerd Hoffmann | const char * const *params, const char *str) |
124 | 62c5802e | Gerd Hoffmann | { |
125 | 62c5802e | Gerd Hoffmann | const char *p; |
126 | 62c5802e | Gerd Hoffmann | int i;
|
127 | 62c5802e | Gerd Hoffmann | |
128 | 62c5802e | Gerd Hoffmann | p = str; |
129 | 62c5802e | Gerd Hoffmann | while (*p != '\0') { |
130 | 62c5802e | Gerd Hoffmann | p = get_opt_name(buf, buf_size, p, '=');
|
131 | 62c5802e | Gerd Hoffmann | if (*p != '=') { |
132 | 62c5802e | Gerd Hoffmann | return -1; |
133 | 62c5802e | Gerd Hoffmann | } |
134 | 62c5802e | Gerd Hoffmann | p++; |
135 | 62c5802e | Gerd Hoffmann | for (i = 0; params[i] != NULL; i++) { |
136 | 62c5802e | Gerd Hoffmann | if (!strcmp(params[i], buf)) {
|
137 | 62c5802e | Gerd Hoffmann | break;
|
138 | 62c5802e | Gerd Hoffmann | } |
139 | 62c5802e | Gerd Hoffmann | } |
140 | 62c5802e | Gerd Hoffmann | if (params[i] == NULL) { |
141 | 62c5802e | Gerd Hoffmann | return -1; |
142 | 62c5802e | Gerd Hoffmann | } |
143 | 62c5802e | Gerd Hoffmann | p = get_opt_value(NULL, 0, p); |
144 | 62c5802e | Gerd Hoffmann | if (*p != ',') { |
145 | 62c5802e | Gerd Hoffmann | break;
|
146 | 62c5802e | Gerd Hoffmann | } |
147 | 62c5802e | Gerd Hoffmann | p++; |
148 | 62c5802e | Gerd Hoffmann | } |
149 | 62c5802e | Gerd Hoffmann | return 0; |
150 | 62c5802e | Gerd Hoffmann | } |
151 | 62c5802e | Gerd Hoffmann | |
152 | d3f24367 | Kevin Wolf | /*
|
153 | d3f24367 | Kevin Wolf | * Searches an option list for an option with the given name
|
154 | d3f24367 | Kevin Wolf | */
|
155 | d3f24367 | Kevin Wolf | QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list, |
156 | d3f24367 | Kevin Wolf | const char *name) |
157 | d3f24367 | Kevin Wolf | { |
158 | d3f24367 | Kevin Wolf | while (list && list->name) {
|
159 | d3f24367 | Kevin Wolf | if (!strcmp(list->name, name)) {
|
160 | d3f24367 | Kevin Wolf | return list;
|
161 | d3f24367 | Kevin Wolf | } |
162 | d3f24367 | Kevin Wolf | list++; |
163 | d3f24367 | Kevin Wolf | } |
164 | d3f24367 | Kevin Wolf | |
165 | d3f24367 | Kevin Wolf | return NULL; |
166 | d3f24367 | Kevin Wolf | } |
167 | d3f24367 | Kevin Wolf | |
168 | 67b1355b | Gerd Hoffmann | static int parse_option_bool(const char *name, const char *value, int *ret) |
169 | 67b1355b | Gerd Hoffmann | { |
170 | 67b1355b | Gerd Hoffmann | if (value != NULL) { |
171 | 67b1355b | Gerd Hoffmann | if (!strcmp(value, "on")) { |
172 | 67b1355b | Gerd Hoffmann | *ret = 1;
|
173 | 67b1355b | Gerd Hoffmann | } else if (!strcmp(value, "off")) { |
174 | 67b1355b | Gerd Hoffmann | *ret = 0;
|
175 | 67b1355b | Gerd Hoffmann | } else {
|
176 | 67b1355b | Gerd Hoffmann | fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name);
|
177 | 67b1355b | Gerd Hoffmann | return -1; |
178 | 67b1355b | Gerd Hoffmann | } |
179 | 67b1355b | Gerd Hoffmann | } else {
|
180 | 67b1355b | Gerd Hoffmann | *ret = 1;
|
181 | 67b1355b | Gerd Hoffmann | } |
182 | 67b1355b | Gerd Hoffmann | return 0; |
183 | 67b1355b | Gerd Hoffmann | } |
184 | 67b1355b | Gerd Hoffmann | |
185 | e27c88fe | Gerd Hoffmann | static int parse_option_number(const char *name, const char *value, uint64_t *ret) |
186 | e27c88fe | Gerd Hoffmann | { |
187 | e27c88fe | Gerd Hoffmann | char *postfix;
|
188 | e27c88fe | Gerd Hoffmann | uint64_t number; |
189 | e27c88fe | Gerd Hoffmann | |
190 | e27c88fe | Gerd Hoffmann | if (value != NULL) { |
191 | e27c88fe | Gerd Hoffmann | number = strtoull(value, &postfix, 0);
|
192 | e27c88fe | Gerd Hoffmann | if (*postfix != '\0') { |
193 | e27c88fe | Gerd Hoffmann | fprintf(stderr, "Option '%s' needs a number as parameter\n", name);
|
194 | e27c88fe | Gerd Hoffmann | return -1; |
195 | e27c88fe | Gerd Hoffmann | } |
196 | 21c9f4cd | Gerd Hoffmann | *ret = number; |
197 | e27c88fe | Gerd Hoffmann | } else {
|
198 | e27c88fe | Gerd Hoffmann | fprintf(stderr, "Option '%s' needs a parameter\n", name);
|
199 | e27c88fe | Gerd Hoffmann | return -1; |
200 | e27c88fe | Gerd Hoffmann | } |
201 | e27c88fe | Gerd Hoffmann | return 0; |
202 | e27c88fe | Gerd Hoffmann | } |
203 | e27c88fe | Gerd Hoffmann | |
204 | 7695019b | Gerd Hoffmann | static int parse_option_size(const char *name, const char *value, uint64_t *ret) |
205 | 7695019b | Gerd Hoffmann | { |
206 | 7695019b | Gerd Hoffmann | char *postfix;
|
207 | 7695019b | Gerd Hoffmann | double sizef;
|
208 | 7695019b | Gerd Hoffmann | |
209 | 7695019b | Gerd Hoffmann | if (value != NULL) { |
210 | 7695019b | Gerd Hoffmann | sizef = strtod(value, &postfix); |
211 | 7695019b | Gerd Hoffmann | switch (*postfix) {
|
212 | 7695019b | Gerd Hoffmann | case 'T': |
213 | 7695019b | Gerd Hoffmann | sizef *= 1024;
|
214 | 7695019b | Gerd Hoffmann | case 'G': |
215 | 7695019b | Gerd Hoffmann | sizef *= 1024;
|
216 | 7695019b | Gerd Hoffmann | case 'M': |
217 | 7695019b | Gerd Hoffmann | sizef *= 1024;
|
218 | 7695019b | Gerd Hoffmann | case 'K': |
219 | 7695019b | Gerd Hoffmann | case 'k': |
220 | 7695019b | Gerd Hoffmann | sizef *= 1024;
|
221 | 7695019b | Gerd Hoffmann | case 'b': |
222 | 7695019b | Gerd Hoffmann | case '\0': |
223 | 7695019b | Gerd Hoffmann | *ret = (uint64_t) sizef; |
224 | 7695019b | Gerd Hoffmann | break;
|
225 | 7695019b | Gerd Hoffmann | default:
|
226 | 7695019b | Gerd Hoffmann | fprintf(stderr, "Option '%s' needs size as parameter\n", name);
|
227 | 7695019b | Gerd Hoffmann | fprintf(stderr, "You may use k, M, G or T suffixes for "
|
228 | 7695019b | Gerd Hoffmann | "kilobytes, megabytes, gigabytes and terabytes.\n");
|
229 | 7695019b | Gerd Hoffmann | return -1; |
230 | 7695019b | Gerd Hoffmann | } |
231 | 7695019b | Gerd Hoffmann | } else {
|
232 | 7695019b | Gerd Hoffmann | fprintf(stderr, "Option '%s' needs a parameter\n", name);
|
233 | 7695019b | Gerd Hoffmann | return -1; |
234 | 7695019b | Gerd Hoffmann | } |
235 | 7695019b | Gerd Hoffmann | return 0; |
236 | 7695019b | Gerd Hoffmann | } |
237 | 7695019b | Gerd Hoffmann | |
238 | d3f24367 | Kevin Wolf | /*
|
239 | d3f24367 | Kevin Wolf | * Sets the value of a parameter in a given option list. The parsing of the
|
240 | d3f24367 | Kevin Wolf | * value depends on the type of option:
|
241 | d3f24367 | Kevin Wolf | *
|
242 | d3f24367 | Kevin Wolf | * OPT_FLAG (uses value.n):
|
243 | d3f24367 | Kevin Wolf | * If no value is given, the flag is set to 1.
|
244 | d3f24367 | Kevin Wolf | * Otherwise the value must be "on" (set to 1) or "off" (set to 0)
|
245 | d3f24367 | Kevin Wolf | *
|
246 | d3f24367 | Kevin Wolf | * OPT_STRING (uses value.s):
|
247 | d3f24367 | Kevin Wolf | * value is strdup()ed and assigned as option value
|
248 | d3f24367 | Kevin Wolf | *
|
249 | d3f24367 | Kevin Wolf | * OPT_SIZE (uses value.n):
|
250 | d3f24367 | Kevin Wolf | * The value is converted to an integer. Suffixes for kilobytes etc. are
|
251 | d3f24367 | Kevin Wolf | * allowed (powers of 1024).
|
252 | d3f24367 | Kevin Wolf | *
|
253 | d3f24367 | Kevin Wolf | * Returns 0 on succes, -1 in error cases
|
254 | d3f24367 | Kevin Wolf | */
|
255 | d3f24367 | Kevin Wolf | int set_option_parameter(QEMUOptionParameter *list, const char *name, |
256 | d3f24367 | Kevin Wolf | const char *value) |
257 | d3f24367 | Kevin Wolf | { |
258 | 67b1355b | Gerd Hoffmann | int flag;
|
259 | 67b1355b | Gerd Hoffmann | |
260 | d3f24367 | Kevin Wolf | // Find a matching parameter
|
261 | d3f24367 | Kevin Wolf | list = get_option_parameter(list, name); |
262 | d3f24367 | Kevin Wolf | if (list == NULL) { |
263 | d3f24367 | Kevin Wolf | fprintf(stderr, "Unknown option '%s'\n", name);
|
264 | d3f24367 | Kevin Wolf | return -1; |
265 | d3f24367 | Kevin Wolf | } |
266 | d3f24367 | Kevin Wolf | |
267 | d3f24367 | Kevin Wolf | // Process parameter
|
268 | d3f24367 | Kevin Wolf | switch (list->type) {
|
269 | d3f24367 | Kevin Wolf | case OPT_FLAG:
|
270 | 3df04ac3 | Mark McLoughlin | if (parse_option_bool(name, value, &flag) == -1) |
271 | 67b1355b | Gerd Hoffmann | return -1; |
272 | 67b1355b | Gerd Hoffmann | list->value.n = flag; |
273 | d3f24367 | Kevin Wolf | break;
|
274 | d3f24367 | Kevin Wolf | |
275 | d3f24367 | Kevin Wolf | case OPT_STRING:
|
276 | d3f24367 | Kevin Wolf | if (value != NULL) { |
277 | d4c3fddd | Jean-Christophe DUBOIS | list->value.s = qemu_strdup(value); |
278 | d3f24367 | Kevin Wolf | } else {
|
279 | d3f24367 | Kevin Wolf | fprintf(stderr, "Option '%s' needs a parameter\n", name);
|
280 | d3f24367 | Kevin Wolf | return -1; |
281 | d3f24367 | Kevin Wolf | } |
282 | d3f24367 | Kevin Wolf | break;
|
283 | d3f24367 | Kevin Wolf | |
284 | d3f24367 | Kevin Wolf | case OPT_SIZE:
|
285 | 3df04ac3 | Mark McLoughlin | if (parse_option_size(name, value, &list->value.n) == -1) |
286 | d3f24367 | Kevin Wolf | return -1; |
287 | d3f24367 | Kevin Wolf | break;
|
288 | 7695019b | Gerd Hoffmann | |
289 | d3f24367 | Kevin Wolf | default:
|
290 | d3f24367 | Kevin Wolf | fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
|
291 | d3f24367 | Kevin Wolf | return -1; |
292 | d3f24367 | Kevin Wolf | } |
293 | d3f24367 | Kevin Wolf | |
294 | d3f24367 | Kevin Wolf | return 0; |
295 | d3f24367 | Kevin Wolf | } |
296 | d3f24367 | Kevin Wolf | |
297 | d3f24367 | Kevin Wolf | /*
|
298 | d3f24367 | Kevin Wolf | * Sets the given parameter to an integer instead of a string.
|
299 | d3f24367 | Kevin Wolf | * This function cannot be used to set string options.
|
300 | d3f24367 | Kevin Wolf | *
|
301 | d3f24367 | Kevin Wolf | * Returns 0 on success, -1 in error cases
|
302 | d3f24367 | Kevin Wolf | */
|
303 | d3f24367 | Kevin Wolf | int set_option_parameter_int(QEMUOptionParameter *list, const char *name, |
304 | d3f24367 | Kevin Wolf | uint64_t value) |
305 | d3f24367 | Kevin Wolf | { |
306 | d3f24367 | Kevin Wolf | // Find a matching parameter
|
307 | d3f24367 | Kevin Wolf | list = get_option_parameter(list, name); |
308 | d3f24367 | Kevin Wolf | if (list == NULL) { |
309 | d3f24367 | Kevin Wolf | fprintf(stderr, "Unknown option '%s'\n", name);
|
310 | d3f24367 | Kevin Wolf | return -1; |
311 | d3f24367 | Kevin Wolf | } |
312 | d3f24367 | Kevin Wolf | |
313 | d3f24367 | Kevin Wolf | // Process parameter
|
314 | d3f24367 | Kevin Wolf | switch (list->type) {
|
315 | d3f24367 | Kevin Wolf | case OPT_FLAG:
|
316 | d3f24367 | Kevin Wolf | case OPT_NUMBER:
|
317 | d3f24367 | Kevin Wolf | case OPT_SIZE:
|
318 | d3f24367 | Kevin Wolf | list->value.n = value; |
319 | d3f24367 | Kevin Wolf | break;
|
320 | d3f24367 | Kevin Wolf | |
321 | d3f24367 | Kevin Wolf | default:
|
322 | d3f24367 | Kevin Wolf | return -1; |
323 | d3f24367 | Kevin Wolf | } |
324 | d3f24367 | Kevin Wolf | |
325 | d3f24367 | Kevin Wolf | return 0; |
326 | d3f24367 | Kevin Wolf | } |
327 | d3f24367 | Kevin Wolf | |
328 | d3f24367 | Kevin Wolf | /*
|
329 | d3f24367 | Kevin Wolf | * Frees a option list. If it contains strings, the strings are freed as well.
|
330 | d3f24367 | Kevin Wolf | */
|
331 | d3f24367 | Kevin Wolf | void free_option_parameters(QEMUOptionParameter *list)
|
332 | d3f24367 | Kevin Wolf | { |
333 | d3f24367 | Kevin Wolf | QEMUOptionParameter *cur = list; |
334 | d3f24367 | Kevin Wolf | |
335 | d3f24367 | Kevin Wolf | while (cur && cur->name) {
|
336 | d3f24367 | Kevin Wolf | if (cur->type == OPT_STRING) {
|
337 | d4c3fddd | Jean-Christophe DUBOIS | qemu_free(cur->value.s); |
338 | d3f24367 | Kevin Wolf | } |
339 | d3f24367 | Kevin Wolf | cur++; |
340 | d3f24367 | Kevin Wolf | } |
341 | d3f24367 | Kevin Wolf | |
342 | d4c3fddd | Jean-Christophe DUBOIS | qemu_free(list); |
343 | d3f24367 | Kevin Wolf | } |
344 | d3f24367 | Kevin Wolf | |
345 | d3f24367 | Kevin Wolf | /*
|
346 | d3f24367 | Kevin Wolf | * Parses a parameter string (param) into an option list (dest).
|
347 | d3f24367 | Kevin Wolf | *
|
348 | d3f24367 | Kevin Wolf | * list is the templace is. If dest is NULL, a new copy of list is created for
|
349 | d3f24367 | Kevin Wolf | * it. If list is NULL, this function fails.
|
350 | d3f24367 | Kevin Wolf | *
|
351 | d3f24367 | Kevin Wolf | * A parameter string consists of one or more parameters, separated by commas.
|
352 | d3f24367 | Kevin Wolf | * Each parameter consists of its name and possibly of a value. In the latter
|
353 | d3f24367 | Kevin Wolf | * case, the value is delimited by an = character. To specify a value which
|
354 | d3f24367 | Kevin Wolf | * contains commas, double each comma so it won't be recognized as the end of
|
355 | d3f24367 | Kevin Wolf | * the parameter.
|
356 | d3f24367 | Kevin Wolf | *
|
357 | d3f24367 | Kevin Wolf | * For more details of the parsing see above.
|
358 | d3f24367 | Kevin Wolf | *
|
359 | d3f24367 | Kevin Wolf | * Returns a pointer to the first element of dest (or the newly allocated copy)
|
360 | d3f24367 | Kevin Wolf | * or NULL in error cases
|
361 | d3f24367 | Kevin Wolf | */
|
362 | d3f24367 | Kevin Wolf | QEMUOptionParameter *parse_option_parameters(const char *param, |
363 | d3f24367 | Kevin Wolf | QEMUOptionParameter *list, QEMUOptionParameter *dest) |
364 | d3f24367 | Kevin Wolf | { |
365 | d3f24367 | Kevin Wolf | QEMUOptionParameter *cur; |
366 | d3f24367 | Kevin Wolf | QEMUOptionParameter *allocated = NULL;
|
367 | d3f24367 | Kevin Wolf | char name[256]; |
368 | d3f24367 | Kevin Wolf | char value[256]; |
369 | d3f24367 | Kevin Wolf | char *param_delim, *value_delim;
|
370 | d3f24367 | Kevin Wolf | char next_delim;
|
371 | d3f24367 | Kevin Wolf | size_t num_options; |
372 | d3f24367 | Kevin Wolf | |
373 | d3f24367 | Kevin Wolf | if (list == NULL) { |
374 | d3f24367 | Kevin Wolf | return NULL; |
375 | d3f24367 | Kevin Wolf | } |
376 | d3f24367 | Kevin Wolf | |
377 | d3f24367 | Kevin Wolf | if (dest == NULL) { |
378 | d3f24367 | Kevin Wolf | // Count valid options
|
379 | d3f24367 | Kevin Wolf | num_options = 0;
|
380 | d3f24367 | Kevin Wolf | cur = list; |
381 | d3f24367 | Kevin Wolf | while (cur->name) {
|
382 | d3f24367 | Kevin Wolf | num_options++; |
383 | d3f24367 | Kevin Wolf | cur++; |
384 | d3f24367 | Kevin Wolf | } |
385 | d3f24367 | Kevin Wolf | |
386 | d3f24367 | Kevin Wolf | // Create a copy of the option list to fill in values
|
387 | d3f24367 | Kevin Wolf | dest = qemu_mallocz((num_options + 1) * sizeof(QEMUOptionParameter)); |
388 | d3f24367 | Kevin Wolf | allocated = dest; |
389 | d3f24367 | Kevin Wolf | memcpy(dest, list, (num_options + 1) * sizeof(QEMUOptionParameter)); |
390 | d3f24367 | Kevin Wolf | } |
391 | d3f24367 | Kevin Wolf | |
392 | d3f24367 | Kevin Wolf | while (*param) {
|
393 | d3f24367 | Kevin Wolf | |
394 | d3f24367 | Kevin Wolf | // Find parameter name and value in the string
|
395 | d3f24367 | Kevin Wolf | param_delim = strchr(param, ',');
|
396 | d3f24367 | Kevin Wolf | value_delim = strchr(param, '=');
|
397 | d3f24367 | Kevin Wolf | |
398 | d3f24367 | Kevin Wolf | if (value_delim && (value_delim < param_delim || !param_delim)) {
|
399 | d3f24367 | Kevin Wolf | next_delim = '=';
|
400 | d3f24367 | Kevin Wolf | } else {
|
401 | d3f24367 | Kevin Wolf | next_delim = ',';
|
402 | d3f24367 | Kevin Wolf | value_delim = NULL;
|
403 | d3f24367 | Kevin Wolf | } |
404 | d3f24367 | Kevin Wolf | |
405 | d3f24367 | Kevin Wolf | param = get_opt_name(name, sizeof(name), param, next_delim);
|
406 | d3f24367 | Kevin Wolf | if (value_delim) {
|
407 | d3f24367 | Kevin Wolf | param = get_opt_value(value, sizeof(value), param + 1); |
408 | d3f24367 | Kevin Wolf | } |
409 | d3f24367 | Kevin Wolf | if (*param != '\0') { |
410 | d3f24367 | Kevin Wolf | param++; |
411 | d3f24367 | Kevin Wolf | } |
412 | d3f24367 | Kevin Wolf | |
413 | d3f24367 | Kevin Wolf | // Set the parameter
|
414 | d3f24367 | Kevin Wolf | if (set_option_parameter(dest, name, value_delim ? value : NULL)) { |
415 | d3f24367 | Kevin Wolf | goto fail;
|
416 | d3f24367 | Kevin Wolf | } |
417 | d3f24367 | Kevin Wolf | } |
418 | d3f24367 | Kevin Wolf | |
419 | d3f24367 | Kevin Wolf | return dest;
|
420 | d3f24367 | Kevin Wolf | |
421 | d3f24367 | Kevin Wolf | fail:
|
422 | d3f24367 | Kevin Wolf | // Only free the list if it was newly allocated
|
423 | d3f24367 | Kevin Wolf | free_option_parameters(allocated); |
424 | d3f24367 | Kevin Wolf | return NULL; |
425 | d3f24367 | Kevin Wolf | } |
426 | d3f24367 | Kevin Wolf | |
427 | d3f24367 | Kevin Wolf | /*
|
428 | d3f24367 | Kevin Wolf | * Prints all options of a list that have a value to stdout
|
429 | d3f24367 | Kevin Wolf | */
|
430 | d3f24367 | Kevin Wolf | void print_option_parameters(QEMUOptionParameter *list)
|
431 | d3f24367 | Kevin Wolf | { |
432 | d3f24367 | Kevin Wolf | while (list && list->name) {
|
433 | d3f24367 | Kevin Wolf | switch (list->type) {
|
434 | d3f24367 | Kevin Wolf | case OPT_STRING:
|
435 | d3f24367 | Kevin Wolf | if (list->value.s != NULL) { |
436 | d3f24367 | Kevin Wolf | printf("%s='%s' ", list->name, list->value.s);
|
437 | d3f24367 | Kevin Wolf | } |
438 | d3f24367 | Kevin Wolf | break;
|
439 | d3f24367 | Kevin Wolf | case OPT_FLAG:
|
440 | d3f24367 | Kevin Wolf | printf("%s=%s ", list->name, list->value.n ? "on" : "off"); |
441 | d3f24367 | Kevin Wolf | break;
|
442 | d3f24367 | Kevin Wolf | case OPT_SIZE:
|
443 | d3f24367 | Kevin Wolf | case OPT_NUMBER:
|
444 | d3f24367 | Kevin Wolf | printf("%s=%" PRId64 " ", list->name, list->value.n); |
445 | d3f24367 | Kevin Wolf | break;
|
446 | d3f24367 | Kevin Wolf | default:
|
447 | d3f24367 | Kevin Wolf | printf("%s=(unkown type) ", list->name);
|
448 | d3f24367 | Kevin Wolf | break;
|
449 | d3f24367 | Kevin Wolf | } |
450 | d3f24367 | Kevin Wolf | list++; |
451 | d3f24367 | Kevin Wolf | } |
452 | d3f24367 | Kevin Wolf | } |
453 | db08adf5 | Kevin Wolf | |
454 | db08adf5 | Kevin Wolf | /*
|
455 | db08adf5 | Kevin Wolf | * Prints an overview of all available options
|
456 | db08adf5 | Kevin Wolf | */
|
457 | db08adf5 | Kevin Wolf | void print_option_help(QEMUOptionParameter *list)
|
458 | db08adf5 | Kevin Wolf | { |
459 | db08adf5 | Kevin Wolf | printf("Supported options:\n");
|
460 | db08adf5 | Kevin Wolf | while (list && list->name) {
|
461 | db08adf5 | Kevin Wolf | printf("%-16s %s\n", list->name,
|
462 | db08adf5 | Kevin Wolf | list->help ? list->help : "No description available");
|
463 | db08adf5 | Kevin Wolf | list++; |
464 | db08adf5 | Kevin Wolf | } |
465 | db08adf5 | Kevin Wolf | } |
466 | e27c88fe | Gerd Hoffmann | |
467 | e27c88fe | Gerd Hoffmann | /* ------------------------------------------------------------------ */
|
468 | e27c88fe | Gerd Hoffmann | |
469 | e27c88fe | Gerd Hoffmann | struct QemuOpt {
|
470 | e27c88fe | Gerd Hoffmann | const char *name; |
471 | e27c88fe | Gerd Hoffmann | const char *str; |
472 | e27c88fe | Gerd Hoffmann | |
473 | e27c88fe | Gerd Hoffmann | QemuOptDesc *desc; |
474 | e27c88fe | Gerd Hoffmann | union {
|
475 | 1f5c1775 | Juan Quintela | int boolean;
|
476 | e27c88fe | Gerd Hoffmann | uint64_t uint; |
477 | e27c88fe | Gerd Hoffmann | } value; |
478 | e27c88fe | Gerd Hoffmann | |
479 | e27c88fe | Gerd Hoffmann | QemuOpts *opts; |
480 | 72cf2d4f | Blue Swirl | QTAILQ_ENTRY(QemuOpt) next; |
481 | e27c88fe | Gerd Hoffmann | }; |
482 | e27c88fe | Gerd Hoffmann | |
483 | e27c88fe | Gerd Hoffmann | struct QemuOpts {
|
484 | e27c88fe | Gerd Hoffmann | const char *id; |
485 | e27c88fe | Gerd Hoffmann | QemuOptsList *list; |
486 | dc9ca4ba | Mark McLoughlin | QTAILQ_HEAD(QemuOptHead, QemuOpt) head; |
487 | 72cf2d4f | Blue Swirl | QTAILQ_ENTRY(QemuOpts) next; |
488 | e27c88fe | Gerd Hoffmann | }; |
489 | e27c88fe | Gerd Hoffmann | |
490 | e27c88fe | Gerd Hoffmann | static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) |
491 | e27c88fe | Gerd Hoffmann | { |
492 | e27c88fe | Gerd Hoffmann | QemuOpt *opt; |
493 | e27c88fe | Gerd Hoffmann | |
494 | dc9ca4ba | Mark McLoughlin | QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) { |
495 | e27c88fe | Gerd Hoffmann | if (strcmp(opt->name, name) != 0) |
496 | e27c88fe | Gerd Hoffmann | continue;
|
497 | e27c88fe | Gerd Hoffmann | return opt;
|
498 | e27c88fe | Gerd Hoffmann | } |
499 | e27c88fe | Gerd Hoffmann | return NULL; |
500 | e27c88fe | Gerd Hoffmann | } |
501 | e27c88fe | Gerd Hoffmann | |
502 | e27c88fe | Gerd Hoffmann | const char *qemu_opt_get(QemuOpts *opts, const char *name) |
503 | e27c88fe | Gerd Hoffmann | { |
504 | e27c88fe | Gerd Hoffmann | QemuOpt *opt = qemu_opt_find(opts, name); |
505 | e27c88fe | Gerd Hoffmann | return opt ? opt->str : NULL; |
506 | e27c88fe | Gerd Hoffmann | } |
507 | e27c88fe | Gerd Hoffmann | |
508 | e27c88fe | Gerd Hoffmann | int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval) |
509 | e27c88fe | Gerd Hoffmann | { |
510 | e27c88fe | Gerd Hoffmann | QemuOpt *opt = qemu_opt_find(opts, name); |
511 | e27c88fe | Gerd Hoffmann | |
512 | e27c88fe | Gerd Hoffmann | if (opt == NULL) |
513 | e27c88fe | Gerd Hoffmann | return defval;
|
514 | e27c88fe | Gerd Hoffmann | assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL); |
515 | 1f5c1775 | Juan Quintela | return opt->value.boolean;
|
516 | e27c88fe | Gerd Hoffmann | } |
517 | e27c88fe | Gerd Hoffmann | |
518 | e27c88fe | Gerd Hoffmann | uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval) |
519 | e27c88fe | Gerd Hoffmann | { |
520 | e27c88fe | Gerd Hoffmann | QemuOpt *opt = qemu_opt_find(opts, name); |
521 | e27c88fe | Gerd Hoffmann | |
522 | e27c88fe | Gerd Hoffmann | if (opt == NULL) |
523 | e27c88fe | Gerd Hoffmann | return defval;
|
524 | e27c88fe | Gerd Hoffmann | assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER); |
525 | e27c88fe | Gerd Hoffmann | return opt->value.uint;
|
526 | e27c88fe | Gerd Hoffmann | } |
527 | e27c88fe | Gerd Hoffmann | |
528 | e27c88fe | Gerd Hoffmann | uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval) |
529 | e27c88fe | Gerd Hoffmann | { |
530 | e27c88fe | Gerd Hoffmann | QemuOpt *opt = qemu_opt_find(opts, name); |
531 | e27c88fe | Gerd Hoffmann | |
532 | e27c88fe | Gerd Hoffmann | if (opt == NULL) |
533 | e27c88fe | Gerd Hoffmann | return defval;
|
534 | e27c88fe | Gerd Hoffmann | assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE); |
535 | e27c88fe | Gerd Hoffmann | return opt->value.uint;
|
536 | e27c88fe | Gerd Hoffmann | } |
537 | e27c88fe | Gerd Hoffmann | |
538 | e27c88fe | Gerd Hoffmann | static int qemu_opt_parse(QemuOpt *opt) |
539 | e27c88fe | Gerd Hoffmann | { |
540 | e27c88fe | Gerd Hoffmann | if (opt->desc == NULL) |
541 | e27c88fe | Gerd Hoffmann | return 0; |
542 | e27c88fe | Gerd Hoffmann | switch (opt->desc->type) {
|
543 | e27c88fe | Gerd Hoffmann | case QEMU_OPT_STRING:
|
544 | e27c88fe | Gerd Hoffmann | /* nothing */
|
545 | e27c88fe | Gerd Hoffmann | return 0; |
546 | e27c88fe | Gerd Hoffmann | case QEMU_OPT_BOOL:
|
547 | 1f5c1775 | Juan Quintela | return parse_option_bool(opt->name, opt->str, &opt->value.boolean);
|
548 | e27c88fe | Gerd Hoffmann | case QEMU_OPT_NUMBER:
|
549 | e27c88fe | Gerd Hoffmann | return parse_option_number(opt->name, opt->str, &opt->value.uint);
|
550 | e27c88fe | Gerd Hoffmann | case QEMU_OPT_SIZE:
|
551 | e27c88fe | Gerd Hoffmann | return parse_option_size(opt->name, opt->str, &opt->value.uint);
|
552 | e27c88fe | Gerd Hoffmann | default:
|
553 | e27c88fe | Gerd Hoffmann | abort(); |
554 | e27c88fe | Gerd Hoffmann | } |
555 | e27c88fe | Gerd Hoffmann | } |
556 | e27c88fe | Gerd Hoffmann | |
557 | e27c88fe | Gerd Hoffmann | static void qemu_opt_del(QemuOpt *opt) |
558 | e27c88fe | Gerd Hoffmann | { |
559 | 72cf2d4f | Blue Swirl | QTAILQ_REMOVE(&opt->opts->head, opt, next); |
560 | e27c88fe | Gerd Hoffmann | qemu_free((/* !const */ char*)opt->name); |
561 | e27c88fe | Gerd Hoffmann | qemu_free((/* !const */ char*)opt->str); |
562 | e27c88fe | Gerd Hoffmann | qemu_free(opt); |
563 | e27c88fe | Gerd Hoffmann | } |
564 | e27c88fe | Gerd Hoffmann | |
565 | e27c88fe | Gerd Hoffmann | int qemu_opt_set(QemuOpts *opts, const char *name, const char *value) |
566 | e27c88fe | Gerd Hoffmann | { |
567 | e27c88fe | Gerd Hoffmann | QemuOpt *opt; |
568 | dc9ca4ba | Mark McLoughlin | QemuOptDesc *desc = opts->list->desc; |
569 | dc9ca4ba | Mark McLoughlin | int i;
|
570 | e27c88fe | Gerd Hoffmann | |
571 | dc9ca4ba | Mark McLoughlin | for (i = 0; desc[i].name != NULL; i++) { |
572 | dc9ca4ba | Mark McLoughlin | if (strcmp(desc[i].name, name) == 0) { |
573 | dc9ca4ba | Mark McLoughlin | break;
|
574 | e27c88fe | Gerd Hoffmann | } |
575 | dc9ca4ba | Mark McLoughlin | } |
576 | dc9ca4ba | Mark McLoughlin | if (desc[i].name == NULL) { |
577 | dc9ca4ba | Mark McLoughlin | if (i == 0) { |
578 | dc9ca4ba | Mark McLoughlin | /* empty list -> allow any */;
|
579 | dc9ca4ba | Mark McLoughlin | } else {
|
580 | dc9ca4ba | Mark McLoughlin | fprintf(stderr, "option \"%s\" is not valid for %s\n",
|
581 | dc9ca4ba | Mark McLoughlin | name, opts->list->name); |
582 | dc9ca4ba | Mark McLoughlin | return -1; |
583 | e27c88fe | Gerd Hoffmann | } |
584 | e27c88fe | Gerd Hoffmann | } |
585 | dc9ca4ba | Mark McLoughlin | |
586 | dc9ca4ba | Mark McLoughlin | opt = qemu_mallocz(sizeof(*opt));
|
587 | dc9ca4ba | Mark McLoughlin | opt->name = qemu_strdup(name); |
588 | dc9ca4ba | Mark McLoughlin | opt->opts = opts; |
589 | dc9ca4ba | Mark McLoughlin | QTAILQ_INSERT_TAIL(&opts->head, opt, next); |
590 | dc9ca4ba | Mark McLoughlin | if (desc[i].name != NULL) { |
591 | dc9ca4ba | Mark McLoughlin | opt->desc = desc+i; |
592 | dc9ca4ba | Mark McLoughlin | } |
593 | e27c88fe | Gerd Hoffmann | if (value) {
|
594 | e27c88fe | Gerd Hoffmann | opt->str = qemu_strdup(value); |
595 | e27c88fe | Gerd Hoffmann | } |
596 | e27c88fe | Gerd Hoffmann | if (qemu_opt_parse(opt) < 0) { |
597 | e27c88fe | Gerd Hoffmann | fprintf(stderr, "Failed to parse \"%s\" for \"%s.%s\"\n", opt->str,
|
598 | e27c88fe | Gerd Hoffmann | opts->list->name, opt->name); |
599 | e27c88fe | Gerd Hoffmann | qemu_opt_del(opt); |
600 | e27c88fe | Gerd Hoffmann | return -1; |
601 | e27c88fe | Gerd Hoffmann | } |
602 | e27c88fe | Gerd Hoffmann | return 0; |
603 | e27c88fe | Gerd Hoffmann | } |
604 | e27c88fe | Gerd Hoffmann | |
605 | 48026075 | Gerd Hoffmann | int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, |
606 | 48026075 | Gerd Hoffmann | int abort_on_failure)
|
607 | 48026075 | Gerd Hoffmann | { |
608 | 48026075 | Gerd Hoffmann | QemuOpt *opt; |
609 | 48026075 | Gerd Hoffmann | int rc = 0; |
610 | 48026075 | Gerd Hoffmann | |
611 | 72cf2d4f | Blue Swirl | QTAILQ_FOREACH(opt, &opts->head, next) { |
612 | 48026075 | Gerd Hoffmann | rc = func(opt->name, opt->str, opaque); |
613 | 48026075 | Gerd Hoffmann | if (abort_on_failure && rc != 0) |
614 | 48026075 | Gerd Hoffmann | break;
|
615 | 48026075 | Gerd Hoffmann | } |
616 | 48026075 | Gerd Hoffmann | return rc;
|
617 | 48026075 | Gerd Hoffmann | } |
618 | 48026075 | Gerd Hoffmann | |
619 | e27c88fe | Gerd Hoffmann | QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id) |
620 | e27c88fe | Gerd Hoffmann | { |
621 | e27c88fe | Gerd Hoffmann | QemuOpts *opts; |
622 | e27c88fe | Gerd Hoffmann | |
623 | 72cf2d4f | Blue Swirl | QTAILQ_FOREACH(opts, &list->head, next) { |
624 | e27c88fe | Gerd Hoffmann | if (!opts->id) {
|
625 | e27c88fe | Gerd Hoffmann | continue;
|
626 | e27c88fe | Gerd Hoffmann | } |
627 | e27c88fe | Gerd Hoffmann | if (strcmp(opts->id, id) != 0) { |
628 | e27c88fe | Gerd Hoffmann | continue;
|
629 | e27c88fe | Gerd Hoffmann | } |
630 | e27c88fe | Gerd Hoffmann | return opts;
|
631 | e27c88fe | Gerd Hoffmann | } |
632 | e27c88fe | Gerd Hoffmann | return NULL; |
633 | e27c88fe | Gerd Hoffmann | } |
634 | e27c88fe | Gerd Hoffmann | |
635 | e27c88fe | Gerd Hoffmann | QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists) |
636 | e27c88fe | Gerd Hoffmann | { |
637 | e27c88fe | Gerd Hoffmann | QemuOpts *opts = NULL;
|
638 | e27c88fe | Gerd Hoffmann | |
639 | e27c88fe | Gerd Hoffmann | if (id) {
|
640 | e27c88fe | Gerd Hoffmann | opts = qemu_opts_find(list, id); |
641 | e27c88fe | Gerd Hoffmann | if (opts != NULL) { |
642 | e27c88fe | Gerd Hoffmann | if (fail_if_exists) {
|
643 | e27c88fe | Gerd Hoffmann | fprintf(stderr, "tried to create id \"%s\" twice for \"%s\"\n",
|
644 | e27c88fe | Gerd Hoffmann | id, list->name); |
645 | e27c88fe | Gerd Hoffmann | return NULL; |
646 | e27c88fe | Gerd Hoffmann | } else {
|
647 | e27c88fe | Gerd Hoffmann | return opts;
|
648 | e27c88fe | Gerd Hoffmann | } |
649 | e27c88fe | Gerd Hoffmann | } |
650 | e27c88fe | Gerd Hoffmann | } |
651 | e27c88fe | Gerd Hoffmann | opts = qemu_mallocz(sizeof(*opts));
|
652 | e27c88fe | Gerd Hoffmann | if (id) {
|
653 | e27c88fe | Gerd Hoffmann | opts->id = qemu_strdup(id); |
654 | e27c88fe | Gerd Hoffmann | } |
655 | e27c88fe | Gerd Hoffmann | opts->list = list; |
656 | 72cf2d4f | Blue Swirl | QTAILQ_INIT(&opts->head); |
657 | 72cf2d4f | Blue Swirl | QTAILQ_INSERT_TAIL(&list->head, opts, next); |
658 | e27c88fe | Gerd Hoffmann | return opts;
|
659 | e27c88fe | Gerd Hoffmann | } |
660 | e27c88fe | Gerd Hoffmann | |
661 | e27c88fe | Gerd Hoffmann | int qemu_opts_set(QemuOptsList *list, const char *id, |
662 | e27c88fe | Gerd Hoffmann | const char *name, const char *value) |
663 | e27c88fe | Gerd Hoffmann | { |
664 | e27c88fe | Gerd Hoffmann | QemuOpts *opts; |
665 | e27c88fe | Gerd Hoffmann | |
666 | e27c88fe | Gerd Hoffmann | opts = qemu_opts_create(list, id, 1);
|
667 | e27c88fe | Gerd Hoffmann | if (opts == NULL) { |
668 | e27c88fe | Gerd Hoffmann | return -1; |
669 | e27c88fe | Gerd Hoffmann | } |
670 | e27c88fe | Gerd Hoffmann | return qemu_opt_set(opts, name, value);
|
671 | e27c88fe | Gerd Hoffmann | } |
672 | e27c88fe | Gerd Hoffmann | |
673 | 48026075 | Gerd Hoffmann | const char *qemu_opts_id(QemuOpts *opts) |
674 | 48026075 | Gerd Hoffmann | { |
675 | 48026075 | Gerd Hoffmann | return opts->id;
|
676 | 48026075 | Gerd Hoffmann | } |
677 | 48026075 | Gerd Hoffmann | |
678 | e27c88fe | Gerd Hoffmann | void qemu_opts_del(QemuOpts *opts)
|
679 | e27c88fe | Gerd Hoffmann | { |
680 | e27c88fe | Gerd Hoffmann | QemuOpt *opt; |
681 | e27c88fe | Gerd Hoffmann | |
682 | e27c88fe | Gerd Hoffmann | for (;;) {
|
683 | 72cf2d4f | Blue Swirl | opt = QTAILQ_FIRST(&opts->head); |
684 | e27c88fe | Gerd Hoffmann | if (opt == NULL) |
685 | e27c88fe | Gerd Hoffmann | break;
|
686 | e27c88fe | Gerd Hoffmann | qemu_opt_del(opt); |
687 | e27c88fe | Gerd Hoffmann | } |
688 | 72cf2d4f | Blue Swirl | QTAILQ_REMOVE(&opts->list->head, opts, next); |
689 | e27c88fe | Gerd Hoffmann | qemu_free(opts); |
690 | e27c88fe | Gerd Hoffmann | } |
691 | e27c88fe | Gerd Hoffmann | |
692 | e27c88fe | Gerd Hoffmann | int qemu_opts_print(QemuOpts *opts, void *dummy) |
693 | e27c88fe | Gerd Hoffmann | { |
694 | e27c88fe | Gerd Hoffmann | QemuOpt *opt; |
695 | e27c88fe | Gerd Hoffmann | |
696 | e27c88fe | Gerd Hoffmann | fprintf(stderr, "%s: %s:", opts->list->name,
|
697 | e27c88fe | Gerd Hoffmann | opts->id ? opts->id : "<noid>");
|
698 | 72cf2d4f | Blue Swirl | QTAILQ_FOREACH(opt, &opts->head, next) { |
699 | e27c88fe | Gerd Hoffmann | fprintf(stderr, " %s=\"%s\"", opt->name, opt->str);
|
700 | e27c88fe | Gerd Hoffmann | } |
701 | e27c88fe | Gerd Hoffmann | fprintf(stderr, "\n");
|
702 | e27c88fe | Gerd Hoffmann | return 0; |
703 | e27c88fe | Gerd Hoffmann | } |
704 | e27c88fe | Gerd Hoffmann | |
705 | 96729cbd | Gerd Hoffmann | int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname) |
706 | e27c88fe | Gerd Hoffmann | { |
707 | 96729cbd | Gerd Hoffmann | char option[128], value[128]; |
708 | e27c88fe | Gerd Hoffmann | const char *p,*pe,*pc; |
709 | e27c88fe | Gerd Hoffmann | |
710 | 2cfa571f | Mark McLoughlin | for (p = params; *p != '\0'; p++) { |
711 | e27c88fe | Gerd Hoffmann | pe = strchr(p, '=');
|
712 | e27c88fe | Gerd Hoffmann | pc = strchr(p, ',');
|
713 | e27c88fe | Gerd Hoffmann | if (!pe || (pc && pc < pe)) {
|
714 | e27c88fe | Gerd Hoffmann | /* found "foo,more" */
|
715 | e27c88fe | Gerd Hoffmann | if (p == params && firstname) {
|
716 | e27c88fe | Gerd Hoffmann | /* implicitly named first option */
|
717 | e27c88fe | Gerd Hoffmann | pstrcpy(option, sizeof(option), firstname);
|
718 | e27c88fe | Gerd Hoffmann | p = get_opt_value(value, sizeof(value), p);
|
719 | e27c88fe | Gerd Hoffmann | } else {
|
720 | e27c88fe | Gerd Hoffmann | /* option without value, probably a flag */
|
721 | e27c88fe | Gerd Hoffmann | p = get_opt_name(option, sizeof(option), p, ','); |
722 | 96729cbd | Gerd Hoffmann | if (strncmp(option, "no", 2) == 0) { |
723 | e27c88fe | Gerd Hoffmann | memmove(option, option+2, strlen(option+2)+1); |
724 | e27c88fe | Gerd Hoffmann | pstrcpy(value, sizeof(value), "off"); |
725 | e27c88fe | Gerd Hoffmann | } else {
|
726 | e27c88fe | Gerd Hoffmann | pstrcpy(value, sizeof(value), "on"); |
727 | e27c88fe | Gerd Hoffmann | } |
728 | e27c88fe | Gerd Hoffmann | } |
729 | e27c88fe | Gerd Hoffmann | } else {
|
730 | e27c88fe | Gerd Hoffmann | /* found "foo=bar,more" */
|
731 | e27c88fe | Gerd Hoffmann | p = get_opt_name(option, sizeof(option), p, '='); |
732 | e27c88fe | Gerd Hoffmann | if (*p != '=') { |
733 | e27c88fe | Gerd Hoffmann | break;
|
734 | e27c88fe | Gerd Hoffmann | } |
735 | e27c88fe | Gerd Hoffmann | p++; |
736 | e27c88fe | Gerd Hoffmann | p = get_opt_value(value, sizeof(value), p);
|
737 | e27c88fe | Gerd Hoffmann | } |
738 | e27c88fe | Gerd Hoffmann | if (strcmp(option, "id") != 0) { |
739 | e27c88fe | Gerd Hoffmann | /* store and parse */
|
740 | 3df04ac3 | Mark McLoughlin | if (qemu_opt_set(opts, option, value) == -1) { |
741 | 96729cbd | Gerd Hoffmann | return -1; |
742 | e27c88fe | Gerd Hoffmann | } |
743 | e27c88fe | Gerd Hoffmann | } |
744 | e27c88fe | Gerd Hoffmann | if (*p != ',') { |
745 | e27c88fe | Gerd Hoffmann | break;
|
746 | e27c88fe | Gerd Hoffmann | } |
747 | e27c88fe | Gerd Hoffmann | } |
748 | 96729cbd | Gerd Hoffmann | return 0; |
749 | 96729cbd | Gerd Hoffmann | } |
750 | 96729cbd | Gerd Hoffmann | |
751 | 96729cbd | Gerd Hoffmann | QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname) |
752 | 96729cbd | Gerd Hoffmann | { |
753 | 96729cbd | Gerd Hoffmann | char value[128], *id = NULL; |
754 | 96729cbd | Gerd Hoffmann | const char *p; |
755 | 96729cbd | Gerd Hoffmann | QemuOpts *opts; |
756 | 96729cbd | Gerd Hoffmann | |
757 | 96729cbd | Gerd Hoffmann | if (strncmp(params, "id=", 3) == 0) { |
758 | 96729cbd | Gerd Hoffmann | get_opt_value(value, sizeof(value), params+3); |
759 | 96729cbd | Gerd Hoffmann | id = qemu_strdup(value); |
760 | 96729cbd | Gerd Hoffmann | } else if ((p = strstr(params, ",id=")) != NULL) { |
761 | 96729cbd | Gerd Hoffmann | get_opt_value(value, sizeof(value), p+4); |
762 | 96729cbd | Gerd Hoffmann | id = qemu_strdup(value); |
763 | 96729cbd | Gerd Hoffmann | } |
764 | 96729cbd | Gerd Hoffmann | opts = qemu_opts_create(list, id, 1);
|
765 | 96729cbd | Gerd Hoffmann | if (opts == NULL) |
766 | 96729cbd | Gerd Hoffmann | return NULL; |
767 | 96729cbd | Gerd Hoffmann | |
768 | 96729cbd | Gerd Hoffmann | if (qemu_opts_do_parse(opts, params, firstname) != 0) { |
769 | 96729cbd | Gerd Hoffmann | qemu_opts_del(opts); |
770 | 96729cbd | Gerd Hoffmann | return NULL; |
771 | 96729cbd | Gerd Hoffmann | } |
772 | 96729cbd | Gerd Hoffmann | |
773 | e27c88fe | Gerd Hoffmann | return opts;
|
774 | e27c88fe | Gerd Hoffmann | } |
775 | e27c88fe | Gerd Hoffmann | |
776 | 5dc519ef | Mark McLoughlin | /* Validate parsed opts against descriptions where no
|
777 | 5dc519ef | Mark McLoughlin | * descriptions were provided in the QemuOptsList.
|
778 | 5dc519ef | Mark McLoughlin | */
|
779 | 5dc519ef | Mark McLoughlin | int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc)
|
780 | 5dc519ef | Mark McLoughlin | { |
781 | 5dc519ef | Mark McLoughlin | QemuOpt *opt; |
782 | 5dc519ef | Mark McLoughlin | |
783 | 5dc519ef | Mark McLoughlin | assert(opts->list->desc[0].name == NULL); |
784 | 5dc519ef | Mark McLoughlin | |
785 | 5dc519ef | Mark McLoughlin | QTAILQ_FOREACH(opt, &opts->head, next) { |
786 | 5dc519ef | Mark McLoughlin | int i;
|
787 | 5dc519ef | Mark McLoughlin | |
788 | 5dc519ef | Mark McLoughlin | for (i = 0; desc[i].name != NULL; i++) { |
789 | 5dc519ef | Mark McLoughlin | if (strcmp(desc[i].name, opt->name) == 0) { |
790 | 5dc519ef | Mark McLoughlin | break;
|
791 | 5dc519ef | Mark McLoughlin | } |
792 | 5dc519ef | Mark McLoughlin | } |
793 | 5dc519ef | Mark McLoughlin | if (desc[i].name == NULL) { |
794 | 5dc519ef | Mark McLoughlin | fprintf(stderr, "option \"%s\" is not valid for %s\n",
|
795 | 5dc519ef | Mark McLoughlin | opt->name, opts->list->name); |
796 | 5dc519ef | Mark McLoughlin | return -1; |
797 | 5dc519ef | Mark McLoughlin | } |
798 | 5dc519ef | Mark McLoughlin | |
799 | 5dc519ef | Mark McLoughlin | opt->desc = &desc[i]; |
800 | 5dc519ef | Mark McLoughlin | |
801 | 5dc519ef | Mark McLoughlin | if (qemu_opt_parse(opt) < 0) { |
802 | 5dc519ef | Mark McLoughlin | return -1; |
803 | 5dc519ef | Mark McLoughlin | } |
804 | 5dc519ef | Mark McLoughlin | } |
805 | 5dc519ef | Mark McLoughlin | |
806 | 5dc519ef | Mark McLoughlin | return 0; |
807 | 5dc519ef | Mark McLoughlin | } |
808 | 5dc519ef | Mark McLoughlin | |
809 | e27c88fe | Gerd Hoffmann | int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, |
810 | e27c88fe | Gerd Hoffmann | int abort_on_failure)
|
811 | e27c88fe | Gerd Hoffmann | { |
812 | e27c88fe | Gerd Hoffmann | QemuOpts *opts; |
813 | e27c88fe | Gerd Hoffmann | int rc = 0; |
814 | e27c88fe | Gerd Hoffmann | |
815 | 72cf2d4f | Blue Swirl | QTAILQ_FOREACH(opts, &list->head, next) { |
816 | e27c88fe | Gerd Hoffmann | rc = func(opts, opaque); |
817 | e27c88fe | Gerd Hoffmann | if (abort_on_failure && rc != 0) |
818 | e27c88fe | Gerd Hoffmann | break;
|
819 | e27c88fe | Gerd Hoffmann | } |
820 | e27c88fe | Gerd Hoffmann | return rc;
|
821 | e27c88fe | Gerd Hoffmann | } |