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"
M
Max Reitz 已提交
19
#include "qapi/qmp/qnull.h"
20
#include "qemu/option.h"
21 22 23
#include "qemu/queue.h"
#include "qemu/range.h"

P
Paolo Bonzini 已提交
24 25 26 27

struct StringInputVisitor
{
    Visitor visitor;
28 29 30 31 32

    GList *ranges;
    GList *cur_range;
    int64_t cur;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

174 175
    tail->next = g_malloc0(size);
    return tail->next;
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 206
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 已提交
207
static void end_list(Visitor *v, void **obj)
208
{
E
Eric Blake 已提交
209 210 211
    StringInputVisitor *siv = to_siv(v);

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

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

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

    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;
        }

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

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

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

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

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

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

    *obj = val;
}

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

287 288 289 290 291 292 293 294 295 296 297
    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 已提交
298 299
    }

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

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

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

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

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

    *obj = val;
}

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

335 336
    *obj = NULL;

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

    *obj = qnull();
344 345
}

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

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

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

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

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

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