string-input-visitor.c 9.0 KB
Newer Older
P
Paolo Bonzini 已提交
1 2 3
/*
 * String parsing visitor
 *
4
 * Copyright Red Hat, Inc. 2012-2016
P
Paolo Bonzini 已提交
5 6 7 8 9 10 11 12
 *
 * Author: Paolo Bonzini <pbonzini@redhat.com>
 *
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 * See the COPYING.LIB file in the top-level directory.
 *
 */

P
Peter Maydell 已提交
13
#include "qemu/osdep.h"
14
#include "qapi/error.h"
P
Paolo Bonzini 已提交
15
#include "qemu-common.h"
16 17 18
#include "qapi/string-input-visitor.h"
#include "qapi/visitor-impl.h"
#include "qapi/qmp/qerror.h"
19
#include "qemu/option.h"
20 21 22
#include "qemu/queue.h"
#include "qemu/range.h"

P
Paolo Bonzini 已提交
23 24 25 26

struct StringInputVisitor
{
    Visitor visitor;
27 28 29 30 31

    GList *ranges;
    GList *cur_range;
    int64_t cur;

P
Paolo Bonzini 已提交
32
    const char *string;
E
Eric Blake 已提交
33
    void *list; /* Only needed for sanity checking the caller */
P
Paolo Bonzini 已提交
34 35
};

36 37 38 39 40
static StringInputVisitor *to_siv(Visitor *v)
{
    return container_of(v, StringInputVisitor, visitor);
}

41 42 43 44 45
static void free_range(void *range, void *dummy)
{
    g_free(range);
}

46
static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
47 48 49 50 51 52 53
{
    char *str = (char *) siv->string;
    long long start, end;
    Range *cur;
    char *endptr;

    if (siv->ranges) {
54
        return 0;
55 56
    }

57 58 59 60
    if (!*str) {
        return 0;
    }

61
    do {
62
        errno = 0;
63
        start = strtoll(str, &endptr, 0);
64
        if (errno == 0 && endptr > str) {
65 66
            if (*endptr == '\0') {
                cur = g_malloc0(sizeof(*cur));
67
                range_set_bounds(cur, start, start);
E
Eric Blake 已提交
68
                siv->ranges = range_list_insert(siv->ranges, cur);
69 70 71 72
                cur = NULL;
                str = NULL;
            } else if (*endptr == '-') {
                str = endptr + 1;
73
                errno = 0;
74
                end = strtoll(str, &endptr, 0);
75
                if (errno == 0 && endptr > str && start <= end &&
76 77 78 79
                    (start > INT64_MAX - 65536 ||
                     end < start + 65536)) {
                    if (*endptr == '\0') {
                        cur = g_malloc0(sizeof(*cur));
80
                        range_set_bounds(cur, start, end);
E
Eric Blake 已提交
81
                        siv->ranges = range_list_insert(siv->ranges, cur);
82 83 84 85 86
                        cur = NULL;
                        str = NULL;
                    } else if (*endptr == ',') {
                        str = endptr + 1;
                        cur = g_malloc0(sizeof(*cur));
87
                        range_set_bounds(cur, start, end);
E
Eric Blake 已提交
88
                        siv->ranges = range_list_insert(siv->ranges, cur);
89 90 91 92 93 94 95 96 97 98
                        cur = NULL;
                    } else {
                        goto error;
                    }
                } else {
                    goto error;
                }
            } else if (*endptr == ',') {
                str = endptr + 1;
                cur = g_malloc0(sizeof(*cur));
99
                range_set_bounds(cur, start, start);
E
Eric Blake 已提交
100
                siv->ranges = range_list_insert(siv->ranges, cur);
101 102 103 104 105 106 107 108 109
                cur = NULL;
            } else {
                goto error;
            }
        } else {
            goto error;
        }
    } while (str);

110
    return 0;
111
error:
112 113 114
    g_list_foreach(siv->ranges, free_range, NULL);
    g_list_free(siv->ranges);
    siv->ranges = NULL;
115 116 117
    error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
               "an int64 value or range");
    return -1;
118 119 120
}

static void
121 122
start_list(Visitor *v, const char *name, GenericList **list, size_t size,
           Error **errp)
123
{
124
    StringInputVisitor *siv = to_siv(v);
125

126 127
    /* We don't support visits without a list */
    assert(list);
E
Eric Blake 已提交
128
    siv->list = list;
129

130
    if (parse_str(siv, name, errp) < 0) {
131
        *list = NULL;
132 133
        return;
    }
134 135 136 137 138

    siv->cur_range = g_list_first(siv->ranges);
    if (siv->cur_range) {
        Range *r = siv->cur_range->data;
        if (r) {
139
            siv->cur = range_lob(r);
140
        }
141 142 143
        *list = g_malloc0(size);
    } else {
        *list = NULL;
144 145 146
    }
}

147
static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
148
{
149
    StringInputVisitor *siv = to_siv(v);
150 151 152 153 154 155 156 157 158 159 160
    Range *r;

    if (!siv->ranges || !siv->cur_range) {
        return NULL;
    }

    r = siv->cur_range->data;
    if (!r) {
        return NULL;
    }

161
    if (!range_contains(r, siv->cur)) {
162 163 164 165 166 167 168 169
        siv->cur_range = g_list_next(siv->cur_range);
        if (!siv->cur_range) {
            return NULL;
        }
        r = siv->cur_range->data;
        if (!r) {
            return NULL;
        }
170
        siv->cur = range_lob(r);
171 172
    }

173 174
    tail->next = g_malloc0(size);
    return tail->next;
175 176
}

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
static void check_list(Visitor *v, Error **errp)
{
    const StringInputVisitor *siv = to_siv(v);
    Range *r;
    GList *cur_range;

    if (!siv->ranges || !siv->cur_range) {
        return;
    }

    r = siv->cur_range->data;
    if (!r) {
        return;
    }

    if (!range_contains(r, siv->cur)) {
        cur_range = g_list_next(siv->cur_range);
        if (!cur_range) {
            return;
        }
        r = cur_range->data;
        if (!r) {
            return;
        }
    }

    error_setg(errp, "Range contains too many values");
}

