blob: 67a0a4a58b522153fa6debbf5890dc55402dcae2 [file] [log] [blame]
Paolo Bonzinia020f982012-02-09 09:36:37 +01001/*
2 * String parsing visitor
3 *
Eric Blake08f95412016-01-29 06:48:59 -07004 * Copyright Red Hat, Inc. 2012-2016
Paolo Bonzinia020f982012-02-09 09:36:37 +01005 *
6 * Author: Paolo Bonzini <pbonzini@redhat.com>
7 *
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.
10 *
11 */
12
Peter Maydellcbf21152016-01-29 17:49:57 +000013#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010014#include "qapi/error.h"
Paolo Bonzinia020f982012-02-09 09:36:37 +010015#include "qemu-common.h"
Paolo Bonzini7b1b5d12012-12-17 18:19:43 +010016#include "qapi/string-input-visitor.h"
17#include "qapi/visitor-impl.h"
18#include "qapi/qmp/qerror.h"
Paolo Bonzinia5829cc2014-02-08 11:01:44 +010019#include "qemu/option.h"
Hu Tao659268f2014-06-10 19:15:27 +080020#include "qemu/queue.h"
21#include "qemu/range.h"
22
Paolo Bonzinia020f982012-02-09 09:36:37 +010023
24struct StringInputVisitor
25{
26 Visitor visitor;
Hu Tao659268f2014-06-10 19:15:27 +080027
Hu Tao659268f2014-06-10 19:15:27 +080028 GList *ranges;
29 GList *cur_range;
30 int64_t cur;
31
Paolo Bonzinia020f982012-02-09 09:36:37 +010032 const char *string;
Eric Blake1158bb22016-06-09 10:48:34 -060033 void *list; /* Only needed for sanity checking the caller */
Paolo Bonzinia020f982012-02-09 09:36:37 +010034};
35
Eric Blaked7bea752016-01-29 06:48:38 -070036static StringInputVisitor *to_siv(Visitor *v)
37{
38 return container_of(v, StringInputVisitor, visitor);
39}
40
Michael S. Tsirkin0d156682014-06-16 18:07:03 +030041static void free_range(void *range, void *dummy)
42{
43 g_free(range);
44}
45
Eric Blake74f24cb2016-04-28 15:45:30 -060046static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
Hu Tao659268f2014-06-10 19:15:27 +080047{
48 char *str = (char *) siv->string;
49 long long start, end;
50 Range *cur;
51 char *endptr;
52
53 if (siv->ranges) {
Eric Blake74f24cb2016-04-28 15:45:30 -060054 return 0;
Hu Tao659268f2014-06-10 19:15:27 +080055 }
56
Markus Armbrusterd2788222017-03-20 17:13:43 +010057 if (!*str) {
58 return 0;
59 }
60
Hu Tao659268f2014-06-10 19:15:27 +080061 do {
Michael S. Tsirkinc210ee92014-06-18 17:50:07 +030062 errno = 0;
Hu Tao659268f2014-06-10 19:15:27 +080063 start = strtoll(str, &endptr, 0);
Michael S. Tsirkinc210ee92014-06-18 17:50:07 +030064 if (errno == 0 && endptr > str) {
Hu Tao659268f2014-06-10 19:15:27 +080065 if (*endptr == '\0') {
66 cur = g_malloc0(sizeof(*cur));
Markus Armbrustera0efbf12016-07-01 13:47:47 +020067 range_set_bounds(cur, start, start);
Eric Blake7c479592016-05-31 10:41:29 -060068 siv->ranges = range_list_insert(siv->ranges, cur);
Hu Tao659268f2014-06-10 19:15:27 +080069 cur = NULL;
70 str = NULL;
71 } else if (*endptr == '-') {
72 str = endptr + 1;
Michael S. Tsirkinc210ee92014-06-18 17:50:07 +030073 errno = 0;
Hu Tao659268f2014-06-10 19:15:27 +080074 end = strtoll(str, &endptr, 0);
Michael S. Tsirkinc210ee92014-06-18 17:50:07 +030075 if (errno == 0 && endptr > str && start <= end &&
Hu Tao659268f2014-06-10 19:15:27 +080076 (start > INT64_MAX - 65536 ||
77 end < start + 65536)) {
78 if (*endptr == '\0') {
79 cur = g_malloc0(sizeof(*cur));
Markus Armbrustera0efbf12016-07-01 13:47:47 +020080 range_set_bounds(cur, start, end);
Eric Blake7c479592016-05-31 10:41:29 -060081 siv->ranges = range_list_insert(siv->ranges, cur);
Hu Tao659268f2014-06-10 19:15:27 +080082 cur = NULL;
83 str = NULL;
84 } else if (*endptr == ',') {
85 str = endptr + 1;
86 cur = g_malloc0(sizeof(*cur));
Markus Armbrustera0efbf12016-07-01 13:47:47 +020087 range_set_bounds(cur, start, end);
Eric Blake7c479592016-05-31 10:41:29 -060088 siv->ranges = range_list_insert(siv->ranges, cur);
Hu Tao659268f2014-06-10 19:15:27 +080089 cur = NULL;
90 } else {
91 goto error;
92 }
93 } else {
94 goto error;
95 }
96 } else if (*endptr == ',') {
97 str = endptr + 1;
98 cur = g_malloc0(sizeof(*cur));
Markus Armbrustera0efbf12016-07-01 13:47:47 +020099 range_set_bounds(cur, start, start);
Eric Blake7c479592016-05-31 10:41:29 -0600100 siv->ranges = range_list_insert(siv->ranges, cur);
Hu Tao659268f2014-06-10 19:15:27 +0800101 cur = NULL;
102 } else {
103 goto error;
104 }
105 } else {
106 goto error;
107 }
108 } while (str);
109
Eric Blake74f24cb2016-04-28 15:45:30 -0600110 return 0;
Hu Tao659268f2014-06-10 19:15:27 +0800111error:
Michael S. Tsirkin0d156682014-06-16 18:07:03 +0300112 g_list_foreach(siv->ranges, free_range, NULL);
113 g_list_free(siv->ranges);
114 siv->ranges = NULL;
Eric Blake74f24cb2016-04-28 15:45:30 -0600115 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
116 "an int64 value or range");
117 return -1;
Hu Tao659268f2014-06-10 19:15:27 +0800118}
119
120static void
Eric Blaked9f62dd2016-04-28 15:45:31 -0600121start_list(Visitor *v, const char *name, GenericList **list, size_t size,
122 Error **errp)
Hu Tao659268f2014-06-10 19:15:27 +0800123{
Eric Blaked7bea752016-01-29 06:48:38 -0700124 StringInputVisitor *siv = to_siv(v);
Hu Tao659268f2014-06-10 19:15:27 +0800125
Eric Blaked9f62dd2016-04-28 15:45:31 -0600126 /* We don't support visits without a list */
127 assert(list);
Eric Blake1158bb22016-06-09 10:48:34 -0600128 siv->list = list;
Eric Blaked9f62dd2016-04-28 15:45:31 -0600129
Eric Blake74f24cb2016-04-28 15:45:30 -0600130 if (parse_str(siv, name, errp) < 0) {
Eric Blaked9f62dd2016-04-28 15:45:31 -0600131 *list = NULL;
Eric Blake74f24cb2016-04-28 15:45:30 -0600132 return;
133 }
Hu Tao659268f2014-06-10 19:15:27 +0800134
135 siv->cur_range = g_list_first(siv->ranges);
136 if (siv->cur_range) {
137 Range *r = siv->cur_range->data;
138 if (r) {
Markus Armbrustera0efbf12016-07-01 13:47:47 +0200139 siv->cur = range_lob(r);
Hu Tao659268f2014-06-10 19:15:27 +0800140 }
Eric Blaked9f62dd2016-04-28 15:45:31 -0600141 *list = g_malloc0(size);
142 } else {
143 *list = NULL;
Hu Tao659268f2014-06-10 19:15:27 +0800144 }
145}
146
Eric Blaked9f62dd2016-04-28 15:45:31 -0600147static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
Hu Tao659268f2014-06-10 19:15:27 +0800148{
Eric Blaked7bea752016-01-29 06:48:38 -0700149 StringInputVisitor *siv = to_siv(v);
Hu Tao659268f2014-06-10 19:15:27 +0800150 Range *r;
151
152 if (!siv->ranges || !siv->cur_range) {
153 return NULL;
154 }
155
156 r = siv->cur_range->data;
157 if (!r) {
158 return NULL;
159 }
160
Markus Armbrustera0efbf12016-07-01 13:47:47 +0200161 if (!range_contains(r, siv->cur)) {
Hu Tao659268f2014-06-10 19:15:27 +0800162 siv->cur_range = g_list_next(siv->cur_range);
163 if (!siv->cur_range) {
164 return NULL;
165 }
166 r = siv->cur_range->data;
167 if (!r) {
168 return NULL;
169 }
Markus Armbrustera0efbf12016-07-01 13:47:47 +0200170 siv->cur = range_lob(r);
Hu Tao659268f2014-06-10 19:15:27 +0800171 }
172
Eric Blaked9f62dd2016-04-28 15:45:31 -0600173 tail->next = g_malloc0(size);
174 return tail->next;
Hu Tao659268f2014-06-10 19:15:27 +0800175}
176
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100177static void check_list(Visitor *v, Error **errp)
178{
179 const StringInputVisitor *siv = to_siv(v);
180 Range *r;
181 GList *cur_range;
182
183 if (!siv->ranges || !siv->cur_range) {
184 return;
185 }
186
187 r = siv->cur_range->data;
188 if (!r) {
189 return;
190 }
191
192 if (!range_contains(r, siv->cur)) {
193 cur_range = g_list_next(siv->cur_range);
194 if (!cur_range) {
195 return;
196 }
197 r = cur_range->data;
198 if (!r) {
199 return;
200 }
201 }
202
203 error_setg(errp, "Range contains too many values");
204}
205
Eric Blake1158bb22016-06-09 10:48:34 -0600206static void end_list(Visitor *v, void **obj)
Hu Tao659268f2014-06-10 19:15:27 +0800207{
Eric Blake1158bb22016-06-09 10:48:34 -0600208 StringInputVisitor *siv = to_siv(v);
209
210 assert(siv->list == obj);
Hu Tao659268f2014-06-10 19:15:27 +0800211}
212
Eric Blake0b2a0d62016-01-29 06:48:56 -0700213static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
Eric Blake4c403142016-01-29 06:48:49 -0700214 Error **errp)
Paolo Bonzinia020f982012-02-09 09:36:37 +0100215{
Eric Blaked7bea752016-01-29 06:48:38 -0700216 StringInputVisitor *siv = to_siv(v);
Paolo Bonzinia020f982012-02-09 09:36:37 +0100217
Eric Blake74f24cb2016-04-28 15:45:30 -0600218 if (parse_str(siv, name, errp) < 0) {
219 return;
220 }
Hu Tao659268f2014-06-10 19:15:27 +0800221
222 if (!siv->ranges) {
223 goto error;
224 }
225
226 if (!siv->cur_range) {
227 Range *r;
228
229 siv->cur_range = g_list_first(siv->ranges);
230 if (!siv->cur_range) {
231 goto error;
232 }
233
234 r = siv->cur_range->data;
235 if (!r) {
236 goto error;
237 }
238
Markus Armbrustera0efbf12016-07-01 13:47:47 +0200239 siv->cur = range_lob(r);
Hu Tao659268f2014-06-10 19:15:27 +0800240 }
241
242 *obj = siv->cur;
243 siv->cur++;
244 return;
245
246error:
Eric Blake0a40bda2016-04-28 15:45:28 -0600247 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100248 "an int64 value or range");
Paolo Bonzinia020f982012-02-09 09:36:37 +0100249}
250
Eric Blake0b2a0d62016-01-29 06:48:56 -0700251static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
Eric Blakef755dea2016-01-29 06:48:50 -0700252 Error **errp)
253{
254 /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
255 int64_t i;
256 Error *err = NULL;
Eric Blake0b2a0d62016-01-29 06:48:56 -0700257 parse_type_int64(v, name, &i, &err);
Eric Blakef755dea2016-01-29 06:48:50 -0700258 if (err) {
259 error_propagate(errp, err);
260 } else {
261 *obj = i;
262 }
263}
264
Eric Blake0b2a0d62016-01-29 06:48:56 -0700265static void parse_type_size(Visitor *v, const char *name, uint64_t *obj,
Paolo Bonzinia5829cc2014-02-08 11:01:44 +0100266 Error **errp)
267{
Eric Blaked7bea752016-01-29 06:48:38 -0700268 StringInputVisitor *siv = to_siv(v);
Paolo Bonzinia5829cc2014-02-08 11:01:44 +0100269 Error *err = NULL;
270 uint64_t val;
271
Markus Armbrusterf332e832017-03-03 13:32:36 +0100272 parse_option_size(name, siv->string, &val, &err);
Paolo Bonzinia5829cc2014-02-08 11:01:44 +0100273 if (err) {
274 error_propagate(errp, err);
275 return;
276 }
277
278 *obj = val;
279}
280
Eric Blake0b2a0d62016-01-29 06:48:56 -0700281static void parse_type_bool(Visitor *v, const char *name, bool *obj,
Paolo Bonzinia020f982012-02-09 09:36:37 +0100282 Error **errp)
283{
Eric Blaked7bea752016-01-29 06:48:38 -0700284 StringInputVisitor *siv = to_siv(v);
Paolo Bonzinia020f982012-02-09 09:36:37 +0100285
Markus Armbrusterf332e832017-03-03 13:32:36 +0100286 if (!strcasecmp(siv->string, "on") ||
287 !strcasecmp(siv->string, "yes") ||
288 !strcasecmp(siv->string, "true")) {
289 *obj = true;
290 return;
291 }
292 if (!strcasecmp(siv->string, "off") ||
293 !strcasecmp(siv->string, "no") ||
294 !strcasecmp(siv->string, "false")) {
295 *obj = false;
296 return;
Paolo Bonzinia020f982012-02-09 09:36:37 +0100297 }
298
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100299 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
300 "boolean");
Paolo Bonzinia020f982012-02-09 09:36:37 +0100301}
302
Eric Blake0b2a0d62016-01-29 06:48:56 -0700303static void parse_type_str(Visitor *v, const char *name, char **obj,
Paolo Bonzinia020f982012-02-09 09:36:37 +0100304 Error **errp)
305{
Eric Blaked7bea752016-01-29 06:48:38 -0700306 StringInputVisitor *siv = to_siv(v);
Markus Armbrusterf332e832017-03-03 13:32:36 +0100307
308 *obj = g_strdup(siv->string);
Paolo Bonzinia020f982012-02-09 09:36:37 +0100309}
310
Eric Blake0b2a0d62016-01-29 06:48:56 -0700311static void parse_type_number(Visitor *v, const char *name, double *obj,
Paolo Bonzinia020f982012-02-09 09:36:37 +0100312 Error **errp)
313{
Eric Blaked7bea752016-01-29 06:48:38 -0700314 StringInputVisitor *siv = to_siv(v);
Paolo Bonzinia020f982012-02-09 09:36:37 +0100315 char *endp = (char *) siv->string;
316 double val;
317
318 errno = 0;
Markus Armbrusterf332e832017-03-03 13:32:36 +0100319 val = strtod(siv->string, &endp);
320 if (errno || endp == siv->string || *endp) {
Markus Armbrusterc6bd8c72015-03-17 11:54:50 +0100321 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
322 "number");
Paolo Bonzinia020f982012-02-09 09:36:37 +0100323 return;
324 }
325
326 *obj = val;
327}
328
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200329static void parse_type_null(Visitor *v, const char *name, QNull **obj,
330 Error **errp)
Greg Kurza7333712016-12-16 16:26:09 +0100331{
332 StringInputVisitor *siv = to_siv(v);
333
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200334 *obj = NULL;
335
Greg Kurza7333712016-12-16 16:26:09 +0100336 if (!siv->string || siv->string[0]) {
337 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
338 "null");
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200339 return;
Greg Kurza7333712016-12-16 16:26:09 +0100340 }
Markus Armbrusterd2f95f42017-06-26 18:22:59 +0200341
342 *obj = qnull();
Greg Kurza7333712016-12-16 16:26:09 +0100343}
344
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600345static void string_input_free(Visitor *v)
346{
347 StringInputVisitor *siv = to_siv(v);
348
Eric Blake7a0525c2016-06-09 10:48:37 -0600349 g_list_foreach(siv->ranges, free_range, NULL);
350 g_list_free(siv->ranges);
351 g_free(siv);
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600352}
353
Eric Blake7a0525c2016-06-09 10:48:37 -0600354Visitor *string_input_visitor_new(const char *str)
Paolo Bonzinia020f982012-02-09 09:36:37 +0100355{
356 StringInputVisitor *v;
357
Markus Armbrusterf332e832017-03-03 13:32:36 +0100358 assert(str);
Paolo Bonzinia020f982012-02-09 09:36:37 +0100359 v = g_malloc0(sizeof(*v));
360
Eric Blake983f52d2016-04-28 15:45:09 -0600361 v->visitor.type = VISITOR_INPUT;
Eric Blake4c403142016-01-29 06:48:49 -0700362 v->visitor.type_int64 = parse_type_int64;
Eric Blakef755dea2016-01-29 06:48:50 -0700363 v->visitor.type_uint64 = parse_type_uint64;
Paolo Bonzinia5829cc2014-02-08 11:01:44 +0100364 v->visitor.type_size = parse_type_size;
Paolo Bonzinia020f982012-02-09 09:36:37 +0100365 v->visitor.type_bool = parse_type_bool;
366 v->visitor.type_str = parse_type_str;
367 v->visitor.type_number = parse_type_number;
Greg Kurza7333712016-12-16 16:26:09 +0100368 v->visitor.type_null = parse_type_null;
Hu Tao659268f2014-06-10 19:15:27 +0800369 v->visitor.start_list = start_list;
370 v->visitor.next_list = next_list;
Markus Armbrustera4a1c702017-03-03 13:32:45 +0100371 v->visitor.check_list = check_list;
Hu Tao659268f2014-06-10 19:15:27 +0800372 v->visitor.end_list = end_list;
Eric Blake2c0ef9f2016-06-09 10:48:35 -0600373 v->visitor.free = string_input_free;
Paolo Bonzinia020f982012-02-09 09:36:37 +0100374
375 v->string = str;
Eric Blake7a0525c2016-06-09 10:48:37 -0600376 return &v->visitor;
Paolo Bonzinia020f982012-02-09 09:36:37 +0100377}