1
2
3
4
5
6
7
8
9
10
11
12
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"
23
24
25struct StringInputVisitor
26{
27 Visitor visitor;
28
29 GList *ranges;
30 GList *cur_range;
31 int64_t cur;
32
33 const char *string;
34 void *list;
35};
36
37static StringInputVisitor *to_siv(Visitor *v)
38{
39 return container_of(v, StringInputVisitor, visitor);
40}
41
42static void free_range(void *range, void *dummy)
43{
44 g_free(range);
45}
46
47static int parse_str(StringInputVisitor *siv, const char *name, Error **errp)
48{
49 char *str = (char *) siv->string;
50 long long start, end;
51 Range *cur;
52 char *endptr;
53
54 if (siv->ranges) {
55 return 0;
56 }
57
58 if (!*str) {
59 return 0;
60 }
61
62 do {
63 errno = 0;
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);
70 cur = NULL;
71 str = NULL;
72 } else if (*endptr == '-') {
73 str = endptr + 1;
74 errno = 0;
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);
83 cur = NULL;
84 str = NULL;
85 } else if (*endptr == ',') {
86 str = endptr + 1;
87 cur = g_malloc0(sizeof(*cur));
88 range_set_bounds(cur, start, end);
89 siv->ranges = range_list_insert(siv->ranges, cur);
90 cur = NULL;
91 } else {
92 goto error;
93 }
94 } else {
95 goto error;
96 }
97 } else if (*endptr == ',') {
98 str = endptr + 1;
99 cur = g_malloc0(sizeof(*cur));
100 range_set_bounds(cur, start, start);
101 siv->ranges = range_list_insert(siv->ranges, cur);
102 cur = NULL;
103 } else {
104 goto error;
105 }
106 } else {
107 goto error;
108 }
109 } while (str);
110
111 return 0;
112error:
113 g_list_foreach(siv->ranges, free_range, NULL);
114 g_list_free(siv->ranges);
115 siv->ranges = NULL;
116 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
117 "an int64 value or range");
118 return -1;
119}
120
121static void
122start_list(Visitor *v, const char *name, GenericList **list, size_t size,
123 Error **errp)
124{
125 StringInputVisitor *siv = to_siv(v);
126
127
128 assert(list);
129 siv->list = list;
130
131 if (parse_str(siv, name, errp) < 0) {
132 *list = NULL;
133 return;
134 }
135
136 siv->cur_range = g_list_first(siv->ranges);
137 if (siv->cur_range) {
138 Range *r = siv->cur_range->data;
139 if (r) {
140 siv->cur = range_lob(r);
141 }
142 *list = g_malloc0(size);
143 } else {
144 *list = NULL;
145 }
146}
147
148static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
149{
150 StringInputVisitor *siv = to_siv(v);
151 Range *r;
152
153 if (!siv->ranges || !siv->cur_range) {
154 return NULL;
155 }
156
157 r = siv->cur_range->data;
158 if (!r) {
159 return NULL;
160 }
161
162 if (!range_contains(r, siv->cur)) {
163 siv->cur_range = g_list_next(siv->cur_range);
164 if (!siv->cur_range) {
165 return NULL;
166 }
167 r = siv->cur_range->data;
168 if (!r) {
169 return NULL;
170 }
171 siv->cur = range_lob(r);
172 }
173
174 tail->next = g_malloc0(size);
175 return tail->next;
176}
177
178static void check_list(Visitor *v, Error **errp)
179{
180 const StringInputVisitor *siv = to_siv(v);
181 Range *r;
182 GList *cur_range;
183
184 if (!siv->ranges || !siv->cur_range) {
185 return;
186 }
187
188 r = siv->cur_range->data;
189 if (!r) {
190 return;
191 }
192
193 if (!range_contains(r, siv->cur)) {
194 cur_range = g_list_next(siv->cur_range);
195 if (!cur_range) {
196 return;
197 }
198 r = cur_range->data;
199 if (!r) {
200 return;
201 }
202 }
203
204 error_setg(errp, "Range contains too many values");
205}
206
207static void end_list(Visitor *v, void **obj)
208{
209 StringInputVisitor *siv = to_siv(v);
210
211 assert(siv->list == obj);
212}
213
214static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
215 Error **errp)
216{
217 StringInputVisitor *siv = to_siv(v);
218
219 if (parse_str(siv, name, errp) < 0) {
220 return;
221 }
222
223 if (!siv->ranges) {
224 goto error;
225 }
226
227 if (!siv->cur_range) {
228 Range *r;
229
230 siv->cur_range = g_list_first(siv->ranges);
231 if (!siv->cur_range) {
232 goto error;
233 }
234
235 r = siv->cur_range->data;
236 if (!r) {
237 goto error;
238 }
239
240 siv->cur = range_lob(r);
241 }
242
243 *obj = siv->cur;
244 siv->cur++;
245 return;
246
247error:
248 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
249 "an int64 value or range");
250}
251
252static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
253 Error **errp)
254{
255
256 int64_t i;
257 Error *err = NULL;
258 parse_type_int64(v, name, &i, &err);
259 if (err) {
260 error_propagate(errp, err);
261 } else {
262 *obj = i;
263 }
264}
265
266static void parse_type_size(Visitor *v, const char *name, uint64_t *obj,
267 Error **errp)
268{
269 StringInputVisitor *siv = to_siv(v);
270 Error *err = NULL;
271 uint64_t val;
272
273 parse_option_size(name, siv->string, &val, &err);
274 if (err) {
275 error_propagate(errp, err);
276 return;
277 }
278
279 *obj = val;
280}
281
282static void parse_type_bool(Visitor *v, const char *name, bool *obj,
283 Error **errp)
284{
285 StringInputVisitor *siv = to_siv(v);
286
287 if (!strcasecmp(siv->string, "on") ||
288 !strcasecmp(siv->string, "yes") ||
289 !strcasecmp(siv->string, "true")) {
290 *obj = true;
291 return;
292 }
293 if (!strcasecmp(siv->string, "off") ||
294 !strcasecmp(siv->string, "no") ||
295 !strcasecmp(siv->string, "false")) {
296 *obj = false;
297 return;
298 }
299
300 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
301 "boolean");
302}
303
304static void parse_type_str(Visitor *v, const char *name, char **obj,
305 Error **errp)
306{
307 StringInputVisitor *siv = to_siv(v);
308
309 *obj = g_strdup(siv->string);
310}
311
312static void parse_type_number(Visitor *v, const char *name, double *obj,
313 Error **errp)
314{
315 StringInputVisitor *siv = to_siv(v);
316 char *endp = (char *) siv->string;
317 double val;
318
319 errno = 0;
320 val = strtod(siv->string, &endp);
321 if (errno || endp == siv->string || *endp) {
322 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
323 "number");
324 return;
325 }
326
327 *obj = val;
328}
329
330static void parse_type_null(Visitor *v, const char *name, QNull **obj,
331 Error **errp)
332{
333 StringInputVisitor *siv = to_siv(v);
334
335 *obj = NULL;
336
337 if (!siv->string || siv->string[0]) {
338 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
339 "null");
340 return;
341 }
342
343 *obj = qnull();
344}
345
346static void string_input_free(Visitor *v)
347{
348 StringInputVisitor *siv = to_siv(v);
349
350 g_list_foreach(siv->ranges, free_range, NULL);
351 g_list_free(siv->ranges);
352 g_free(siv);
353}
354
355Visitor *string_input_visitor_new(const char *str)
356{
357 StringInputVisitor *v;
358
359 assert(str);
360 v = g_malloc0(sizeof(*v));
361
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;
375
376 v->string = str;
377 return &v->visitor;
378}
379