2 * String parsing visitor
4 * Copyright Red Hat, Inc. 2012-2016
6 * Author: Paolo Bonzini <pbonzini@redhat.com>
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.
13 #include "qemu/osdep.h"
14 #include "qapi/error.h"
15 #include "qemu-common.h"
16 #include "qapi/string-input-visitor.h"
17 #include "qapi/visitor-impl.h"
18 #include "qapi/qmp/qerror.h"
19 #include "qapi/qmp/qnull.h"
20 #include "qemu/option.h"
21 #include "qemu/queue.h"
22 #include "qemu/range.h"
25 struct StringInputVisitor
34 void *list
; /* Only needed for sanity checking the caller */
37 static StringInputVisitor
*to_siv(Visitor
*v
)
39 return container_of(v
, StringInputVisitor
, visitor
);
42 static void free_range(void *range
, void *dummy
)
47 static int parse_str(StringInputVisitor
*siv
, const char *name
, Error
**errp
)
49 char *str
= (char *) siv
->string
;
64 start
= strtoll(str
, &endptr
, 0);
65 if (errno
== 0 && endptr
> str
) {
66 if (*endptr
== '\0') {
67 cur
= g_malloc0(sizeof(*cur
));
68 range_set_bounds(cur
, start
, start
);
69 siv
->ranges
= range_list_insert(siv
->ranges
, cur
);
72 } else if (*endptr
== '-') {
75 end
= strtoll(str
, &endptr
, 0);
76 if (errno
== 0 && endptr
> str
&& start
<= end
&&
77 (start
> INT64_MAX
- 65536 ||
78 end
< start
+ 65536)) {
79 if (*endptr
== '\0') {
80 cur
= g_malloc0(sizeof(*cur
));
81 range_set_bounds(cur
, start
, end
);
82 siv
->ranges
= range_list_insert(siv
->ranges
, cur
);
85 } else if (*endptr
== ',') {
87 cur
= g_malloc0(sizeof(*cur
));
88 range_set_bounds(cur
, start
, end
);
89 siv
->ranges
= range_list_insert(siv
->ranges
, cur
);
97 } else if (*endptr
== ',') {
99 cur
= g_malloc0(sizeof(*cur
));
100 range_set_bounds(cur
, start
, start
);
101 siv
->ranges
= range_list_insert(siv
->ranges
, cur
);
113 g_list_foreach(siv
->ranges
, free_range
, NULL
);
114 g_list_free(siv
->ranges
);
116 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, name
? name
: "null",
117 "an int64 value or range");
122 start_list(Visitor
*v
, const char *name
, GenericList
**list
, size_t size
,
125 StringInputVisitor
*siv
= to_siv(v
);
127 /* We don't support visits without a list */
131 if (parse_str(siv
, name
, errp
) < 0) {
136 siv
->cur_range
= g_list_first(siv
->ranges
);
137 if (siv
->cur_range
) {
138 Range
*r
= siv
->cur_range
->data
;
140 siv
->cur
= range_lob(r
);
142 *list
= g_malloc0(size
);
148 static GenericList
*next_list(Visitor
*v
, GenericList
*tail
, size_t size
)
150 StringInputVisitor
*siv
= to_siv(v
);
153 if (!siv
->ranges
|| !siv
->cur_range
) {
157 r
= siv
->cur_range
->data
;
162 if (!range_contains(r
, siv
->cur
)) {
163 siv
->cur_range
= g_list_next(siv
->cur_range
);
164 if (!siv
->cur_range
) {
167 r
= siv
->cur_range
->data
;
171 siv
->cur
= range_lob(r
);
174 tail
->next
= g_malloc0(size
);
178 static void check_list(Visitor
*v
, Error
**errp
)
180 const StringInputVisitor
*siv
= to_siv(v
);
184 if (!siv
->ranges
|| !siv
->cur_range
) {
188 r
= siv
->cur_range
->data
;
193 if (!range_contains(r
, siv
->cur
)) {
194 cur_range
= g_list_next(siv
->cur_range
);
204 error_setg(errp
, "Range contains too many values");
207 static void end_list(Visitor
*v
, void **obj
)
209 StringInputVisitor
*siv
= to_siv(v
);
211 assert(siv
->list
== obj
);
214 static void parse_type_int64(Visitor
*v
, const char *name
, int64_t *obj
,
217 StringInputVisitor
*siv
= to_siv(v
);
219 if (parse_str(siv
, name
, errp
) < 0) {
227 if (!siv
->cur_range
) {
230 siv
->cur_range
= g_list_first(siv
->ranges
);
231 if (!siv
->cur_range
) {
235 r
= siv
->cur_range
->data
;
240 siv
->cur
= range_lob(r
);
248 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, name
? name
: "null",
249 "an int64 value or range");
252 static void parse_type_uint64(Visitor
*v
, const char *name
, uint64_t *obj
,
255 /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
258 parse_type_int64(v
, name
, &i
, &err
);
260 error_propagate(errp
, err
);
266 static void parse_type_size(Visitor
*v
, const char *name
, uint64_t *obj
,
269 StringInputVisitor
*siv
= to_siv(v
);
273 parse_option_size(name
, siv
->string
, &val
, &err
);
275 error_propagate(errp
, err
);
282 static void parse_type_bool(Visitor
*v
, const char *name
, bool *obj
,
285 StringInputVisitor
*siv
= to_siv(v
);
287 if (!strcasecmp(siv
->string
, "on") ||
288 !strcasecmp(siv
->string
, "yes") ||
289 !strcasecmp(siv
->string
, "true")) {
293 if (!strcasecmp(siv
->string
, "off") ||
294 !strcasecmp(siv
->string
, "no") ||
295 !strcasecmp(siv
->string
, "false")) {
300 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
304 static void parse_type_str(Visitor
*v
, const char *name
, char **obj
,
307 StringInputVisitor
*siv
= to_siv(v
);
309 *obj
= g_strdup(siv
->string
);
312 static void parse_type_number(Visitor
*v
, const char *name
, double *obj
,
315 StringInputVisitor
*siv
= to_siv(v
);
316 char *endp
= (char *) siv
->string
;
320 val
= strtod(siv
->string
, &endp
);
321 if (errno
|| endp
== siv
->string
|| *endp
) {
322 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
330 static void parse_type_null(Visitor
*v
, const char *name
, QNull
**obj
,
333 StringInputVisitor
*siv
= to_siv(v
);
337 if (!siv
->string
|| siv
->string
[0]) {
338 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
346 static void string_input_free(Visitor
*v
)
348 StringInputVisitor
*siv
= to_siv(v
);
350 g_list_foreach(siv
->ranges
, free_range
, NULL
);
351 g_list_free(siv
->ranges
);
355 Visitor
*string_input_visitor_new(const char *str
)
357 StringInputVisitor
*v
;
360 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
;
366 v
->visitor
.type_bool
= parse_type_bool
;
367 v
->visitor
.type_str
= parse_type_str
;
368 v
->visitor
.type_number
= parse_type_number
;
369 v
->visitor
.type_null
= parse_type_null
;
370 v
->visitor
.start_list
= start_list
;
371 v
->visitor
.next_list
= next_list
;
372 v
->visitor
.check_list
= check_list
;
373 v
->visitor
.end_list
= end_list
;
374 v
->visitor
.free
= string_input_free
;