~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to .pc/v2.8.1.diff/qapi/opts-visitor.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Options Visitor
3
 
 *
4
 
 * Copyright Red Hat, Inc. 2012-2016
5
 
 *
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
 
 
13
 
#include "qemu/osdep.h"
14
 
#include "qapi/error.h"
15
 
#include "qemu/cutils.h"
16
 
#include "qapi/qmp/qerror.h"
17
 
#include "qapi/opts-visitor.h"
18
 
#include "qemu/queue.h"
19
 
#include "qemu/option_int.h"
20
 
#include "qapi/visitor-impl.h"
21
 
 
22
 
 
23
 
enum ListMode
24
 
{
25
 
    LM_NONE,             /* not traversing a list of repeated options */
26
 
 
27
 
    LM_IN_PROGRESS,      /* opts_next_list() ready to be called.
28
 
                          *
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. */
52
 
};
53
 
 
54
 
typedef enum ListMode ListMode;
55
 
 
56
 
struct 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. */
73
 
    ListMode list_mode;
74
 
    GQueue *repeated_opts;
75
 
 
76
 
    /* 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
 
 
85
 
    /* 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
 
 
93
 
static OptsVisitor *to_ov(Visitor *v)
94
 
{
95
 
    return container_of(v, OptsVisitor, visitor);
96
 
}
97
 
 
98
 
 
99
 
static void
100
 
destroy_list(gpointer list)
101
 
{
102
 
  g_queue_free(list);
103
 
}
104
 
 
105
 
 
106
 
static void
107
 
opts_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
 
 
127
 
static void
128
 
opts_start_struct(Visitor *v, const char *name, void **obj,
129
 
                  size_t size, Error **errp)
130
 
{
131
 
    OptsVisitor *ov = to_ov(v);
132
 
    const QemuOpt *opt;
133
 
 
134
 
    if (obj) {
135
 
        *obj = g_malloc0(size);
136
 
    }
137
 
    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
 
 
153
 
        ov->fake_id_opt->name = g_strdup("id");
154
 
        ov->fake_id_opt->str = g_strdup(ov->opts_root->id);
155
 
        opts_visitor_insert(ov->unprocessed_opts, ov->fake_id_opt);
156
 
    }
157
 
}
158
 
 
159
 
 
160
 
static void
161
 
opts_check_struct(Visitor *v, Error **errp)
162
 
{
163
 
    OptsVisitor *ov = to_ov(v);
164
 
    GHashTableIter iter;
165
 
    GQueue *any;
166
 
 
167
 
    if (ov->depth > 0) {
168
 
        return;
169
 
    }
170
 
 
171
 
    /* we should have processed all (distinct) QemuOpt instances */
172
 
    g_hash_table_iter_init(&iter, ov->unprocessed_opts);
173
 
    if (g_hash_table_iter_next(&iter, NULL, (void **)&any)) {
174
 
        const QemuOpt *first;
175
 
 
176
 
        first = g_queue_peek_head(any);
177
 
        error_setg(errp, QERR_INVALID_PARAMETER, first->name);
178
 
    }
179
 
}
180
 
 
181
 
 
182
 
static void
183
 
opts_end_struct(Visitor *v, void **obj)
184
 
{
185
 
    OptsVisitor *ov = to_ov(v);
186
 
 
187
 
    if (--ov->depth > 0) {
188
 
        return;
189
 
    }
190
 
 
191
 
    g_hash_table_destroy(ov->unprocessed_opts);
192
 
    ov->unprocessed_opts = NULL;
193
 
    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
 
    }
198
 
    ov->fake_id_opt = NULL;
199
 
}
200
 
 
201
 
 
202
 
static GQueue *
203
 
lookup_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) {
209
 
        error_setg(errp, QERR_MISSING_PARAMETER, name);
210
 
    }
211
 
    return list;
212
 
}
213
 
 
214
 
 
215
 
static void
216
 
opts_start_list(Visitor *v, const char *name, GenericList **list, size_t size,
217
 
                Error **errp)
218
 
