1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92#include "qemu/osdep.h"
93#include "qapi/error.h"
94#include "qapi/qmp/qdict.h"
95#include "qapi/qmp/qlist.h"
96#include "qapi/qmp/qstring.h"
97#include "qemu/cutils.h"
98#include "qemu/keyval.h"
99#include "qemu/help_option.h"
100
101
102
103
104
105
106
107
108
109
110
111
112
113static int key_to_index(const char *key, const char **end)
114{
115 int ret;
116 unsigned long index;
117
118 if (*key < '0' || *key > '9') {
119 return -EINVAL;
120 }
121 ret = qemu_strtoul(key, end, 10, &index);
122 if (ret) {
123 return ret == -ERANGE ? INT_MAX : ret;
124 }
125 return index <= INT_MAX ? index : INT_MAX;
126}
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145static QObject *keyval_parse_put(QDict *cur,
146 const char *key_in_cur, QString *value,
147 const char *key, const char *key_cursor,
148 Error **errp)
149{
150 QObject *old, *new;
151
152 old = qdict_get(cur, key_in_cur);
153 if (old) {
154 if (qobject_type(old) != (value ? QTYPE_QSTRING : QTYPE_QDICT)) {
155 error_setg(errp, "Parameters '%.*s.*' used inconsistently",
156 (int)(key_cursor - key), key);
157 qobject_unref(value);
158 return NULL;
159 }
160 if (!value) {
161 return old;
162 }
163 new = QOBJECT(value);
164 } else {
165 new = value ? QOBJECT(value) : QOBJECT(qdict_new());
166 }
167 qdict_put_obj(cur, key_in_cur, new);
168 return new;
169}
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184static const char *keyval_parse_one(QDict *qdict, const char *params,
185 const char *implied_key, bool *help,
186 Error **errp)
187{
188 const char *key, *key_end, *val_end, *s, *end;
189 size_t len;
190 char key_in_cur[128];
191 QDict *cur;
192 int ret;
193 QObject *next;
194 GString *val;
195
196 key = params;
197 val_end = NULL;
198 len = strcspn(params, "=,");
199 if (len && key[len] != '=') {
200 if (starts_with_help_option(key) == len) {
201 *help = true;
202 s = key + len;
203 if (*s == ',') {
204 s++;
205 }
206 return s;
207 }
208 if (implied_key) {
209
210 key = implied_key;
211 val_end = params + len;
212 len = strlen(implied_key);
213 }
214 }
215 key_end = key + len;
216
217
218
219
220
221 cur = qdict;
222 s = key;
223 for (;;) {
224
225 if (s != key && key_to_index(s, &end) >= 0) {
226 len = end - s;
227 } else {
228 ret = parse_qapi_name(s, false);
229 len = ret < 0 ? 0 : ret;
230 }
231 assert(s + len <= key_end);
232 if (!len || (s + len < key_end && s[len] != '.')) {
233 assert(key != implied_key);
234 error_setg(errp, "Invalid parameter '%.*s'",
235 (int)(key_end - key), key);
236 return NULL;
237 }
238 if (len >= sizeof(key_in_cur)) {
239 assert(key != implied_key);
240 error_setg(errp, "Parameter%s '%.*s' is too long",
241 s != key || s + len != key_end ? " fragment" : "",
242 (int)len, s);
243 return NULL;
244 }
245
246 if (s != key) {
247 next = keyval_parse_put(cur, key_in_cur, NULL,
248 key, s - 1, errp);
249 if (!next) {
250 return NULL;
251 }
252 cur = qobject_to(QDict, next);
253 assert(cur);
254 }
255
256 memcpy(key_in_cur, s, len);
257 key_in_cur[len] = 0;
258 s += len;
259
260 if (*s != '.') {
261 break;
262 }
263 s++;
264 }
265
266 if (key == implied_key) {
267 assert(!*s);
268 val = g_string_new_len(params, val_end - params);
269 s = val_end;
270 if (*s == ',') {
271 s++;
272 }
273 } else {
274 if (*s != '=') {
275 error_setg(errp, "Expected '=' after parameter '%.*s'",
276 (int)(s - key), key);
277 return NULL;
278 }
279 s++;
280
281 val = g_string_new(NULL);
282 for (;;) {
283 if (!*s) {
284 break;
285 } else if (*s == ',') {
286 s++;
287 if (*s != ',') {
288 break;
289 }
290 }
291 g_string_append_c(val, *s++);
292 }
293 }
294
295 if (!keyval_parse_put(cur, key_in_cur, qstring_from_gstring(val),
296 key, key_end, errp)) {
297 return NULL;
298 }
299 return s;
300}
301
302static char *reassemble_key(GSList *key)
303{
304 GString *s = g_string_new("");
305 GSList *p;
306
307 for (p = key; p; p = p->next) {
308 g_string_prepend_c(s, '.');
309 g_string_prepend(s, (char *)p->data);
310 }
311
312 return g_string_free(s, FALSE);
313}
314
315
316
317
318
319
320
321
322static void keyval_do_merge(QDict *dest, const QDict *merged, GString *str, Error **errp)
323{
324 size_t save_len = str->len;
325 const QDictEntry *ent;
326 QObject *old_value;
327
328 for (ent = qdict_first(merged); ent; ent = qdict_next(merged, ent)) {
329 old_value = qdict_get(dest, ent->key);
330 if (old_value) {
331 if (qobject_type(old_value) != qobject_type(ent->value)) {
332 error_setg(errp, "Parameter '%s%s' used inconsistently",
333 str->str, ent->key);
334 return;
335 } else if (qobject_type(ent->value) == QTYPE_QDICT) {
336
337 g_string_append(str, ent->key);
338 g_string_append_c(str, '.');
339 keyval_do_merge(qobject_to(QDict, old_value),
340 qobject_to(QDict, ent->value),
341 str, errp);
342 g_string_truncate(str, save_len);
343 continue;
344 } else if (qobject_type(ent->value) == QTYPE_QLIST) {
345
346 QList *old = qobject_to(QList, old_value);
347 QList *new = qobject_to(QList, ent->value);
348 const QListEntry *item;
349 QLIST_FOREACH_ENTRY(new, item) {
350 qobject_ref(item->value);
351 qlist_append_obj(old, item->value);
352 }
353 continue;
354 } else {
355 assert(qobject_type(ent->value) == QTYPE_QSTRING);
356 }
357 }
358
359 qobject_ref(ent->value);
360 qdict_put_obj(dest, ent->key, ent->value);
361 }
362}
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386void keyval_merge(QDict *dest, const QDict *merged, Error **errp)
387{
388 GString *str;
389
390 str = g_string_new("");
391 keyval_do_merge(dest, merged, str, errp);
392 g_string_free(str, TRUE);
393}
394
395
396
397
398
399
400
401
402static QObject *keyval_listify(QDict *cur, GSList *key_of_cur, Error **errp)
403{
404 GSList key_node;
405 bool has_index, has_member;
406 const QDictEntry *ent;
407 QDict *qdict;
408 QObject *val;
409 char *key;
410 size_t nelt;
411 QObject **elt;
412 int index, max_index, i;
413 QList *list;
414
415 key_node.next = key_of_cur;
416
417
418
419
420
421 has_index = false;
422 has_member = false;
423 for (ent = qdict_first(cur); ent; ent = qdict_next(cur, ent)) {
424 if (key_to_index(ent->key, NULL) >= 0) {
425 has_index = true;
426 } else {
427 has_member = true;
428 }
429
430 qdict = qobject_to(QDict, ent->value);
431 if (!qdict) {
432 continue;
433 }
434
435 key_node.data = ent->key;
436 val = keyval_listify(qdict, &key_node, errp);
437 if (!val) {
438 return NULL;
439 }
440 if (val != ent->value) {
441 qdict_put_obj(cur, ent->key, val);
442 }
443 }
444
445 if (has_index && has_member) {
446 key = reassemble_key(key_of_cur);
447 error_setg(errp, "Parameters '%s*' used inconsistently", key);
448 g_free(key);
449 return NULL;
450 }
451 if (!has_index) {
452 return QOBJECT(cur);
453 }
454
455
456 nelt = qdict_size(cur) + 1;
457 elt = g_new0(QObject *, nelt);
458 max_index = -1;
459 for (ent = qdict_first(cur); ent; ent = qdict_next(cur, ent)) {
460 index = key_to_index(ent->key, NULL);
461 assert(index >= 0);
462 if (index > max_index) {
463 max_index = index;
464 }
465
466
467
468
469
470 if ((size_t)index >= nelt - 1) {
471 continue;
472 }
473
474 elt[index] = ent->value;
475 }
476
477
478
479
480
481
482
483 list = qlist_new();
484 assert(!elt[nelt-1]);
485 for (i = 0; i < MIN(nelt, max_index + 1); i++) {
486 if (!elt[i]) {
487 key = reassemble_key(key_of_cur);
488 error_setg(errp, "Parameter '%s%d' missing", key, i);
489 g_free(key);
490 g_free(elt);
491 qobject_unref(list);
492 return NULL;
493 }
494 qobject_ref(elt[i]);
495 qlist_append_obj(list, elt[i]);
496 }
497
498 g_free(elt);
499 return QOBJECT(list);
500}
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521QDict *keyval_parse_into(QDict *qdict, const char *params, const char *implied_key,
522 bool *p_help, Error **errp)
523{
524 QObject *listified;
525 const char *s;
526 bool help = false;
527
528 s = params;
529 while (*s) {
530 s = keyval_parse_one(qdict, s, implied_key, &help, errp);
531 if (!s) {
532 return NULL;
533 }
534 implied_key = NULL;
535 }
536
537 if (p_help) {
538 *p_help = help;
539 } else if (help) {
540 error_setg(errp, "Help is not available for this option");
541 return NULL;
542 }
543
544 listified = keyval_listify(qdict, NULL, errp);
545 if (!listified) {
546 return NULL;
547 }
548 assert(listified == QOBJECT(qdict));
549 return qdict;
550}
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569QDict *keyval_parse(const char *params, const char *implied_key,
570 bool *p_help, Error **errp)
571{
572 QDict *qdict = qdict_new();
573 QDict *ret = keyval_parse_into(qdict, params, implied_key, p_help, errp);
574
575 if (!ret) {
576 qobject_unref(qdict);
577 }
578 return ret;
579}
580