xref: /openbmc/qemu/qapi/string-input-visitor.c (revision 1e0a7549e1f93112a2c0c08d95eb16b604d32cca)
1a020f980SPaolo Bonzini /*
2a020f980SPaolo Bonzini  * String parsing visitor
3a020f980SPaolo Bonzini  *
408f9541dSEric Blake  * Copyright Red Hat, Inc. 2012-2016
5a020f980SPaolo Bonzini  *
6a020f980SPaolo Bonzini  * Author: Paolo Bonzini <pbonzini@redhat.com>
7c9fba9deSDavid Hildenbrand  *         David Hildenbrand <david@redhat.com>
8a020f980SPaolo Bonzini  *
9a020f980SPaolo Bonzini  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10a020f980SPaolo Bonzini  * See the COPYING.LIB file in the top-level directory.
11a020f980SPaolo Bonzini  */
12a020f980SPaolo Bonzini 
13cbf21151SPeter Maydell #include "qemu/osdep.h"
14da34e65cSMarkus Armbruster #include "qapi/error.h"
157b1b5d19SPaolo Bonzini #include "qapi/string-input-visitor.h"
167b1b5d19SPaolo Bonzini #include "qapi/visitor-impl.h"
177b1b5d19SPaolo Bonzini #include "qapi/qmp/qerror.h"
1884be629dSMax Reitz #include "qapi/qmp/qnull.h"
19a5829ccfSPaolo Bonzini #include "qemu/option.h"
204b69d4c3SDavid Hildenbrand #include "qemu/cutils.h"
21659268ffSHu Tao 
22c9fba9deSDavid Hildenbrand typedef enum ListMode {
23c9fba9deSDavid Hildenbrand     /* no list parsing active / no list expected */
24c9fba9deSDavid Hildenbrand     LM_NONE,
25c9fba9deSDavid Hildenbrand     /* we have an unparsed string remaining */
26c9fba9deSDavid Hildenbrand     LM_UNPARSED,
27c9fba9deSDavid Hildenbrand     /* we have an unfinished int64 range */
28c9fba9deSDavid Hildenbrand     LM_INT64_RANGE,
29c9fba9deSDavid Hildenbrand     /* we have an unfinished uint64 range */
30c9fba9deSDavid Hildenbrand     LM_UINT64_RANGE,
31c9fba9deSDavid Hildenbrand     /* we have parsed the string completely and no range is remaining */
32c9fba9deSDavid Hildenbrand     LM_END,
33c9fba9deSDavid Hildenbrand } ListMode;
34c9fba9deSDavid Hildenbrand 
35c9fba9deSDavid Hildenbrand /* protect against DOS attacks, limit the amount of elements per range */
36c9fba9deSDavid Hildenbrand #define RANGE_MAX_ELEMENTS 65536
37c9fba9deSDavid Hildenbrand 
38c9fba9deSDavid Hildenbrand typedef union RangeElement {
39c9fba9deSDavid Hildenbrand     int64_t i64;
40c9fba9deSDavid Hildenbrand     uint64_t u64;
41c9fba9deSDavid Hildenbrand } RangeElement;
42a020f980SPaolo Bonzini 
43a020f980SPaolo Bonzini struct StringInputVisitor
44a020f980SPaolo Bonzini {
45a020f980SPaolo Bonzini     Visitor visitor;
46659268ffSHu Tao 
47c9fba9deSDavid Hildenbrand     /* List parsing state */
48c9fba9deSDavid Hildenbrand     ListMode lm;
49c9fba9deSDavid Hildenbrand     RangeElement rangeNext;
50c9fba9deSDavid Hildenbrand     RangeElement rangeEnd;
51c9fba9deSDavid Hildenbrand     const char *unparsed_string;
52c9fba9deSDavid Hildenbrand     void *list;
53659268ffSHu Tao 
54c9fba9deSDavid Hildenbrand     /* The original string to parse */
55a020f980SPaolo Bonzini     const char *string;
56a020f980SPaolo Bonzini };
57a020f980SPaolo Bonzini 
to_siv(Visitor * v)58d7bea75dSEric Blake static StringInputVisitor *to_siv(Visitor *v)
59d7bea75dSEric Blake {
60d7bea75dSEric Blake     return container_of(v, StringInputVisitor, visitor);
61d7bea75dSEric Blake }
62d7bea75dSEric Blake 
start_list(Visitor * v,const char * name,GenericList ** list,size_t size,Error ** errp)63012d4c96SMarkus Armbruster static bool start_list(Visitor *v, const char *name, GenericList **list,
64c9fba9deSDavid Hildenbrand                        size_t size, Error **errp)
65659268ffSHu Tao {
66d7bea75dSEric Blake     StringInputVisitor *siv = to_siv(v);
67659268ffSHu Tao 
68c9fba9deSDavid Hildenbrand     assert(siv->lm == LM_NONE);
691158bb2aSEric Blake     siv->list = list;
70c9fba9deSDavid Hildenbrand     siv->unparsed_string = siv->string;
71d9f62ddeSEric Blake 
72c9fba9deSDavid Hildenbrand     if (!siv->string[0]) {
73c9fba9deSDavid Hildenbrand         if (list) {
74d9f62ddeSEric Blake             *list = NULL;
7574f24cb6SEric Blake         }
76c9fba9deSDavid Hildenbrand         siv->lm = LM_END;
77d9f62ddeSEric Blake     } else {
78c9fba9deSDavid Hildenbrand         if (list) {
79c9fba9deSDavid Hildenbrand             *list = g_malloc0(size);
80c9fba9deSDavid Hildenbrand         }
81c9fba9deSDavid Hildenbrand         siv->lm = LM_UNPARSED;
82659268ffSHu Tao     }
83012d4c96SMarkus Armbruster     return true;
84659268ffSHu Tao }
85659268ffSHu Tao 
next_list(Visitor * v,GenericList * tail,size_t size)86d9f62ddeSEric Blake static GenericList *next_list(Visitor *v, GenericList *tail, size_t size)
87659268ffSHu Tao {
88d7bea75dSEric Blake     StringInputVisitor *siv = to_siv(v);
89659268ffSHu Tao 
90c9fba9deSDavid Hildenbrand     switch (siv->lm) {
91c9fba9deSDavid Hildenbrand     case LM_END:
92659268ffSHu Tao         return NULL;
93c9fba9deSDavid Hildenbrand     case LM_INT64_RANGE:
94c9fba9deSDavid Hildenbrand     case LM_UINT64_RANGE:
95c9fba9deSDavid Hildenbrand     case LM_UNPARSED:
96c9fba9deSDavid Hildenbrand         /* we have an unparsed string or something left in a range */
97c9fba9deSDavid Hildenbrand         break;
98c9fba9deSDavid Hildenbrand     default:
99c9fba9deSDavid Hildenbrand         abort();
100659268ffSHu Tao     }
101659268ffSHu Tao 
102d9f62ddeSEric Blake     tail->next = g_malloc0(size);
103d9f62ddeSEric Blake     return tail->next;
104659268ffSHu Tao }
105659268ffSHu Tao 
check_list(Visitor * v,Error ** errp)106012d4c96SMarkus Armbruster static bool check_list(Visitor *v, Error **errp)
107a4a1c70dSMarkus Armbruster {
108a4a1c70dSMarkus Armbruster     const StringInputVisitor *siv = to_siv(v);
109a4a1c70dSMarkus Armbruster 
110c9fba9deSDavid Hildenbrand     switch (siv->lm) {
111c9fba9deSDavid Hildenbrand     case LM_INT64_RANGE:
112c9fba9deSDavid Hildenbrand     case LM_UINT64_RANGE:
113c9fba9deSDavid Hildenbrand     case LM_UNPARSED:
114c9fba9deSDavid Hildenbrand         error_setg(errp, "Fewer list elements expected");
115012d4c96SMarkus Armbruster         return false;
116c9fba9deSDavid Hildenbrand     case LM_END:
117012d4c96SMarkus Armbruster         return true;
118c9fba9deSDavid Hildenbrand     default:
119c9fba9deSDavid Hildenbrand         abort();
120a4a1c70dSMarkus Armbruster     }
121a4a1c70dSMarkus Armbruster }
122a4a1c70dSMarkus Armbruster 
end_list(Visitor * v,void ** obj)1231158bb2aSEric Blake static void end_list(Visitor *v, void **obj)
124659268ffSHu Tao {
1251158bb2aSEric Blake     StringInputVisitor *siv = to_siv(v);
1261158bb2aSEric Blake 
127c9fba9deSDavid Hildenbrand     assert(siv->lm != LM_NONE);
1281158bb2aSEric Blake     assert(siv->list == obj);
129c9fba9deSDavid Hildenbrand     siv->list = NULL;
130c9fba9deSDavid Hildenbrand     siv->unparsed_string = NULL;
131c9fba9deSDavid Hildenbrand     siv->lm = LM_NONE;
132c9fba9deSDavid Hildenbrand }
133c9fba9deSDavid Hildenbrand 
try_parse_int64_list_entry(StringInputVisitor * siv,int64_t * obj)134c9fba9deSDavid Hildenbrand static int try_parse_int64_list_entry(StringInputVisitor *siv, int64_t *obj)
135c9fba9deSDavid Hildenbrand {
136c9fba9deSDavid Hildenbrand     const char *endptr;
137c9fba9deSDavid Hildenbrand     int64_t start, end;
138c9fba9deSDavid Hildenbrand 
139c9fba9deSDavid Hildenbrand     /* parse a simple int64 or range */
140c9fba9deSDavid Hildenbrand     if (qemu_strtoi64(siv->unparsed_string, &endptr, 0, &start)) {
141c9fba9deSDavid Hildenbrand         return -EINVAL;
142c9fba9deSDavid Hildenbrand     }
143c9fba9deSDavid Hildenbrand     end = start;
144c9fba9deSDavid Hildenbrand 
145c9fba9deSDavid Hildenbrand     switch (endptr[0]) {
146c9fba9deSDavid Hildenbrand     case '\0':
147c9fba9deSDavid Hildenbrand         siv->unparsed_string = endptr;
148c9fba9deSDavid Hildenbrand         break;
149c9fba9deSDavid Hildenbrand     case ',':
150c9fba9deSDavid Hildenbrand         siv->unparsed_string = endptr + 1;
151c9fba9deSDavid Hildenbrand         break;
152c9fba9deSDavid Hildenbrand     case '-':
153c9fba9deSDavid Hildenbrand         /* parse the end of the range */
154c9fba9deSDavid Hildenbrand         if (qemu_strtoi64(endptr + 1, &endptr, 0, &end)) {
155c9fba9deSDavid Hildenbrand             return -EINVAL;
156c9fba9deSDavid Hildenbrand         }
157c9fba9deSDavid Hildenbrand         if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
158c9fba9deSDavid Hildenbrand             return -EINVAL;
159c9fba9deSDavid Hildenbrand         }
160c9fba9deSDavid Hildenbrand         switch (endptr[0]) {
161c9fba9deSDavid Hildenbrand         case '\0':
162c9fba9deSDavid Hildenbrand             siv->unparsed_string = endptr;
163c9fba9deSDavid Hildenbrand             break;
164c9fba9deSDavid Hildenbrand         case ',':
165c9fba9deSDavid Hildenbrand             siv->unparsed_string = endptr + 1;
166c9fba9deSDavid Hildenbrand             break;
167c9fba9deSDavid Hildenbrand         default:
168c9fba9deSDavid Hildenbrand             return -EINVAL;
169c9fba9deSDavid Hildenbrand         }
170c9fba9deSDavid Hildenbrand         break;
171c9fba9deSDavid Hildenbrand     default:
172c9fba9deSDavid Hildenbrand         return -EINVAL;
173c9fba9deSDavid Hildenbrand     }
174c9fba9deSDavid Hildenbrand 
175c9fba9deSDavid Hildenbrand     /* we have a proper range (with maybe only one element) */
176c9fba9deSDavid Hildenbrand     siv->lm = LM_INT64_RANGE;
177c9fba9deSDavid Hildenbrand     siv->rangeNext.i64 = start;
178c9fba9deSDavid Hildenbrand     siv->rangeEnd.i64 = end;
179c9fba9deSDavid Hildenbrand     return 0;
180659268ffSHu Tao }
181659268ffSHu Tao 
parse_type_int64(Visitor * v,const char * name,int64_t * obj,Error ** errp)182012d4c96SMarkus Armbruster static bool parse_type_int64(Visitor *v, const char *name, int64_t *obj,
183a020f980SPaolo Bonzini                              Error **errp)
184a020f980SPaolo Bonzini {
185d7bea75dSEric Blake     StringInputVisitor *siv = to_siv(v);
186c9fba9deSDavid Hildenbrand     int64_t val;
187a020f980SPaolo Bonzini 
188c9fba9deSDavid Hildenbrand     switch (siv->lm) {
189c9fba9deSDavid Hildenbrand     case LM_NONE:
190c9fba9deSDavid Hildenbrand         /* just parse a simple int64, bail out if not completely consumed */
191c9fba9deSDavid Hildenbrand         if (qemu_strtoi64(siv->string, NULL, 0, &val)) {
192c9fba9deSDavid Hildenbrand             error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
193c9fba9deSDavid Hildenbrand                        name ? name : "null", "int64");
194012d4c96SMarkus Armbruster             return false;
19574f24cb6SEric Blake         }
196c9fba9deSDavid Hildenbrand         *obj = val;
197012d4c96SMarkus Armbruster         return true;
198c9fba9deSDavid Hildenbrand     case LM_UNPARSED:
199c9fba9deSDavid Hildenbrand         if (try_parse_int64_list_entry(siv, obj)) {
2000a40bdabSEric Blake             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
201c9fba9deSDavid Hildenbrand                        "list of int64 values or ranges");
202012d4c96SMarkus Armbruster             return false;
203c9fba9deSDavid Hildenbrand         }
204c9fba9deSDavid Hildenbrand         assert(siv->lm == LM_INT64_RANGE);
205c9fba9deSDavid Hildenbrand         /* fall through */
206c9fba9deSDavid Hildenbrand     case LM_INT64_RANGE:
207c9fba9deSDavid Hildenbrand         /* return the next element in the range */
208c9fba9deSDavid Hildenbrand         assert(siv->rangeNext.i64 <= siv->rangeEnd.i64);
209c9fba9deSDavid Hildenbrand         *obj = siv->rangeNext.i64++;
210c9fba9deSDavid Hildenbrand 
211c9fba9deSDavid Hildenbrand         if (siv->rangeNext.i64 > siv->rangeEnd.i64 || *obj == INT64_MAX) {
212c9fba9deSDavid Hildenbrand             /* end of range, check if there is more to parse */
213c9fba9deSDavid Hildenbrand             siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
214c9fba9deSDavid Hildenbrand         }
215012d4c96SMarkus Armbruster         return true;
216c9fba9deSDavid Hildenbrand     case LM_END:
217c9fba9deSDavid Hildenbrand         error_setg(errp, "Fewer list elements expected");
218012d4c96SMarkus Armbruster         return false;
219c9fba9deSDavid Hildenbrand     default:
220c9fba9deSDavid Hildenbrand         abort();
221c9fba9deSDavid Hildenbrand     }
222c9fba9deSDavid Hildenbrand }
223c9fba9deSDavid Hildenbrand 
try_parse_uint64_list_entry(StringInputVisitor * siv,uint64_t * obj)224c9fba9deSDavid Hildenbrand static int try_parse_uint64_list_entry(StringInputVisitor *siv, uint64_t *obj)
225c9fba9deSDavid Hildenbrand {
226c9fba9deSDavid Hildenbrand     const char *endptr;
227c9fba9deSDavid Hildenbrand     uint64_t start, end;
228c9fba9deSDavid Hildenbrand 
229c9fba9deSDavid Hildenbrand     /* parse a simple uint64 or range */
230c9fba9deSDavid Hildenbrand     if (qemu_strtou64(siv->unparsed_string, &endptr, 0, &start)) {
231c9fba9deSDavid Hildenbrand         return -EINVAL;
232c9fba9deSDavid Hildenbrand     }
233c9fba9deSDavid Hildenbrand     end = start;
234c9fba9deSDavid Hildenbrand 
235c9fba9deSDavid Hildenbrand     switch (endptr[0]) {
236c9fba9deSDavid Hildenbrand     case '\0':
237c9fba9deSDavid Hildenbrand         siv->unparsed_string = endptr;
238c9fba9deSDavid Hildenbrand         break;
239c9fba9deSDavid Hildenbrand     case ',':
240c9fba9deSDavid Hildenbrand         siv->unparsed_string = endptr + 1;
241c9fba9deSDavid Hildenbrand         break;
242c9fba9deSDavid Hildenbrand     case '-':
243c9fba9deSDavid Hildenbrand         /* parse the end of the range */
244c9fba9deSDavid Hildenbrand         if (qemu_strtou64(endptr + 1, &endptr, 0, &end)) {
245c9fba9deSDavid Hildenbrand             return -EINVAL;
246c9fba9deSDavid Hildenbrand         }
247c9fba9deSDavid Hildenbrand         if (start > end || end - start >= RANGE_MAX_ELEMENTS) {
248c9fba9deSDavid Hildenbrand             return -EINVAL;
249c9fba9deSDavid Hildenbrand         }
250c9fba9deSDavid Hildenbrand         switch (endptr[0]) {
251c9fba9deSDavid Hildenbrand         case '\0':
252c9fba9deSDavid Hildenbrand             siv->unparsed_string = endptr;
253c9fba9deSDavid Hildenbrand             break;
254c9fba9deSDavid Hildenbrand         case ',':
255c9fba9deSDavid Hildenbrand             siv->unparsed_string = endptr + 1;
256c9fba9deSDavid Hildenbrand             break;
257c9fba9deSDavid Hildenbrand         default:
258c9fba9deSDavid Hildenbrand             return -EINVAL;
259c9fba9deSDavid Hildenbrand         }
260c9fba9deSDavid Hildenbrand         break;
261c9fba9deSDavid Hildenbrand     default:
262c9fba9deSDavid Hildenbrand         return -EINVAL;
263c9fba9deSDavid Hildenbrand     }
264c9fba9deSDavid Hildenbrand 
265c9fba9deSDavid Hildenbrand     /* we have a proper range (with maybe only one element) */
266c9fba9deSDavid Hildenbrand     siv->lm = LM_UINT64_RANGE;
267c9fba9deSDavid Hildenbrand     siv->rangeNext.u64 = start;
268c9fba9deSDavid Hildenbrand     siv->rangeEnd.u64 = end;
269c9fba9deSDavid Hildenbrand     return 0;
270a020f980SPaolo Bonzini }
271a020f980SPaolo Bonzini 
parse_type_uint64(Visitor * v,const char * name,uint64_t * obj,Error ** errp)272012d4c96SMarkus Armbruster static bool parse_type_uint64(Visitor *v, const char *name, uint64_t *obj,
273f755dea7SEric Blake                               Error **errp)
274f755dea7SEric Blake {
275c9fba9deSDavid Hildenbrand     StringInputVisitor *siv = to_siv(v);
276c9fba9deSDavid Hildenbrand     uint64_t val;
277c9fba9deSDavid Hildenbrand 
278c9fba9deSDavid Hildenbrand     switch (siv->lm) {
279c9fba9deSDavid Hildenbrand     case LM_NONE:
280c9fba9deSDavid Hildenbrand         /* just parse a simple uint64, bail out if not completely consumed */
281c9fba9deSDavid Hildenbrand         if (qemu_strtou64(siv->string, NULL, 0, &val)) {
282c9fba9deSDavid Hildenbrand             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
283c9fba9deSDavid Hildenbrand                        "uint64");
284012d4c96SMarkus Armbruster             return false;
285c9fba9deSDavid Hildenbrand         }
286c9fba9deSDavid Hildenbrand         *obj = val;
287012d4c96SMarkus Armbruster         return true;
288c9fba9deSDavid Hildenbrand     case LM_UNPARSED:
289c9fba9deSDavid Hildenbrand         if (try_parse_uint64_list_entry(siv, obj)) {
290c9fba9deSDavid Hildenbrand             error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
291c9fba9deSDavid Hildenbrand                        "list of uint64 values or ranges");
292012d4c96SMarkus Armbruster             return false;
293c9fba9deSDavid Hildenbrand         }
294c9fba9deSDavid Hildenbrand         assert(siv->lm == LM_UINT64_RANGE);
295c9fba9deSDavid Hildenbrand         /* fall through */
296c9fba9deSDavid Hildenbrand     case LM_UINT64_RANGE:
297c9fba9deSDavid Hildenbrand         /* return the next element in the range */
298c9fba9deSDavid Hildenbrand         assert(siv->rangeNext.u64 <= siv->rangeEnd.u64);
299c9fba9deSDavid Hildenbrand         *obj = siv->rangeNext.u64++;
300c9fba9deSDavid Hildenbrand 
301c9fba9deSDavid Hildenbrand         if (siv->rangeNext.u64 > siv->rangeEnd.u64 || *obj == UINT64_MAX) {
302c9fba9deSDavid Hildenbrand             /* end of range, check if there is more to parse */
303c9fba9deSDavid Hildenbrand             siv->lm = siv->unparsed_string[0] ? LM_UNPARSED : LM_END;
304c9fba9deSDavid Hildenbrand         }
305012d4c96SMarkus Armbruster         return true;
306c9fba9deSDavid Hildenbrand     case LM_END:
307c9fba9deSDavid Hildenbrand         error_setg(errp, "Fewer list elements expected");
308012d4c96SMarkus Armbruster         return false;
309c9fba9deSDavid Hildenbrand     default:
310c9fba9deSDavid Hildenbrand         abort();
311f755dea7SEric Blake     }
312f755dea7SEric Blake }
313f755dea7SEric Blake 
parse_type_size(Visitor * v,const char * name,uint64_t * obj,Error ** errp)314012d4c96SMarkus Armbruster static bool parse_type_size(Visitor *v, const char *name, uint64_t *obj,
315a5829ccfSPaolo Bonzini                             Error **errp)
316a5829ccfSPaolo Bonzini {
317d7bea75dSEric Blake     StringInputVisitor *siv = to_siv(v);
318a5829ccfSPaolo Bonzini     uint64_t val;
319a5829ccfSPaolo Bonzini 
320c9fba9deSDavid Hildenbrand     assert(siv->lm == LM_NONE);
321668f62ecSMarkus Armbruster     if (!parse_option_size(name, siv->string, &val, errp)) {
322012d4c96SMarkus Armbruster         return false;
323a5829ccfSPaolo Bonzini     }
324a5829ccfSPaolo Bonzini 
325a5829ccfSPaolo Bonzini     *obj = val;
326012d4c96SMarkus Armbruster     return true;
327a5829ccfSPaolo Bonzini }
328a5829ccfSPaolo Bonzini 
parse_type_bool(Visitor * v,const char * name,bool * obj,Error ** errp)329012d4c96SMarkus Armbruster static bool parse_type_bool(Visitor *v, const char *name, bool *obj,
330a020f980SPaolo Bonzini                             Error **errp)
331a020f980SPaolo Bonzini {
332d7bea75dSEric Blake     StringInputVisitor *siv = to_siv(v);
333a020f980SPaolo Bonzini 
334c9fba9deSDavid Hildenbrand     assert(siv->lm == LM_NONE);
335372bcb25SPaolo Bonzini     return qapi_bool_parse(name ? name : "null", siv->string, obj, errp);
336a020f980SPaolo Bonzini }
337a020f980SPaolo Bonzini 
parse_type_str(Visitor * v,const char * name,char ** obj,Error ** errp)338012d4c96SMarkus Armbruster static bool parse_type_str(Visitor *v, const char *name, char **obj,
339a020f980SPaolo Bonzini                            Error **errp)
340a020f980SPaolo Bonzini {
341d7bea75dSEric Blake     StringInputVisitor *siv = to_siv(v);
342f332e830SMarkus Armbruster 
343c9fba9deSDavid Hildenbrand     assert(siv->lm == LM_NONE);
344a020f980SPaolo Bonzini     *obj = g_strdup(siv->string);
345012d4c96SMarkus Armbruster     return true;
346a020f980SPaolo Bonzini }
347a020f980SPaolo Bonzini 
parse_type_number(Visitor * v,const char * name,double * obj,Error ** errp)348012d4c96SMarkus Armbruster static bool parse_type_number(Visitor *v, const char *name, double *obj,
349a020f980SPaolo Bonzini                               Error **errp)
350a020f980SPaolo Bonzini {
351d7bea75dSEric Blake     StringInputVisitor *siv = to_siv(v);
352a020f980SPaolo Bonzini     double val;
353a020f980SPaolo Bonzini 
354c9fba9deSDavid Hildenbrand     assert(siv->lm == LM_NONE);
3554b69d4c3SDavid Hildenbrand     if (qemu_strtod_finite(siv->string, NULL, &val)) {
356*aaeafa50SPhilippe Mathieu-Daudé         error_setg(errp, "Invalid parameter type for '%s', expected: number",
357*aaeafa50SPhilippe Mathieu-Daudé                    name ? name : "null");
358012d4c96SMarkus Armbruster         return false;
359a020f980SPaolo Bonzini     }
360a020f980SPaolo Bonzini 
361a020f980SPaolo Bonzini     *obj = val;
362012d4c96SMarkus Armbruster     return true;
363a020f980SPaolo Bonzini }
364a020f980SPaolo Bonzini 
parse_type_null(Visitor * v,const char * name,QNull ** obj,Error ** errp)365012d4c96SMarkus Armbruster static bool parse_type_null(Visitor *v, const char *name, QNull **obj,
366d2f95f4dSMarkus Armbruster                             Error **errp)
367a7333712SGreg Kurz {
368a7333712SGreg Kurz     StringInputVisitor *siv = to_siv(v);
369a7333712SGreg Kurz 
370c9fba9deSDavid Hildenbrand     assert(siv->lm == LM_NONE);
371d2f95f4dSMarkus Armbruster     *obj = NULL;
372d2f95f4dSMarkus Armbruster 
373c9fba9deSDavid Hildenbrand     if (siv->string[0]) {
374*aaeafa50SPhilippe Mathieu-Daudé         error_setg(errp, "Invalid parameter type for '%s', expected: null",
375*aaeafa50SPhilippe Mathieu-Daudé                    name ? name : "null");
376012d4c96SMarkus Armbruster         return false;
377a7333712SGreg Kurz     }
378d2f95f4dSMarkus Armbruster 
379d2f95f4dSMarkus Armbruster     *obj = qnull();
380012d4c96SMarkus Armbruster     return true;
381a7333712SGreg Kurz }
382a7333712SGreg Kurz 
string_input_free(Visitor * v)3832c0ef9f4SEric Blake static void string_input_free(Visitor *v)
3842c0ef9f4SEric Blake {
3852c0ef9f4SEric Blake     StringInputVisitor *siv = to_siv(v);
3862c0ef9f4SEric Blake 
3877a0525c7SEric Blake     g_free(siv);
3882c0ef9f4SEric Blake }
3892c0ef9f4SEric Blake 
string_input_visitor_new(const char * str)3907a0525c7SEric Blake Visitor *string_input_visitor_new(const char *str)
391a020f980SPaolo Bonzini {
392a020f980SPaolo Bonzini     StringInputVisitor *v;
393a020f980SPaolo Bonzini 
394f332e830SMarkus Armbruster     assert(str);
395a020f980SPaolo Bonzini     v = g_malloc0(sizeof(*v));
396a020f980SPaolo Bonzini 
397983f52d4SEric Blake     v->visitor.type = VISITOR_INPUT;
3984c40314aSEric Blake     v->visitor.type_int64 = parse_type_int64;
399f755dea7SEric Blake     v->visitor.type_uint64 = parse_type_uint64;
400a5829ccfSPaolo Bonzini     v->visitor.type_size = parse_type_size;
401a020f980SPaolo Bonzini     v->visitor.type_bool = parse_type_bool;
402a020f980SPaolo Bonzini     v->visitor.type_str = parse_type_str;
403a020f980SPaolo Bonzini     v->visitor.type_number = parse_type_number;
404a7333712SGreg Kurz     v->visitor.type_null = parse_type_null;
405659268ffSHu Tao     v->visitor.start_list = start_list;
406659268ffSHu Tao     v->visitor.next_list = next_list;
407a4a1c70dSMarkus Armbruster     v->visitor.check_list = check_list;
408659268ffSHu Tao     v->visitor.end_list = end_list;
4092c0ef9f4SEric Blake     v->visitor.free = string_input_free;
410a020f980SPaolo Bonzini 
411a020f980SPaolo Bonzini     v->string = str;
412c9fba9deSDavid Hildenbrand     v->lm = LM_NONE;
4137a0525c7SEric Blake     return &v->visitor;
414a020f980SPaolo Bonzini }
415