{
219
 
    OptsVisitor *ov = to_ov(v);
220
 
 
221
 
    /* we can't traverse a list in a list */
222
 
    assert(ov->list_mode == LM_NONE);
223
 
    /* we don't support visits without a list */
224
 
    assert(list);
225
 
    ov->repeated_opts = lookup_distinct(ov, name, errp);
226
 
    if (ov->repeated_opts) {
227
 
        ov->list_mode = LM_IN_PROGRESS;
228
 
        *list = g_malloc0(size);
229
 
    } else {
230
 
        *list = NULL;
231
 
    }
232
 
}
233
 
 
234
 
 
235
 
static GenericList *
236
 
opts_next_list(Visitor *v, GenericList *tail, size_t size)
237
 
{
238
 
    OptsVisitor *ov = to_ov(v);
239
 
 
240
 
    switch (ov->list_mode) {
241
 
    case LM_SIGNED_INTERVAL:
242
 
    case LM_UNSIGNED_INTERVAL:
243
 
        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
 
 
255
 
    case LM_IN_PROGRESS: {
256
 
        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
 
        }
263
 
        break;
264
 
    }
265
 
 
266
 
    default:
267
 
        abort();
268
 
    }
269
 
 
270
 
    tail->next = g_malloc0(size);
271
 
    return tail->next;
272
 
}
273
 
 
274
 
 
275
 
static void
276
 
opts_end_list(Visitor *v, void **obj)
277
 
{
278
 
    OptsVisitor *ov = to_ov(v);
279
 
 
280
 
    assert(ov->list_mode == LM_IN_PROGRESS ||
281
 
           ov->list_mode == LM_SIGNED_INTERVAL ||
282
 
           ov->list_mode == LM_UNSIGNED_INTERVAL);
283
 
    ov->repeated_opts = NULL;
284
 
    ov->list_mode = LM_NONE;
285
 
}
286
 
 
287
 
 
288
 
static const QemuOpt *
289
 
lookup_scalar(const OptsVisitor *ov, const char *name, Error **errp)
290
 
{
291
 
    if (ov->list_mode == LM_NONE) {
292
 
        GQueue *list;
293
 
 
294
 
        /* the last occurrence of any QemuOpt takes effect when queried by name
295
 
         */
296
 
        list = lookup_distinct(ov, name, errp);
297
 
        return list ? g_queue_peek_tail(list) : NULL;
298
 
    }
299
 
    assert(ov->list_mode == LM_IN_PROGRESS);
300
 
    return g_queue_peek_head(ov->repeated_opts);
301
 
}
302
 
 
303
 
 
304
 
static void
305
 
processed(OptsVisitor *ov, const char *name)
306
 
{
307
 
    if (ov->list_mode == LM_NONE) {
308
 
        g_hash_table_remove(ov->unprocessed_opts, name);
309
 
        return;
310
 
    }
311
 
    assert(ov->list_mode == LM_IN_PROGRESS);
312
 
    /* do nothing */
313
 
}
314
 
 
315
 
 
316
 
static void
317
 
opts_type_str(Visitor *v, const char *name, char **obj, Error **errp)
318
 
{
319
 
    OptsVisitor *ov = to_ov(v);
320
 
    const QemuOpt *opt;
321
 
 
322
 
    opt = lookup_scalar(ov, name, errp);
323
 
    if (!opt) {
324
 
        *obj = NULL;
325
 
        return;
326
 
    }
327
 
    *obj = g_strdup(opt->str ? opt->str : "");
328
 
    /* Note that we consume a string even if this is called as part of
329
 
     * an enum visit that later fails because the string is not a
330
 
     * valid enum value; this is harmless because tracking what gets
331
 
     * consumed only matters to visit_end_struct() as the final error
332
 
     * check if there were no other failures during the visit.  */
333
 
    processed(ov, name);
334
 
}
335
 
 
336
 
 
337
 
/* mimics qemu-option.c::parse_option_bool() */
338
 
static void
339
 
opts_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
340
 
