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 32 33

    bool head;

    GList *ranges;
    GList *cur_range;
    int64_t cur;

P
Paolo Bonzini 已提交
34 35 36
    const char *string;
};

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 48 49 50 51 52 53 54 55 56 57 58
static void parse_str(StringInputVisitor *siv, Error **errp)
{
    char *str = (char *) siv->string;
    long long start, end;
    Range *cur;
    char *endptr;

    if (siv->ranges) {
        return;
    }

    do {
59
        errno = 0;
60
        start = strtoll(str, &endptr, 0);
61
        if (errno == 0 && endptr > str) {
62 63 64 65 66 67 68 69 70 71
            if (*endptr == '\0') {
                cur = g_malloc0(sizeof(*cur));
                cur->begin = start;
                cur->end = start + 1;
                siv->ranges = g_list_insert_sorted_merged(siv->ranges, cur,
                                                          range_compare);
                cur = NULL;
                str = NULL;
            } else if (*endptr == '-') {
                str = endptr + 1;
72
                errno = 0;
73
                end = strtoll(str, &endptr, 0);
74
                if (errno == 0 && endptr > str && start <= end &&
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
                    (start > INT64_MAX - 65536 ||
                     end < start + 65536)) {
                    if (*endptr == '\0') {
                        cur = g_malloc0(sizeof(*cur));
                        cur->begin = start;
                        cur->end = end + 1;
                        siv->ranges =
                            g_list_insert_sorted_merged(siv->ranges,
                                                        cur,
                                                        range_compare);
                        cur = NULL;
                        str = NULL;
                    } else if (*endptr == ',') {
                        str = endptr + 1;
                        cur = g_malloc0(sizeof(*cur));
                        cur->begin = start;
                        cur->end = end + 1;
                        siv->ranges =
                            g_list_insert_sorted_merged(siv->ranges,
                                                        cur,
                                                        range_compare);
                        cur = NULL;
                    } else {
                        goto error;
                    }
                } else {
                    goto error;
                }
            } else if (*endptr == ',') {
                str = endptr + 1;
                cur = g_malloc0(sizeof(*cur));
                cur->begin = start;
                cur->end = start + 1;
                siv->ranges = g_list_insert_sorted_merged(siv->ranges,
                                                          cur,
                                                          range_compare);
                cur = NULL;
            } else {
                goto error;
            }
        } else {
            goto error;
        }
    } while (str);

    return;
error:
122 123 124
    g_list_foreach(siv->ranges, free_range, NULL);
    g_list_free(siv->ranges);
    siv->ranges = NULL;
125 126 127 128 129
}

static void
start_list(Visitor *v, const char *name, Error **errp)
{
130
    StringInputVisitor *siv = to_siv(v);
131 132 133 134 135 136 137 138 139 140 141 142

    parse_str(siv, errp);

    siv->cur_range = g_list_first(siv->ranges);
    if (siv->cur_range) {
        Range *r = siv->cur_range->data;
        if (r) {
            siv->cur = r->begin;
        }
    }
}

143
static GenericList *next_list(Visitor *v, GenericList **list, size_t size)
144
{
145
    StringInputVisitor *siv = to_siv(v);
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    GenericList **link;
    Range *r;

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

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

    if (siv->cur < r->begin || siv->cur >= r->end) {
        siv->cur_range = g_list_next(siv->cur_range);
        if (!siv->cur_range) {
            return NULL;
        }
        r = siv->cur_range->data;
        if (!r) {
            return NULL;
        }
        siv->cur = r->begin;
    }

    if (siv->head) {
        link = list;
        siv->head = false;
    } else {
        link = &(*list)->next;
    }

177
    *link = g_malloc0(size);
178 179 180
    return *link;
}

181
static void end_list(Visitor *v)
182
{
183
    StringInputVisitor *siv = to_siv(v);
184 185 186
    siv->head = true;
}

187
static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
188
                             Error **errp)
