b25503a9d752698e75ba1b50dd3fd4f681dc768e
[src/app-framework-main.git] / src / wrap-json.c
1 /*
2  Copyright (C) 2016, 2017, 2018 "IoT.bzh"
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
6  Licensed under the Apache License, Version 2.0 (the "License");
7  you may not use this file except in compliance with the License.
8  You may obtain a copy of the License at
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 */
18
19 #include <string.h>
20
21 #include "wrap-json.h"
22
23 #define STACKCOUNT  32
24 #define STRCOUNT    8
25
26 enum {
27         wrap_json_error_none,
28         wrap_json_error_null_object,
29         wrap_json_error_truncated,
30         wrap_json_error_internal_error,
31         wrap_json_error_out_of_memory,
32         wrap_json_error_invalid_character,
33         wrap_json_error_too_long,
34         wrap_json_error_too_deep,
35         wrap_json_error_null_spec,
36         wrap_json_error_null_key,
37         wrap_json_error_null_string,
38         wrap_json_error_out_of_range,
39         wrap_json_error_incomplete,
40         wrap_json_error_missfit_type,
41         wrap_json_error_key_not_found,
42         _wrap_json_error_count_
43 };
44
45 static const char ignore_all[] = " \t\n\r,:";
46 static const char pack_accept_arr[] = "][{snbiIfoO";
47 static const char pack_accept_key[] = "s}";
48 #define pack_accept_any (&pack_accept_arr[1])
49
50 static const char unpack_accept_arr[] = "*!][{snbiIfFoO";
51 static const char unpack_accept_key[] = "*!s}";
52 #define unpack_accept_any (&unpack_accept_arr[3])
53
54 static const char *pack_errors[_wrap_json_error_count_] =
55 {
56         [wrap_json_error_none] = "unknown error",
57         [wrap_json_error_null_object] = "null object",
58         [wrap_json_error_truncated] = "truncated",
59         [wrap_json_error_internal_error] = "internal error",
60         [wrap_json_error_out_of_memory] = "out of memory",
61         [wrap_json_error_invalid_character] = "invalid character",
62         [wrap_json_error_too_long] = "too long",
63         [wrap_json_error_too_deep] = "too deep",
64         [wrap_json_error_null_spec] = "spec is NULL",
65         [wrap_json_error_null_key] = "key is NULL",
66         [wrap_json_error_null_string] = "string is NULL",
67         [wrap_json_error_out_of_range] = "array too small",
68         [wrap_json_error_incomplete] = "incomplete container",
69         [wrap_json_error_missfit_type] = "missfit of type",
70         [wrap_json_error_key_not_found] = "key not found"
71 };
72
73 int wrap_json_get_error_position(int rc)
74 {
75         if (rc < 0)
76                 rc = -rc;
77         return (rc >> 4) + 1;
78 }
79
80 int wrap_json_get_error_code(int rc)
81 {
82         if (rc < 0)
83                 rc = -rc;
84         return rc & 15;
85 }
86
87 const char *wrap_json_get_error_string(int rc)
88 {
89         rc = wrap_json_get_error_code(rc);
90         if (rc >= sizeof pack_errors / sizeof *pack_errors)
91                 rc = 0;
92         return pack_errors[rc];
93 }
94
95
96
97 static inline const char *skip(const char *d)
98 {
99         while (*d && strchr(ignore_all, *d))
100                 d++;
101         return d;
102 }
103
104 int wrap_json_vpack(struct json_object **result, const char *desc, va_list args)
105 {
106         /* TODO: the case of structs with key being single char should be optimized */
107         int nstr, notnull, nullable, rc;
108         size_t sz, dsz, ssz;
109         char *s;
110         char c;
111         const char *d;
112         char buffer[256];
113         struct { const char *str; size_t sz; } strs[STRCOUNT];
114         struct { struct json_object *cont, *key; const char *acc; char type; } stack[STACKCOUNT], *top;
115         struct json_object *obj;
116
117         ssz = sizeof buffer;
118         s = buffer;
119         top = stack;
120         top->key = NULL;
121         top->cont = NULL;
122         top->acc = pack_accept_any;
123         top->type = 0;
124         d = desc;
125         if (!d)
126                 goto null_spec;
127         d = skip(d);
128         for(;;) {
129                 c = *d;
130                 if (!c)
131                         goto truncated;
132                 if (!strchr(top->acc, c))
133                         goto invalid_character;
134                 d = skip(++d);
135                 switch(c) {
136                 case 's':
137                         nullable = 0;
138                         notnull = 0;
139                         nstr = 0;
140                         sz = 0;
141                         for (;;) {
142                                 strs[nstr].str = va_arg(args, const char*);
143                                 if (strs[nstr].str)
144                                         notnull = 1;
145                                 if (*d == '?') {
146                                         d = skip(++d);
147                                         nullable = 1;
148                                 }
149                                 switch(*d) {
150                                 case '%': strs[nstr].sz = va_arg(args, size_t); d = skip(++d); break;
151                                 case '#': strs[nstr].sz = (size_t)va_arg(args, int); d = skip(++d); break;
152                                 default: strs[nstr].sz = strs[nstr].str ? strlen(strs[nstr].str) : 0; break;
153                                 }
154                                 sz += strs[nstr++].sz;
155                                 if (*d == '?') {
156                                         d = skip(++d);
157                                         nullable = 1;
158                                 }
159                                 if (*d != '+')
160                                         break;
161                                 if (nstr >= STRCOUNT)
162                                         goto too_long;
163                                 d = skip(++d);
164                         }
165                         if (*d == '*')
166                                 nullable = 1;
167                         if (notnull) {
168                                 if (sz > ssz) {
169                                         ssz += ssz;
170                                         if (ssz < sz)
171                                                 ssz = sz;
172                                         s = alloca(sz);
173                                 }
174                                 dsz = sz;
175                                 while (nstr) {
176                                         nstr--;
177                                         dsz -= strs[nstr].sz;
178                                         memcpy(&s[dsz], strs[nstr].str, strs[nstr].sz);
179                                 }
180                                 obj = json_object_new_string_len(s, (int)sz);
181                                 if (!obj)
182                                         goto out_of_memory;
183                         } else if (nullable)
184                                 obj = NULL;
185                         else
186                                 goto null_string;
187                         break;
188                 case 'n':
189                         obj = NULL;
190                         break;
191                 case 'b':
192                         obj = json_object_new_boolean(va_arg(args, int));
193                         if (!obj)
194                                 goto out_of_memory;
195                         break;
196                 case 'i':
197                         obj = json_object_new_int(va_arg(args, int));
198                         if (!obj)
199                                 goto out_of_memory;
200                         break;
201                 case 'I':
202                         obj = json_object_new_int64(va_arg(args, int64_t));
203                         if (!obj)
204                                 goto out_of_memory;
205                         break;
206                 case 'f':
207                         obj = json_object_new_double(va_arg(args, double));
208                         if (!obj)
209                                 goto out_of_memory;
210                         break;
211                 case 'o':
212                 case 'O':
213                         obj = va_arg(args, struct json_object*);
214                         if (*d == '?')
215                                 d = skip(++d);
216                         else if (*d != '*' && !obj)
217                                 goto null_object;
218                         if (c == 'O')
219                                 json_object_get(obj);
220                         break;
221                 case '[':
222                 case '{':
223                         if (++top >= &stack[STACKCOUNT])
224                                 goto too_deep;
225                         top->key = NULL;
226                         if (c == '[') {
227                                 top->type = ']';
228                                 top->acc = pack_accept_arr;
229                                 top->cont = json_object_new_array();
230                         } else {
231                                 top->type = '}';
232                                 top->acc = pack_accept_key;
233                                 top->cont = json_object_new_object();
234                         }
235                         if (!top->cont)
236                                 goto out_of_memory;
237                         continue;
238                 case '}':
239                 case ']':
240                         if (c != top->type || top <= stack)
241                                 goto internal_error;
242                         obj = (top--)->cont;
243                         if (*d == '*' && !(c == '}' ? json_object_object_length(obj) : json_object_array_length(obj))) {
244                                 json_object_put(obj);
245                                 obj = NULL;
246                         }
247                         break;
248                 default:
249                         goto internal_error;
250                 }
251                 switch (top->type) {
252                 case 0:
253                         if (top != stack)
254                                 goto internal_error;
255                         if (*d)
256                                 goto invalid_character;
257                         *result = obj;
258                         return 0;
259                 case ']':
260                         if (obj || *d != '*')
261                                 json_object_array_add(top->cont, obj);
262                         if (*d == '*')
263                                 d = skip(++d);
264                         break;
265                 case '}':
266                         if (!obj)
267                                 goto null_key;
268                         top->key = obj;
269                         top->acc = pack_accept_any;
270                         top->type = ':';
271                         break;
272                 case ':':
273                         if (obj || *d != '*')
274                                 json_object_object_add(top->cont, json_object_get_string(top->key), obj);
275                         if (*d == '*')
276                                 d = skip(++d);
277                         json_object_put(top->key);
278                         top->key = NULL;
279                         top->acc = pack_accept_key;
280                         top->type = '}';
281                         break;
282                 default:
283                         goto internal_error;
284                 }
285         }
286
287 null_object:
288         rc = wrap_json_error_null_object;
289         goto error;
290 truncated:
291         rc = wrap_json_error_truncated;
292         goto error;
293 internal_error:
294         rc = wrap_json_error_internal_error;
295         goto error;
296 out_of_memory:
297         rc = wrap_json_error_out_of_memory;
298         goto error;
299 invalid_character:
300         rc = wrap_json_error_invalid_character;
301         goto error;
302 too_long:
303         rc = wrap_json_error_too_long;
304         goto error;
305 too_deep:
306         rc = wrap_json_error_too_deep;
307         goto error;
308 null_spec:
309         rc = wrap_json_error_null_spec;
310         goto error;
311 null_key:
312         rc = wrap_json_error_null_key;
313         goto error;
314 null_string:
315         rc = wrap_json_error_null_string;
316         goto error;
317 error:
318         do {
319                 json_object_put(top->key);
320                 json_object_put(top->cont);
321         } while (--top >= stack);
322         *result = NULL;
323         rc = rc | (int)((d - desc) << 4);
324         return -rc;
325 }
326
327 int wrap_json_pack(struct json_object **result, const char *desc, ...)
328 {
329         int rc;
330         va_list args;
331
332         va_start(args, desc);
333         rc = wrap_json_vpack(result, desc, args);
334         va_end(args);
335         return rc;
336 }
337
338 static int vunpack(struct json_object *object, const char *desc, va_list args, int store)
339 {
340         int rc = 0, optionnal, ignore;
341         char c, xacc[2] = { 0, 0 };
342         const char *acc;
343         const char *d, *fit = NULL;
344         const char *key = NULL;
345         const char **ps = NULL;
346         double *pf = NULL;
347         int *pi = NULL;
348         int64_t *pI = NULL;
349         size_t *pz = NULL;
350         struct { struct json_object *parent; const char *acc; int index, count; char type; } stack[STACKCOUNT], *top;
351         struct json_object *obj;
352         struct json_object **po;
353
354         xacc[0] = 0;
355         ignore = 0;
356         top = NULL;
357         acc = unpack_accept_any;
358         d = desc;
359         if (!d)
360                 goto null_spec;
361         d = skip(d);
362         obj = object;
363         for(;;) {
364                 fit = d;
365                 c = *d;
366                 if (!c)
367                         goto truncated;
368                 if (!strchr(acc, c))
369                         goto invalid_character;
370                 d = skip(++d);
371                 switch(c) {
372                 case 's':
373                         if (xacc[0] == '}') {
374                                 /* expects a key */
375                                 key = va_arg(args, const char *);
376                                 if (!key)
377                                         goto null_key;
378                                 if (*d != '?')
379                                         optionnal = 0;
380                                 else {
381                                         optionnal = 1;
382                                         d = skip(++d);
383                                 }
384                                 if (ignore)
385                                         ignore++;
386                                 else {
387                                         if (json_object_object_get_ex(top->parent, key, &obj)) {
388                                                 /* found */
389                                                 top->index++;
390                                         } else {
391                                                 /* not found */
392                                                 if (!optionnal)
393                                                         goto key_not_found;
394                                                 ignore = 1;
395                                                 obj = NULL;
396                                         }
397                                 }
398                                 xacc[0] = ':';
399                                 acc = unpack_accept_any;
400                                 continue;
401                         }
402                         /* get a string */
403                         if (store)
404                                 ps = va_arg(args, const char **);
405                         if (!ignore) {
406                                 if (!json_object_is_type(obj, json_type_string))
407                                         goto missfit;
408                                 if (store && ps)
409                                         *ps = json_object_get_string(obj);
410                         }
411                         if (*d == '%') {
412                                 d = skip(++d);
413                                 if (store) {
414                                         pz = va_arg(args, size_t *);
415                                         if (!ignore && pz)
416                                                 *pz = (size_t)json_object_get_string_len(obj);
417                                 }
418                         }
419                         break;
420                 case 'n':
421                         if (!ignore && !json_object_is_type(obj, json_type_null))
422                                 goto missfit;
423                         break;
424                 case 'b':
425                         if (store)
426                                 pi = va_arg(args, int *);
427
428                         if (!ignore) {
429                                 if (!json_object_is_type(obj, json_type_boolean))
430                                         goto missfit;
431                                 if (store && pi)
432                                         *pi = json_object_get_boolean(obj);
433                         }
434                         break;
435                 case 'i':
436                         if (store)
437                                 pi = va_arg(args, int *);
438
439                         if (!ignore) {
440                                 if (!json_object_is_type(obj, json_type_int))
441                                         goto missfit;
442                                 if (store && pi)
443                                         *pi = json_object_get_int(obj);
444                         }
445                         break;
446                 case 'I':
447                         if (store)
448                                 pI = va_arg(args, int64_t *);
449
450                         if (!ignore) {
451                                 if (!json_object_is_type(obj, json_type_int))
452                                         goto missfit;
453                                 if (store && pI)
454                                         *pI = json_object_get_int64(obj);
455                         }
456                         break;
457                 case 'f':
458                 case 'F':
459                         if (store)
460                                 pf = va_arg(args, double *);
461
462                         if (!ignore) {
463                                 if (!(json_object_is_type(obj, json_type_double) || (c == 'F' && json_object_is_type(obj, json_type_int))))
464                                         goto missfit;
465                                 if (store && pf)
466                                         *pf = json_object_get_double(obj);
467                         }
468                         break;
469                 case 'o':
470                 case 'O':
471                         if (store) {
472                                 po = va_arg(args, struct json_object **);
473                                 if (!ignore && po) {
474                                         if (c == 'O')
475                                                 obj = json_object_get(obj);
476                                         *po = obj;
477                                 }
478                         }
479                         break;
480
481                 case '[':
482                 case '{':
483                         if (!top)
484                                 top = stack;
485                         else if (++top  >= &stack[STACKCOUNT])
486                                 goto too_deep;
487
488                         top->acc = acc;
489                         top->type = xacc[0];
490                         top->index = 0;
491                         top->parent = obj;
492                         if (ignore)
493                                 ignore++;
494                         if (c == '[') {
495                                 if (!ignore) {
496                                         if (!json_object_is_type(obj, json_type_array))
497                                                 goto missfit;
498                                         top->count = json_object_array_length(obj);
499                                 }
500                                 xacc[0] = ']';
501                                 acc = unpack_accept_arr;
502                         } else {
503                                 if (!ignore) {
504                                         if (!json_object_is_type(obj, json_type_object))
505                                                 goto missfit;
506                                         top->count = json_object_object_length(obj);
507                                 }
508                                 xacc[0] = '}';
509                                 acc = unpack_accept_key;
510                                 continue;
511                         }
512                         break;
513                 case '}':
514                 case ']':
515                         if (!top || c != xacc[0])
516                                 goto internal_error;
517                         acc = top->acc;
518                         xacc[0] = top->type;
519                         top = top == stack ? NULL : top - 1;
520                         if (ignore)
521                                 ignore--;
522                         break;
523                 case '!':
524                         if (*d != xacc[0])
525                                 goto invalid_character;
526                         if (!ignore && top->index != top->count)
527                                 goto incomplete;
528                         /*@fallthrough@*/
529                 case '*':
530                         acc = xacc;
531                         continue;
532                 default:
533                         goto internal_error;
534                 }
535                 switch (xacc[0]) {
536                 case 0:
537                         if (top)
538                                 goto internal_error;
539                         if (*d)
540                                 goto invalid_character;
541                         return 0;
542                 case ']':
543                         if (!ignore) {
544                                 key = strchr(unpack_accept_arr, *d);
545                                 if (key && key >= unpack_accept_any) {
546                                         if (top->index >= top->count)
547                                                 goto out_of_range;
548                                         obj = json_object_array_get_idx(top->parent, top->index++);
549                                 }
550                         }
551                         break;
552                 case ':':
553                         acc = unpack_accept_key;
554                         xacc[0] = '}';
555                         if (ignore)
556                                 ignore--;
557                         break;
558                 default:
559                         goto internal_error;
560                 }
561         }
562 truncated:
563         rc = wrap_json_error_truncated;
564         goto error;
565 internal_error:
566         rc = wrap_json_error_internal_error;
567         goto error;
568 invalid_character:
569         rc = wrap_json_error_invalid_character;
570         goto error;
571 too_deep:
572         rc = wrap_json_error_too_deep;
573         goto error;
574 null_spec:
575         rc = wrap_json_error_null_spec;
576         goto error;
577 null_key:
578         rc = wrap_json_error_null_key;
579         goto error;
580 out_of_range:
581         rc = wrap_json_error_out_of_range;
582         goto error;
583 incomplete:
584         rc = wrap_json_error_incomplete;
585         goto error;
586 missfit:
587         rc = wrap_json_error_missfit_type;
588         goto errorfit;
589 key_not_found:
590         rc = wrap_json_error_key_not_found;
591         goto error;
592 errorfit:
593         d = fit;
594 error:
595         rc = rc | (int)((d - desc) << 4);
596         return -rc;
597 }
598
599 int wrap_json_vcheck(struct json_object *object, const char *desc, va_list args)
600 {
601         return vunpack(object, desc, args, 0);
602 }
603
604 int wrap_json_check(struct json_object *object, const char *desc, ...)
605 {
606         int rc;
607         va_list args;
608
609         va_start(args, desc);
610         rc = vunpack(object, desc, args, 0);
611         va_end(args);
612         return rc;
613 }
614
615 int wrap_json_vmatch(struct json_object *object, const char *desc, va_list args)
616 {
617         return !vunpack(object, desc, args, 0);
618 }
619
620 int wrap_json_match(struct json_object *object, const char *desc, ...)
621 {
622         int rc;
623         va_list args;
624
625         va_start(args, desc);
626         rc = vunpack(object, desc, args, 0);
627         va_end(args);
628         return !rc;
629 }
630
631 int wrap_json_vunpack(struct json_object *object, const char *desc, va_list args)
632 {
633         return vunpack(object, desc, args, 1);
634 }
635
636 int wrap_json_unpack(struct json_object *object, const char *desc, ...)
637 {
638         int rc;
639         va_list args;
640
641         va_start(args, desc);
642         rc = vunpack(object, desc, args, 1);
643         va_end(args);
644         return rc;
645 }
646
647 static void object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
648 {
649         struct json_object_iterator it = json_object_iter_begin(object);
650         struct json_object_iterator end = json_object_iter_end(object);
651         while (!json_object_iter_equal(&it, &end)) {
652                 callback(closure, json_object_iter_peek_value(&it), json_object_iter_peek_name(&it));
653                 json_object_iter_next(&it);
654         }
655 }
656
657 static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
658 {
659         int n = json_object_array_length(object);
660         int i = 0;
661         while(i < n)
662                 callback(closure, json_object_array_get_idx(object, i++));
663 }
664
665 void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
666 {
667         if (json_object_is_type(object, json_type_array))
668                 array_for_all(object, callback, closure);
669         else
670                 callback(closure, object);
671 }
672
673 void wrap_json_array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure)
674 {
675         if (json_object_is_type(object, json_type_array))
676                 array_for_all(object, callback, closure);
677 }
678
679 void wrap_json_object_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
680 {
681         if (json_object_is_type(object, json_type_object))
682                 object_for_all(object, callback, closure);
683 }
684
685 void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
686 {
687         if (json_object_is_type(object, json_type_object))
688                 object_for_all(object, callback, closure);
689         else
690                 callback(closure, object, NULL);
691 }
692
693 void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure)
694 {
695         if (!object)
696                 /* do nothing */;
697         else if (json_object_is_type(object, json_type_object))
698                 object_for_all(object, callback, closure);
699         else if (!json_object_is_type(object, json_type_array))
700                 callback(closure, object, NULL);
701         else {
702                 int n = json_object_array_length(object);
703                 int i = 0;
704                 while(i < n)
705                         callback(closure, json_object_array_get_idx(object, i++), NULL);
706         }
707 }
708
709 #if defined(WRAP_JSON_TEST)
710 #include <stdio.h>
711
712 void p(const char *desc, ...)
713 {
714         int rc;
715         va_list args;
716         struct json_object *result;
717
718         va_start(args, desc);
719         rc = wrap_json_vpack(&result, desc, args);
720         va_end(args);
721         if (!rc)
722                 printf("  SUCCESS %s\n\n", json_object_to_json_string(result));
723         else
724                 printf("  ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
725         json_object_put(result);
726 }
727
728 const char *xs[10];
729 int *xi[10];
730 int64_t *xI[10];
731 double *xf[10];
732 struct json_object *xo[10];
733 size_t xz[10];
734
735 void u(const char *value, const char *desc, ...)
736 {
737         unsigned m, k;
738         int rc;
739         va_list args;
740         struct json_object *obj, *o;
741
742         memset(xs, 0, sizeof xs);
743         memset(xi, 0, sizeof xi);
744         memset(xI, 0, sizeof xI);
745         memset(xf, 0, sizeof xf);
746         memset(xo, 0, sizeof xo);
747         memset(xz, 0, sizeof xz);
748         obj = json_tokener_parse(value);
749         va_start(args, desc);
750         rc = wrap_json_vunpack(obj, desc, args);
751         va_end(args);
752         if (rc)
753                 printf("  ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc));
754         else {
755                 value = NULL;
756                 printf("  SUCCESS");
757                 va_start(args, desc);
758                 k = m = 0;
759                 while(*desc) {
760                         switch(*desc) {
761                         case '{': m = (m << 1) | 1; k = 1; break;
762                         case '}': m = m >> 1; k = m&1; break;
763                         case '[': m = m << 1; k = 0; break;
764                         case ']': m = m >> 1; k = m&1; break;
765                         case 's': printf(" s:%s", k ? va_arg(args, const char*) : *(va_arg(args, const char**)?:&value)); k ^= m&1; break;
766                         case '%': printf(" %%:%zu", *va_arg(args, size_t*)); k = m&1; break;
767                         case 'n': printf(" n"); k = m&1; break;
768                         case 'b': printf(" b:%d", *va_arg(args, int*)); k = m&1; break;
769                         case 'i': printf(" i:%d", *va_arg(args, int*)); k = m&1; break;
770                         case 'I': printf(" I:%lld", *va_arg(args, int64_t*)); k = m&1; break;
771                         case 'f': printf(" f:%f", *va_arg(args, double*)); k = m&1; break;
772                         case 'F': printf(" F:%f", *va_arg(args, double*)); k = m&1; break;
773                         case 'o': printf(" o:%s", json_object_to_json_string(*va_arg(args, struct json_object**))); k = m&1; break;
774                         case 'O': o = *va_arg(args, struct json_object**); printf(" O:%s", json_object_to_json_string(o)); json_object_put(o); k = m&1; break;
775                         default: break;
776                         }
777                         desc++;
778                 }
779                 va_end(args);
780                 printf("\n\n");
781         }
782         json_object_put(obj);
783 }
784
785 #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0)
786 #define U(...) do{ printf("unpack(%s)\n",#__VA_ARGS__); u(__VA_ARGS__); } while(0)
787
788 int main()
789 {
790         char buffer[4] = {'t', 'e', 's', 't'};
791
792         P("n");
793         P("b", 1);
794         P("b", 0);
795         P("i", 1);
796         P("I", (uint64_t)0x123456789abcdef);
797         P("f", 3.14);
798         P("s", "test");
799         P("s?", "test");
800         P("s?", NULL);
801         P("s#", "test asdf", 4);
802         P("s%", "test asdf", (size_t)4);
803         P("s#", buffer, 4);
804         P("s%", buffer, (size_t)4);
805         P("s++", "te", "st", "ing");
806         P("s#+#+", "test", 1, "test", 2, "test");
807         P("s%+%+", "test", (size_t)1, "test", (size_t)2, "test");
808         P("{}", 1.0);
809         P("[]", 1.0);
810         P("o", json_object_new_int(1));
811         P("o?", json_object_new_int(1));
812         P("o?", NULL);
813         P("O", json_object_new_int(1));
814         P("O?", json_object_new_int(1));
815         P("O?", NULL);
816         P("{s:[]}", "foo");
817         P("{s+#+: []}", "foo", "barbar", 3, "baz");
818         P("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL);
819         P("{s:**}", "a", NULL);
820         P("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL);
821         P("[i,i,i]", 0, 1, 2);
822         P("[s,o,O]", NULL, NULL, NULL);
823         P("[**]", NULL);
824         P("[s*,o*,O*]", NULL, NULL, NULL);
825         P(" s ", "test");
826         P("[ ]");
827         P("[ i , i,  i ] ", 1, 2, 3);
828         P("{\n\n1");
829         P("[}");
830         P("{]");
831         P("[");
832         P("{");
833         P("[i]a", 42);
834         P("ia", 42);
835         P("s", NULL);
836         P("+", NULL);
837         P(NULL);
838         P("{s:i}", NULL, 1);
839         P("{ {}: s }", "foo");
840         P("{ s: {},  s:[ii{} }", "foo", "bar", 12, 13);
841         P("[[[[[   [[[[[  [[[[ }]]]] ]]]] ]]]]]");
842
843         U("true", "b", &xi[0]);
844         U("false", "b", &xi[0]);
845         U("null", "n");
846         U("42", "i", &xi[0]);
847         U("123456789", "I", &xI[0]);
848         U("3.14", "f", &xf[0]);
849         U("12345", "F", &xf[0]);
850         U("3.14", "F", &xf[0]);
851         U("\"foo\"", "s", &xs[0]);
852         U("\"foo\"", "s%", &xs[0], &xz[0]);
853         U("{}", "{}");
854         U("[]", "[]");
855         U("{}", "o", &xo[0]);
856         U("{}", "O", &xo[0]);
857         U("{\"foo\":42}", "{si}", "foo", &xi[0]);
858         U("[1,2,3]", "[i,i,i]", &xi[0], &xi[1], &xi[2]);
859         U("{\"a\":1,\"b\":2,\"c\":3}", "{s:i, s:i, s:i}", "a", &xi[0], "b", &xi[1], "c", &xi[2]);
860         U("42", "z");
861         U("null", "[i]");
862         U("[]", "[}");
863         U("{}", "{]");
864         U("[]", "[");
865         U("{}", "{");
866         U("[42]", "[i]a", &xi[0]);
867         U("42", "ia", &xi[0]);
868         U("[]", NULL);
869         U("\"foo\"", "s", NULL);
870         U("42", "s", NULL);
871         U("42", "n");
872         U("42", "b", NULL);
873         U("42", "f", NULL);
874         U("42", "[i]", NULL);
875         U("42", "{si}", "foo", NULL);
876         U("\"foo\"", "n");
877         U("\"foo\"", "b", NULL);
878         U("\"foo\"", "i", NULL);
879         U("\"foo\"", "I", NULL);
880         U("\"foo\"", "f", NULL);
881         U("\"foo\"", "F", NULL);
882         U("true", "s", NULL);
883         U("true", "n");
884         U("true", "i", NULL);
885         U("true", "I", NULL);
886         U("true", "f", NULL);
887         U("true", "F", NULL);
888         U("[42]", "[ii]", &xi[0], &xi[1]);
889         U("{\"foo\":42}", "{si}", NULL, &xi[0]);
890         U("{\"foo\":42}", "{si}", "baz", &xi[0]);
891         U("[1,2,3]", "[iii!]", &xi[0], &xi[1], &xi[2]);
892         U("[1,2,3]", "[ii!]", &xi[0], &xi[1]);
893         U("[1,2,3]", "[ii]", &xi[0], &xi[1]);
894         U("[1,2,3]", "[ii*]", &xi[0], &xi[1]);
895         U("{\"foo\":42,\"baz\":45}", "{sisi}", "baz", &xi[0], "foo", &xi[1]);
896         U("{\"foo\":42,\"baz\":45}", "{sisi*}", "baz", &xi[0], "foo", &xi[1]);
897         U("{\"foo\":42,\"baz\":45}", "{sisi!}", "baz", &xi[0], "foo", &xi[1]);
898         U("{\"foo\":42,\"baz\":45}", "{si}", "baz", &xi[0], "foo", &xi[1]);
899         U("{\"foo\":42,\"baz\":45}", "{si*}", "baz", &xi[0], "foo", &xi[1]);
900         U("{\"foo\":42,\"baz\":45}", "{si!}", "baz", &xi[0], "foo", &xi[1]);
901         U("[1,{\"foo\":2,\"bar\":null},[3,4]]", "[i{sisn}[ii]]", &xi[0], "foo", &xi[1], "bar", &xi[2], &xi[3]);
902         U("[1,2,3]", "[ii!i]", &xi[0], &xi[1], &xi[2]);
903         U("[1,2,3]", "[ii*i]", &xi[0], &xi[1], &xi[2]);
904         U("{\"foo\":1,\"bar\":2}", "{si!si}", "foo", &xi[1], "bar", &xi[2]);
905         U("{\"foo\":1,\"bar\":2}", "{si*si}", "foo", &xi[1], "bar", &xi[2]);
906         U("{\"foo\":{\"baz\":null,\"bar\":null}}", "{s{sn!}}", "foo", "bar");
907         U("[[1,2,3]]", "[[ii!]]", &xi[0], &xi[1]);
908         U("{}", "{s?i}", "foo", &xi[0]);
909         U("{\"foo\":1}", "{s?i}", "foo", &xi[0]);
910         U("{}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
911         U("{\"foo\":[1,2]}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
912         U("{\"bar\":{\"baz\":{\"quux\":15}}}", "{s?[ii]s?{s{si!}}}", "foo", &xi[0], &xi[1], "bar", "baz", "quux", &xi[2]);
913         U("{\"foo\":{\"bar\":4}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
914         U("{\"foo\":{}}", "{s?{s?i}}", "foo", "bar", &xi[0]);
915         U("{}", "{s?{s?i}}", "foo", "bar", &xi[0]);
916         U("{\"foo\":42,\"baz\":45}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
917         U("{\"foo\":42}", "{s?isi!}", "baz", &xi[0], "foo", &xi[1]);
918         return 0;
919 }
920
921 #endif
922
923 #if 0
924
925
926     /* Unpack the same item twice */
927     j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1);
928     if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s))
929         fail("json_unpack object with strict validation failed");
930     {
931         const char *possible_errors[] = {
932             "2 object item(s) left unpacked: baz, quux",
933             "2 object item(s) left unpacked: quux, baz"
934         };
935         check_errors(possible_errors, 2, "<validation>", 1, 10, 10);
936     }
937     json_decref(j);
938
939 #endif