{
341
 
    OptsVisitor *ov = to_ov(v);
342
 
    const QemuOpt *opt;
343
 
 
344
 
    opt = lookup_scalar(ov, name, errp);
345
 
    if (!opt) {
346
 
        return;
347
 
    }
348
 
 
349
 
    if (opt->str) {
350
 
        if (strcmp(opt->str, "on") == 0 ||
351
 
            strcmp(opt->str, "yes") == 0 ||
352
 
            strcmp(opt->str, "y") == 0) {
353
 
            *obj = true;
354
 
        } else if (strcmp(opt->str, "off") == 0 ||
355
 
            strcmp(opt->str, "no") == 0 ||
356
 
            strcmp(opt->str, "n") == 0) {
357
 
            *obj = false;
358
 
        } else {
359
 
            error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
360
 
                       "on|yes|y|off|no|n");
361
 
            return;
362
 
        }
363
 
    } else {
364
 
        *obj = true;
365
 
    }
366
 
 
367
 
    processed(ov, name);
368
 
}
369
 
 
370
 
 
371
 
static void
372
 
opts_type_int64(Visitor *v, const char *name, int64_t *obj, Error **errp)
373
 
{
374
 
    OptsVisitor *ov = to_ov(v);
375
 
    const QemuOpt *opt;
376
 
    const char *str;
377
 
    long long val;
378
 
    char *endptr;
379
 
 
380
 
    if (ov->list_mode == LM_SIGNED_INTERVAL) {
381
 
        *obj = ov->range_next.s;
382
 
        return;
383
 
    }
384
 
 
385
 
    opt = lookup_scalar(ov, name, errp);
386
 
    if (!opt) {
387
 
        return;
388
 
    }
389
 
    str = opt->str ? opt->str : "";
390
 
 
391
 
    /* we've gotten past lookup_scalar() */
392
 
    assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS);
393
 
 
394
 
    errno = 0;
395
 
    val = strtoll(str, &endptr, 0);
396
 
    if (errno == 0 && endptr > str && INT64_MIN <= val && val <= INT64_MAX) {
397
 
        if (*endptr == '\0') {
398
 
            *obj = val;
399
 
            processed(ov, name);
400
 
            return;
401
 
        }
402
 
        if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) {
403
 
            long long val2;
404
 
 
405
 
            str = endptr + 1;
406
 
            val2 = strtoll(str, &endptr, 0);
407
 
            if (errno == 0 && endptr > str && *endptr == '\0' &&
408
 
                INT64_MIN <= val2 && val2 <= INT64_MAX && val <= val2 &&
409
 
                (val > INT64_MAX - OPTS_VISITOR_RANGE_MAX ||
410
 
                 val2 < val + OPTS_VISITOR_RANGE_MAX)) {
411
 
                ov->range_next.s = val;
412
 
                ov->range_limit.s = val2;
413
 
                ov->list_mode = LM_SIGNED_INTERVAL;
414
 
 
415
 
                /* as if entering on the top */
416
 
                *obj = ov->range_next.s;
417
 
                return;
418
 
            }
419
 
        }
420
 
    }
421
 
    error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
422
 
               (ov->list_mode == LM_NONE) ? "an int64 value" :
423
 
                                            "an int64 value or range");
424
 
}
425
 
 
426
 
 
427
 
static void
428
 
opts_type_uint64(Visitor *v, const char *name, uint64_t *obj, Error **errp)
429
 
{
430
 
    OptsVisitor *ov = to_ov(v);
431
 
    const QemuOpt *opt;
432
 
    const char *str;
433
 
    unsigned long long val;
434
 
    char *endptr;
435
 
 
436
 
    if (ov->list_mode == LM_UNSIGNED_INTERVAL) {
437
 
        *obj = ov->range_next.u;
438
 
        return;
439
 
    }
440
 
 
441
 
    opt = lookup_scalar(ov, name, errp);
442
 
    if (!opt) {
443
 
        return;
444
 
    }
445
 
    str = opt->str;
446
 
 
447
 
    /* we've gotten past lookup_scalar() */
448
 
    assert(ov->list_mode == LM_NONE || ov->list_mode == LM_IN_PROGRESS);
449
 
 
450
 
    if (parse_uint(str, &val, &endptr, 0) == 0 && val <= UINT64_MAX) {
451
 
        if (*endptr == '\0') {
452
 
            *obj = val;
453
 
            processed(ov, name);
454
 
            return;
455
 
        }
456
 
        if (*endptr == '-' && ov->list_mode == LM_IN_PROGRESS) {
457
 
            unsigned long long val2;
458
 
 
459
 
            str = endptr + 1;
460
 
            if (parse_uint_full(str, &val2, 0) == 0 &&
461
 
                val2 <= UINT64_MAX && val <= val2 &&
462
 
                val2 - val < OPTS_VISITOR_RANGE_MAX) {
463
 
                ov->range_next.u = val;
464
 
                ov->range_limit.u = val2;
465
 
                ov->list_mode = LM_UNSIGNED_INTERVAL;
466
 
 
467
 
                /* as if entering on the top */
468
 
                *obj = ov->range_next.u;
469
 
                return;
470
 
            }
471
 
        }
472
 
    }
473
 
    error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
474
 
               (ov->list_mode == LM_NONE) ? "a uint64 value" :
475
 
                                            "a uint64 value or range");
