File: | util/qemu-option.c |
Location: | line 250, column 27 |
Description: | Assigned value is garbage or undefined |
1 | /* | |||
2 | * Commandline option parsing functions | |||
3 | * | |||
4 | * Copyright (c) 2003-2008 Fabrice Bellard | |||
5 | * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com> | |||
6 | * | |||
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |||
8 | * of this software and associated documentation files (the "Software"), to deal | |||
9 | * in the Software without restriction, including without limitation the rights | |||
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
11 | * copies of the Software, and to permit persons to whom the Software is | |||
12 | * furnished to do so, subject to the following conditions: | |||
13 | * | |||
14 | * The above copyright notice and this permission notice shall be included in | |||
15 | * all copies or substantial portions of the Software. | |||
16 | * | |||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
23 | * THE SOFTWARE. | |||
24 | */ | |||
25 | ||||
26 | #include <stdio.h> | |||
27 | #include <string.h> | |||
28 | ||||
29 | #include "qemu-common.h" | |||
30 | #include "qemu/error-report.h" | |||
31 | #include "qapi/qmp/types.h" | |||
32 | #include "qapi/error.h" | |||
33 | #include "qapi/qmp/qerror.h" | |||
34 | #include "qemu/option_int.h" | |||
35 | ||||
36 | /* | |||
37 | * Extracts the name of an option from the parameter string (p points at the | |||
38 | * first byte of the option name) | |||
39 | * | |||
40 | * The option name is delimited by delim (usually , or =) or the string end | |||
41 | * and is copied into buf. If the option name is longer than buf_size, it is | |||
42 | * truncated. buf is always zero terminated. | |||
43 | * | |||
44 | * The return value is the position of the delimiter/zero byte after the option | |||
45 | * name in p. | |||
46 | */ | |||
47 | const char *get_opt_name(char *buf, int buf_size, const char *p, char delim) | |||
48 | { | |||
49 | char *q; | |||
50 | ||||
51 | q = buf; | |||
52 | while (*p != '\0' && *p != delim) { | |||
53 | if (q && (q - buf) < buf_size - 1) | |||
54 | *q++ = *p; | |||
55 | p++; | |||
56 | } | |||
57 | if (q) | |||
58 | *q = '\0'; | |||
59 | ||||
60 | return p; | |||
61 | } | |||
62 | ||||
63 | /* | |||
64 | * Extracts the value of an option from the parameter string p (p points at the | |||
65 | * first byte of the option value) | |||
66 | * | |||
67 | * This function is comparable to get_opt_name with the difference that the | |||
68 | * delimiter is fixed to be comma which starts a new option. To specify an | |||
69 | * option value that contains commas, double each comma. | |||
70 | */ | |||
71 | const char *get_opt_value(char *buf, int buf_size, const char *p) | |||
72 | { | |||
73 | char *q; | |||
74 | ||||
75 | q = buf; | |||
76 | while (*p != '\0') { | |||
77 | if (*p == ',') { | |||
78 | if (*(p + 1) != ',') | |||
79 | break; | |||
80 | p++; | |||
81 | } | |||
82 | if (q && (q - buf) < buf_size - 1) | |||
83 | *q++ = *p; | |||
84 | p++; | |||
85 | } | |||
86 | if (q) | |||
87 | *q = '\0'; | |||
88 | ||||
89 | return p; | |||
90 | } | |||
91 | ||||
92 | int get_next_param_value(char *buf, int buf_size, | |||
93 | const char *tag, const char **pstr) | |||
94 | { | |||
95 | const char *p; | |||
96 | char option[128]; | |||
97 | ||||
98 | p = *pstr; | |||
99 | for(;;) { | |||
100 | p = get_opt_name(option, sizeof(option), p, '='); | |||
101 | if (*p != '=') | |||
102 | break; | |||
103 | p++; | |||
104 | if (!strcmp(tag, option)) { | |||
105 | *pstr = get_opt_value(buf, buf_size, p); | |||
106 | if (**pstr == ',') { | |||
107 | (*pstr)++; | |||
108 | } | |||
109 | return strlen(buf); | |||
110 | } else { | |||
111 | p = get_opt_value(NULL((void*)0), 0, p); | |||
112 | } | |||
113 | if (*p != ',') | |||
114 | break; | |||
115 | p++; | |||
116 | } | |||
117 | return 0; | |||
118 | } | |||
119 | ||||
120 | int get_param_value(char *buf, int buf_size, | |||
121 | const char *tag, const char *str) | |||
122 | { | |||
123 | return get_next_param_value(buf, buf_size, tag, &str); | |||
124 | } | |||
125 | ||||
126 | /* | |||
127 | * Searches an option list for an option with the given name | |||
128 | */ | |||
129 | QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list, | |||
130 | const char *name) | |||
131 | { | |||
132 | while (list && list->name) { | |||
133 | if (!strcmp(list->name, name)) { | |||
134 | return list; | |||
135 | } | |||
136 | list++; | |||
137 | } | |||
138 | ||||
139 | return NULL((void*)0); | |||
140 | } | |||
141 | ||||
142 | static void parse_option_bool(const char *name, const char *value, bool_Bool *ret, | |||
143 | Error **errp) | |||
144 | { | |||
145 | if (value != NULL((void*)0)) { | |||
146 | if (!strcmp(value, "on")) { | |||
147 | *ret = 1; | |||
148 | } else if (!strcmp(value, "off")) { | |||
149 | *ret = 0; | |||
150 | } else { | |||
151 | error_set(errp,QERR_INVALID_PARAMETER_VALUEERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s", name, "'on' or 'off'"); | |||
152 | } | |||
153 | } else { | |||
154 | *ret = 1; | |||
155 | } | |||
156 | } | |||
157 | ||||
158 | static void parse_option_number(const char *name, const char *value, | |||
159 | uint64_t *ret, Error **errp) | |||
160 | { | |||
161 | char *postfix; | |||
162 | uint64_t number; | |||
163 | ||||
164 | if (value != NULL((void*)0)) { | |||
165 | number = strtoull(value, &postfix, 0); | |||
166 | if (*postfix != '\0') { | |||
167 | error_set(errp, QERR_INVALID_PARAMETER_VALUEERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s", name, "a number"); | |||
168 | return; | |||
169 | } | |||
170 | *ret = number; | |||
171 | } else { | |||
172 | error_set(errp, QERR_INVALID_PARAMETER_VALUEERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s", name, "a number"); | |||
173 | } | |||
174 | } | |||
175 | ||||
176 | void parse_option_size(const char *name, const char *value, | |||
177 | uint64_t *ret, Error **errp) | |||
178 | { | |||
179 | char *postfix; | |||
180 | double sizef; | |||
181 | ||||
182 | if (value != NULL((void*)0)) { | |||
183 | sizef = strtod(value, &postfix); | |||
184 | switch (*postfix) { | |||
185 | case 'T': | |||
186 | sizef *= 1024; | |||
187 | /* fall through */ | |||
188 | case 'G': | |||
189 | sizef *= 1024; | |||
190 | /* fall through */ | |||
191 | case 'M': | |||
192 | sizef *= 1024; | |||
193 | /* fall through */ | |||
194 | case 'K': | |||
195 | case 'k': | |||
196 | sizef *= 1024; | |||
197 | /* fall through */ | |||
198 | case 'b': | |||
199 | case '\0': | |||
200 | *ret = (uint64_t) sizef; | |||
201 | break; | |||
202 | default: | |||
203 | error_set(errp, QERR_INVALID_PARAMETER_VALUEERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s", name, "a size"); | |||
204 | #if 0 /* conversion from qerror_report() to error_set() broke this: */ | |||
205 | error_printf_unless_qmp("You may use k, M, G or T suffixes for " | |||
206 | "kilobytes, megabytes, gigabytes and terabytes.\n"); | |||
207 | #endif | |||
208 | return; | |||
209 | } | |||
210 | } else { | |||
211 | error_set(errp, QERR_INVALID_PARAMETER_VALUEERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s", name, "a size"); | |||
212 | } | |||
213 | } | |||
214 | ||||
215 | /* | |||
216 | * Sets the value of a parameter in a given option list. The parsing of the | |||
217 | * value depends on the type of option: | |||
218 | * | |||
219 | * OPT_FLAG (uses value.n): | |||
220 | * If no value is given, the flag is set to 1. | |||
221 | * Otherwise the value must be "on" (set to 1) or "off" (set to 0) | |||
222 | * | |||
223 | * OPT_STRING (uses value.s): | |||
224 | * value is strdup()ed and assigned as option value | |||
225 | * | |||
226 | * OPT_SIZE (uses value.n): | |||
227 | * The value is converted to an integer. Suffixes for kilobytes etc. are | |||
228 | * allowed (powers of 1024). | |||
229 | * | |||
230 | * Returns 0 on succes, -1 in error cases | |||
231 | */ | |||
232 | int set_option_parameter(QEMUOptionParameter *list, const char *name, | |||
233 | const char *value) | |||
234 | { | |||
235 | bool_Bool flag; | |||
236 | Error *local_err = NULL((void*)0); | |||
237 | ||||
238 | // Find a matching parameter | |||
239 | list = get_option_parameter(list, name); | |||
240 | if (list == NULL((void*)0)) { | |||
241 | fprintf(stderrstderr, "Unknown option '%s'\n", name); | |||
242 | return -1; | |||
243 | } | |||
244 | ||||
245 | // Process parameter | |||
246 | switch (list->type) { | |||
247 | case OPT_FLAG: | |||
248 | parse_option_bool(name, value, &flag, &local_err); | |||
249 | if (!error_is_set(&local_err)) { | |||
250 | list->value.n = flag; | |||
| ||||
251 | } | |||
252 | break; | |||
253 | ||||
254 | case OPT_STRING: | |||
255 | if (value != NULL((void*)0)) { | |||
256 | list->value.s = g_strdup(value); | |||
257 | } else { | |||
258 | fprintf(stderrstderr, "Option '%s' needs a parameter\n", name); | |||
259 | return -1; | |||
260 | } | |||
261 | break; | |||
262 | ||||
263 | case OPT_SIZE: | |||
264 | parse_option_size(name, value, &list->value.n, &local_err); | |||
265 | break; | |||
266 | ||||
267 | default: | |||
268 | fprintf(stderrstderr, "Bug: Option '%s' has an unknown type\n", name); | |||
269 | return -1; | |||
270 | } | |||
271 | ||||
272 | if (error_is_set(&local_err)) { | |||
273 | qerror_report_err(local_err); | |||
274 | error_free(local_err); | |||
275 | return -1; | |||
276 | } | |||
277 | ||||
278 | list->assigned = true1; | |||
279 | ||||
280 | return 0; | |||
281 | } | |||
282 | ||||
283 | /* | |||
284 | * Sets the given parameter to an integer instead of a string. | |||
285 | * This function cannot be used to set string options. | |||
286 | * | |||
287 | * Returns 0 on success, -1 in error cases | |||
288 | */ | |||
289 | int set_option_parameter_int(QEMUOptionParameter *list, const char *name, | |||
290 | uint64_t value) | |||
291 | { | |||
292 | // Find a matching parameter | |||
293 | list = get_option_parameter(list, name); | |||
294 | if (list == NULL((void*)0)) { | |||
295 | fprintf(stderrstderr, "Unknown option '%s'\n", name); | |||
296 | return -1; | |||
297 | } | |||
298 | ||||
299 | // Process parameter | |||
300 | switch (list->type) { | |||
301 | case OPT_FLAG: | |||
302 | case OPT_NUMBER: | |||
303 | case OPT_SIZE: | |||
304 | list->value.n = value; | |||
305 | break; | |||
306 | ||||
307 | default: | |||
308 | return -1; | |||
309 | } | |||
310 | ||||
311 | list->assigned = true1; | |||
312 | ||||
313 | return 0; | |||
314 | } | |||
315 | ||||
316 | /* | |||
317 | * Frees a option list. If it contains strings, the strings are freed as well. | |||
318 | */ | |||
319 | void free_option_parameters(QEMUOptionParameter *list) | |||
320 | { | |||
321 | QEMUOptionParameter *cur = list; | |||
322 | ||||
323 | while (cur && cur->name) { | |||
324 | if (cur->type == OPT_STRING) { | |||
325 | g_free(cur->value.s); | |||
326 | } | |||
327 | cur++; | |||
328 | } | |||
329 | ||||
330 | g_free(list); | |||
331 | } | |||
332 | ||||
333 | /* | |||
334 | * Count valid options in list | |||
335 | */ | |||
336 | static size_t count_option_parameters(QEMUOptionParameter *list) | |||
337 | { | |||
338 | size_t num_options = 0; | |||
339 | ||||
340 | while (list && list->name) { | |||
341 | num_options++; | |||
342 | list++; | |||
343 | } | |||
344 | ||||
345 | return num_options; | |||
346 | } | |||
347 | ||||
348 | /* | |||
349 | * Append an option list (list) to an option list (dest). | |||
350 | * | |||
351 | * If dest is NULL, a new copy of list is created. | |||
352 | * | |||
353 | * Returns a pointer to the first element of dest (or the newly allocated copy) | |||
354 | */ | |||
355 | QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest, | |||
356 | QEMUOptionParameter *list) | |||
357 | { | |||
358 | size_t num_options, num_dest_options; | |||
359 | ||||
360 | num_options = count_option_parameters(dest); | |||
361 | num_dest_options = num_options; | |||
362 | ||||
363 | num_options += count_option_parameters(list); | |||
364 | ||||
365 | dest = g_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter)); | |||
366 | dest[num_dest_options].name = NULL((void*)0); | |||
367 | ||||
368 | while (list && list->name) { | |||
369 | if (get_option_parameter(dest, list->name) == NULL((void*)0)) { | |||
370 | dest[num_dest_options++] = *list; | |||
371 | dest[num_dest_options].name = NULL((void*)0); | |||
372 | } | |||
373 | list++; | |||
374 | } | |||
375 | ||||
376 | return dest; | |||
377 | } | |||
378 | ||||
379 | /* | |||
380 | * Parses a parameter string (param) into an option list (dest). | |||
381 | * | |||
382 | * list is the template option list. If dest is NULL, a new copy of list is | |||
383 | * created. If list is NULL, this function fails. | |||
384 | * | |||
385 | * A parameter string consists of one or more parameters, separated by commas. | |||
386 | * Each parameter consists of its name and possibly of a value. In the latter | |||
387 | * case, the value is delimited by an = character. To specify a value which | |||
388 | * contains commas, double each comma so it won't be recognized as the end of | |||
389 | * the parameter. | |||
390 | * | |||
391 | * For more details of the parsing see above. | |||
392 | * | |||
393 | * Returns a pointer to the first element of dest (or the newly allocated copy) | |||
394 | * or NULL in error cases | |||
395 | */ | |||
396 | QEMUOptionParameter *parse_option_parameters(const char *param, | |||
397 | QEMUOptionParameter *list, QEMUOptionParameter *dest) | |||
398 | { | |||
399 | QEMUOptionParameter *allocated = NULL((void*)0); | |||
400 | char name[256]; | |||
401 | char value[256]; | |||
402 | char *param_delim, *value_delim; | |||
403 | char next_delim; | |||
404 | int i; | |||
405 | ||||
406 | if (list == NULL((void*)0)) { | |||
| ||||
407 | return NULL((void*)0); | |||
408 | } | |||
409 | ||||
410 | if (dest == NULL((void*)0)) { | |||
411 | dest = allocated = append_option_parameters(NULL((void*)0), list); | |||
412 | } | |||
413 | ||||
414 | for (i = 0; dest[i].name; i++) { | |||
415 | dest[i].assigned = false0; | |||
416 | } | |||
417 | ||||
418 | while (*param) { | |||
419 | ||||
420 | // Find parameter name and value in the string | |||
421 | param_delim = strchr(param, ','); | |||
422 | value_delim = strchr(param, '='); | |||
423 | ||||
424 | if (value_delim && (value_delim < param_delim || !param_delim)) { | |||
425 | next_delim = '='; | |||
426 | } else { | |||
427 | next_delim = ','; | |||
428 | value_delim = NULL((void*)0); | |||
429 | } | |||
430 | ||||
431 | param = get_opt_name(name, sizeof(name), param, next_delim); | |||
432 | if (value_delim) { | |||
433 | param = get_opt_value(value, sizeof(value), param + 1); | |||
434 | } | |||
435 | if (*param != '\0') { | |||
436 | param++; | |||
437 | } | |||
438 | ||||
439 | // Set the parameter | |||
440 | if (set_option_parameter(dest, name, value_delim ? value : NULL((void*)0))) { | |||
441 | goto fail; | |||
442 | } | |||
443 | } | |||
444 | ||||
445 | return dest; | |||
446 | ||||
447 | fail: | |||
448 | // Only free the list if it was newly allocated | |||
449 | free_option_parameters(allocated); | |||
450 | return NULL((void*)0); | |||
451 | } | |||
452 | ||||
453 | /* | |||
454 | * Prints all options of a list that have a value to stdout | |||
455 | */ | |||
456 | void print_option_parameters(QEMUOptionParameter *list) | |||
457 | { | |||
458 | while (list && list->name) { | |||
459 | switch (list->type) { | |||
460 | case OPT_STRING: | |||
461 | if (list->value.s != NULL((void*)0)) { | |||
462 | printf("%s='%s' ", list->name, list->value.s); | |||
463 | } | |||
464 | break; | |||
465 | case OPT_FLAG: | |||
466 | printf("%s=%s ", list->name, list->value.n ? "on" : "off"); | |||
467 | break; | |||
468 | case OPT_SIZE: | |||
469 | case OPT_NUMBER: | |||
470 | printf("%s=%" PRId64"l" "d" " ", list->name, list->value.n); | |||
471 | break; | |||
472 | default: | |||
473 | printf("%s=(unknown type) ", list->name); | |||
474 | break; | |||
475 | } | |||
476 | list++; | |||
477 | } | |||
478 | } | |||
479 | ||||
480 | /* | |||
481 | * Prints an overview of all available options | |||
482 | */ | |||
483 | void print_option_help(QEMUOptionParameter *list) | |||
484 | { | |||
485 | printf("Supported options:\n"); | |||
486 | while (list && list->name) { | |||
487 | printf("%-16s %s\n", list->name, | |||
488 | list->help ? list->help : "No description available"); | |||
489 | list++; | |||
490 | } | |||
491 | } | |||
492 | ||||
493 | /* ------------------------------------------------------------------ */ | |||
494 | ||||
495 | static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name) | |||
496 | { | |||
497 | QemuOpt *opt; | |||
498 | ||||
499 | QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next)for ((opt) = (*(((struct QemuOptHead *)((&opts->head)-> tqh_last))->tqh_last)); (opt); (opt) = (*(((struct QemuOptHead *)((opt)->next.tqe_prev))->tqh_last))) { | |||
500 | if (strcmp(opt->name, name) != 0) | |||
501 | continue; | |||
502 | return opt; | |||
503 | } | |||
504 | return NULL((void*)0); | |||
505 | } | |||
506 | ||||
507 | const char *qemu_opt_get(QemuOpts *opts, const char *name) | |||
508 | { | |||
509 | QemuOpt *opt = qemu_opt_find(opts, name); | |||
510 | return opt ? opt->str : NULL((void*)0); | |||
511 | } | |||
512 | ||||
513 | bool_Bool qemu_opt_has_help_opt(QemuOpts *opts) | |||
514 | { | |||
515 | QemuOpt *opt; | |||
516 | ||||
517 | QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next)for ((opt) = (*(((struct QemuOptHead *)((&opts->head)-> tqh_last))->tqh_last)); (opt); (opt) = (*(((struct QemuOptHead *)((opt)->next.tqe_prev))->tqh_last))) { | |||
518 | if (is_help_option(opt->name)) { | |||
519 | return true1; | |||
520 | } | |||
521 | } | |||
522 | return false0; | |||
523 | } | |||
524 | ||||
525 | bool_Bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool_Bool defval) | |||
526 | { | |||
527 | QemuOpt *opt = qemu_opt_find(opts, name); | |||
528 | ||||
529 | if (opt == NULL((void*)0)) | |||
530 | return defval; | |||
531 | assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL)((opt->desc && opt->desc->type == QEMU_OPT_BOOL ) ? (void) (0) : __assert_fail ("opt->desc && opt->desc->type == QEMU_OPT_BOOL" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 531 , __PRETTY_FUNCTION__)); | |||
532 | return opt->value.boolean; | |||
533 | } | |||
534 | ||||
535 | uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval) | |||
536 | { | |||
537 | QemuOpt *opt = qemu_opt_find(opts, name); | |||
538 | ||||
539 | if (opt == NULL((void*)0)) | |||
540 | return defval; | |||
541 | assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER)((opt->desc && opt->desc->type == QEMU_OPT_NUMBER ) ? (void) (0) : __assert_fail ("opt->desc && opt->desc->type == QEMU_OPT_NUMBER" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 541 , __PRETTY_FUNCTION__)); | |||
542 | return opt->value.uint; | |||
543 | } | |||
544 | ||||
545 | uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval) | |||
546 | { | |||
547 | QemuOpt *opt = qemu_opt_find(opts, name); | |||
548 | ||||
549 | if (opt == NULL((void*)0)) | |||
550 | return defval; | |||
551 | assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE)((opt->desc && opt->desc->type == QEMU_OPT_SIZE ) ? (void) (0) : __assert_fail ("opt->desc && opt->desc->type == QEMU_OPT_SIZE" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 551 , __PRETTY_FUNCTION__)); | |||
552 | return opt->value.uint; | |||
553 | } | |||
554 | ||||
555 | static void qemu_opt_parse(QemuOpt *opt, Error **errp) | |||
556 | { | |||
557 | if (opt->desc == NULL((void*)0)) | |||
558 | return; | |||
559 | ||||
560 | switch (opt->desc->type) { | |||
561 | case QEMU_OPT_STRING: | |||
562 | /* nothing */ | |||
563 | return; | |||
564 | case QEMU_OPT_BOOL: | |||
565 | parse_option_bool(opt->name, opt->str, &opt->value.boolean, errp); | |||
566 | break; | |||
567 | case QEMU_OPT_NUMBER: | |||
568 | parse_option_number(opt->name, opt->str, &opt->value.uint, errp); | |||
569 | break; | |||
570 | case QEMU_OPT_SIZE: | |||
571 | parse_option_size(opt->name, opt->str, &opt->value.uint, errp); | |||
572 | break; | |||
573 | default: | |||
574 | abort(); | |||
575 | } | |||
576 | } | |||
577 | ||||
578 | static void qemu_opt_del(QemuOpt *opt) | |||
579 | { | |||
580 | QTAILQ_REMOVE(&opt->opts->head, opt, next)do { if (((opt)->next.tqe_next) != ((void*)0)) (opt)->next .tqe_next->next.tqe_prev = (opt)->next.tqe_prev; else ( &opt->opts->head)->tqh_last = (opt)->next.tqe_prev ; *(opt)->next.tqe_prev = (opt)->next.tqe_next; } while ( 0); | |||
581 | g_free((/* !const */ char*)opt->name); | |||
582 | g_free((/* !const */ char*)opt->str); | |||
583 | g_free(opt); | |||
584 | } | |||
585 | ||||
586 | static bool_Bool opts_accepts_any(const QemuOpts *opts) | |||
587 | { | |||
588 | return opts->list->desc[0].name == NULL((void*)0); | |||
589 | } | |||
590 | ||||
591 | static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, | |||
592 | const char *name) | |||
593 | { | |||
594 | int i; | |||
595 | ||||
596 | for (i = 0; desc[i].name != NULL((void*)0); i++) { | |||
597 | if (strcmp(desc[i].name, name) == 0) { | |||
598 | return &desc[i]; | |||
599 | } | |||
600 | } | |||
601 | ||||
602 | return NULL((void*)0); | |||
603 | } | |||
604 | ||||
605 | int qemu_opt_unset(QemuOpts *opts, const char *name) | |||
606 | { | |||
607 | QemuOpt *opt = qemu_opt_find(opts, name); | |||
608 | ||||
609 | assert(opts_accepts_any(opts))((opts_accepts_any(opts)) ? (void) (0) : __assert_fail ("opts_accepts_any(opts)" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 609 , __PRETTY_FUNCTION__)); | |||
610 | ||||
611 | if (opt == NULL((void*)0)) { | |||
612 | return -1; | |||
613 | } else { | |||
614 | qemu_opt_del(opt); | |||
615 | return 0; | |||
616 | } | |||
617 | } | |||
618 | ||||
619 | static void opt_set(QemuOpts *opts, const char *name, const char *value, | |||
620 | bool_Bool prepend, Error **errp) | |||
621 | { | |||
622 | QemuOpt *opt; | |||
623 | const QemuOptDesc *desc; | |||
624 | Error *local_err = NULL((void*)0); | |||
625 | ||||
626 | desc = find_desc_by_name(opts->list->desc, name); | |||
627 | if (!desc && !opts_accepts_any(opts)) { | |||
628 | error_set(errp, QERR_INVALID_PARAMETERERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'", name); | |||
629 | return; | |||
630 | } | |||
631 | ||||
632 | opt = g_malloc0(sizeof(*opt)); | |||
633 | opt->name = g_strdup(name); | |||
634 | opt->opts = opts; | |||
635 | if (prepend) { | |||
636 | QTAILQ_INSERT_HEAD(&opts->head, opt, next)do { if (((opt)->next.tqe_next = (&opts->head)-> tqh_first) != ((void*)0)) (&opts->head)->tqh_first-> next.tqe_prev = &(opt)->next.tqe_next; else (&opts ->head)->tqh_last = &(opt)->next.tqe_next; (& opts->head)->tqh_first = (opt); (opt)->next.tqe_prev = &(&opts->head)->tqh_first; } while ( 0); | |||
637 | } else { | |||
638 | QTAILQ_INSERT_TAIL(&opts->head, opt, next)do { (opt)->next.tqe_next = ((void*)0); (opt)->next.tqe_prev = (&opts->head)->tqh_last; *(&opts->head)-> tqh_last = (opt); (&opts->head)->tqh_last = &(opt )->next.tqe_next; } while ( 0); | |||
639 | } | |||
640 | opt->desc = desc; | |||
641 | opt->str = g_strdup(value); | |||
642 | qemu_opt_parse(opt, &local_err); | |||
643 | if (error_is_set(&local_err)) { | |||
644 | error_propagate(errp, local_err); | |||
645 | qemu_opt_del(opt); | |||
646 | } | |||
647 | } | |||
648 | ||||
649 | int qemu_opt_set(QemuOpts *opts, const char *name, const char *value) | |||
650 | { | |||
651 | Error *local_err = NULL((void*)0); | |||
652 | ||||
653 | opt_set(opts, name, value, false0, &local_err); | |||
654 | if (error_is_set(&local_err)) { | |||
655 | qerror_report_err(local_err); | |||
656 | error_free(local_err); | |||
657 | return -1; | |||
658 | } | |||
659 | ||||
660 | return 0; | |||
661 | } | |||
662 | ||||
663 | void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value, | |||
664 | Error **errp) | |||
665 | { | |||
666 | opt_set(opts, name, value, false0, errp); | |||
667 | } | |||
668 | ||||
669 | int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool_Bool val) | |||
670 | { | |||
671 | QemuOpt *opt; | |||
672 | const QemuOptDesc *desc = opts->list->desc; | |||
673 | ||||
674 | opt = g_malloc0(sizeof(*opt)); | |||
675 | opt->desc = find_desc_by_name(desc, name); | |||
676 | if (!opt->desc && !opts_accepts_any(opts)) { | |||
677 | qerror_report(QERR_INVALID_PARAMETERERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'", name); | |||
678 | g_free(opt); | |||
679 | return -1; | |||
680 | } | |||
681 | ||||
682 | opt->name = g_strdup(name); | |||
683 | opt->opts = opts; | |||
684 | opt->value.boolean = !!val; | |||
685 | opt->str = g_strdup(val ? "on" : "off"); | |||
686 | QTAILQ_INSERT_TAIL(&opts->head, opt, next)do { (opt)->next.tqe_next = ((void*)0); (opt)->next.tqe_prev = (&opts->head)->tqh_last; *(&opts->head)-> tqh_last = (opt); (&opts->head)->tqh_last = &(opt )->next.tqe_next; } while ( 0); | |||
687 | ||||
688 | return 0; | |||
689 | } | |||
690 | ||||
691 | int qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val) | |||
692 | { | |||
693 | QemuOpt *opt; | |||
694 | const QemuOptDesc *desc = opts->list->desc; | |||
695 | ||||
696 | opt = g_malloc0(sizeof(*opt)); | |||
697 | opt->desc = find_desc_by_name(desc, name); | |||
698 | if (!opt->desc && !opts_accepts_any(opts)) { | |||
699 | qerror_report(QERR_INVALID_PARAMETERERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'", name); | |||
700 | g_free(opt); | |||
701 | return -1; | |||
702 | } | |||
703 | ||||
704 | opt->name = g_strdup(name); | |||
705 | opt->opts = opts; | |||
706 | opt->value.uint = val; | |||
707 | opt->str = g_strdup_printf("%" PRId64"l" "d", val); | |||
708 | QTAILQ_INSERT_TAIL(&opts->head, opt, next)do { (opt)->next.tqe_next = ((void*)0); (opt)->next.tqe_prev = (&opts->head)->tqh_last; *(&opts->head)-> tqh_last = (opt); (&opts->head)->tqh_last = &(opt )->next.tqe_next; } while ( 0); | |||
709 | ||||
710 | return 0; | |||
711 | } | |||
712 | ||||
713 | int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque, | |||
714 | int abort_on_failure) | |||
715 | { | |||
716 | QemuOpt *opt; | |||
717 | int rc = 0; | |||
718 | ||||
719 | QTAILQ_FOREACH(opt, &opts->head, next)for ((opt) = ((&opts->head)->tqh_first); (opt); (opt ) = ((opt)->next.tqe_next)) { | |||
720 | rc = func(opt->name, opt->str, opaque); | |||
721 | if (abort_on_failure && rc != 0) | |||
722 | break; | |||
723 | } | |||
724 | return rc; | |||
725 | } | |||
726 | ||||
727 | QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id) | |||
728 | { | |||
729 | QemuOpts *opts; | |||
730 | ||||
731 | QTAILQ_FOREACH(opts, &list->head, next)for ((opts) = ((&list->head)->tqh_first); (opts); ( opts) = ((opts)->next.tqe_next)) { | |||
732 | if (!opts->id && !id) { | |||
733 | return opts; | |||
734 | } | |||
735 | if (opts->id && id && !strcmp(opts->id, id)) { | |||
736 | return opts; | |||
737 | } | |||
738 | } | |||
739 | return NULL((void*)0); | |||
740 | } | |||
741 | ||||
742 | static int id_wellformed(const char *id) | |||
743 | { | |||
744 | int i; | |||
745 | ||||
746 | if (!qemu_isalpha(id[0])((*__ctype_b_loc ())[(int) (((unsigned char)(id[0])))] & ( unsigned short int) _ISalpha)) { | |||
747 | return 0; | |||
748 | } | |||
749 | for (i = 1; id[i]; i++) { | |||
750 | if (!qemu_isalnum(id[i])((*__ctype_b_loc ())[(int) (((unsigned char)(id[i])))] & ( unsigned short int) _ISalnum) && !strchr("-._", id[i])) { | |||
751 | return 0; | |||
752 | } | |||
753 | } | |||
754 | return 1; | |||
755 | } | |||
756 | ||||
757 | QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, | |||
758 | int fail_if_exists, Error **errp) | |||
759 | { | |||
760 | QemuOpts *opts = NULL((void*)0); | |||
761 | ||||
762 | if (id) { | |||
763 | if (!id_wellformed(id)) { | |||
764 | error_set(errp,QERR_INVALID_PARAMETER_VALUEERROR_CLASS_GENERIC_ERROR, "Parameter '%s' expects %s", "id", "an identifier"); | |||
765 | #if 0 /* conversion from qerror_report() to error_set() broke this: */ | |||
766 | error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n"); | |||
767 | #endif | |||
768 | return NULL((void*)0); | |||
769 | } | |||
770 | opts = qemu_opts_find(list, id); | |||
771 | if (opts != NULL((void*)0)) { | |||
772 | if (fail_if_exists && !list->merge_lists) { | |||
773 | error_set(errp, QERR_DUPLICATE_IDERROR_CLASS_GENERIC_ERROR, "Duplicate ID '%s' for %s", id, list->name); | |||
774 | return NULL((void*)0); | |||
775 | } else { | |||
776 | return opts; | |||
777 | } | |||
778 | } | |||
779 | } else if (list->merge_lists) { | |||
780 | opts = qemu_opts_find(list, NULL((void*)0)); | |||
781 | if (opts) { | |||
782 | return opts; | |||
783 | } | |||
784 | } | |||
785 | opts = g_malloc0(sizeof(*opts)); | |||
786 | opts->id = g_strdup(id); | |||
787 | opts->list = list; | |||
788 | loc_save(&opts->loc); | |||
789 | QTAILQ_INIT(&opts->head)do { (&opts->head)->tqh_first = ((void*)0); (&opts ->head)->tqh_last = &(&opts->head)->tqh_first ; } while ( 0); | |||
790 | QTAILQ_INSERT_TAIL(&list->head, opts, next)do { (opts)->next.tqe_next = ((void*)0); (opts)->next.tqe_prev = (&list->head)->tqh_last; *(&list->head)-> tqh_last = (opts); (&list->head)->tqh_last = &( opts)->next.tqe_next; } while ( 0); | |||
791 | return opts; | |||
792 | } | |||
793 | ||||
794 | QemuOpts *qemu_opts_create_nofail(QemuOptsList *list) | |||
795 | { | |||
796 | QemuOpts *opts; | |||
797 | Error *errp = NULL((void*)0); | |||
798 | opts = qemu_opts_create(list, NULL((void*)0), 0, &errp); | |||
799 | assert_no_error(errp); | |||
800 | return opts; | |||
801 | } | |||
802 | ||||
803 | void qemu_opts_reset(QemuOptsList *list) | |||
804 | { | |||
805 | QemuOpts *opts, *next_opts; | |||
806 | ||||
807 | QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts)for ((opts) = ((&list->head)->tqh_first); (opts) && ((next_opts) = ((opts)->next.tqe_next), 1); (opts) = (next_opts )) { | |||
808 | qemu_opts_del(opts); | |||
809 | } | |||
810 | } | |||
811 | ||||
812 | void qemu_opts_loc_restore(QemuOpts *opts) | |||
813 | { | |||
814 | loc_restore(&opts->loc); | |||
815 | } | |||
816 | ||||
817 | int qemu_opts_set(QemuOptsList *list, const char *id, | |||
818 | const char *name, const char *value) | |||
819 | { | |||
820 | QemuOpts *opts; | |||
821 | Error *local_err = NULL((void*)0); | |||
822 | ||||
823 | opts = qemu_opts_create(list, id, 1, &local_err); | |||
824 | if (error_is_set(&local_err)) { | |||
825 | qerror_report_err(local_err); | |||
826 | error_free(local_err); | |||
827 | return -1; | |||
828 | } | |||
829 | return qemu_opt_set(opts, name, value); | |||
830 | } | |||
831 | ||||
832 | const char *qemu_opts_id(QemuOpts *opts) | |||
833 | { | |||
834 | return opts->id; | |||
835 | } | |||
836 | ||||
837 | /* The id string will be g_free()d by qemu_opts_del */ | |||
838 | void qemu_opts_set_id(QemuOpts *opts, char *id) | |||
839 | { | |||
840 | opts->id = id; | |||
841 | } | |||
842 | ||||
843 | void qemu_opts_del(QemuOpts *opts) | |||
844 | { | |||
845 | QemuOpt *opt; | |||
846 | ||||
847 | for (;;) { | |||
848 | opt = QTAILQ_FIRST(&opts->head)((&opts->head)->tqh_first); | |||
849 | if (opt == NULL((void*)0)) | |||
850 | break; | |||
851 | qemu_opt_del(opt); | |||
852 | } | |||
853 | QTAILQ_REMOVE(&opts->list->head, opts, next)do { if (((opts)->next.tqe_next) != ((void*)0)) (opts)-> next.tqe_next->next.tqe_prev = (opts)->next.tqe_prev; else (&opts->list->head)->tqh_last = (opts)->next .tqe_prev; *(opts)->next.tqe_prev = (opts)->next.tqe_next ; } while ( 0); | |||
854 | g_free(opts->id); | |||
855 | g_free(opts); | |||
856 | } | |||
857 | ||||
858 | int qemu_opts_print(QemuOpts *opts, void *dummy) | |||
859 | { | |||
860 | QemuOpt *opt; | |||
861 | ||||
862 | fprintf(stderrstderr, "%s: %s:", opts->list->name, | |||
863 | opts->id ? opts->id : "<noid>"); | |||
864 | QTAILQ_FOREACH(opt, &opts->head, next)for ((opt) = ((&opts->head)->tqh_first); (opt); (opt ) = ((opt)->next.tqe_next)) { | |||
865 | fprintf(stderrstderr, " %s=\"%s\"", opt->name, opt->str); | |||
866 | } | |||
867 | fprintf(stderrstderr, "\n"); | |||
868 | return 0; | |||
869 | } | |||
870 | ||||
871 | static int opts_do_parse(QemuOpts *opts, const char *params, | |||
872 | const char *firstname, bool_Bool prepend) | |||
873 | { | |||
874 | char option[128], value[1024]; | |||
875 | const char *p,*pe,*pc; | |||
876 | Error *local_err = NULL((void*)0); | |||
877 | ||||
878 | for (p = params; *p != '\0'; p++) { | |||
879 | pe = strchr(p, '='); | |||
880 | pc = strchr(p, ','); | |||
881 | if (!pe || (pc && pc < pe)) { | |||
882 | /* found "foo,more" */ | |||
883 | if (p == params && firstname) { | |||
884 | /* implicitly named first option */ | |||
885 | pstrcpy(option, sizeof(option), firstname); | |||
886 | p = get_opt_value(value, sizeof(value), p); | |||
887 | } else { | |||
888 | /* option without value, probably a flag */ | |||
889 | p = get_opt_name(option, sizeof(option), p, ','); | |||
890 | if (strncmp(option, "no", 2) == 0) { | |||
891 | memmove(option, option+2, strlen(option+2)+1); | |||
892 | pstrcpy(value, sizeof(value), "off"); | |||
893 | } else { | |||
894 | pstrcpy(value, sizeof(value), "on"); | |||
895 | } | |||
896 | } | |||
897 | } else { | |||
898 | /* found "foo=bar,more" */ | |||
899 | p = get_opt_name(option, sizeof(option), p, '='); | |||
900 | if (*p != '=') { | |||
901 | break; | |||
902 | } | |||
903 | p++; | |||
904 | p = get_opt_value(value, sizeof(value), p); | |||
905 | } | |||
906 | if (strcmp(option, "id") != 0) { | |||
907 | /* store and parse */ | |||
908 | opt_set(opts, option, value, prepend, &local_err); | |||
909 | if (error_is_set(&local_err)) { | |||
910 | qerror_report_err(local_err); | |||
911 | error_free(local_err); | |||
912 | return -1; | |||
913 | } | |||
914 | } | |||
915 | if (*p != ',') { | |||
916 | break; | |||
917 | } | |||
918 | } | |||
919 | return 0; | |||
920 | } | |||
921 | ||||
922 | int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname) | |||
923 | { | |||
924 | return opts_do_parse(opts, params, firstname, false0); | |||
925 | } | |||
926 | ||||
927 | static QemuOpts *opts_parse(QemuOptsList *list, const char *params, | |||
928 | int permit_abbrev, bool_Bool defaults) | |||
929 | { | |||
930 | const char *firstname; | |||
931 | char value[1024], *id = NULL((void*)0); | |||
932 | const char *p; | |||
933 | QemuOpts *opts; | |||
934 | Error *local_err = NULL((void*)0); | |||
935 | ||||
936 | assert(!permit_abbrev || list->implied_opt_name)((!permit_abbrev || list->implied_opt_name) ? (void) (0) : __assert_fail ("!permit_abbrev || list->implied_opt_name" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 936 , __PRETTY_FUNCTION__)); | |||
937 | firstname = permit_abbrev ? list->implied_opt_name : NULL((void*)0); | |||
938 | ||||
939 | if (strncmp(params, "id=", 3) == 0) { | |||
940 | get_opt_value(value, sizeof(value), params+3); | |||
941 | id = value; | |||
942 | } else if ((p = strstr(params, ",id=")) != NULL((void*)0)) { | |||
943 | get_opt_value(value, sizeof(value), p+4); | |||
944 | id = value; | |||
945 | } | |||
946 | ||||
947 | /* | |||
948 | * This code doesn't work for defaults && !list->merge_lists: when | |||
949 | * params has no id=, and list has an element with !opts->id, it | |||
950 | * appends a new element instead of returning the existing opts. | |||
951 | * However, we got no use for this case. Guard against possible | |||
952 | * (if unlikely) future misuse: | |||
953 | */ | |||
954 | assert(!defaults || list->merge_lists)((!defaults || list->merge_lists) ? (void) (0) : __assert_fail ("!defaults || list->merge_lists", "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c" , 954, __PRETTY_FUNCTION__)); | |||
955 | opts = qemu_opts_create(list, id, !defaults, &local_err); | |||
956 | if (opts == NULL((void*)0)) { | |||
957 | if (error_is_set(&local_err)) { | |||
958 | qerror_report_err(local_err); | |||
959 | error_free(local_err); | |||
960 | } | |||
961 | return NULL((void*)0); | |||
962 | } | |||
963 | ||||
964 | if (opts_do_parse(opts, params, firstname, defaults) != 0) { | |||
965 | qemu_opts_del(opts); | |||
966 | return NULL((void*)0); | |||
967 | } | |||
968 | ||||
969 | return opts; | |||
970 | } | |||
971 | ||||
972 | QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, | |||
973 | int permit_abbrev) | |||
974 | { | |||
975 | return opts_parse(list, params, permit_abbrev, false0); | |||
976 | } | |||
977 | ||||
978 | void qemu_opts_set_defaults(QemuOptsList *list, const char *params, | |||
979 | int permit_abbrev) | |||
980 | { | |||
981 | QemuOpts *opts; | |||
982 | ||||
983 | opts = opts_parse(list, params, permit_abbrev, true1); | |||
984 | assert(opts)((opts) ? (void) (0) : __assert_fail ("opts", "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c" , 984, __PRETTY_FUNCTION__)); | |||
985 | } | |||
986 | ||||
987 | typedef struct OptsFromQDictState { | |||
988 | QemuOpts *opts; | |||
989 | Error **errp; | |||
990 | } OptsFromQDictState; | |||
991 | ||||
992 | static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque) | |||
993 | { | |||
994 | OptsFromQDictState *state = opaque; | |||
995 | char buf[32]; | |||
996 | const char *value; | |||
997 | int n; | |||
998 | ||||
999 | if (!strcmp(key, "id") || error_is_set(state->errp)) { | |||
1000 | return; | |||
1001 | } | |||
1002 | ||||
1003 | switch (qobject_type(obj)) { | |||
1004 | case QTYPE_QSTRING: | |||
1005 | value = qstring_get_str(qobject_to_qstring(obj)); | |||
1006 | break; | |||
1007 | case QTYPE_QINT: | |||
1008 | n = snprintf(buf, sizeof(buf), "%" PRId64"l" "d", | |||
1009 | qint_get_int(qobject_to_qint(obj))); | |||
1010 | assert(n < sizeof(buf))((n < sizeof(buf)) ? (void) (0) : __assert_fail ("n < sizeof(buf)" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 1010 , __PRETTY_FUNCTION__)); | |||
1011 | value = buf; | |||
1012 | break; | |||
1013 | case QTYPE_QFLOAT: | |||
1014 | n = snprintf(buf, sizeof(buf), "%.17g", | |||
1015 | qfloat_get_double(qobject_to_qfloat(obj))); | |||
1016 | assert(n < sizeof(buf))((n < sizeof(buf)) ? (void) (0) : __assert_fail ("n < sizeof(buf)" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 1016 , __PRETTY_FUNCTION__)); | |||
1017 | value = buf; | |||
1018 | break; | |||
1019 | case QTYPE_QBOOL: | |||
1020 | pstrcpy(buf, sizeof(buf), | |||
1021 | qbool_get_int(qobject_to_qbool(obj)) ? "on" : "off"); | |||
1022 | value = buf; | |||
1023 | break; | |||
1024 | default: | |||
1025 | return; | |||
1026 | } | |||
1027 | ||||
1028 | qemu_opt_set_err(state->opts, key, value, state->errp); | |||
1029 | } | |||
1030 | ||||
1031 | /* | |||
1032 | * Create QemuOpts from a QDict. | |||
1033 | * Use value of key "id" as ID if it exists and is a QString. | |||
1034 | * Only QStrings, QInts, QFloats and QBools are copied. Entries with | |||
1035 | * other types are silently ignored. | |||
1036 | */ | |||
1037 | QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, | |||
1038 | Error **errp) | |||
1039 | { | |||
1040 | OptsFromQDictState state; | |||
1041 | Error *local_err = NULL((void*)0); | |||
1042 | QemuOpts *opts; | |||
1043 | ||||
1044 | opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, | |||
1045 | &local_err); | |||
1046 | if (error_is_set(&local_err)) { | |||
1047 | error_propagate(errp, local_err); | |||
1048 | return NULL((void*)0); | |||
1049 | } | |||
1050 | ||||
1051 | assert(opts != NULL)((opts != ((void*)0)) ? (void) (0) : __assert_fail ("opts != ((void*)0)" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 1051 , __PRETTY_FUNCTION__)); | |||
1052 | ||||
1053 | state.errp = &local_err; | |||
1054 | state.opts = opts; | |||
1055 | qdict_iter(qdict, qemu_opts_from_qdict_1, &state); | |||
1056 | if (error_is_set(&local_err)) { | |||
1057 | error_propagate(errp, local_err); | |||
1058 | qemu_opts_del(opts); | |||
1059 | return NULL((void*)0); | |||
1060 | } | |||
1061 | ||||
1062 | return opts; | |||
1063 | } | |||
1064 | ||||
1065 | /* | |||
1066 | * Adds all QDict entries to the QemuOpts that can be added and removes them | |||
1067 | * from the QDict. When this function returns, the QDict contains only those | |||
1068 | * entries that couldn't be added to the QemuOpts. | |||
1069 | */ | |||
1070 | void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) | |||
1071 | { | |||
1072 | const QDictEntry *entry, *next; | |||
1073 | ||||
1074 | entry = qdict_first(qdict); | |||
1075 | ||||
1076 | while (entry != NULL((void*)0)) { | |||
1077 | Error *local_err = NULL((void*)0); | |||
1078 | OptsFromQDictState state = { | |||
1079 | .errp = &local_err, | |||
1080 | .opts = opts, | |||
1081 | }; | |||
1082 | ||||
1083 | next = qdict_next(qdict, entry); | |||
1084 | ||||
1085 | if (find_desc_by_name(opts->list->desc, entry->key)) { | |||
1086 | qemu_opts_from_qdict_1(entry->key, entry->value, &state); | |||
1087 | if (error_is_set(&local_err)) { | |||
1088 | error_propagate(errp, local_err); | |||
1089 | return; | |||
1090 | } else { | |||
1091 | qdict_del(qdict, entry->key); | |||
1092 | } | |||
1093 | } | |||
1094 | ||||
1095 | entry = next; | |||
1096 | } | |||
1097 | } | |||
1098 | ||||
1099 | /* | |||
1100 | * Convert from QemuOpts to QDict. | |||
1101 | * The QDict values are of type QString. | |||
1102 | * TODO We'll want to use types appropriate for opt->desc->type, but | |||
1103 | * this is enough for now. | |||
1104 | */ | |||
1105 | QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict) | |||
1106 | { | |||
1107 | QemuOpt *opt; | |||
1108 | QObject *val; | |||
1109 | ||||
1110 | if (!qdict) { | |||
1111 | qdict = qdict_new(); | |||
1112 | } | |||
1113 | if (opts->id) { | |||
1114 | qdict_put(qdict, "id", qstring_from_str(opts->id))qdict_put_obj(qdict, "id", (&(qstring_from_str(opts->id ))->base)); | |||
1115 | } | |||
1116 | QTAILQ_FOREACH(opt, &opts->head, next)for ((opt) = ((&opts->head)->tqh_first); (opt); (opt ) = ((opt)->next.tqe_next)) { | |||
1117 | val = QOBJECT(qstring_from_str(opt->str))(&(qstring_from_str(opt->str))->base); | |||
1118 | qdict_put_obj(qdict, opt->name, val); | |||
1119 | } | |||
1120 | return qdict; | |||
1121 | } | |||
1122 | ||||
1123 | /* Validate parsed opts against descriptions where no | |||
1124 | * descriptions were provided in the QemuOptsList. | |||
1125 | */ | |||
1126 | void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) | |||
1127 | { | |||
1128 | QemuOpt *opt; | |||
1129 | Error *local_err = NULL((void*)0); | |||
1130 | ||||
1131 | assert(opts_accepts_any(opts))((opts_accepts_any(opts)) ? (void) (0) : __assert_fail ("opts_accepts_any(opts)" , "/home/stefan/src/qemu/qemu.org/qemu/util/qemu-option.c", 1131 , __PRETTY_FUNCTION__)); | |||
1132 | ||||
1133 | QTAILQ_FOREACH(opt, &opts->head, next)for ((opt) = ((&opts->head)->tqh_first); (opt); (opt ) = ((opt)->next.tqe_next)) { | |||
1134 | opt->desc = find_desc_by_name(desc, opt->name); | |||
1135 | if (!opt->desc) { | |||
1136 | error_set(errp, QERR_INVALID_PARAMETERERROR_CLASS_GENERIC_ERROR, "Invalid parameter '%s'", opt->name); | |||
1137 | return; | |||
1138 | } | |||
1139 | ||||
1140 | qemu_opt_parse(opt, &local_err); | |||
1141 | if (error_is_set(&local_err)) { | |||
1142 | error_propagate(errp, local_err); | |||
1143 | return; | |||
1144 | } | |||
1145 | } | |||
1146 | } | |||
1147 | ||||
1148 | int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, | |||
1149 | int abort_on_failure) | |||
1150 | { | |||
1151 | Location loc; | |||
1152 | QemuOpts *opts; | |||
1153 | int rc = 0; | |||
1154 | ||||
1155 | loc_push_none(&loc); | |||
1156 | QTAILQ_FOREACH(opts, &list->head, next)for ((opts) = ((&list->head)->tqh_first); (opts); ( opts) = ((opts)->next.tqe_next)) { | |||
1157 | loc_restore(&opts->loc); | |||
1158 | rc |= func(opts, opaque); | |||
1159 | if (abort_on_failure && rc != 0) | |||
1160 | break; | |||
1161 | } | |||
1162 | loc_pop(&loc); | |||
1163 | return rc; | |||
1164 | } |