1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14#include "qapi/error.h"
15#include "qapi/string-input-visitor.h"
16#include "qapi/visitor-impl.h"
17#include "qapi/qmp/qerror.h"
18#include "qapi/qmp/qnull.h"
19#include "qemu/option.h"
20#include "qemu/cutils.h"
21
22typedef enum ListMode {
23
24 LM_NONE,
25
26 LM_UNPARSED,
27
28 LM_INT64_RANGE,
29
30 LM_UINT64_RANGE,
31
32 LM_END,
33} ListMode;
34
35
36#define RANGE_MAX_ELEMENTS 65536
37
38typedef union RangeElement {
39 int64_t i64;
40 uint64_t u64;
41} RangeElement;
42
43struct StringInputVisitor
44{
45 Visitor visitor;
46
47
48 ListMode lm;
49 RangeElement rangeNext;
50 RangeElement rangeEnd;
51 const char *unparsed_string;
52 void *list;
53
54
55 const char *string;
56};
57
58static StringInputVisitor *to_siv(Visitor *v)
59{
60 return container_of(v, StringInputVisitor, visitor);
61}
62
63static bool start_list(Visitor *v, const char *name, GenericList **list,
64 size_t size, Error **errp)
65{
66 StringInputVisitor *siv = to_siv(v);
67
68 assert(siv->lm == LM_NONE);
69 siv->list = list;
70 siv->unparsed_string = siv->string;
71
72 if (!siv->string[0]) {
73 if (list) {
74 *list = NULL;
75 }
76 siv->lm = LM_END;
77 } else {
78 if (list) {
79 *list = g_malloc0(size);
80 }
81 siv->lm = LM_UNPARSED;
82 }
83 return true;
84}
85
86static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
87{
88 StringInputVisitor *siv = to_siv(v);
89
90 switch (siv->lm) {
91 case LM_END:
92 return NULL;
93 case LM_INT64_RANGE:
94 case LM_UINT64_RANGE:
95 case LM_UNPARSED:
96
97 break;
98 default:
99 abort();
100 }
101
102 tail->next = g_malloc0(size);
103 return tail->next;
104}
105
106static bool check_list(Visitor *v, Error **errp)
107{
108 const StringInputVisitor *siv = to_siv(v);
109
110 switch (siv->lm) {
111 case LM_INT64_RANGE:
112 case LM_UINT64_RANGE:
113 case LM_UNPARSED:
114 error_setg(errp, "Fewer list elements expected");
115 return false;
116 case LM_END:
117 return true;
118 default:
119 abort();
120 }
121}
122
123static void end_list(Visitor *v, void **obj)
124{
125 StringInputVisitor *siv = to_siv(v);
126
127 assert(siv->lm != LM_NONE);
128 assert(siv->list == obj);
129 siv->list = NULL;
130 siv->unparsed_string = NULL;
131 siv->lm = LM_NONE;
132}
133
134static int try_parse_int64_list_entry(StringInputVisitor *siv, int64_t *obj)
135{
136 const char *endptr;
137 int64_t start, end;
138
139
140 if (qemu_strtoi64(siv->unparsed_string, &endptr, 0, &start)) {
141 return -EINVAL;
142 }
143 end = start;
144
145 switch (endptr[0]) {
146 case '\0':
147 siv->unparsed_string = endptr;
148 break;
149 case ',':
150 siv->unparsed_string = endptr + 1;
151 break;
152 case '-':
153
154 if (qemu_strtoi64(endptr + 1, &endptr, 0, &end)) {
155 return -EINVAL;
156 }
157 if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
158 return -EINVAL;
159 }
160 switch (endptr[0]) {
161 case '\0':
162 siv->unparsed_string = endptr;
163 break;
164 case ',':
165 siv->unparsed_string = endptr + 1;
166 break;
167 default:
168 return -EINVAL;
169 }
170 break;
171 default:
172 return -EINVAL;
173 }
174
175
176 siv->lm = LM_INT64_RANGE;
177 siv->rangeNext.i64 = start;
178 siv->rangeEnd.i64 = end;
179 return 0;
180}
181
182static bool parse_type_int64(Visitor *v, const char *name, int64_t *obj,
183 Error **errp)
184{
185 StringInputVisitor *siv = to_siv(v);
186 int64_t val;
187
188 switch (siv->lm) {
189 case LM_NONE:
190
191 if (qemu_strtoi64(siv->string, NULL, 0, &val)) {
192 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
193 name ? name : "null", "int64");
194 return false;
195 }
196 *obj = val;
197 return true;
198 case LM_UNPARSED:
199 if (try_parse_int64_list_entry(siv, obj)) {
200 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
201 "list of int64 values or ranges");
202 return false;
203 }
204 assert(siv->lm == LM_INT64_RANGE);
205
206 case LM_INT64_RANGE:
207
208 assert(siv->rangeNext.i64 <= siv->rangeEnd.i64);
209 *obj = siv->rangeNext.i64++;
210
211 if (siv->rangeNext.i64 > siv->rangeEnd.i64 || *obj == INT64_MAX) {
212
213 siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
214 }
215 return true;
216 case LM_END:
217 error_setg(errp, "Fewer list elements expected");
218 return false;
219 default:
220 abort();
221 }
222}
223
224static int try_parse_uint64_list_entry(StringInputVisitor *siv, uint64_t *obj)
225{
226 const char *endptr;
227 uint64_t start, end;
228
229
230 if (qemu_strtou64(siv->unparsed_string, &endptr, 0, &start)) {
231 return -EINVAL;
232 }
233 end = start;
234
235 switch (endptr[0]) {
236 case '\0':
237 siv->unparsed_string = endptr;
238 break;
239 case ',':
240 siv->unparsed_string = endptr + 1;
241 break;
242 case '-':
243
244 if (qemu_strtou64(endptr + 1, &endptr, 0, &end)) {
245 return -EINVAL;
246 }
247 if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
248 return -EINVAL;
249 }
250 switch (endptr[0]) {
251 case '\0':
252 siv->unparsed_string = endptr;
253 break;
254 case ',':
255 siv->unparsed_string = endptr + 1;
256 break;
257 default:
258 return -EINVAL;
259 }
260 break;
261 default:
262 return -EINVAL;
263 }
264
265
266 siv->lm = LM_UINT64_RANGE;
267 siv->rangeNext.u64 = start;
268 siv->rangeEnd.u64 = end;
269 return 0;
270}
271
272static bool parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
273 Error **errp)
274{
275 StringInputVisitor *siv = to_siv(v);
276 uint64_t val;
277
278 switch (siv->lm) {
279 case LM_NONE:
280
281 if (qemu_strtou64(siv->string, NULL, 0, &val)) {
282 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
283 "uint64");
284 return false;
285 }
286 *obj = val;
287 return true;
288 case LM_UNPARSED:
289 if (try_parse_uint64_list_entry(siv, obj)) {
290 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
291 "list of uint64 values or ranges");
292 return false;
293 }
294 assert(siv->lm == LM_UINT64_RANGE);
295
296 case LM_UINT64_RANGE:
297
298 assert(siv->rangeNext.u64 <= siv->rangeEnd.u64);
299 *obj = siv->rangeNext.u64++;
300
301 if (siv->rangeNext.u64 > siv->rangeEnd.u64 || *obj == UINT64_MAX) {
302
303 siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
304 }
305 return true;
306 case LM_END:
307 error_setg(errp, "Fewer list elements expected");
308 return false;
309 default:
310 abort();
311 }
312}
313
314static bool parse_type_size(Visitor *v, const char *name, uint64_t *obj,
315 Error **errp)
316{
317 StringInputVisitor *siv = to_siv(v);
318 uint64_t val;
319
320 assert(siv->lm == LM_NONE);
321 if (!parse_option_size(name, siv->string, &val, errp)) {
322 return false;
323 }
324
325 *obj = val;
326 return true;
327}
328
329static bool parse_type_bool(Visitor *v, const char *name, bool *obj,
330 Error **errp)
331{
332 StringInputVisitor *siv = to_siv(v);
333
334 assert(siv->lm == LM_NONE);
335 if (!strcasecmp(siv->string, "on") ||
336 !strcasecmp(siv->string, "yes") ||
337 !strcasecmp(siv->string, "true")) {
338 *obj = true;
339 return true;
340 }
341 if (!strcasecmp(siv->string, "off") ||
342 !strcasecmp(siv->string, "no") ||
343 !strcasecmp(siv->string, "false")) {
344 *obj = false;
345 return true;
346 }
347
348 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
349 "boolean");
350 return false;
351}
352
353static bool parse_type_str(Visitor *v, const char *name, char **obj,
354 Error **errp)
355{
356 StringInputVisitor *siv = to_siv(v);
357
358 assert(siv->lm == LM_NONE);
359 *obj = g_strdup(siv->string);
360 return true;
361}
362
363static bool parse_type_number(Visitor *v, const char *name, double *obj,
364 Error **errp)
365{
366 StringInputVisitor *siv = to_siv(v);
367 double val;
368
369 assert(siv->lm == LM_NONE);
370 if (qemu_strtod_finite(siv->string, NULL, &val)) {
371 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
372 "number");
373 return false;
374 }
375
376 *obj = val;
377 return true;
378}
379
380static bool parse_type_null(Visitor *v, const char *name, QNull **obj,
381 Error **errp)
382{
383 StringInputVisitor *siv = to_siv(v);
384
385 assert(siv->lm == LM_NONE);
386 *obj = NULL;
387
388 if (siv->string[0]) {
389 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
390 "null");
391 return false;
392 }
393
394 *obj = qnull();
395 return true;
396}
397
398static void string_input_free(Visitor *v)
399{
400 StringInputVisitor *siv = to_siv(v);
401
402 g_free(siv);
403}
404
405Visitor *string_input_visitor_new(const char *str)
406{
407 StringInputVisitor *v;
408
409 assert(str);
410 v = g_malloc0(sizeof(*v));
411
412 v->visitor.type = VISITOR_INPUT;
413 v->visitor.type_int64 = parse_type_int64;
414 v->visitor.type_uint64 = parse_type_uint64;
415 v->visitor.type_size = parse_type_size;
416 v->visitor.type_bool = parse_type_bool;
417 v->visitor.type_str = parse_type_str;
418 v->visitor.type_number = parse_type_number;
419 v->visitor.type_null = parse_type_null;
420 v->visitor.start_list = start_list;
421 v->visitor.next_list = next_list;
422 v->visitor.check_list = check_list;
423 v->visitor.end_list = end_list;
424 v->visitor.free = string_input_free;
425
426 v->string = str;
427 v->lm = LM_NONE;
428 return &v->visitor;
429}
430