P
Paolo Bonzini 已提交
189
{
190
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
191

192
    if (!siv->string) {
193 194
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
                   "integer");
P
Paolo Bonzini 已提交
195 196 197
        return;
    }

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224
    parse_str(siv, errp);

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

        siv->cur = r->begin;
    }

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

error:
225
    error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
226
               "an int64 value or range");
P
Paolo Bonzini 已提交
227 228
}

229
static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
230 231 232 233 234
                              Error **errp)
{
    /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
    int64_t i;
    Error *err = NULL;
235
    parse_type_int64(v, name, &i, &err);
236 237 238 239 240 241 242
    if (err) {
        error_propagate(errp, err);
    } else {
        *obj = i;
    }
}

243
static void parse_type_size(Visitor *v, const char *name, uint64_t *obj,
244 245
                            Error **errp)
{
246
    StringInputVisitor *siv = to_siv(v);
247 248 249 250 251 252
    Error *err = NULL;
    uint64_t val;

    if (siv->string) {
        parse_option_size(name, siv->string, &val, &err);
    } else {
253 254
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
                   "size");
255 256 257 258 259 260 261 262 263 264
        return;
    }
    if (err) {
        error_propagate(errp, err);
        return;
    }

    *obj = val;
}

265
static void parse_type_bool(Visitor *v, const char *name, bool *obj,
P
Paolo Bonzini 已提交
266 267
                            Error **errp)
{
268
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284

    if (siv->string) {
        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;
        }
    }

285 286
    error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
               "boolean");
P
Paolo Bonzini 已提交
287 288
}

289
static void parse_type_str(Visitor *v, const char *name, char **obj,
P
Paolo Bonzini 已提交
290 291
                           Error **errp)
{
292
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
293 294 295
    if (siv->string) {
        *obj = g_strdup(siv->string);
    } else {
296 297
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
                   "string");
P
Paolo Bonzini 已提交
298 299 300
    }
}

301
static void parse_type_number(Visitor *v, const char *name, double *obj,
P
Paolo Bonzini 已提交
302 303
                              Error **errp)
{
304
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
305 306 307 308 309 310 311 312
    char *endp = (char *) siv->string;
    double val;

    errno = 0;
    if (siv->string) {
        val = strtod(siv->string, &endp);
    }
    if (!siv->string || errno || endp == siv->string || *endp) {
313 314
        error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
                   "number");
P
Paolo Bonzini 已提交
315 316 317 318 319 320
        return;
    }

    *obj = val;
}

321
static void parse_optional(Visitor *v, const char *name, bool *present)
P
Paolo Bonzini 已提交
322
{
323
    StringInputVisitor *siv = to_siv(v);
P
Paolo Bonzini 已提交
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339

    if (!siv->string) {
        *present = false;
        return;
    }

    *present = true;
}

Visitor *string_input_get_visitor(StringInputVisitor *v)
{
    return &v->visitor;
}

void string_input_visitor_cleanup(StringInputVisitor *v)
{
340 341
    g_list_foreach(v->ranges, free_range, NULL);
    g_list_free(v->ranges);
P
Paolo Bonzini 已提交
342 343 344 345 346 347 348 349 350 351
    g_free(v);
}

StringInputVisitor *string_input_visitor_new(const char *str)
{
    StringInputVisitor *v;

    v = g_malloc0(sizeof(*v));

    v->visitor.type_enum = input_type_enum;
352
    v->visitor.type_int64 = parse_type_int64;
353
    v->visitor.type_uint64 = parse_type_uint64;
354
    v->visitor.type_size = parse_type_size;
P
Paolo Bonzini 已提交
355 356 357
    v->visitor.type_bool = parse_type_bool;
    v->visitor.type_str = parse_type_str;
    v->visitor.type_number = parse_type_number;
358 359 360
    v->visitor.start_list = start_list;
    v->visitor.next_list = next_list;
    v->visitor.end_list = end_list;
361
    v->visitor.optional = parse_optional;
P
Paolo Bonzini 已提交
362 363

    v->string = str;
364
    v->head = true;
P
Paolo Bonzini 已提交
365 366
    return v;
}