Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 1273 lines (1035 sloc) 33.121 kb
dac025c [libu] json module integration (wip)
tho authored
1 /*
2 * Copyright (c) 2005-2010 by KoanLogic s.r.l. - All rights reserved.
3 */
4
5 #include <stdlib.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 #include <toolbox/json.h>
10 #include <toolbox/carpal.h>
11 #include <toolbox/misc.h>
12 #include <toolbox/memory.h>
13 #include <toolbox/lexer.h>
14
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
15 /* Pointer to the name part of .fqn */
16 #define U_JSON_OBJ_NAME(jo) \
17 ((jo->parent != NULL) ? jo->fqn + strlen(p->fqn) : jo->fqn)
18
19 /* XXX Test if a name is a fully qualified name */
20 #define NAME_IS_FQN(name) \
21 (name[0] == '.' && (name[1] == '.' || name[1] == '[' || name[1] == '\0')
22
dac025c [libu] json module integration (wip)
tho authored
23 /* Internal representation of any JSON value. */
24 struct u_json_obj_s
25 {
26 u_json_type_t type;
27
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
28 unsigned int icur; /* Aux stuff used when indexing on arrays. */
29 u_hmap_t *map;
dac025c [libu] json module integration (wip)
tho authored
30
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
31 char fqn[U_JSON_FQN_SZ]; /* Fully qualified name of this (sub)object. */
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
32
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
33 char key[U_TOKEN_SZ]; /* If applicable, i.e. !anonymous */
34 char val[U_TOKEN_SZ]; /* If applicable, i.e. (!object && !array) */
35
36 struct u_json_obj_s *parent;
dac025c [libu] json module integration (wip)
tho authored
37 TAILQ_ENTRY(u_json_obj_s) siblings;
38 TAILQ_HEAD(, u_json_obj_s) children;
39 };
40
41 /* Lexer methods */
42 static int u_json_match_value (u_lexer_t *jl, u_json_obj_t *jo);
43 static int u_json_match_number_first (u_lexer_t *jl);
44 static int u_json_match_number (u_lexer_t *jl, u_json_obj_t *jo);
45 static int u_json_match_int (u_lexer_t *jl);
46 static int u_json_match_frac_first (char c);
47 static int u_json_match_frac (u_lexer_t *jl);
48 static int u_json_match_exp_first (char c);
49 static int u_json_match_exp (u_lexer_t *jl);
50 static int u_json_match_true_first (u_lexer_t *jl);
51 static int u_json_match_false_first (u_lexer_t *jl);
52 static int u_json_match_true (u_lexer_t *jl, u_json_obj_t *jo);
53 static int u_json_match_false (u_lexer_t *jl, u_json_obj_t *jo);
54 static int u_json_match_null_first (u_lexer_t *jl);
55 static int u_json_match_null (u_lexer_t *jl, u_json_obj_t *jo);
56 static int u_json_match_string (u_lexer_t *jl, u_json_obj_t *jo);
57 static int u_json_match_string_first (u_lexer_t *jl);
58 static int u_json_match_escaped_unicode (u_lexer_t *jl);
59 static int u_json_match_object (u_lexer_t *jl, u_json_obj_t *jo);
60 static int u_json_match_object_first (u_lexer_t *jl);
61 static int u_json_match_array (u_lexer_t *jl, u_json_obj_t *jo);
62 static int u_json_match_array_first (u_lexer_t *jl);
63 static int u_json_match_pair (u_lexer_t *jl, u_json_obj_t *jo);
64 static int u_json_match_pair_first (u_lexer_t *jl);
65
66 /* Lexer misc stuff. */
67 static int u_json_match_seq (u_lexer_t *jl, u_json_obj_t *jo, int type,
68 char first, const char *rem, size_t rem_sz);
69 static const char *u_json_type_str (int type);
70
71 /* Objects misc stuff. */
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
72 static void u_json_obj_do_print (u_json_obj_t *jo, size_t l, void *opaque);
73 static void u_json_obj_do_free (u_json_obj_t *jo, size_t l, void *opaque);
74 static void u_json_obj_do_freeze (u_json_obj_t *jo, size_t l, void *map);
dac025c [libu] json module integration (wip)
tho authored
75
76 /* Encoder. */
77 static int u_json_do_encode (u_json_obj_t *jo, u_string_t *s);
78
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
79 /* Needed by hmap_easy* because we are storing pointer data not owned by the
80 * hmap. */
81 static void nopf (void *dummy) { return; }
82
83 static int u_json_obj_new_container (u_json_type_t type, const char *key,
84 u_json_obj_t **pjo);
85
dac025c [libu] json module integration (wip)
tho authored
86 /**
87 \defgroup json JSON
88 \{
2d8e2ce [libu] json += unit test
tho authored
89 The \ref json module implements encoding and decoding of JSON objects as
90 defined in <a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>.
91 TODO
dac025c [libu] json module integration (wip)
tho authored
92 */
93
94 /**
95 * \brief Create a new and empty JSON object container
96 *
97 * Create a new and empty JSON object container and return its handler as
98 * the result argument \p *pjo
99 *
100 * \param pjo Pointer to the ::u_json_obj_t that will be returned
101 *
102 * \retval ~0 on failure
103 * \retval 0 on success
104 */
105 int u_json_obj_new (u_json_obj_t **pjo)
106 {
107 u_json_obj_t *jo = NULL;
108
109 dbg_return_if (pjo == NULL, ~0);
110
111 warn_err_sif ((jo = u_zalloc(sizeof *jo)) == NULL);
112 TAILQ_INIT(&jo->children);
113 jo->type = U_JSON_TYPE_UNKNOWN;
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
114 jo->key[0] = jo->val[0] = jo->fqn[0] = '\0';
115 jo->parent = NULL;
116 jo->map = NULL;
dac025c [libu] json module integration (wip)
tho authored
117
118 *pjo = jo;
119
120 return 0;
121 err:
122 if (jo)
123 u_free(jo);
124 return ~0;
125 }
126
127 /**
128 * \brief Set the type of a JSON object
129 *
130 * Set the type of the supplied JSON object \p jo to \p type.
131 *
132 * \param jo Pointer to a ::u_json_obj_t object
133 * \param type One of the available ::u_json_type_t types
134 *
135 * \retval ~0 on failure
136 * \retval 0 on success
137 */
138 int u_json_obj_set_type (u_json_obj_t *jo, u_json_type_t type)
139 {
140 dbg_return_if (jo == NULL, ~0);
141
142 switch (type)
143 {
144 case U_JSON_TYPE_STRING:
145 case U_JSON_TYPE_NUMBER:
146 case U_JSON_TYPE_ARRAY:
147 case U_JSON_TYPE_OBJECT:
148 case U_JSON_TYPE_TRUE:
149 case U_JSON_TYPE_FALSE:
150 case U_JSON_TYPE_NULL:
151 case U_JSON_TYPE_UNKNOWN:
152 jo->type = type;
153 break;
154 default:
155 u_err("unhandled type %d", type);
156 return ~0;
157 }
158
159 return 0;
160 }
161
162 /**
163 * \brief Set the value of a JSON object
164 *
165 * Set the value of the JSON object \p jo to the string value pointed by
166 * \p val. This operation is meaningful only in case the underlying object
167 * is a number or a string.
168 *
169 * \param jo Pointer to a ::u_json_obj_t object
170 * \param val Pointer to the (non-NULL) value string
171 *
172 * \retval ~0 on failure
173 * \retval 0 on success
174 */
175 int u_json_obj_set_val (u_json_obj_t *jo, const char *val)
176 {
177 dbg_return_if (jo == NULL, ~0);
178 dbg_return_if (val == NULL, ~0);
179
180 /* Non-critical error, just emit some debug info. */
181 dbg_if (jo->type != U_JSON_TYPE_STRING && jo->type != U_JSON_TYPE_NUMBER);
182
183 dbg_return_if (u_strlcpy(jo->val, val, sizeof jo->val), ~0);
184
185 return 0;
186 }
187
188 /**
189 * \brief Set the key of a JSON object
190 *
191 * Set the key of the JSON object \p jo to the string value pointed by
192 * \p key.
193 *
194 * \param jo Pointer to a ::u_json_obj_t object
44a04ad [libu] json doxy in progress
tho authored
195 * \param key Pointer to the (non-NULL) key string
dac025c [libu] json module integration (wip)
tho authored
196 *
197 * \retval ~0 on failure
198 * \retval 0 on success
199 */
200 int u_json_obj_set_key (u_json_obj_t *jo, const char *key)
201 {
202 dbg_return_if (jo == NULL, ~0);
203 dbg_return_if (key == NULL, ~0);
204
205 dbg_return_if (u_strlcpy(jo->key, key, sizeof jo->key), ~0);
206
207 return 0;
208 }
209
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
210 /** \brief Wrapper function around u_json_obj_set_*()'s for one-shot
211 * settings of leaf nodes. */
212 int u_json_obj_new_leaf (u_json_type_t type, const char *key, const char *val,
213 u_json_obj_t **pjo)
214 {
215 u_json_obj_t *jo = NULL;
216
217 dbg_return_if (pjo == NULL, ~0);
218
219 dbg_err_if (u_json_obj_new(&jo));
220
221 dbg_err_if (u_json_obj_set_type(jo, type));
222 dbg_err_if (u_json_obj_set_key(jo, key));
223
224 /* Values are meaningful only in case of string and number objects. */
225 switch (type)
226 {
227 case U_JSON_TYPE_NUMBER:
228 case U_JSON_TYPE_STRING:
229 dbg_err_if (u_json_obj_set_val(jo, val));
230 default: break;
231 }
232
233 *pjo = jo;
234
235 return 0;
236 err:
237 if (jo)
238 u_json_obj_free(jo);
239 return ~0;
240 }
241
242 /** \brief Wrapper function that creates an array container.
243 * (\p key may be \c NULL). */
244 int u_json_obj_new_array (const char *key, u_json_obj_t **pjo)
245 {
246 return u_json_obj_new_container(U_JSON_TYPE_ARRAY, key, pjo);
247 }
248
249 /** \brief Wrapper function that creates an object container
250 * (\p key may be \c NULL). */
251 int u_json_obj_new_object (const char *key, u_json_obj_t **pjo)
252 {
253 return u_json_obj_new_container(U_JSON_TYPE_OBJECT, key, pjo);
254 }
255
dac025c [libu] json module integration (wip)
tho authored
256 /**
257 * \brief Add a child JSON object to its parent container
258 *
259 * Add the child JSON object \p jo to its parent container \p head.
260 *
261 * \param head Pointer to the parent container
262 * \param jo Pointer to the child JSON object that shall be attached
263 *
264 * \retval ~0 on failure
265 * \retval 0 on success
266 */
267 int u_json_obj_add (u_json_obj_t *head, u_json_obj_t *jo)
268 {
269 dbg_return_if (head == NULL, ~0);
270 dbg_return_if (jo == NULL, ~0);
271
272 #ifdef U_JSON_OBJ_DEBUG
273 u_con("chld (%p): %s {%s} added", jo, u_json_type_str(jo->type), jo->key);
274 u_con("prnt (%p): %s {%s}\n", head, u_json_type_str(head->type), head->key);
275 #endif /* U_JSON_OBJ_DEBUG */
276
277 TAILQ_INSERT_TAIL(&head->children, jo, siblings);
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
278 jo->parent = head;
dac025c [libu] json module integration (wip)
tho authored
279
280 return 0;
281 }
282
283 /**
284 * \brief Break down a JSON string into pieces
285 *
286 * Parse and validate the supplied JSON string \p json and, in case of success,
287 * return its internal representation into the result argument \p *pjo.
288 *
289 * \param json A NUL-terminated string containing some serialized JSON
290 * \param pjo Result argument which will point to the internal
291 * representation of the parsed \p json string
292 *
293 * \retval ~0 on failure
294 * \retval 0 on success
295 */
2d8e2ce [libu] json += unit test
tho authored
296 int u_json_decode (const char *json, u_json_obj_t **pjo)
dac025c [libu] json module integration (wip)
tho authored
297 {
298 u_json_obj_t *jo = NULL;
299 u_lexer_t *jl = NULL;
300
301 dbg_return_if (json == NULL, ~0);
302 dbg_return_if (pjo == NULL, ~0);
303
304 /* Create a disposable lexer context associated to the supplied
305 * 'json' string. */
306 warn_err_if (u_lexer_new(json, &jl));
307
308 /* Create top level json object. */
309 warn_err_if (u_json_obj_new(&jo));
310
311 /* Consume any trailing white space before starting actual parsing. */
312 if (u_lexer_eat_ws(jl) == -1)
313 U_LEXER_ERR(jl, "Empty JSON text !");
314
315 /* Launch the lexer expecting the input JSON text as a serialized object
316 * or array. */
317 if (u_json_match_object_first(jl))
318 warn_err_if (u_json_match_object(jl, jo));
319 else if (u_json_match_array_first(jl))
320 warn_err_if (u_json_match_array(jl, jo));
321 else
322 {
323 U_LEXER_ERR(jl,
324 "Expecting \'{\' or \'[\', found \'%c\'.", u_lexer_peek(jl));
325 }
326
327 /* Dispose the lexer context. */
328 u_lexer_free(jl);
329
330 /* Copy out the broken down tree. */
331 *pjo = jo;
332
333 return 0;
334 err:
335 u_json_obj_free(jo);
336 u_lexer_free(jl);
337 return ~0;
338 }
339
340 /**
341 * \brief Dispose any resource allocated to a JSON object
342 *
343 * Dispose any resource allocated to the supplied JSON object \p jo
344 *
345 * \param jo Pointer to the ::u_json_obj_t object that must be free'd
346 *
347 * \return nothing
348 */
349 void u_json_obj_free (u_json_obj_t *jo)
350 {
351 size_t dummy = 0;
352
353 if (jo == NULL)
354 return;
355
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
356 /* If there is an associated hmap free it. */
357 if (jo->map)
358 {
359 u_hmap_easy_free(jo->map);
360 jo->map = NULL;
361 }
362
dac025c [libu] json module integration (wip)
tho authored
363 /* Walk the tree in post order and free each node while we traverse. */
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
364 u_json_obj_walk(jo, U_JSON_WALK_POSTORDER, dummy, u_json_obj_do_free, NULL);
dac025c [libu] json module integration (wip)
tho authored
365
366 return;
367 }
368
369 /**
370 * \brief Encode a JSON object
371 *
372 * Encode the supplied JSON object \p jo to the result string pointed by
373 * \p *ps
374 *
375 * \param jo Pointer to the ::u_json_obj_t object that must be encoded
376 * \param ps serialized JSON text corresponding to \p jo
377 *
378 * \retval ~0 on failure
379 * \retval 0 on success
380 */
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
381 int u_json_encode (u_json_obj_t *jo, char **ps)
dac025c [libu] json module integration (wip)
tho authored
382 {
383 u_string_t *s = NULL;
384
385 dbg_return_if (jo == NULL, ~0);
386 dbg_return_if (ps == NULL, ~0);
387
388 dbg_err_if (u_string_create(NULL, 0, &s));
389 dbg_err_if (u_json_do_encode(jo, s));
390 *ps = u_string_c(s);
391
392 return 0;
393 err:
394 if (s)
395 u_string_free(s);
396 return ~0;
397 }
398
399 /**
bbf1dce [libu] json += missing doxy
tho authored
400 * \brief Pre/post-order tree walker
401 *
402 * Traverse the supplied JSON object \p jo in pre/post-order, depending on
403 * \p strategy, invoking the callback function \p cb on each node.
404 *
405 * \param jo Pointer to ::u_json_obj_t object to traverse
406 * \param strategy one of ::U_JSON_WALK_PREORDER or ::U_JSON_WALK_POSTORDER
407 * \param l depth level in the JSON tree (the root is at depth 0)
408 * \param cb function to invoke on each traversed node
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
409 * \param cb_args optional opaque data which will be supplied to \p cb
bbf1dce [libu] json += missing doxy
tho authored
410 *
411 * \return nothing
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
412 */
bbf1dce [libu] json += missing doxy
tho authored
413 void u_json_obj_walk (u_json_obj_t *jo, int strategy, size_t l,
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
414 void (*cb)(u_json_obj_t *, size_t, void *), void *cb_args)
bbf1dce [libu] json += missing doxy
tho authored
415 {
416 dbg_return_if (strategy != U_JSON_WALK_PREORDER &&
417 strategy != U_JSON_WALK_POSTORDER, );
418
419 if (jo == NULL)
420 return;
421
422 if (strategy == U_JSON_WALK_PREORDER && cb)
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
423 cb(jo, l, cb_args);
bbf1dce [libu] json += missing doxy
tho authored
424
425 /* When recurring into the children branch, increment depth by one. */
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
426 u_json_obj_walk(TAILQ_FIRST(&jo->children), strategy, l + 1, cb, cb_args);
bbf1dce [libu] json += missing doxy
tho authored
427
428 /* Siblings are at the same depth as the current node. */
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
429 u_json_obj_walk(TAILQ_NEXT(jo, siblings), strategy, l, cb, cb_args);
bbf1dce [libu] json += missing doxy
tho authored
430
431 if (strategy == U_JSON_WALK_POSTORDER && cb)
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
432 cb(jo, l, cb_args);
bbf1dce [libu] json += missing doxy
tho authored
433
434 return;
435 }
436
437 /**
438 * \brief Print to stderr the internal representation of a JSON object
439 *
440 * Print to stderr the supplied JSON object \p jo
441 *
442 * \param jo Pointer to the ::u_json_obj_t object that must be printed
443 *
444 * \return nothing
445 */
446 void u_json_obj_print (u_json_obj_t *jo)
447 {
448 dbg_return_if (jo == NULL, );
449
450 /* Tree root is at '0' depth. */
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
451 u_json_obj_walk(jo, U_JSON_WALK_PREORDER, 0, u_json_obj_do_print, NULL);
bbf1dce [libu] json += missing doxy
tho authored
452
453 return;
454 }
455
456 /**
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
457 * \brief TODO
458 *
459 * TODO
460 *
461 * \param jo Pointer to the ::u_json_obj_t object that must be indexed
462 *
463 * \return nothing
464 */
465 int u_json_freeze (u_json_obj_t *jo)
466 {
467 size_t u; /* Unused. */
468 u_hmap_opts_t opts;
469 u_hmap_t *hmap = NULL;
470
471 dbg_return_if (jo == NULL, ~0);
472 nop_return_if (jo->map, 0); /* If already frozen, return ok. */
473
474 /* Create the associative array. */
475 u_hmap_opts_init(&opts);
476 dbg_err_if (u_hmap_opts_set_val_type(&opts, U_HMAP_OPTS_DATATYPE_POINTER));
477 dbg_err_if (u_hmap_opts_set_val_freefunc(&opts, nopf));
478 dbg_err_if (u_hmap_easy_new(&opts, &hmap));
479
480 /* Initialize array elems' indexing. */
481 jo->icur = 0;
482
483 /* Walk the tree in pre-order and freeze each node while we traverse. */
484 u_json_obj_walk(jo, U_JSON_WALK_PREORDER, u, u_json_obj_do_freeze, hmap);
485
486 /* Attach the associative array to the top level object. */
487 jo->map = hmap, hmap = NULL;
488
489 return 0;
490 err:
491 if (hmap)
492 u_hmap_easy_free(hmap);
493 return ~0;
494 }
495
496 /**
497 * \brief TODO
498 *
499 * TODO
500 *
501 * \param jo Pointer to the ::u_json_obj_t object that must be de-indexed
502 *
503 * \return nothing
504 */
505 int u_json_defrost (u_json_obj_t *jo)
506 {
507 dbg_return_if (jo == NULL, ~0);
508 nop_return_if (jo->map == NULL, 0);
509
510 u_hmap_easy_free(jo->map);
511 jo->map = NULL;
512
513 return 0;
514 }
515
516 /**
517 * \brief TODO
518 *
519 * TODO
520 *
521 * \param jo Pointer to the ::u_json_obj_t object that must be de-indexed
522 * \param key name of the element that must be searched
523 *
524 * \return the retrieved JSON (sub)object on success; \c NULL in case \p key
525 * was not found
526 */
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
527 u_json_obj_t *u_json_get (u_json_obj_t *jo, const char *name)
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
528 {
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
529 u_json_obj_t *res, *p;
530 char fqn[U_JSON_FQN_SZ];
531
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
532 dbg_return_if (jo == NULL, NULL);
533 dbg_return_if (jo->map == NULL, NULL);
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
534 dbg_return_if (name == NULL, NULL);
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
535
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
536 if ((p = jo->parent) == NULL)
537 {
538 /* If 'jo' is top level, 'name' must be fully qualified. */
539 return (u_json_obj_t *) u_hmap_easy_get(jo->map, name);
540 }
541
542 /* Else ('jo' != top): first try 'name' as it were fully qualified. */
543 if ((res = (u_json_obj_t *) u_hmap_easy_get(jo->map, name)))
544 return res;
545
546 /* If 'name' is relative, prefix it with the expected name space. */
547 dbg_if (u_snprintf(fqn, sizeof fqn, "%s%s", jo->fqn, name));
548
549 return (u_json_obj_t *) u_hmap_easy_get(jo->map, fqn);
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
550 }
551
552 /** \brief Wrapper around ::u_json_get to retrieve string values from
553 * terminal (i.e. non-container objects). */
554 const char *u_json_get_val (u_json_obj_t *jo, const char *key)
555 {
556 u_json_obj_t *res = u_json_get(jo, key);
557
558 if (res == NULL)
559 return NULL;
560
561 switch (res->type)
562 {
563 case U_JSON_TYPE_STRING:
564 case U_JSON_TYPE_NUMBER:
565 return res->val;
566 case U_JSON_TYPE_TRUE:
567 return "true";
568 case U_JSON_TYPE_FALSE:
569 return "false";
570 case U_JSON_TYPE_NULL:
571 return "null";
572 case U_JSON_TYPE_OBJECT:
573 case U_JSON_TYPE_ARRAY:
574 case U_JSON_TYPE_UNKNOWN:
575 return NULL;
576 }
577
578 return NULL;
579 }
580
581 /**
dac025c [libu] json module integration (wip)
tho authored
582 * \}
583 */
584
585 static int u_json_do_encode (u_json_obj_t *jo, u_string_t *s)
586 {
587 if (jo == NULL)
588 return 0;
589
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
590 /* Optional key. */
dac025c [libu] json module integration (wip)
tho authored
591 if (strlen(jo->key))
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
592 dbg_err_if (u_string_aprintf(s, "\"%s\": ", jo->key));
dac025c [libu] json module integration (wip)
tho authored
593
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
594 /* Value. */
dac025c [libu] json module integration (wip)
tho authored
595 switch (jo->type)
596 {
597 case U_JSON_TYPE_STRING:
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
598 dbg_err_if (u_string_aprintf(s, "\"%s\"", jo->val));
599 break;
dac025c [libu] json module integration (wip)
tho authored
600 case U_JSON_TYPE_NUMBER:
601 dbg_err_if (u_string_aprintf(s, "%s", jo->val));
602 break;
603 case U_JSON_TYPE_OBJECT:
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
604 dbg_err_if (u_string_aprintf(s, "{ "));
dac025c [libu] json module integration (wip)
tho authored
605 break;
606 case U_JSON_TYPE_ARRAY:
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
607 dbg_err_if (u_string_aprintf(s, "[ "));
dac025c [libu] json module integration (wip)
tho authored
608 break;
609 case U_JSON_TYPE_TRUE:
610 dbg_err_if (u_string_aprintf(s, "true"));
611 break;
612 case U_JSON_TYPE_FALSE:
613 dbg_err_if (u_string_aprintf(s, "false"));
614 break;
615 case U_JSON_TYPE_NULL:
616 dbg_err_if (u_string_aprintf(s, "null"));
617 break;
618 default:
619 dbg_err("!");
620 }
621
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
622 /* Explore depth. */
dac025c [libu] json module integration (wip)
tho authored
623 dbg_err_if (u_json_do_encode(TAILQ_FIRST(&jo->children), s));
624
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
625 /* Close matching paren. */
626 switch (jo->type)
627 {
628 case U_JSON_TYPE_ARRAY:
629 dbg_err_if (u_string_aprintf(s, " ]"));
630 break;
631 case U_JSON_TYPE_OBJECT:
632 dbg_err_if (u_string_aprintf(s, " }"));
633 break;
634 default:
635 break;
636 }
637
638 /* When needed, add comma to separate siblings. */
639 if (TAILQ_NEXT(jo, siblings))
640 dbg_err_if (u_string_aprintf(s, ", "));
641
642 /* Explore horizontally. */
643 dbg_err_if (u_json_do_encode(TAILQ_NEXT(jo, siblings), s));
dac025c [libu] json module integration (wip)
tho authored
644
645 return 0;
646 err:
647 return ~0;
648 }
649
650 static int u_json_match_value (u_lexer_t *jl, u_json_obj_t *jo)
651 {
652 dbg_return_if (jl == NULL, ~0);
653 dbg_return_if (jo == NULL, ~0);
654
655 if (u_json_match_string_first(jl))
656 warn_err_if (u_json_match_string(jl, jo));
657 else if (u_json_match_number_first(jl))
658 warn_err_if (u_json_match_number(jl, jo));
659 else if (u_json_match_object_first(jl))
660 warn_err_if (u_json_match_object(jl, jo));
661 else if (u_json_match_array_first(jl))
662 warn_err_if (u_json_match_array(jl, jo));
663 else if (u_json_match_true_first(jl))
664 warn_err_if (u_json_match_true(jl, jo));
665 else if (u_json_match_false_first(jl))
666 warn_err_if (u_json_match_false(jl, jo));
667 else if (u_json_match_null_first(jl))
668 warn_err_if (u_json_match_null(jl, jo));
669 else
670 {
671 U_LEXER_ERR(jl, "unexpected value syntax at \'%s\'",
672 u_lexer_lookahead(jl));
673 }
674
675 return 0;
676 err:
677 return ~0;
678 }
679
680 static int u_json_match_array_first (u_lexer_t *jl)
681 {
682 return (u_lexer_peek(jl) == '[');
683 }
684
685 static int u_json_match_object_first (u_lexer_t *jl)
686 {
687 return (u_lexer_peek(jl) == '{');
688 }
689
690 static int u_json_match_number_first (u_lexer_t *jl)
691 {
692 char r, c = u_lexer_peek(jl);
693
694 if ((r = (c == '-' || isdigit(c))))
695 u_lexer_record_lmatch(jl);
696
697 return r;
698 }
699
700 static int u_json_match_pair_first (u_lexer_t *jl)
701 {
702 return u_json_match_string_first(jl);
703 }
704
705 static int u_json_match_false_first (u_lexer_t *jl)
706 {
707 return (u_lexer_peek(jl) == 'f');
708 }
709
710 static int u_json_match_true_first (u_lexer_t *jl)
711 {
712 return (u_lexer_peek(jl) == 't');
713 }
714
715 static int u_json_match_null_first (u_lexer_t *jl)
716 {
717 return (u_lexer_peek(jl) == 'n');
718 }
719
720 static int u_json_match_string_first (u_lexer_t *jl)
721 {
722 char r, c = u_lexer_peek(jl);
723
724 if ((r = (c == '"')))
725 u_lexer_record_lmatch(jl);
726
727 return r;
728 }
729
730 /* number ::= INT[FRAC][EXP] */
731 static int u_json_match_number (u_lexer_t *jl, u_json_obj_t *jo)
732 {
733 char match[U_TOKEN_SZ];
734
735 /* INT is mandatory */
736 warn_err_if (u_json_match_int(jl));
737
738 /* c IN first(FRAC) */
739 if (u_json_match_frac_first(u_lexer_peek(jl)))
740 warn_err_if (u_json_match_frac(jl));
741
742 /* c IN first(EXP) */
743 if (u_json_match_exp_first(u_lexer_peek(jl)))
744 warn_err_if (u_json_match_exp(jl));
745
746 /* Register right side of the matched number. */
747 u_lexer_record_rmatch(jl);
748
749 /* Take care of the fact that the match includes the first non-number char
750 * (see u_json_match_{int,exp,frac} for details). */
751 (void) u_lexer_get_match(jl, match);
752 match[strlen(match) - 1] = '\0';
753
754 /* Push the matched number into the supplied json object. */
755 warn_err_if (u_json_obj_set_type(jo, U_JSON_TYPE_NUMBER));
756 warn_err_if (u_json_obj_set_val(jo, match));
757
758 #ifdef U_JSON_LEX_DEBUG
759 u_con("matched number: %s", u_lexer_get_match(jl, match));
760 #endif /* U_JSON_LEX_DEBUG */
761
762 return 0;
763 err:
764 return ~0;
765 }
766
767 static int u_json_match_int (u_lexer_t *jl)
768 {
769 char c = u_lexer_peek(jl);
770
771 /* optional minus sign */
772 if (c == '-')
773 U_LEXER_NEXT(jl, &c);
774
775 /* on '0' as the first char, we're done */
776 if (c == '0')
777 {
778 U_LEXER_NEXT(jl, &c);
779 goto end;
780 }
781
782 /* [1-9][0-9]+ */
783 if (c >= 48 && c <= 57)
784 do { U_LEXER_NEXT(jl, &c); } while (isdigit(c));
785 else
786 U_LEXER_ERR(jl, "bad int syntax at %s", u_lexer_lookahead(jl));
787
788 /* fall through */
789 end:
790 return 0;
791 err:
792 return ~0;
793 }
794
795 static int u_json_match_exp_first (char c)
796 {
797 return (c == 'e' || c == 'E');
798 }
799
800 static int u_json_match_frac_first (char c)
801 {
802 return (c == '.');
803 }
804
805 static int u_json_match_frac (u_lexer_t *jl)
806 {
807 char c = u_lexer_peek(jl);
808
809 /* Mandatory dot. */
810 if (c != '.')
811 U_LEXER_ERR(jl, "bad frac syntax at %s", u_lexer_lookahead(jl));
812
813 U_LEXER_NEXT(jl, &c);
814
815 /* [0-9] */
816 if (!isdigit(c))
817 U_LEXER_ERR(jl, "bad frac syntax at %s", u_lexer_lookahead(jl));
818
819 /* [0-9]* */
820 while (isdigit(c))
821 U_LEXER_NEXT(jl, &c);
822
823 return 0;
824 err:
825 return ~0;
826 }
827
828 static int u_json_match_exp (u_lexer_t *jl)
829 {
830 char c = u_lexer_peek(jl);
831
832 /* [eE] */
833 if (c != 'e' && c != 'E')
834 U_LEXER_ERR(jl, "bad exp syntax at %s", u_lexer_lookahead(jl));
835
836 U_LEXER_NEXT(jl, &c);
837
838 /* Optional plus/minus sign. */
839 if (c == '+' || c == '-')
840 U_LEXER_NEXT(jl, &c);
841
842 /* [0-9] */
843 if (!isdigit(c))
844 U_LEXER_ERR(jl, "bad exp syntax at %s", u_lexer_lookahead(jl));
845
846 /* [0-9]* */
847 while (isdigit(c))
848 U_LEXER_NEXT(jl, &c);
849
850 return 0;
851 err:
852 return ~0;
853 }
854
855 static int u_json_match_seq (u_lexer_t *jl, u_json_obj_t *jo, int type,
856 char first, const char *rem, size_t rem_sz)
857 {
858 char c;
859 size_t i = 0;
860
861 if ((c = u_lexer_peek(jl)) != first)
862 {
863 U_LEXER_ERR(jl, "expect \'%c\', got %c at %s",
864 first, c, u_lexer_lookahead(jl));
865 }
866
867 for (i = 0; i < rem_sz; i++)
868 {
869 U_LEXER_SKIP(jl, &c);
870 if (c != *(rem + i))
871 {
872 U_LEXER_ERR(jl, "expect \'%c\', got %c at %s",
873 *(rem + i), c, u_lexer_lookahead(jl));
874 }
875 }
876
877 /* Consume last checked char. */
878 U_LEXER_SKIP(jl, NULL);
879
880 warn_err_if (u_json_obj_set_type(jo, type));
881
882 #ifdef U_JSON_LEX_DEBUG
883 u_con("matched \'%s\' sequence", u_json_type_str(type));
884 #endif /* U_JSON_LEX_DEBUG */
885 return 0;
886 err:
887 return ~0;
888 }
889
890 static int u_json_match_null (u_lexer_t *jl, u_json_obj_t *jo)
891 {
892 return u_json_match_seq(jl, jo, U_JSON_TYPE_NULL,
893 'n', "ull", strlen("ull"));
894 }
895
896 static int u_json_match_true (u_lexer_t *jl, u_json_obj_t *jo)
897 {
898 return u_json_match_seq(jl, jo, U_JSON_TYPE_TRUE,
899 't', "rue", strlen("rue"));
900 }
901
902 static int u_json_match_false (u_lexer_t *jl, u_json_obj_t *jo)
903 {
904 return u_json_match_seq(jl, jo, U_JSON_TYPE_FALSE,
905 'f', "alse", strlen("alse"));
906 }
907
908 static int u_json_match_array (u_lexer_t *jl, u_json_obj_t *jo)
909 {
910 char c;
911 u_json_obj_t *elem = NULL;
912
913 #ifdef U_JSON_LEX_DEBUG
914 u_con("ARRAY");
915 #endif /* U_JSON_LEX_DEBUG */
916
917 if ((c = u_lexer_peek(jl)) != '[')
918 {
919 U_LEXER_ERR(jl, "expect \'[\', got %c at %s",
920 c, u_lexer_lookahead(jl));
921 }
922
923 /* Parent object is an array. */
924 warn_err_if (u_json_obj_set_type(jo, U_JSON_TYPE_ARRAY));
925
926 do {
927 U_LEXER_SKIP(jl, &c);
928
929 if (c == ']') /* break on empty array */
930 break;
931
932 /* Create a new object to store next array element. */
933 warn_err_if (u_json_obj_new(&elem));
934 warn_err_if (u_json_obj_set_type(elem, U_JSON_TYPE_UNKNOWN));
935
936 /* Fetch new value. */
937 warn_err_if (u_json_match_value(jl, elem));
938
939 /* Push the fetched element to its parent array. */
940 warn_err_if (u_json_obj_add(jo, elem));
941 elem = NULL;
942
943 /* Consume any trailing white spaces. */
944 if (isspace(u_lexer_peek(jl)))
945 U_LEXER_SKIP(jl, NULL);
946
947 } while (u_lexer_peek(jl) == ',');
948
949 if ((c = u_lexer_peek(jl)) != ']')
950 {
951 U_LEXER_ERR(jl, "expect \']\', got %c at %s",
952 c, u_lexer_lookahead(jl));
953 }
954
2d8e2ce [libu] json += unit test
tho authored
955 /* Ignore EOT, shall be catched later. */
956 (void) u_lexer_skip(jl, NULL);
dac025c [libu] json module integration (wip)
tho authored
957
958 return 0;
959 err:
960 u_json_obj_free(elem);
961 return ~0;
962 }
963
964 static int u_json_match_object (u_lexer_t *jl, u_json_obj_t *jo)
965 {
966 char c;
967
968 #ifdef U_JSON_LEX_DEBUG
969 u_con("OBJECT");
970 #endif /* U_JSON_LEX_DEBUG */
971
972 if ((c = u_lexer_peek(jl)) != '{')
973 {
974 U_LEXER_ERR(jl, "expect \'{\', got %c at %s",
975 c, u_lexer_lookahead(jl));
976 }
977
978 warn_err_if (u_json_obj_set_type(jo, U_JSON_TYPE_OBJECT));
979
980 do {
981 U_LEXER_SKIP(jl, &c);
982
983 /* Break on empty object. */
984 if (c == '}')
985 break;
986
987 /* Process assignement. */
988 warn_err_if (!u_json_match_pair_first(jl) || u_json_match_pair(jl, jo));
989
990 /* Consume trailing white spaces, if any. */
991 if (isspace(u_lexer_peek(jl)))
992 U_LEXER_SKIP(jl, NULL);
993
994 } while (u_lexer_peek(jl) == ',');
995
996 if ((c = u_lexer_peek(jl)) != '}')
997 {
998 U_LEXER_ERR(jl, "expect \'}\', got %c at %s",
999 c, u_lexer_lookahead(jl));
1000 }
1001
2d8e2ce [libu] json += unit test
tho authored
1002 /* Ignore EOT, shall be catched later. */
1003 (void) u_lexer_skip(jl, NULL);
dac025c [libu] json module integration (wip)
tho authored
1004
1005 return 0;
1006 err:
1007 return ~0;
1008 }
1009
1010 static int u_json_match_pair (u_lexer_t *jl, u_json_obj_t *jo)
1011 {
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
1012 size_t mlen;
dac025c [libu] json module integration (wip)
tho authored
1013 char c, match[U_TOKEN_SZ];
1014 u_json_obj_t *pair = NULL;
1015
1016 dbg_return_if (jl == NULL, ~0);
1017 dbg_return_if (jo == NULL, ~0);
1018
1019 #ifdef U_JSON_LEX_DEBUG
1020 u_con("PAIR");
1021 #endif /* U_JSON_LEX_DEBUG */
1022
1023 /* Here we use the matched string as the 'key' for the associated value,
1024 * hence there is no associated json object. */
1025 warn_err_if (u_json_match_string(jl, NULL));
1026
1027 /* Initialize new json object to store the key/value pair. */
1028 warn_err_if (u_json_obj_new(&pair));
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
1029
1030 (void) u_lexer_get_match(jl, match);
1031
1032 /* Trim trailing '"'. */
1033 if ((mlen = strlen(match)) >= 1)
1034 match[mlen - 1] = '\0';
1035
1036 warn_err_if (u_json_obj_set_key(pair, match));
dac025c [libu] json module integration (wip)
tho authored
1037
1038 /* Consume ':' */
1039 if ((c = u_lexer_peek(jl)) != ':')
1040 {
1041 U_LEXER_ERR(jl, "expect \':\', got %c at %s",
1042 c, u_lexer_lookahead(jl));
1043 }
1044
1045 U_LEXER_SKIP(jl, &c);
1046
1047 /* Assign value. */
1048 warn_err_if (u_json_match_value(jl, pair));
1049
1050 /* Push the new value to the parent json object. */
1051 warn_err_if (u_json_obj_add(jo, pair));
1052 pair = NULL;
1053
1054 return 0;
1055 err:
1056 u_json_obj_free(pair);
1057 return ~0;
1058 }
1059
1060 static int u_json_match_string (u_lexer_t *jl, u_json_obj_t *jo)
1061 {
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
1062 size_t mlen;
dac025c [libu] json module integration (wip)
tho authored
1063 char c, match[U_TOKEN_SZ];
1064
1065 /* In case string is matched as an lval (i.e. the key side of a 'pair'),
1066 * there is no json object. */
1067 dbg_return_if (jl == NULL, ~0);
1068
1069 #ifdef U_JSON_LEX_DEBUG
1070 u_con("STRING");
1071 #endif /* U_JSON_LEX_DEBUG */
1072
1073 if ((c = u_lexer_peek(jl)) != '"')
1074 U_LEXER_ERR(jl, "expect \", got %c at %s", c, u_lexer_lookahead(jl));
1075
1076 U_LEXER_NEXT(jl, &c);
1077
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
1078 /* Re-record the left side match pointer (trim leading '"'). */
1079 u_lexer_record_lmatch(jl);
1080
dac025c [libu] json module integration (wip)
tho authored
1081 while (c != '"')
1082 {
1083 if (c == '\\')
1084 {
1085 U_LEXER_NEXT(jl, &c);
1086 switch (c)
1087 {
1088 case 'u':
1089 warn_err_if (u_json_match_escaped_unicode(jl));
1090 break;
1091 case '"': case '\\': case '/': case 'b':
1092 case 'f': case 'n': case 'r': case 't':
1093 U_LEXER_NEXT(jl, &c);
1094 break;
1095 default:
1096 U_LEXER_ERR(jl, "invalid char %c in escape", c);
1097 }
1098 }
1099 else if (iscntrl(c))
1100 U_LEXER_ERR(jl, "control character in string", c);
1101 else
1102 U_LEXER_NEXT(jl, &c);
1103 }
1104
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
1105 /* Record right match pointer.
1106 * This is a greedy match, which includes the trailing '"', and must
1107 * be taken into account when pulling out the string. */
dac025c [libu] json module integration (wip)
tho authored
1108 u_lexer_record_rmatch(jl);
1109
1110 /* Consume last '"'. */
1111 U_LEXER_NEXT(jl, &c);
1112
1113 #ifdef U_JSON_LEX_DEBUG
1114 u_con("matched string: \'%s\'", u_lexer_get_match(jl, match));
1115 #endif /* U_JSON_LEX_DEBUG */
1116
1117 /* In case the string is matched as an rval, the caller shall
1118 * supply the json object that has to be set. */
1119 if (jo)
1120 {
1121 warn_err_if (u_json_obj_set_type(jo, U_JSON_TYPE_STRING));
7ee39db [libu] json += encoder completed ; cleaner string matching
tho authored
1122
1123 /* Remove trailing '"' from match. */
1124 (void) u_lexer_get_match(jl, match);
1125
1126 /* Trim trailing '"'. */
1127 if ((mlen = strlen(match)) >= 1)
1128 match[mlen - 1] = '\0';
1129
1130 warn_err_if (u_json_obj_set_val(jo, match));
dac025c [libu] json module integration (wip)
tho authored
1131 }
1132
1133 return 0;
1134 err:
1135 return ~0;
1136 }
1137
1138 static int u_json_match_escaped_unicode (u_lexer_t *jl)
1139 {
1140 char i, c;
1141
1142 for (i = 0; i < 4; i++)
1143 {
1144 U_LEXER_NEXT(jl, &c);
1145
1146 if (!isxdigit(c))
1147 U_LEXER_ERR(jl, "non hex digit %c in escaped unicode", c);
1148 }
1149
1150 return 0;
1151 err:
1152 return ~0;
1153 }
1154
1155 static const char *u_json_type_str (int type)
1156 {
1157 switch (type)
1158 {
1159 case U_JSON_TYPE_STRING: return "string";
1160 case U_JSON_TYPE_NUMBER: return "number";
1161 case U_JSON_TYPE_ARRAY: return "array";
1162 case U_JSON_TYPE_OBJECT: return "object";
1163 case U_JSON_TYPE_TRUE: return "true";
1164 case U_JSON_TYPE_FALSE: return "false";
1165 case U_JSON_TYPE_NULL: return "null";
1166 case U_JSON_TYPE_UNKNOWN: default: break;
1167 }
1168
1169 return "unknown";
1170 }
1171
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1172 static void u_json_obj_do_free (u_json_obj_t *jo, size_t l, void *opaque)
dac025c [libu] json module integration (wip)
tho authored
1173 {
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1174 u_unused_args(l, opaque);
dac025c [libu] json module integration (wip)
tho authored
1175
1176 if (jo)
1177 u_free(jo);
1178
1179 return;
1180 }
1181
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1182 static void u_json_obj_do_print (u_json_obj_t *jo, size_t l, void *opaque)
dac025c [libu] json module integration (wip)
tho authored
1183 {
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1184 u_unused_args(opaque);
1185
dac025c [libu] json module integration (wip)
tho authored
1186 dbg_return_if (jo == NULL, );
1187
1188 switch (jo->type)
1189 {
1190 case U_JSON_TYPE_ARRAY:
1191 case U_JSON_TYPE_OBJECT:
1192 /* No value. */
1193 u_con("%*c %s %s", l, ' ', u_json_type_str(jo->type), jo->key);
1194 break;
1195 default:
1196 u_con("%*c %s %s : \'%s\'", l, ' ',
1197 u_json_type_str(jo->type), jo->key, jo->val);
1198 break;
1199 }
1200
1201 return;
1202 }
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1203
1204 static void u_json_obj_do_freeze (u_json_obj_t *jo, size_t l, void *map)
1205 {
1206 u_json_obj_t *p;
1207 u_hmap_t *hmap = (u_hmap_t *) map;
1208
1209 u_unused_args(l);
1210
1211 if ((p = jo->parent) == NULL)
1212 {
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
1213 /* Root node is named '.', its name and fully qualified name match. */
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1214 (void) u_strlcpy(jo->fqn, ".", sizeof jo->fqn);
1215 }
1216 else if (p->type == U_JSON_TYPE_OBJECT)
1217 {
1218 /* Nodes in object containers are named after their key. */
1219 dbg_if (u_snprintf(jo->fqn, sizeof jo->fqn, "%s.%s", p->fqn, jo->key));
1220 }
1221 else if (p->type == U_JSON_TYPE_ARRAY)
1222 {
1223 /* Nodes in array containers are named after their ordinal position. */
1224 dbg_if (u_snprintf(jo->fqn, sizeof jo->fqn, "%s[%u]", p->fqn, p->icur));
1225
1226 /* Increment the counting index in the parent array. */
1227 p->icur += 1;
1228
1229 /* In case we have an array inside another array, initialize the
1230 * counter for later recursive invocation. */
1231 if (jo->type == U_JSON_TYPE_ARRAY)
1232 jo->icur = 0;
1233 }
1234 else
1235 warn("Expecting an object, an array, or a top-level node.");
1236
1237 /* Insert node into the hmap. */
1238 dbg_if (u_hmap_easy_put(hmap, jo->fqn, (const void *) jo));
1239
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
1240 /* Stick the map pointer inside each visited node, so that it can
1241 * be readily referenced on retrieval. */
1242 jo->map = map;
1243
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1244 #ifdef U_JSON_IDX_DEBUG
d0490ad @babongo fragmented name match through namespace in JSON
babongo authored
1245 u_con("%p => %s (%s) = %s", jo, jo->fqn, U_JSON_OBJ_NAME(jo), jo->val);
a63e435 @babongo JSON indexing interface wip (again)
babongo authored
1246 #endif
1247
1248 return;
1249 }
1250
1251 static int u_json_obj_new_container (u_json_type_t type, const char *key,
1252 u_json_obj_t **pjo)
1253 {
1254 u_json_obj_t *jo = NULL;
1255
1256 dbg_return_if (pjo == NULL, ~0);
1257
1258 dbg_err_if (u_json_obj_new(&jo));
1259
1260 dbg_err_if (u_json_obj_set_type(jo, type));
1261 /* TBT: allow for anonymous containers via NULL key's ? */
1262 dbg_err_if (u_json_obj_set_key(jo, key ? key : ""));
1263
1264 *pjo = jo;
1265
1266 return 0;
1267 err:
1268 if (jo)
1269 u_json_obj_free(jo);
1270 return ~0;
1271 }
1272
Something went wrong with that request. Please try again.