E
Eric Blake 已提交
206
static void end_list(Visitor *v, void **obj)
207
{
E
Eric Blake 已提交
208 209 210
    StringInputVisitor *siv = to_siv(v);

    assert(siv->list == obj);
211 212
}

213
static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
214
                             Error **errp)
P
Paolo Bonzini 已提交
215
{
216
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
217

218 219 220
    if (parse_str(siv, name, errp) < 0) {
        return;
    }
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238

    if (!siv->ranges) {
        goto error;
    }

    if (!siv->cur_range) {
        Range *r;

        siv->cur_range = g_list_first(siv->ranges);
        if (!siv->cur_range) {
            goto error;
        }

        r = siv->cur_range->data;
        if (!r) {
            goto error;
        }

239
        siv->cur = range_lob(r);
240 241 242 243 244 245 246
    }

    *obj = siv->cur;
    siv->cur++;
    return;

error:
247
    error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
248
               "an int64 value or range");
P
Paolo Bonzini 已提交
249 250
}

251
static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
252 253 254 255 256
                              Error **errp)
{
    /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
    int64_t i;
    Error *err = NULL;
257
    parse_type_int64(v, name, &i, &err);
258 259 260 261 262 263 264
    if (err) {
        error_propagate(errp, err);
    } else {
        *obj = i;
    }
}

265
static void parse_type_size(Visitor *v, const char *name, uint64_t *obj,
266 267
                            Error **errp)
{
268
    StringInputVisitor *siv = to_siv(v);
269 270 271
    Error *err = NULL;
    uint64_t val;

272
    parse_option_size(name, siv->string, &val, &err);
273 274 275 276 277 278 279 280
    if (err) {
        error_propagate(errp, err);
        return;
    }

    *obj = val;
}

281
static void parse_type_bool(Visitor *v, const char *name, bool *obj,
P
Paolo Bonzini 已提交
282 283
                            Error **errp)
{
284
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
285

286 287 288 289 290 291 292 293 294 295 296
    if (!strcasecmp(siv->string, "on") ||
        !strcasecmp(siv->string, "yes") ||
        !strcasecmp(siv->string, "true")) {
        *obj = true;
        return;
    }
    if (!strcasecmp(siv->string, "off") ||
        !strcasecmp(siv->string, "no") ||
        !strcasecmp(siv->string, "false")) {
        *obj = false;
        return;
P
Paolo Bonzini 已提交
297 298
    }

299 300
    error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
               "boolean");
P
Paolo Bonzini 已提交
301 302
}

303
static void parse_type_str(Visitor *v, const char *name, char **obj,
P
Paolo Bonzini 已提交
304 305
                           Error **errp)
{
306
    StringInputVisitor *siv = to_siv(v);
307 308

    *obj = g_strdup(siv->string);
P
Paolo Bonzini 已提交
309 310
}

311
static void parse_type_number(Visitor *v, const char *name, double *obj,
P
Paolo Bonzini 已提交
312 313
                              Error **errp)
{
314
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
315 316 317 318
    char *endp = (char *) siv->string;
    double val;

    errno = 0;
319 320
    val = strtod(siv->string, &endp);
    if (errno || endp == siv->string || *endp) {
321 322
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
                   "number");
P
Paolo Bonzini 已提交
323 324 325 326 327 328
        return;
    }

    *obj = val;
}

329 330
static void parse_type_null(Visitor *v, const char *name, QNull **obj,
                            Error **errp)
331 332 333
{
    StringInputVisitor *siv = to_siv(v);

334 335
    *obj = NULL;

336 337 338
    if (!siv->string || siv->string[0]) {
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
                   "null");
339
        return;
340
    }
341 342

    *obj = qnull();
343 344
}

E
Eric Blake 已提交
345 346 347 348
static void string_input_free(Visitor *v)
{
    StringInputVisitor *siv = to_siv(v);

349 350 351
    g_list_foreach(siv->ranges, free_range, NULL);
    g_list_free(siv->ranges);
    g_free(siv);
P
Paolo Bonzini 已提交
352 353
}

354
Visitor *string_input_visitor_new(const char *str)
P
Paolo Bonzini 已提交
355 356 357
{
    StringInputVisitor *v;

358
    assert(str);
P
Paolo Bonzini 已提交
359 360
    v = g_malloc0(sizeof(*v));

361
    v->visitor.type = VISITOR_INPUT;
362
    v->visitor.type_int64 = parse_type_int64;
363
    v->visitor.type_uint64 = parse_type_uint64;
364
    v->visitor.type_size = parse_type_size;
P
Paolo Bonzini 已提交
365 366 367
    v->visitor.type_bool = parse_type_bool;
    v->visitor.type_str = parse_type_str;
    v->visitor.type_number = parse_type_number;
368
    v->visitor.type_null = parse_type_null;
369 370
    v->visitor.start_list = start_list;
    v->visitor.next_list = next_list;
371
    v->visitor.check_list = check_list;
372
    v->visitor.end_list = end_list;
E
Eric Blake 已提交
373
    v->visitor.free = string_input_free;
P
Paolo Bonzini 已提交
374 375

    v->string = str;
376
    return &v->visitor;
P
Paolo Bonzini 已提交
377
}