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 "qemu/option.h"
20 #include "qemu/queue.h"
21 #include "qemu/range.h"
24 struct StringInputVisitor
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 void parse_str(StringInputVisitor
*siv
, Error
**errp
)
49 char *str
= (char *) siv
->string
;
60 start
= strtoll(str
, &endptr
, 0);
61 if (errno
== 0 && endptr
> str
) {
62 if (*endptr
== '\0') {
63 cur
= g_malloc0(sizeof(*cur
));
66 siv
->ranges
= g_list_insert_sorted_merged(siv
->ranges
, cur
,
70 } else if (*endptr
== '-') {
73 end
= strtoll(str
, &endptr
, 0);
74 if (errno
== 0 && endptr
> str
&& start
<= end
&&
75 (start
> INT64_MAX
- 65536 ||
76 end
< start
+ 65536)) {
77 if (*endptr
== '\0') {
78 cur
= g_malloc0(sizeof(*cur
));
82 g_list_insert_sorted_merged(siv
->ranges
,
87 } else if (*endptr
== ',') {
89 cur
= g_malloc0(sizeof(*cur
));
93 g_list_insert_sorted_merged(siv
->ranges
,
103 } else if (*endptr
== ',') {
105 cur
= g_malloc0(sizeof(*cur
));
107 cur
->end
= start
+ 1;
108 siv
->ranges
= g_list_insert_sorted_merged(siv
->ranges
,
122 g_list_foreach(siv
->ranges
, free_range
, NULL
);
123 g_list_free(siv
->ranges
);
128 start_list(Visitor
*v
, const char *name
, Error
**errp
)
130 StringInputVisitor
*siv
= to_siv(v
);
132 parse_str(siv
, errp
);
134 siv
->cur_range
= g_list_first(siv
->ranges
);
135 if (siv
->cur_range
) {
136 Range
*r
= siv
->cur_range
->data
;
143 static GenericList
*next_list(Visitor
*v
, GenericList
**list
, size_t size
)
145 StringInputVisitor
*siv
= to_siv(v
);
149 if (!siv
->ranges
|| !siv
->cur_range
) {
153 r
= siv
->cur_range
->data
;
158 if (siv
->cur
< r
->begin
|| siv
->cur
>= r
->end
) {
159 siv
->cur_range
= g_list_next(siv
->cur_range
);
160 if (!siv
->cur_range
) {
163 r
= siv
->cur_range
->data
;
174 link
= &(*list
)->next
;
177 *link
= g_malloc0(size
);
181 static void end_list(Visitor
*v
)
183 StringInputVisitor
*siv
= to_siv(v
);
187 static void parse_type_int64(Visitor
*v
, const char *name
, int64_t *obj
,
190 StringInputVisitor
*siv
= to_siv(v
);
193 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
198 parse_str(siv
, errp
);
204 if (!siv
->cur_range
) {
207 siv
->cur_range
= g_list_first(siv
->ranges
);
208 if (!siv
->cur_range
) {
212 r
= siv
->cur_range
->data
;
225 error_setg(errp
, QERR_INVALID_PARAMETER_VALUE
, name
,
226 "an int64 value or range");
229 static void parse_type_uint64(Visitor
*v
, const char *name
, uint64_t *obj
,
232 /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
235 parse_type_int64(v
, name
, &i
, &err
);
237 error_propagate(errp
, err
);
243 static void parse_type_size(Visitor
*v
, const char *name
, uint64_t *obj
,
246 StringInputVisitor
*siv
= to_siv(v
);
251 parse_option_size(name
, siv
->string
, &val
, &err
);
253 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
258 error_propagate(errp
, err
);
265 static void parse_type_bool(Visitor
*v
, const char *name
, bool *obj
,
268 StringInputVisitor
*siv
= to_siv(v
);
271 if (!strcasecmp(siv
->string
, "on") ||
272 !strcasecmp(siv
->string
, "yes") ||
273 !strcasecmp(siv
->string
, "true")) {
277 if (!strcasecmp(siv
->string
, "off") ||
278 !strcasecmp(siv
->string
, "no") ||
279 !strcasecmp(siv
->string
, "false")) {
285 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
289 static void parse_type_str(Visitor
*v
, const char *name
, char **obj
,
292 StringInputVisitor
*siv
= to_siv(v
);
294 *obj
= g_strdup(siv
->string
);
296 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
301 static void parse_type_number(Visitor
*v
, const char *name
, double *obj
,
304 StringInputVisitor
*siv
= to_siv(v
);
305 char *endp
= (char *) siv
->string
;
310 val
= strtod(siv
->string
, &endp
);
312 if (!siv
->string
|| errno
|| endp
== siv
->string
|| *endp
) {
313 error_setg(errp
, QERR_INVALID_PARAMETER_TYPE
, name
? name
: "null",
321 static void parse_optional(Visitor
*v
, const char *name
, bool *present
)
323 StringInputVisitor
*siv
= to_siv(v
);
333 Visitor
*string_input_get_visitor(StringInputVisitor
*v
)
338 void string_input_visitor_cleanup(StringInputVisitor
*v
)
340 g_list_foreach(v
->ranges
, free_range
, NULL
);
341 g_list_free(v
->ranges
);
345 StringInputVisitor
*string_input_visitor_new(const char *str
)
347 StringInputVisitor
*v
;
349 v
= g_malloc0(sizeof(*v
));
351 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
;
355 v
->visitor
.type_bool
= parse_type_bool
;
356 v
->visitor
.type_str
= parse_type_str
;
357 v
->visitor
.type_number
= parse_type_number
;
358 v
->visitor
.start_list
= start_list
;
359 v
->visitor
.next_list
= next_list
;
360 v
->visitor
.end_list
= end_list
;
361 v
->visitor
.optional
= parse_optional
;