root / qapi / opts-visitor.c @ 79ee7df8
History | View | Annotate | Download (10.6 kB)
1 | eb7ee2cb | Laszlo Ersek | /*
|
---|---|---|---|
2 | eb7ee2cb | Laszlo Ersek | * Options Visitor
|
3 | eb7ee2cb | Laszlo Ersek | *
|
4 | eb7ee2cb | Laszlo Ersek | * Copyright Red Hat, Inc. 2012
|
5 | eb7ee2cb | Laszlo Ersek | *
|
6 | eb7ee2cb | Laszlo Ersek | * Author: Laszlo Ersek <lersek@redhat.com>
|
7 | eb7ee2cb | Laszlo Ersek | *
|
8 | eb7ee2cb | Laszlo Ersek | * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
9 | eb7ee2cb | Laszlo Ersek | * See the COPYING.LIB file in the top-level directory.
|
10 | eb7ee2cb | Laszlo Ersek | *
|
11 | eb7ee2cb | Laszlo Ersek | */
|
12 | eb7ee2cb | Laszlo Ersek | |
13 | 79ee7df8 | Paolo Bonzini | #include "qemu-common.h" |
14 | eb7ee2cb | Laszlo Ersek | #include "opts-visitor.h" |
15 | eb7ee2cb | Laszlo Ersek | #include "qemu-queue.h" |
16 | eb7ee2cb | Laszlo Ersek | #include "qemu-option-internal.h" |
17 | eb7ee2cb | Laszlo Ersek | #include "qapi-visit-impl.h" |
18 | eb7ee2cb | Laszlo Ersek | |
19 | eb7ee2cb | Laszlo Ersek | |
20 | eb7ee2cb | Laszlo Ersek | struct OptsVisitor
|
21 | eb7ee2cb | Laszlo Ersek | { |
22 | eb7ee2cb | Laszlo Ersek | Visitor visitor; |
23 | eb7ee2cb | Laszlo Ersek | |
24 | eb7ee2cb | Laszlo Ersek | /* Ownership remains with opts_visitor_new()'s caller. */
|
25 | eb7ee2cb | Laszlo Ersek | const QemuOpts *opts_root;
|
26 | eb7ee2cb | Laszlo Ersek | |
27 | eb7ee2cb | Laszlo Ersek | unsigned depth;
|
28 | eb7ee2cb | Laszlo Ersek | |
29 | eb7ee2cb | Laszlo Ersek | /* Non-null iff depth is positive. Each key is a QemuOpt name. Each value
|
30 | eb7ee2cb | Laszlo Ersek | * is a non-empty GQueue, enumerating all QemuOpt occurrences with that
|
31 | eb7ee2cb | Laszlo Ersek | * name. */
|
32 | eb7ee2cb | Laszlo Ersek | GHashTable *unprocessed_opts; |
33 | eb7ee2cb | Laszlo Ersek | |
34 | eb7ee2cb | Laszlo Ersek | /* The list currently being traversed with opts_start_list() /
|
35 | eb7ee2cb | Laszlo Ersek | * opts_next_list(). The list must have a struct element type in the
|
36 | eb7ee2cb | Laszlo Ersek | * schema, with a single mandatory scalar member. */
|
37 | eb7ee2cb | Laszlo Ersek | GQueue *repeated_opts; |
38 | eb7ee2cb | Laszlo Ersek | bool repeated_opts_first;
|
39 | eb7ee2cb | Laszlo Ersek | |
40 | eb7ee2cb | Laszlo Ersek | /* If "opts_root->id" is set, reinstantiate it as a fake QemuOpt for
|
41 | eb7ee2cb | Laszlo Ersek | * uniformity. Only its "name" and "str" fields are set. "fake_id_opt" does
|
42 | eb7ee2cb | Laszlo Ersek | * not survive or escape the OptsVisitor object.
|
43 | eb7ee2cb | Laszlo Ersek | */
|
44 | eb7ee2cb | Laszlo Ersek | QemuOpt *fake_id_opt; |
45 | eb7ee2cb | Laszlo Ersek | }; |
46 | eb7ee2cb | Laszlo Ersek | |
47 | eb7ee2cb | Laszlo Ersek | |
48 | eb7ee2cb | Laszlo Ersek | static void |
49 | eb7ee2cb | Laszlo Ersek | destroy_list(gpointer list) |
50 | eb7ee2cb | Laszlo Ersek | { |
51 | eb7ee2cb | Laszlo Ersek | g_queue_free(list); |
52 | eb7ee2cb | Laszlo Ersek | } |
53 | eb7ee2cb | Laszlo Ersek | |
54 | eb7ee2cb | Laszlo Ersek | |
55 | eb7ee2cb | Laszlo Ersek | static void |
56 | eb7ee2cb | Laszlo Ersek | opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt)
|
57 | eb7ee2cb | Laszlo Ersek | { |
58 | eb7ee2cb | Laszlo Ersek | GQueue *list; |
59 | eb7ee2cb | Laszlo Ersek | |
60 | eb7ee2cb | Laszlo Ersek | list = g_hash_table_lookup(unprocessed_opts, opt->name); |
61 | eb7ee2cb | Laszlo Ersek | if (list == NULL) { |
62 | eb7ee2cb | Laszlo Ersek | list = g_queue_new(); |
63 | eb7ee2cb | Laszlo Ersek | |
64 | eb7ee2cb | Laszlo Ersek | /* GHashTable will never try to free the keys -- we supply NULL as
|
65 | eb7ee2cb | Laszlo Ersek | * "key_destroy_func" in opts_start_struct(). Thus cast away key
|
66 | eb7ee2cb | Laszlo Ersek | * const-ness in order to suppress gcc's warning.
|
67 | eb7ee2cb | Laszlo Ersek | */
|
68 | eb7ee2cb | Laszlo Ersek | g_hash_table_insert(unprocessed_opts, (gpointer)opt->name, list); |
69 | eb7ee2cb | Laszlo Ersek | } |
70 | eb7ee2cb | Laszlo Ersek | |
71 | eb7ee2cb | Laszlo Ersek | /* Similarly, destroy_list() doesn't call g_queue_free_full(). */
|
72 | eb7ee2cb | Laszlo Ersek | g_queue_push_tail(list, (gpointer)opt); |
73 | eb7ee2cb | Laszlo Ersek | } |
74 | eb7ee2cb | Laszlo Ersek | |
75 | eb7ee2cb | Laszlo Ersek | |
76 | eb7ee2cb | Laszlo Ersek | static void |
77 | eb7ee2cb | Laszlo Ersek | opts_start_struct(Visitor *v, void **obj, const char *kind, |
78 | eb7ee2cb | Laszlo Ersek | const char *name, size_t size, Error **errp) |
79 | eb7ee2cb | Laszlo Ersek | { |
80 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
81 | eb7ee2cb | Laszlo Ersek | const QemuOpt *opt;
|
82 | eb7ee2cb | Laszlo Ersek | |
83 | eb7ee2cb | Laszlo Ersek | *obj = g_malloc0(size > 0 ? size : 1); |
84 | eb7ee2cb | Laszlo Ersek | if (ov->depth++ > 0) { |
85 | eb7ee2cb | Laszlo Ersek | return;
|
86 | eb7ee2cb | Laszlo Ersek | } |
87 | eb7ee2cb | Laszlo Ersek | |
88 | eb7ee2cb | Laszlo Ersek | ov->unprocessed_opts = g_hash_table_new_full(&g_str_hash, &g_str_equal, |
89 | eb7ee2cb | Laszlo Ersek | NULL, &destroy_list);
|
90 | eb7ee2cb | Laszlo Ersek | QTAILQ_FOREACH(opt, &ov->opts_root->head, next) { |
91 | eb7ee2cb | Laszlo Ersek | /* ensured by qemu-option.c::opts_do_parse() */
|
92 | eb7ee2cb | Laszlo Ersek | assert(strcmp(opt->name, "id") != 0); |
93 | eb7ee2cb | Laszlo Ersek | |
94 | eb7ee2cb | Laszlo Ersek | opts_visitor_insert(ov->unprocessed_opts, opt); |
95 | eb7ee2cb | Laszlo Ersek | } |
96 | eb7ee2cb | Laszlo Ersek | |
97 | eb7ee2cb | Laszlo Ersek | if (ov->opts_root->id != NULL) { |
98 | eb7ee2cb | Laszlo Ersek | ov->fake_id_opt = g_malloc0(sizeof *ov->fake_id_opt);
|
99 | eb7ee2cb | Laszlo Ersek | |
100 | eb7ee2cb | Laszlo Ersek | ov->fake_id_opt->name = "id";
|
101 | eb7ee2cb | Laszlo Ersek | ov->fake_id_opt->str = ov->opts_root->id; |
102 | eb7ee2cb | Laszlo Ersek | opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt); |
103 | eb7ee2cb | Laszlo Ersek | } |
104 | eb7ee2cb | Laszlo Ersek | } |
105 | eb7ee2cb | Laszlo Ersek | |
106 | eb7ee2cb | Laszlo Ersek | |
107 | eb7ee2cb | Laszlo Ersek | static gboolean
|
108 | eb7ee2cb | Laszlo Ersek | ghr_true(gpointer ign_key, gpointer ign_value, gpointer ign_user_data) |
109 | eb7ee2cb | Laszlo Ersek | { |
110 | eb7ee2cb | Laszlo Ersek | return TRUE;
|
111 | eb7ee2cb | Laszlo Ersek | } |
112 | eb7ee2cb | Laszlo Ersek | |
113 | eb7ee2cb | Laszlo Ersek | |
114 | eb7ee2cb | Laszlo Ersek | static void |
115 | eb7ee2cb | Laszlo Ersek | opts_end_struct(Visitor *v, Error **errp) |
116 | eb7ee2cb | Laszlo Ersek | { |
117 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
118 | eb7ee2cb | Laszlo Ersek | GQueue *any; |
119 | eb7ee2cb | Laszlo Ersek | |
120 | eb7ee2cb | Laszlo Ersek | if (--ov->depth > 0) { |
121 | eb7ee2cb | Laszlo Ersek | return;
|
122 | eb7ee2cb | Laszlo Ersek | } |
123 | eb7ee2cb | Laszlo Ersek | |
124 | eb7ee2cb | Laszlo Ersek | /* we should have processed all (distinct) QemuOpt instances */
|
125 | eb7ee2cb | Laszlo Ersek | any = g_hash_table_find(ov->unprocessed_opts, &ghr_true, NULL);
|
126 | eb7ee2cb | Laszlo Ersek | if (any) {
|
127 | eb7ee2cb | Laszlo Ersek | const QemuOpt *first;
|
128 | eb7ee2cb | Laszlo Ersek | |
129 | eb7ee2cb | Laszlo Ersek | first = g_queue_peek_head(any); |
130 | eb7ee2cb | Laszlo Ersek | error_set(errp, QERR_INVALID_PARAMETER, first->name); |
131 | eb7ee2cb | Laszlo Ersek | } |
132 | eb7ee2cb | Laszlo Ersek | g_hash_table_destroy(ov->unprocessed_opts); |
133 | eb7ee2cb | Laszlo Ersek | ov->unprocessed_opts = NULL;
|
134 | eb7ee2cb | Laszlo Ersek | g_free(ov->fake_id_opt); |
135 | eb7ee2cb | Laszlo Ersek | ov->fake_id_opt = NULL;
|
136 | eb7ee2cb | Laszlo Ersek | } |
137 | eb7ee2cb | Laszlo Ersek | |
138 | eb7ee2cb | Laszlo Ersek | |
139 | eb7ee2cb | Laszlo Ersek | static GQueue *
|
140 | eb7ee2cb | Laszlo Ersek | lookup_distinct(const OptsVisitor *ov, const char *name, Error **errp) |
141 | eb7ee2cb | Laszlo Ersek | { |
142 | eb7ee2cb | Laszlo Ersek | GQueue *list; |
143 | eb7ee2cb | Laszlo Ersek | |
144 | eb7ee2cb | Laszlo Ersek | list = g_hash_table_lookup(ov->unprocessed_opts, name); |
145 | eb7ee2cb | Laszlo Ersek | if (!list) {
|
146 | eb7ee2cb | Laszlo Ersek | error_set(errp, QERR_MISSING_PARAMETER, name); |
147 | eb7ee2cb | Laszlo Ersek | } |
148 | eb7ee2cb | Laszlo Ersek | return list;
|
149 | eb7ee2cb | Laszlo Ersek | } |
150 | eb7ee2cb | Laszlo Ersek | |
151 | eb7ee2cb | Laszlo Ersek | |
152 | eb7ee2cb | Laszlo Ersek | static void |
153 | eb7ee2cb | Laszlo Ersek | opts_start_list(Visitor *v, const char *name, Error **errp) |
154 | eb7ee2cb | Laszlo Ersek | { |
155 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
156 | eb7ee2cb | Laszlo Ersek | |
157 | eb7ee2cb | Laszlo Ersek | /* we can't traverse a list in a list */
|
158 | eb7ee2cb | Laszlo Ersek | assert(ov->repeated_opts == NULL);
|
159 | eb7ee2cb | Laszlo Ersek | ov->repeated_opts = lookup_distinct(ov, name, errp); |
160 | eb7ee2cb | Laszlo Ersek | ov->repeated_opts_first = (ov->repeated_opts != NULL);
|
161 | eb7ee2cb | Laszlo Ersek | } |
162 | eb7ee2cb | Laszlo Ersek | |
163 | eb7ee2cb | Laszlo Ersek | |
164 | eb7ee2cb | Laszlo Ersek | static GenericList *
|
165 | eb7ee2cb | Laszlo Ersek | opts_next_list(Visitor *v, GenericList **list, Error **errp) |
166 | eb7ee2cb | Laszlo Ersek | { |
167 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
168 | eb7ee2cb | Laszlo Ersek | GenericList **link; |
169 | eb7ee2cb | Laszlo Ersek | |
170 | eb7ee2cb | Laszlo Ersek | if (ov->repeated_opts_first) {
|
171 | eb7ee2cb | Laszlo Ersek | ov->repeated_opts_first = false;
|
172 | eb7ee2cb | Laszlo Ersek | link = list; |
173 | eb7ee2cb | Laszlo Ersek | } else {
|
174 | eb7ee2cb | Laszlo Ersek | const QemuOpt *opt;
|
175 | eb7ee2cb | Laszlo Ersek | |
176 | eb7ee2cb | Laszlo Ersek | opt = g_queue_pop_head(ov->repeated_opts); |
177 | eb7ee2cb | Laszlo Ersek | if (g_queue_is_empty(ov->repeated_opts)) {
|
178 | eb7ee2cb | Laszlo Ersek | g_hash_table_remove(ov->unprocessed_opts, opt->name); |
179 | eb7ee2cb | Laszlo Ersek | return NULL; |
180 | eb7ee2cb | Laszlo Ersek | } |
181 | eb7ee2cb | Laszlo Ersek | link = &(*list)->next; |
182 | eb7ee2cb | Laszlo Ersek | } |
183 | eb7ee2cb | Laszlo Ersek | |
184 | eb7ee2cb | Laszlo Ersek | *link = g_malloc0(sizeof **link);
|
185 | eb7ee2cb | Laszlo Ersek | return *link;
|
186 | eb7ee2cb | Laszlo Ersek | } |
187 | eb7ee2cb | Laszlo Ersek | |
188 | eb7ee2cb | Laszlo Ersek | |
189 | eb7ee2cb | Laszlo Ersek | static void |
190 | eb7ee2cb | Laszlo Ersek | opts_end_list(Visitor *v, Error **errp) |
191 | eb7ee2cb | Laszlo Ersek | { |
192 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
193 | eb7ee2cb | Laszlo Ersek | |
194 | eb7ee2cb | Laszlo Ersek | ov->repeated_opts = NULL;
|
195 | eb7ee2cb | Laszlo Ersek | } |
196 | eb7ee2cb | Laszlo Ersek | |
197 | eb7ee2cb | Laszlo Ersek | |
198 | eb7ee2cb | Laszlo Ersek | static const QemuOpt * |
199 | eb7ee2cb | Laszlo Ersek | lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp) |
200 | eb7ee2cb | Laszlo Ersek | { |
201 | eb7ee2cb | Laszlo Ersek | if (ov->repeated_opts == NULL) { |
202 | eb7ee2cb | Laszlo Ersek | GQueue *list; |
203 | eb7ee2cb | Laszlo Ersek | |
204 | eb7ee2cb | Laszlo Ersek | /* the last occurrence of any QemuOpt takes effect when queried by name
|
205 | eb7ee2cb | Laszlo Ersek | */
|
206 | eb7ee2cb | Laszlo Ersek | list = lookup_distinct(ov, name, errp); |
207 | eb7ee2cb | Laszlo Ersek | return list ? g_queue_peek_tail(list) : NULL; |
208 | eb7ee2cb | Laszlo Ersek | } |
209 | eb7ee2cb | Laszlo Ersek | return g_queue_peek_head(ov->repeated_opts);
|
210 | eb7ee2cb | Laszlo Ersek | } |
211 | eb7ee2cb | Laszlo Ersek | |
212 | eb7ee2cb | Laszlo Ersek | |
213 | eb7ee2cb | Laszlo Ersek | static void |
214 | eb7ee2cb | Laszlo Ersek | processed(OptsVisitor *ov, const char *name) |
215 | eb7ee2cb | Laszlo Ersek | { |
216 | eb7ee2cb | Laszlo Ersek | if (ov->repeated_opts == NULL) { |
217 | eb7ee2cb | Laszlo Ersek | g_hash_table_remove(ov->unprocessed_opts, name); |
218 | eb7ee2cb | Laszlo Ersek | } |
219 | eb7ee2cb | Laszlo Ersek | } |
220 | eb7ee2cb | Laszlo Ersek | |
221 | eb7ee2cb | Laszlo Ersek | |
222 | eb7ee2cb | Laszlo Ersek | static void |
223 | eb7ee2cb | Laszlo Ersek | opts_type_str(Visitor *v, char **obj, const char *name, Error **errp) |
224 | eb7ee2cb | Laszlo Ersek | { |
225 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
226 | eb7ee2cb | Laszlo Ersek | const QemuOpt *opt;
|
227 | eb7ee2cb | Laszlo Ersek | |
228 | eb7ee2cb | Laszlo Ersek | opt = lookup_scalar(ov, name, errp); |
229 | eb7ee2cb | Laszlo Ersek | if (!opt) {
|
230 | eb7ee2cb | Laszlo Ersek | return;
|
231 | eb7ee2cb | Laszlo Ersek | } |
232 | eb7ee2cb | Laszlo Ersek | *obj = g_strdup(opt->str ? opt->str : "");
|
233 | eb7ee2cb | Laszlo Ersek | processed(ov, name); |
234 | eb7ee2cb | Laszlo Ersek | } |
235 | eb7ee2cb | Laszlo Ersek | |
236 | eb7ee2cb | Laszlo Ersek | |
237 | eb7ee2cb | Laszlo Ersek | /* mimics qemu-option.c::parse_option_bool() */
|
238 | eb7ee2cb | Laszlo Ersek | static void |
239 | eb7ee2cb | Laszlo Ersek | opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) |
240 | eb7ee2cb | Laszlo Ersek | { |
241 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
242 | eb7ee2cb | Laszlo Ersek | const QemuOpt *opt;
|
243 | eb7ee2cb | Laszlo Ersek | |
244 | eb7ee2cb | Laszlo Ersek | opt = lookup_scalar(ov, name, errp); |
245 | eb7ee2cb | Laszlo Ersek | if (!opt) {
|
246 | eb7ee2cb | Laszlo Ersek | return;
|
247 | eb7ee2cb | Laszlo Ersek | } |
248 | eb7ee2cb | Laszlo Ersek | |
249 | eb7ee2cb | Laszlo Ersek | if (opt->str) {
|
250 | eb7ee2cb | Laszlo Ersek | if (strcmp(opt->str, "on") == 0 || |
251 | eb7ee2cb | Laszlo Ersek | strcmp(opt->str, "yes") == 0 || |
252 | eb7ee2cb | Laszlo Ersek | strcmp(opt->str, "y") == 0) { |
253 | eb7ee2cb | Laszlo Ersek | *obj = true;
|
254 | eb7ee2cb | Laszlo Ersek | } else if (strcmp(opt->str, "off") == 0 || |
255 | eb7ee2cb | Laszlo Ersek | strcmp(opt->str, "no") == 0 || |
256 | eb7ee2cb | Laszlo Ersek | strcmp(opt->str, "n") == 0) { |
257 | eb7ee2cb | Laszlo Ersek | *obj = false;
|
258 | eb7ee2cb | Laszlo Ersek | } else {
|
259 | eb7ee2cb | Laszlo Ersek | error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, |
260 | eb7ee2cb | Laszlo Ersek | "on|yes|y|off|no|n");
|
261 | eb7ee2cb | Laszlo Ersek | return;
|
262 | eb7ee2cb | Laszlo Ersek | } |
263 | eb7ee2cb | Laszlo Ersek | } else {
|
264 | eb7ee2cb | Laszlo Ersek | *obj = true;
|
265 | eb7ee2cb | Laszlo Ersek | } |
266 | eb7ee2cb | Laszlo Ersek | |
267 | eb7ee2cb | Laszlo Ersek | processed(ov, name); |
268 | eb7ee2cb | Laszlo Ersek | } |
269 | eb7ee2cb | Laszlo Ersek | |
270 | eb7ee2cb | Laszlo Ersek | |
271 | eb7ee2cb | Laszlo Ersek | static void |
272 | eb7ee2cb | Laszlo Ersek | opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp) |
273 | eb7ee2cb | Laszlo Ersek | { |
274 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
275 | eb7ee2cb | Laszlo Ersek | const QemuOpt *opt;
|
276 | eb7ee2cb | Laszlo Ersek | const char *str; |
277 | eb7ee2cb | Laszlo Ersek | long long val; |
278 | eb7ee2cb | Laszlo Ersek | char *endptr;
|
279 | eb7ee2cb | Laszlo Ersek | |
280 | eb7ee2cb | Laszlo Ersek | opt = lookup_scalar(ov, name, errp); |
281 | eb7ee2cb | Laszlo Ersek | if (!opt) {
|
282 | eb7ee2cb | Laszlo Ersek | return;
|
283 | eb7ee2cb | Laszlo Ersek | } |
284 | eb7ee2cb | Laszlo Ersek | str = opt->str ? opt->str : "";
|
285 | eb7ee2cb | Laszlo Ersek | |
286 | eb7ee2cb | Laszlo Ersek | errno = 0;
|
287 | eb7ee2cb | Laszlo Ersek | val = strtoll(str, &endptr, 0);
|
288 | eb7ee2cb | Laszlo Ersek | if (*str != '\0' && *endptr == '\0' && errno == 0 && INT64_MIN <= val && |
289 | eb7ee2cb | Laszlo Ersek | val <= INT64_MAX) { |
290 | eb7ee2cb | Laszlo Ersek | *obj = val; |
291 | eb7ee2cb | Laszlo Ersek | processed(ov, name); |
292 | eb7ee2cb | Laszlo Ersek | return;
|
293 | eb7ee2cb | Laszlo Ersek | } |
294 | eb7ee2cb | Laszlo Ersek | error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, "an int64 value");
|
295 | eb7ee2cb | Laszlo Ersek | } |
296 | eb7ee2cb | Laszlo Ersek | |
297 | eb7ee2cb | Laszlo Ersek | |
298 | eb7ee2cb | Laszlo Ersek | static void |
299 | eb7ee2cb | Laszlo Ersek | opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp) |
300 | eb7ee2cb | Laszlo Ersek | { |
301 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
302 | eb7ee2cb | Laszlo Ersek | const QemuOpt *opt;
|
303 | eb7ee2cb | Laszlo Ersek | const char *str; |
304 | eb7ee2cb | Laszlo Ersek | |
305 | eb7ee2cb | Laszlo Ersek | opt = lookup_scalar(ov, name, errp); |
306 | eb7ee2cb | Laszlo Ersek | if (!opt) {
|
307 | eb7ee2cb | Laszlo Ersek | return;
|
308 | eb7ee2cb | Laszlo Ersek | } |
309 | eb7ee2cb | Laszlo Ersek | |
310 | eb7ee2cb | Laszlo Ersek | str = opt->str; |
311 | eb7ee2cb | Laszlo Ersek | if (str != NULL) { |
312 | eb7ee2cb | Laszlo Ersek | while (isspace((unsigned char)*str)) { |
313 | eb7ee2cb | Laszlo Ersek | ++str; |
314 | eb7ee2cb | Laszlo Ersek | } |
315 | eb7ee2cb | Laszlo Ersek | |
316 | eb7ee2cb | Laszlo Ersek | if (*str != '-' && *str != '\0') { |
317 | eb7ee2cb | Laszlo Ersek | unsigned long long val; |
318 | eb7ee2cb | Laszlo Ersek | char *endptr;
|
319 | eb7ee2cb | Laszlo Ersek | |
320 | eb7ee2cb | Laszlo Ersek | /* non-empty, non-negative subject sequence */
|
321 | eb7ee2cb | Laszlo Ersek | errno = 0;
|
322 | eb7ee2cb | Laszlo Ersek | val = strtoull(str, &endptr, 0);
|
323 | eb7ee2cb | Laszlo Ersek | if (*endptr == '\0' && errno == 0 && val <= UINT64_MAX) { |
324 | eb7ee2cb | Laszlo Ersek | *obj = val; |
325 | eb7ee2cb | Laszlo Ersek | processed(ov, name); |
326 | eb7ee2cb | Laszlo Ersek | return;
|
327 | eb7ee2cb | Laszlo Ersek | } |
328 | eb7ee2cb | Laszlo Ersek | } |
329 | eb7ee2cb | Laszlo Ersek | } |
330 | eb7ee2cb | Laszlo Ersek | error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, |
331 | eb7ee2cb | Laszlo Ersek | "an uint64 value");
|
332 | eb7ee2cb | Laszlo Ersek | } |
333 | eb7ee2cb | Laszlo Ersek | |
334 | eb7ee2cb | Laszlo Ersek | |
335 | eb7ee2cb | Laszlo Ersek | static void |
336 | eb7ee2cb | Laszlo Ersek | opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp) |
337 | eb7ee2cb | Laszlo Ersek | { |
338 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
339 | eb7ee2cb | Laszlo Ersek | const QemuOpt *opt;
|
340 | eb7ee2cb | Laszlo Ersek | int64_t val; |
341 | eb7ee2cb | Laszlo Ersek | char *endptr;
|
342 | eb7ee2cb | Laszlo Ersek | |
343 | eb7ee2cb | Laszlo Ersek | opt = lookup_scalar(ov, name, errp); |
344 | eb7ee2cb | Laszlo Ersek | if (!opt) {
|
345 | eb7ee2cb | Laszlo Ersek | return;
|
346 | eb7ee2cb | Laszlo Ersek | } |
347 | eb7ee2cb | Laszlo Ersek | |
348 | eb7ee2cb | Laszlo Ersek | val = strtosz_suffix(opt->str ? opt->str : "", &endptr,
|
349 | eb7ee2cb | Laszlo Ersek | STRTOSZ_DEFSUFFIX_B); |
350 | eb7ee2cb | Laszlo Ersek | if (val != -1 && *endptr == '\0') { |
351 | eb7ee2cb | Laszlo Ersek | *obj = val; |
352 | eb7ee2cb | Laszlo Ersek | processed(ov, name); |
353 | eb7ee2cb | Laszlo Ersek | return;
|
354 | eb7ee2cb | Laszlo Ersek | } |
355 | eb7ee2cb | Laszlo Ersek | error_set(errp, QERR_INVALID_PARAMETER_VALUE, opt->name, |
356 | eb7ee2cb | Laszlo Ersek | "a size value representible as a non-negative int64");
|
357 | eb7ee2cb | Laszlo Ersek | } |
358 | eb7ee2cb | Laszlo Ersek | |
359 | eb7ee2cb | Laszlo Ersek | |
360 | eb7ee2cb | Laszlo Ersek | static void |
361 | eb7ee2cb | Laszlo Ersek | opts_start_optional(Visitor *v, bool *present, const char *name, |
362 | eb7ee2cb | Laszlo Ersek | Error **errp) |
363 | eb7ee2cb | Laszlo Ersek | { |
364 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov = DO_UPCAST(OptsVisitor, visitor, v); |
365 | eb7ee2cb | Laszlo Ersek | |
366 | eb7ee2cb | Laszlo Ersek | /* we only support a single mandatory scalar field in a list node */
|
367 | eb7ee2cb | Laszlo Ersek | assert(ov->repeated_opts == NULL);
|
368 | eb7ee2cb | Laszlo Ersek | *present = (lookup_distinct(ov, name, NULL) != NULL); |
369 | eb7ee2cb | Laszlo Ersek | } |
370 | eb7ee2cb | Laszlo Ersek | |
371 | eb7ee2cb | Laszlo Ersek | |
372 | eb7ee2cb | Laszlo Ersek | OptsVisitor * |
373 | eb7ee2cb | Laszlo Ersek | opts_visitor_new(const QemuOpts *opts)
|
374 | eb7ee2cb | Laszlo Ersek | { |
375 | eb7ee2cb | Laszlo Ersek | OptsVisitor *ov; |
376 | eb7ee2cb | Laszlo Ersek | |
377 | eb7ee2cb | Laszlo Ersek | ov = g_malloc0(sizeof *ov);
|
378 | eb7ee2cb | Laszlo Ersek | |
379 | eb7ee2cb | Laszlo Ersek | ov->visitor.start_struct = &opts_start_struct; |
380 | eb7ee2cb | Laszlo Ersek | ov->visitor.end_struct = &opts_end_struct; |
381 | eb7ee2cb | Laszlo Ersek | |
382 | eb7ee2cb | Laszlo Ersek | ov->visitor.start_list = &opts_start_list; |
383 | eb7ee2cb | Laszlo Ersek | ov->visitor.next_list = &opts_next_list; |
384 | eb7ee2cb | Laszlo Ersek | ov->visitor.end_list = &opts_end_list; |
385 | eb7ee2cb | Laszlo Ersek | |
386 | eb7ee2cb | Laszlo Ersek | /* input_type_enum() covers both "normal" enums and union discriminators.
|
387 | eb7ee2cb | Laszlo Ersek | * The union discriminator field is always generated as "type"; it should
|
388 | eb7ee2cb | Laszlo Ersek | * match the "type" QemuOpt child of any QemuOpts.
|
389 | eb7ee2cb | Laszlo Ersek | *
|
390 | eb7ee2cb | Laszlo Ersek | * input_type_enum() will remove the looked-up key from the
|
391 | eb7ee2cb | Laszlo Ersek | * "unprocessed_opts" hash even if the lookup fails, because the removal is
|
392 | eb7ee2cb | Laszlo Ersek | * done earlier in opts_type_str(). This should be harmless.
|
393 | eb7ee2cb | Laszlo Ersek | */
|
394 | eb7ee2cb | Laszlo Ersek | ov->visitor.type_enum = &input_type_enum; |
395 | eb7ee2cb | Laszlo Ersek | |
396 | eb7ee2cb | Laszlo Ersek | ov->visitor.type_int = &opts_type_int; |
397 | eb7ee2cb | Laszlo Ersek | ov->visitor.type_uint64 = &opts_type_uint64; |
398 | eb7ee2cb | Laszlo Ersek | ov->visitor.type_size = &opts_type_size; |
399 | eb7ee2cb | Laszlo Ersek | ov->visitor.type_bool = &opts_type_bool; |
400 | eb7ee2cb | Laszlo Ersek | ov->visitor.type_str = &opts_type_str; |
401 | eb7ee2cb | Laszlo Ersek | |
402 | eb7ee2cb | Laszlo Ersek | /* type_number() is not filled in, but this is not the first visitor to
|
403 | eb7ee2cb | Laszlo Ersek | * skip some mandatory methods... */
|
404 | eb7ee2cb | Laszlo Ersek | |
405 | eb7ee2cb | Laszlo Ersek | ov->visitor.start_optional = &opts_start_optional; |
406 | eb7ee2cb | Laszlo Ersek | |
407 | eb7ee2cb | Laszlo Ersek | ov->opts_root = opts; |
408 | eb7ee2cb | Laszlo Ersek | |
409 | eb7ee2cb | Laszlo Ersek | return ov;
|
410 | eb7ee2cb | Laszlo Ersek | } |
411 | eb7ee2cb | Laszlo Ersek | |
412 | eb7ee2cb | Laszlo Ersek | |
413 | eb7ee2cb | Laszlo Ersek | void
|
414 | eb7ee2cb | Laszlo Ersek | opts_visitor_cleanup(OptsVisitor *ov) |
415 | eb7ee2cb | Laszlo Ersek | { |
416 | eb7ee2cb | Laszlo Ersek | if (ov->unprocessed_opts != NULL) { |
417 | eb7ee2cb | Laszlo Ersek | g_hash_table_destroy(ov->unprocessed_opts); |
418 | eb7ee2cb | Laszlo Ersek | } |
419 | eb7ee2cb | Laszlo Ersek | g_free(ov->fake_id_opt); |
420 | e36c8766 | Stefan Weil | g_free(ov); |
421 | eb7ee2cb | Laszlo Ersek | } |
422 | eb7ee2cb | Laszlo Ersek | |
423 | eb7ee2cb | Laszlo Ersek | |
424 | eb7ee2cb | Laszlo Ersek | Visitor * |
425 | eb7ee2cb | Laszlo Ersek | opts_get_visitor(OptsVisitor *ov) |
426 | eb7ee2cb | Laszlo Ersek | { |
427 | eb7ee2cb | Laszlo Ersek | return &ov->visitor;
|
428 | eb7ee2cb | Laszlo Ersek | } |