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