Statistics
| Branch: | Revision:

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
}