476
 
}
477
 
 
478
 
 
479
 
static void
480
 
opts_type_size(Visitor *v, const char *name, uint64_t *obj, Error **errp)
481
 
{
482
 
    OptsVisitor *ov = to_ov(v);
483
 
    const QemuOpt *opt;
484
 
    int64_t val;
485
 
    char *endptr;
486
 
 
487
 
    opt = lookup_scalar(ov, name, errp);
488
 
    if (!opt) {
489
 
        return;
490
 
    }
491
 
 
492
 
    val = qemu_strtosz_suffix(opt->str ? opt->str : "", &endptr,
493
 
                         QEMU_STRTOSZ_DEFSUFFIX_B);
494
 
    if (val < 0 || *endptr) {
495
 
        error_setg(errp, QERR_INVALID_PARAMETER_VALUE, opt->name,
496
 
                   "a size value representible as a non-negative int64");
497
 
        return;
498
 
    }
499
 
 
500
 
    *obj = val;
501
 
    processed(ov, name);
502
 
}
503
 
 
504
 
 
505
 
static void
506
 
opts_optional(Visitor *v, const char *name, bool *present)
507
 
{
508
 
    OptsVisitor *ov = to_ov(v);
509
 
 
510
 
    /* we only support a single mandatory scalar field in a list node */
511
 
    assert(ov->list_mode == LM_NONE);
512
 
    *present = (lookup_distinct(ov, name, NULL) != NULL);
513
 
}
514
 
 
515
 
 
516
 
static void
517
 
opts_free(Visitor *v)
518
 
{
519
 
    OptsVisitor *ov = to_ov(v);
520
 
 
521
 
    if (ov->unprocessed_opts != NULL) {
522
 
        g_hash_table_destroy(ov->unprocessed_opts);
523
 
    }
524
 
    g_free(ov->fake_id_opt);
525
 
    g_free(ov);
526
 
}
527
 
 
528
 
 
529
 
Visitor *
530
 
opts_visitor_new(const QemuOpts *opts)
531
 
{
532
 
    OptsVisitor *ov;
533
 
 
534
 
    ov = g_malloc0(sizeof *ov);
535
 
 
536
 
    ov->visitor.type = VISITOR_INPUT;
537
 
 
538
 
    ov->visitor.start_struct = &opts_start_struct;
539
 
    ov->visitor.check_struct = &opts_check_struct;
540
 
    ov->visitor.end_struct   = &opts_end_struct;
541
 
 
542
 
    ov->visitor.start_list = &opts_start_list;
543
 
    ov->visitor.next_list  = &opts_next_list;
544
 
    ov->visitor.end_list   = &opts_end_list;
545
 
 
546
 
    ov->visitor.type_int64  = &opts_type_int64;
547
 
    ov->visitor.type_uint64 = &opts_type_uint64;
548
 
    ov->visitor.type_size   = &opts_type_size;
549
 
    ov->visitor.type_bool   = &opts_type_bool;
550
 
    ov->visitor.type_str    = &opts_type_str;
551
 
 
552
 
    /* type_number() is not filled in, but this is not the first visitor to
553
 
     * skip some mandatory methods... */
554
 
 
555
 
    ov->visitor.optional = &opts_optional;
556
 
    ov->visitor.free = opts_free;
557
 
 
558
 
    ov->opts_root = opts;
559
 
 
560
 
    return &ov->visitor;
561
 
}