blob: 324b197495a0c55f533f37965838df3ab41363bd [file] [log] [blame]
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +02001/*
2 * Options Visitor
3 *
Eric Blake08f95412016-01-29 06:48:59 -07004 * Copyright Red Hat, Inc. 2012-2016
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +02005 *
6 * Author: Laszlo Ersek <lersek@redhat.com>
7 *
8 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
9 * See the COPYING.LIB file in the top-level directory.
10 *
11 */
12
Peter Maydellcbf21152016-01-29 17:49:57 +000013#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010014#include "qapi/error.h"
Veronia Bahaaf348b6d2016-03-20 19:16:19 +020015#include "qemu/cutils.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010016#include "qapi/qmp/qerror.h"
17#include "qapi/opts-visitor.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010018#include "qemu/queue.h"
19#include "qemu/option_int.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010020#include "qapi/visitor-impl.h"
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +020021
22
Laszlo Ersekd9570432013-08-20 00:35:33 +020023enum ListMode
24{
25 LM_NONE, /* not traversing a list of repeated options */
Laszlo Ersekd8754f42013-08-20 00:35:34 +020026
Eric Blaked9f62dd2016-04-28 15:45:31 -060027 LM_IN_PROGRESS, /* opts_next_list() ready to be called.
Laszlo Ersekd8754f42013-08-20 00:35:34 +020028 *
29 * Generating the next list link will consume the most
30 * recently parsed QemuOpt instance of the repeated
31 * option.
32 *
33 * Parsing a value into the list link will examine the
34 * next QemuOpt instance of the repeated option, and
35 * possibly enter LM_SIGNED_INTERVAL or
36 * LM_UNSIGNED_INTERVAL.
37 */
38
39 LM_SIGNED_INTERVAL, /* opts_next_list() has been called.
40 *
41 * Generating the next list link will consume the most
42 * recently stored element from the signed interval,
43 * parsed from the most recent QemuOpt instance of the
44 * repeated option. This may consume QemuOpt itself
45 * and return to LM_IN_PROGRESS.
46 *
47 * Parsing a value into the list link will store the
48 * next element of the signed interval.
49 */
50
51 LM_UNSIGNED_INTERVAL /* Same as above, only for an unsigned interval. */
Laszlo Ersekd9570432013-08-20 00:35:33 +020052};
53
54typedef enum ListMode ListMode;
55
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +020056struct OptsVisitor
57{
58 Visitor visitor;
59
60 /* Ownership remains with opts_visitor_new()'s caller. */
61 const QemuOpts *opts_root;
62
63 unsigned depth;
64
65 /* Non-null iff depth is positive. Each key is a QemuOpt name. Each value
66 * is a non-empty GQueue, enumerating all QemuOpt occurrences with that
67 * name. */
68 GHashTable *unprocessed_opts;
69
70 /* The list currently being traversed with opts_start_list() /
71 * opts_next_list(). The list must have a struct element type in the
72 * schema, with a single mandatory scalar member. */
Laszlo Ersekd9570432013-08-20 00:35:33 +020073 ListMode list_mode;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +020074 GQueue *repeated_opts;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +020075
Laszlo Ersekd8754f42013-08-20 00:35:34 +020076 /* When parsing a list of repeating options as integers, values of the form
77 * "a-b", representing a closed interval, are allowed. Elements in the
78 * range are generated individually.
79 */
80 union {
81 int64_t s;
82 uint64_t u;
83 } range_next, range_limit;
84
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +020085 /* If "opts_root->id" is set, reinstantiate it as a fake QemuOpt for
86 * uniformity. Only its "name" and "str" fields are set. "fake_id_opt" does
87 * not survive or escape the OptsVisitor object.
88 */
89 QemuOpt *fake_id_opt;
90};
91
92
Eric Blaked7bea752016-01-29 06:48:38 -070093static OptsVisitor *to_ov(Visitor *v)
94{
95 return container_of(v, OptsVisitor, visitor);
96}
97
98
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +020099static void
100destroy_list(gpointer list)
101{
102 g_queue_free(list);
103}
104
105
106static void
107opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt)
108{
109 GQueue *list;
110
111 list = g_hash_table_lookup(unprocessed_opts, opt->name);
112 if (list == NULL) {
113 list = g_queue_new();
114
115 /* GHashTable will never try to free the keys -- we supply NULL as
116 * "key_destroy_func" in opts_start_struct(). Thus cast away key
117 * const-ness in order to suppress gcc's warning.
118 */
119 g_hash_table_insert(unprocessed_opts, (gpointer)opt->name, list);
120 }
121
122 /* Similarly, destroy_list() doesn't call g_queue_free_full(). */
123 g_queue_push_tail(list, (gpointer)opt);
124}
125
126
127static void
Eric Blake337283d2016-01-29 06:48:57 -0700128opts_start_struct(Visitor *v, const char *name, void **obj,
Eric Blake0b2a0d62016-01-29 06:48:56 -0700129 size_t size, Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200130{
Eric Blaked7bea752016-01-29 06:48:38 -0700131 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200132 const QemuOpt *opt;
133
Markus Armbrusterb7745392014-03-01 08:40:39 +0100134 if (obj) {
Eric Blakee58d6952016-04-28 15:45:10 -0600135 *obj = g_malloc0(size);
Markus Armbrusterb7745392014-03-01 08:40:39 +0100136 }
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200137 if (ov->depth++ > 0) {
138 return;
139 }
140
141 ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal,
142 NULL, &destroy_list);
143 QTAILQ_FOREACH(opt, &ov->opts_root->head, next) {
144 /* ensured by qemu-option.c::opts_do_parse() */
145 assert(strcmp(opt->name, "id") != 0);
146
147 opts_visitor_insert(ov->unprocessed_opts, opt);
148 }
149
150 if (ov->opts_root->id != NULL) {
151 ov->fake_id_opt = g_malloc0(sizeof *ov->fake_id_opt);
152
Chunyan Liudc8622f2014-06-05 17:20:44 +0800153 ov->fake_id_opt->name = g_strdup("id");
154 ov->fake_id_opt->str = g_strdup(ov->opts_root->id);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200155 opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt);
156 }
157}
158
159
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200160static void
Eric Blake15c2f662016-04-28 15:45:27 -0600161opts_check_struct(Visitor *v, Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200162{
Eric Blaked7bea752016-01-29 06:48:38 -0700163 OptsVisitor *ov = to_ov(v);
Eric Blakef96493b2016-02-17 23:48:15 -0700164 GHashTableIter iter;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200165 GQueue *any;
166
Eric Blake21f88d02017-03-22 09:45:25 -0500167 if (ov->depth > 1) {
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200168 return;
169 }
170
171 /* we should have processed all (distinct) QemuOpt instances */
Eric Blakef96493b2016-02-17 23:48:15 -0700172 g_hash_table_iter_init(&iter, ov->unprocessed_opts);
173 if (g_hash_table_iter_next(&iter, NULL, (void **)&any)) {
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200174 const QemuOpt *first;
175
176 first = g_queue_peek_head(any);
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100177 error_setg(errp, QERR_INVALID_PARAMETER, first->name);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200178 }
Eric Blake15c2f662016-04-28 15:45:27 -0600179}
180
181
182static void
Eric Blake1158bb22016-06-09 10:48:34 -0600183opts_end_struct(Visitor *v, void **obj)
Eric Blake15c2f662016-04-28 15:45:27 -0600184{
185 OptsVisitor *ov = to_ov(v);
186
187 if (--ov->depth > 0) {
188 return;
189 }
190
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200191 g_hash_table_destroy(ov->unprocessed_opts);
192 ov->unprocessed_opts = NULL;
Chunyan Liudc8622f2014-06-05 17:20:44 +0800193 if (ov->fake_id_opt) {
194 g_free(ov->fake_id_opt->name);
195 g_free(ov->fake_id_opt->str);
196 g_free(ov->fake_id_opt);
197 }
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200198 ov->fake_id_opt = NULL;
199}
200
201
202static GQueue *
203lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp)
204{
205 GQueue *list;
206
207 list = g_hash_table_lookup(ov->unprocessed_opts, name);
208 if (!list) {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100209 error_setg(errp, QERR_MISSING_PARAMETER, name);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200210 }
211 return list;
212}
213
214
215static void
Eric Blaked9f62dd2016-04-28 15:45:31 -0600216opts_start_list(Visitor *v, const char *name, GenericList **list, size_t size,
217 Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200218{
Eric Blaked7bea752016-01-29 06:48:38 -0700219 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200220
221 /* we can't traverse a list in a list */
Laszlo Ersekd9570432013-08-20 00:35:33 +0200222 assert(ov->list_mode == LM_NONE);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600223 /* we don't support visits without a list */
224 assert(list);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200225 ov->repeated_opts = lookup_distinct(ov, name, errp);
Eric Blaked9f62dd2016-04-28 15:45:31 -0600226 if (ov->repeated_opts) {
227 ov->list_mode = LM_IN_PROGRESS;
228 *list = g_malloc0(size);
229 } else {
230 *list = NULL;
Laszlo Ersekd9570432013-08-20 00:35:33 +0200231 }
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200232}
233
234
235static GenericList *
Eric Blaked9f62dd2016-04-28 15:45:31 -0600236opts_next_list(Visitor *v, GenericList *tail, size_t size)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200237{
Eric Blaked7bea752016-01-29 06:48:38 -0700238 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200239
Laszlo Ersekd9570432013-08-20 00:35:33 +0200240 switch (ov->list_mode) {
Laszlo Ersekd8754f42013-08-20 00:35:34 +0200241 case LM_SIGNED_INTERVAL:
242 case LM_UNSIGNED_INTERVAL:
Laszlo Ersekd8754f42013-08-20 00:35:34 +0200243 if (ov->list_mode == LM_SIGNED_INTERVAL) {
244 if (ov->range_next.s < ov->range_limit.s) {
245 ++ov->range_next.s;
246 break;
247 }
248 } else if (ov->range_next.u < ov->range_limit.u) {
249 ++ov->range_next.u;
250 break;
251 }
252 ov->list_mode = LM_IN_PROGRESS;
253 /* range has been completed, fall through in order to pop option */
254
Laszlo Ersekd9570432013-08-20 00:35:33 +0200255 case LM_IN_PROGRESS: {
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200256 const QemuOpt *opt;
257
258 opt = g_queue_pop_head(ov->repeated_opts);
259 if (g_queue_is_empty(ov->repeated_opts)) {
260 g_hash_table_remove(ov->unprocessed_opts, opt->name);
261 return NULL;
262 }
Laszlo Ersekd9570432013-08-20 00:35:33 +0200263 break;
264 }
265
266 default:
267 abort();
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200268 }
269
Eric Blaked9f62dd2016-04-28 15:45:31 -0600270 tail->next = g_malloc0(size);
271 return tail->next;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200272}
273
274
275static void
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100276opts_check_list(Visitor *v, Error **errp)
277{
278 /*
Eric Blake21f88d02017-03-22 09:45:25 -0500279 * Unvisited list elements will be reported later when checking
280 * whether unvisited struct members remain.
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100281 */
282}
283
284
285static void
Eric Blake1158bb22016-06-09 10:48:34 -0600286opts_end_list(Visitor *v, void **obj)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200287{
Eric Blaked7bea752016-01-29 06:48:38 -0700288 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200289
Eric Blaked9f62dd2016-04-28 15:45:31 -0600290 assert(ov->list_mode == LM_IN_PROGRESS ||
Laszlo Ersekd8754f42013-08-20 00:35:34 +0200291 ov->list_mode == LM_SIGNED_INTERVAL ||
292 ov->list_mode == LM_UNSIGNED_INTERVAL);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200293 ov->repeated_opts = NULL;
Laszlo Ersekd9570432013-08-20 00:35:33 +0200294 ov->list_mode = LM_NONE;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200295}
296
297
298static const QemuOpt *
299lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp)
300{
Laszlo Ersekd9570432013-08-20 00:35:33 +0200301 if (ov->list_mode == LM_NONE) {
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200302 GQueue *list;
303
304 /* the last occurrence of any QemuOpt takes effect when queried by name
305 */
306 list = lookup_distinct(ov, name, errp);
307 return list ? g_queue_peek_tail(list) : NULL;
308 }
Laszlo Ersekd9570432013-08-20 00:35:33 +0200309 assert(ov->list_mode == LM_IN_PROGRESS);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200310 return g_queue_peek_head(ov->repeated_opts);
311}
312
313
314static void
315processed(OptsVisitor *ov, const char *name)
316{
Laszlo Ersekd9570432013-08-20 00:35:33 +0200317 if (ov->list_mode == LM_NONE) {
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200318 g_hash_table_remove(ov->unprocessed_opts, name);
Laszlo Ersekd9570432013-08-20 00:35:33 +0200319 return;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200320 }
Laszlo Ersekd9570432013-08-20 00:35:33 +0200321 assert(ov->list_mode == LM_IN_PROGRESS);
322 /* do nothing */
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200323}
324
325
326static void
Eric Blake0b2a0d62016-01-29 06:48:56 -0700327opts_type_str(Visitor *v, const char *name, char **obj, Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200328{
Eric Blaked7bea752016-01-29 06:48:38 -0700329 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200330 const QemuOpt *opt;
331
332 opt = lookup_scalar(ov, name, errp);
333 if (!opt) {
Eric Blakee58d6952016-04-28 15:45:10 -0600334 *obj = NULL;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200335 return;
336 }
337 *obj = g_strdup(opt->str ? opt->str : "");
Eric Blake983f52d2016-04-28 15:45:09 -0600338 /* Note that we consume a string even if this is called as part of
339 * an enum visit that later fails because the string is not a
340 * valid enum value; this is harmless because tracking what gets
341 * consumed only matters to visit_end_struct() as the final error
342 * check if there were no other failures during the visit. */
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200343 processed(ov, name);
344}
345
346
347/* mimics qemu-option.c::parse_option_bool() */
348static void
Eric Blake0b2a0d62016-01-29 06:48:56 -0700349opts_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200350{
Eric Blaked7bea752016-01-29 06:48:38 -0700351 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200352 const QemuOpt *opt;
353
354 opt = lookup_scalar(ov, name, errp);
355 if (!opt) {
356 return;
357 }
358
359 if (opt->str) {
360 if (strcmp(opt->str, "on") == 0 ||
361 strcmp(opt->str, "yes") == 0 ||
362 strcmp(opt->str, "y") == 0) {
363 *obj = true;
364 } else if (strcmp(opt->str, "off") == 0 ||
365 strcmp(opt->str, "no") == 0 ||
366 strcmp(opt->str, "n") == 0) {
367 *obj = false;
368 } else {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100369 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
370 "on|yes|y|off|no|n");
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200371 return;
372 }
373 } else {
374 *obj = true;
375 }
376
377 processed(ov, name);
378}
379
380
381static void
Eric Blake0b2a0d62016-01-29 06:48:56 -0700382opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200383{
Eric Blaked7bea752016-01-29 06:48:38 -0700384 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200385 const QemuOpt *opt;
386 const char *str;
387 long long val;
388 char *endptr;
389
Laszlo Ersekd8754f42013-08-20 00:35:34 +0200390 if (ov->list_mode == LM_SIGNED_INTERVAL) {
391 *obj = ov->range_next.s;
392 return;
393 }
394
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200395 opt = lookup_scalar(ov, name, errp);
396 if (!opt) {
397 return;
398 }
399 str = opt->str ? opt->str : "";
400
Laszlo Ersek1e1c5552013-08-20 00:35:35 +0200401 /* we've gotten past lookup_scalar() */
402 assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS);
403
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200404 errno = 0;
405 val = strtoll(str, &endptr, 0);
Laszlo Ersek1e1c5552013-08-20 00:35:35 +0200406 if (errno == 0 && endptr > str && INT64_MIN <= val && val <= INT64_MAX) {
407 if (*endptr == '\0') {
408 *obj = val;
409 processed(ov, name);
410 return;
411 }
412 if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) {
413 long long val2;
414
415 str = endptr + 1;
416 val2 = strtoll(str, &endptr, 0);
417 if (errno == 0 && endptr > str && *endptr == '\0' &&
Laszlo Ersek15a849b2013-08-20 00:35:38 +0200418 INT64_MIN <= val2 && val2 <= INT64_MAX && val <= val2 &&
419 (val > INT64_MAX - OPTS_VISITOR_RANGE_MAX ||
420 val2 < val + OPTS_VISITOR_RANGE_MAX)) {
Laszlo Ersek1e1c5552013-08-20 00:35:35 +0200421 ov->range_next.s = val;
422 ov->range_limit.s = val2;
423 ov->list_mode = LM_SIGNED_INTERVAL;
424
425 /* as if entering on the top */
426 *obj = ov->range_next.s;
427 return;
428 }
429 }
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200430 }
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100431 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
432 (ov->list_mode == LM_NONE) ? "an int64 value" :
433 "an int64 value or range");
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200434}
435
436
437static void
Eric Blake0b2a0d62016-01-29 06:48:56 -0700438opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200439{
Eric Blaked7bea752016-01-29 06:48:38 -0700440 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200441 const QemuOpt *opt;
442 const char *str;
Laszlo Ersek62d090e2013-08-20 00:35:36 +0200443 unsigned long long val;
Laszlo Ersek581a8a82013-08-20 00:35:37 +0200444 char *endptr;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200445
Laszlo Ersekd8754f42013-08-20 00:35:34 +0200446 if (ov->list_mode == LM_UNSIGNED_INTERVAL) {
447 *obj = ov->range_next.u;
448 return;
449 }
450
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200451 opt = lookup_scalar(ov, name, errp);
452 if (!opt) {
453 return;
454 }
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200455 str = opt->str;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200456
Laszlo Ersek581a8a82013-08-20 00:35:37 +0200457 /* we've gotten past lookup_scalar() */
458 assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS);
459
460 if (parse_uint(str, &val, &endptr, 0) == 0 && val <= UINT64_MAX) {
461 if (*endptr == '\0') {
462 *obj = val;
463 processed(ov, name);
464 return;
465 }
466 if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) {
467 unsigned long long val2;
468
469 str = endptr + 1;
470 if (parse_uint_full(str, &val2, 0) == 0 &&
Laszlo Ersek15a849b2013-08-20 00:35:38 +0200471 val2 <= UINT64_MAX && val <= val2 &&
472 val2 - val < OPTS_VISITOR_RANGE_MAX) {
Laszlo Ersek581a8a82013-08-20 00:35:37 +0200473 ov->range_next.u = val;
474 ov->range_limit.u = val2;
475 ov->list_mode = LM_UNSIGNED_INTERVAL;
476
477 /* as if entering on the top */
478 *obj = ov->range_next.u;
479 return;
480 }
481 }
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200482 }
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100483 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
484 (ov->list_mode == LM_NONE) ? "a uint64 value" :
485 "a uint64 value or range");
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200486}
487
488
489static void
Eric Blake0b2a0d62016-01-29 06:48:56 -0700490opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200491{
Eric Blaked7bea752016-01-29 06:48:38 -0700492 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200493 const QemuOpt *opt;
Markus Armbrusterf17fd4f2017-02-21 21:14:06 +0100494 int err;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200495
496 opt = lookup_scalar(ov, name, errp);
497 if (!opt) {
498 return;
499 }
500
Markus Armbrusterf46bfdb2017-02-21 21:14:07 +0100501 err = qemu_strtosz(opt->str ? opt->str : "", NULL, obj);
Markus Armbrusterf17fd4f2017-02-21 21:14:06 +0100502 if (err < 0) {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100503 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
Markus Armbrusterf46bfdb2017-02-21 21:14:07 +0100504 "a size value");
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200505 return;
506 }
Amos Kongcb45de62014-04-28 13:53:49 +0800507
Amos Kongcb45de62014-04-28 13:53:49 +0800508 processed(ov, name);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200509}
510
511
512static void
Eric Blake0b2a0d62016-01-29 06:48:56 -0700513opts_optional(Visitor *v, const char *name, bool *present)
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200514{
Eric Blaked7bea752016-01-29 06:48:38 -0700515 OptsVisitor *ov = to_ov(v);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200516
517 /* we only support a single mandatory scalar field in a list node */
Laszlo Ersekd9570432013-08-20 00:35:33 +0200518 assert(ov->list_mode == LM_NONE);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200519 *present = (lookup_distinct(ov, name, NULL) != NULL);
520}
521
522
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600523static void
524opts_free(Visitor *v)
525{
526 OptsVisitor *ov = to_ov(v);
527
Eric Blake09204ea2016-06-09 10:48:36 -0600528 if (ov->unprocessed_opts != NULL) {
529 g_hash_table_destroy(ov->unprocessed_opts);
530 }
531 g_free(ov->fake_id_opt);
532 g_free(ov);
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600533}
534
535
Eric Blake09204ea2016-06-09 10:48:36 -0600536Visitor *
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200537opts_visitor_new(const QemuOpts *opts)
538{
539 OptsVisitor *ov;
540
Markus Armbrusterf332e832017-03-03 13:32:36 +0100541 assert(opts);
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200542 ov = g_malloc0(sizeof *ov);
543
Eric Blake983f52d2016-04-28 15:45:09 -0600544 ov->visitor.type = VISITOR_INPUT;
545
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200546 ov->visitor.start_struct = &opts_start_struct;
Eric Blake15c2f662016-04-28 15:45:27 -0600547 ov->visitor.check_struct = &opts_check_struct;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200548 ov->visitor.end_struct = &opts_end_struct;
549
550 ov->visitor.start_list = &opts_start_list;
551 ov->visitor.next_list = &opts_next_list;
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100552 ov->visitor.check_list = &opts_check_list;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200553 ov->visitor.end_list = &opts_end_list;
554
Eric Blake4c403142016-01-29 06:48:49 -0700555 ov->visitor.type_int64 = &opts_type_int64;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200556 ov->visitor.type_uint64 = &opts_type_uint64;
557 ov->visitor.type_size = &opts_type_size;
558 ov->visitor.type_bool = &opts_type_bool;
559 ov->visitor.type_str = &opts_type_str;
560
561 /* type_number() is not filled in, but this is not the first visitor to
562 * skip some mandatory methods... */
563
Markus Armbrustere2cd0f42014-05-07 09:53:46 +0200564 ov->visitor.optional = &opts_optional;
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600565 ov->visitor.free = opts_free;
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200566
567 ov->opts_root = opts;
568
Laszlo Ersekeb7ee2c2012-07-17 16:17:09 +0200569 return &ov->visitor;
570}