Statistics
| Branch: | Revision:

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
}