These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / qapi / string-input-visitor.c
1 /*
2  * String parsing visitor
3  *
4  * Copyright Red Hat, Inc. 2012-2016
5  *
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
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"
22
23
24 struct StringInputVisitor
25 {
26     Visitor visitor;
27
28     bool head;
29
30     GList *ranges;
31     GList *cur_range;
32     int64_t cur;
33
34     const char *string;
35 };
36
37 static StringInputVisitor *to_siv(Visitor *v)
38 {
39     return container_of(v, StringInputVisitor, visitor);
40 }
41
42 static void free_range(void *range, void *dummy)
43 {
44     g_free(range);
45 }
46
47 static void parse_str(StringInputVisitor *siv, 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;
56     }
57
58     do {
59         errno = 0;
60         start = strtoll(str, &endptr, 0);
61         if (errno == 0 && endptr > str) {
62             if (*endptr == '\0') {
63                 cur = g_malloc0(sizeof(*cur));
64                 cur->begin = start;
65                 cur->end = start + 1;
66                 siv->ranges = g_list_insert_sorted_merged(siv->ranges, cur,
67                                                           range_compare);
68                 cur = NULL;
69                 str = NULL;
70             } else if (*endptr == '-') {
71                 str = endptr + 1;
72                 errno = 0;
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));
79                         cur->begin = start;
80                         cur->end = end + 1;
81                         siv->ranges =
82                             g_list_insert_sorted_merged(siv->ranges,
83                                                         cur,
84                                                         range_compare);
85                         cur = NULL;
86                         str = NULL;
87                     } else if (*endptr == ',') {
88                         str = endptr + 1;
89                         cur = g_malloc0(sizeof(*cur));
90                         cur->begin = start;
91                         cur->end = end + 1;
92                         siv->ranges =
93                             g_list_insert_sorted_merged(siv->ranges,
94                                                         cur,
95                                                         range_compare);
96                         cur = NULL;
97                     } else {
98                         goto error;
99                     }
100                 } else {
101                     goto error;
102                 }
103             } else if (*endptr == ',') {
104                 str = endptr + 1;
105                 cur = g_malloc0(sizeof(*cur));
106                 cur->begin = start;
107                 cur->end = start + 1;
108                 siv->ranges = g_list_insert_sorted_merged(siv->ranges,
109                                                           cur,
110                                                           range_compare);
111                 cur = NULL;
112             } else {
113                 goto error;
114             }
115         } else {
116             goto error;
117         }
118     } while (str);
119
120     return;
121 error:
122     g_list_foreach(siv->ranges, free_range, NULL);
123     g_list_free(siv->ranges);
124     siv->ranges = NULL;
125 }
126
127 static void
128 start_list(Visitor *v, const char *name, Error **errp)
129 {
130     StringInputVisitor *siv = to_siv(v);
131
132     parse_str(siv, errp);
133
134     siv->cur_range = g_list_first(siv->ranges);
135     if (siv->cur_range) {
136         Range *r = siv->cur_range->data;
137         if (r) {
138             siv->cur = r->begin;
139         }
140     }
141 }
142
143 static GenericList *next_list(Visitor *v, GenericList **list, size_t size)
144 {
145     StringInputVisitor *siv = to_siv(v);
146     GenericList **link;
147     Range *r;
148
149     if (!siv->ranges || !siv->cur_range) {
150         return NULL;
151     }
152
153     r = siv->cur_range->data;
154     if (!r) {
155         return NULL;
156     }
157
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) {
161             return NULL;
162         }
163         r = siv->cur_range->data;
164         if (!r) {
165             return NULL;
166         }
167         siv->cur = r->begin;
168     }
169
170     if (siv->head) {
171         link = list;
172         siv->head = false;
173     } else {
174         link = &(*list)->next;
175     }
176
177     *link = g_malloc0(size);
178     return *link;
179 }
180
181 static void end_list(Visitor *v)
182 {
183     StringInputVisitor *siv = to_siv(v);
184     siv->head = true;
185 }
186
187 static void parse_type_int64(Visitor *v, const char *name, int64_t *obj,
188                              Error **errp)
189 {
190     StringInputVisitor *siv = to_siv(v);
191
192     if (!siv->string) {
193         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
194                    "integer");
195         return;
196     }
197
198     parse_str(siv, errp);
199
200     if (!siv->ranges) {
201         goto error;
202     }
203
204     if (!siv->cur_range) {
205         Range *r;
206
207         siv->cur_range = g_list_first(siv->ranges);
208         if (!siv->cur_range) {
209             goto error;
210         }
211
212         r = siv->cur_range->data;
213         if (!r) {
214             goto error;
215         }
216
217         siv->cur = r->begin;
218     }
219
220     *obj = siv->cur;
221     siv->cur++;
222     return;
223
224 error:
225     error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
226                "an int64 value or range");
227 }
228
229 static void parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
230                               Error **errp)
231 {
232     /* FIXME: parse_type_int64 mishandles values over INT64_MAX */
233     int64_t i;
234     Error *err = NULL;
235     parse_type_int64(v, name, &i, &err);
236     if (err) {
237         error_propagate(errp, err);
238     } else {
239         *obj = i;
240     }
241 }
242
243 static void parse_type_size(Visitor *v, const char *name, uint64_t *obj,
244                             Error **errp)
245 {
246     StringInputVisitor *siv = to_siv(v);
247     Error *err = NULL;
248     uint64_t val;
249
250     if (siv->string) {
251         parse_option_size(name, siv->string, &val, &err);
252     } else {
253         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
254                    "size");
255         return;
256     }
257     if (err) {
258         error_propagate(errp, err);
259         return;
260     }
261
262     *obj = val;
263 }
264
265 static void parse_type_bool(Visitor *v, const char *name, bool *obj,
266                             Error **errp)
267 {
268     StringInputVisitor *siv = to_siv(v);
269
270     if (siv->string) {
271         if (!strcasecmp(siv->string, "on") ||
272             !strcasecmp(siv->string, "yes") ||
273             !strcasecmp(siv->string, "true")) {
274             *obj = true;
275             return;
276         }
277         if (!strcasecmp(siv->string, "off") ||
278             !strcasecmp(siv->string, "no") ||
279             !strcasecmp(siv->string, "false")) {
280             *obj = false;
281             return;
282         }
283     }
284
285     error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
286                "boolean");
287 }
288
289 static void parse_type_str(Visitor *v, const char *name, char **obj,
290                            Error **errp)
291 {
292     StringInputVisitor *siv = to_siv(v);
293     if (siv->string) {
294         *obj = g_strdup(siv->string);
295     } else {
296         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
297                    "string");
298     }
299 }
300
301 static void parse_type_number(Visitor *v, const char *name, double *obj,
302                               Error **errp)
303 {
304     StringInputVisitor *siv = to_siv(v);
305     char *endp = (char *) siv->string;
306     double val;
307
308     errno = 0;
309     if (siv->string) {
310         val = strtod(siv->string, &endp);
311     }
312     if (!siv->string || errno || endp == siv->string || *endp) {
313         error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
314                    "number");
315         return;
316     }
317
318     *obj = val;
319 }
320
321 static void parse_optional(Visitor *v, const char *name, bool *present)
322 {
323     StringInputVisitor *siv = to_siv(v);
324
325     if (!siv->string) {
326         *present = false;
327         return;
328     }
329
330     *present = true;
331 }
332
333 Visitor *string_input_get_visitor(StringInputVisitor *v)
334 {
335     return &v->visitor;
336 }
337
338 void string_input_visitor_cleanup(StringInputVisitor *v)
339 {
340     g_list_foreach(v->ranges, free_range, NULL);
341     g_list_free(v->ranges);
342     g_free(v);
343 }
344
345 StringInputVisitor *string_input_visitor_new(const char *str)
346 {
347     StringInputVisitor *v;
348
349     v = g_malloc0(sizeof(*v));
350
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;
362
363     v->string = str;
364     v->head = true;
365     return v;
366 }