2 * Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
3 * Copyright (c) 2010 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
5 * Jansson is free software; you can redistribute it and/or modify
6 * it under the terms of the MIT license. See LICENSE for details.
14 #include "jansson_private.h"
16 static void error_init(json_error_t **error)
22 static void error_set(json_error_t **error, const int line, const char *msg, ...)
29 *error = calloc(1, sizeof(json_error_t));
34 vsnprintf((*error)->msg, JSON_ERROR_MSG_LENGTH, msg, ap);
38 vfprintf(stderr, msg, ap);
41 (*error)->line = line;
44 json_t *json_pack(json_error_t **error, const char *fmt, ...) {
45 int fmt_length = strlen(fmt);
48 /* Keep a stack of containers (lists and objects) */
50 json_t **stack = NULL;
52 /* Keep a list of objects we create in case of error */
54 json_t **free_list = NULL;
56 json_t *cur = NULL; /* Current container */
57 json_t *root = NULL; /* root object */
60 char *key = NULL; /* Current key in an object */
65 /* Allocation provisioned for worst case */
66 stack = calloc(fmt_length, sizeof(json_t *));
67 free_list = calloc(fmt_length, sizeof(json_t *));
71 if(!stack || !free_list)
81 case ' ': /* Whitespace */
84 case ',': /* Element spacer */
87 error_set(error, line,
88 "Unexpected COMMA precedes root element!");
95 error_set(error, line,
96 "Unexpected COMMA outside a list or object!");
103 error_set(error, line, "Expected KEY, got COMMA!");
109 case ':': /* Key/value separator */
112 error_set(error, line, "Got key/value separator without "
113 "a key preceding it!");
118 if(!json_is_object(cur))
120 error_set(error, line, "Got a key/value separator "
121 "(':') outside an object!");
128 case ']': /* Close array or object */
133 error_set(error, line, "OBJECT or ARRAY ended with an "
134 "incomplete key/value pair!");
141 error_set(error, line,
142 "Too many close-brackets '%c'", *fmt);
147 if(*fmt == ']' && !json_is_array(cur))
149 error_set(error, line,
150 "Stray close-array ']' character");
155 if(*fmt == '}' && !json_is_object(cur))
157 error_set(error, line,
158 "Stray close-object '}' character");
163 cur = stack[--depth];
174 case 's': /* string */
175 s = va_arg(ap, char*);
179 error_set(error, line,
180 "Refusing to handle a NULL string");
185 if(json_is_object(cur) && !key)
192 obj = json_string(s);
199 case 'b': /* boolean */
200 obj = va_arg(ap, int) ?
201 json_true() : json_false();
204 case 'i': /* integer */
205 obj = json_integer(va_arg(ap, int));
208 case 'f': /* double-precision float */
209 obj = json_real(va_arg(ap, double));
212 case 'O': /* a json_t object; increments refcount */
213 obj = va_arg(ap, json_t *);
217 case 'o': /* a json_t object; doesn't increment refcount */
218 obj = va_arg(ap, json_t *);
221 obj_common: free_list[free_count++] = obj;
223 /* Root this object to its parent */
224 if(json_is_object(cur)) {
227 error_set(error, line,
228 "Expected key, got identifier '%c'!", *fmt);
233 json_object_set_new(cur, key, obj);
236 else if(json_is_array(cur))
238 json_array_append_new(cur, obj);
247 error_set(error, line, "Can't figure out where to attach "
248 "'%c' object!", *fmt);
253 /* If it was a container ('[' or '{'), descend on the stack */
254 if(json_is_array(obj) || json_is_object(obj))
256 stack[depth++] = cur;
267 error_set(error, line,
268 "Missing object or array close-brackets in format string");
273 /* Success: don't free everything we just built! */
278 json_decref(free_list[--free_count]);
289 int json_unpack(json_t *root, json_error_t **error, const char *fmt, ...) {
292 int rv=0; /* Return value */
293 int line = 1; /* Line number */
295 /* Keep a stack of containers (lists and objects) */
300 char *key = NULL; /* Current key in an object */
302 json_t *cur = NULL; /* Current container */
305 int fmt_length = strlen(fmt);
309 /* Allocation provisioned for worst case */
310 stack = calloc(fmt_length, sizeof(json_t *));
313 error_set(error, line, "Out of memory!");
318 /* Even if we're successful, we need to know if the number of
319 * arguments provided matches the number of JSON objects.
320 * We can do this by counting the elements in every array or
321 * object we open up, and decrementing the count as we visit
330 case ' ': /* Whitespace */
333 case '\n': /* Line break */
337 case ',': /* Element spacer */
341 error_set(error, line,
342 "Unexpected COMMA outside a list or object!");
349 error_set(error, line, "Expected KEY, got COMMA!");
355 case ':': /* Key/value separator */
356 if(!json_is_object(cur) || !key)
358 error_set(error, line, "Unexpected ':'");
371 else if(json_is_object(cur))
375 error_set(error, line, "Objects can't be keys");
379 obj = json_object_get(cur, key);
383 else if(json_is_array(cur))
385 obj = json_array_get(cur, array_index);
394 /* Make sure we got what we expected */
395 if(*fmt=='{' && !json_is_object(obj))
401 if(*fmt=='[' && !json_is_array(obj))
407 unvisited += json_is_object(obj) ?
408 json_object_size(obj) :
409 json_array_size(obj);
412 stack[depth++] = cur;
423 if(json_is_array(cur) && *fmt!=']')
425 error_set(error, line, "Missing ']'");
430 if(json_is_object(cur) && *fmt!='}')
432 error_set(error, line, "Missing '}'");
439 error_set(error, line, "Unexpected '%c'", *fmt);
446 error_set(error, line, "Unexpected '%c'", *fmt);
451 cur = stack[--depth];
456 if(!key && json_is_object(cur))
458 /* constant string for key */
459 key = va_arg(ap, char*);
464 case 'i': /* integer */
465 case 'f': /* double-precision float */
466 case 'O': /* a json_t object; increments refcount */
467 case 'o': /* a json_t object; borrowed reference */
468 case 'b': /* boolean */
476 else if(json_is_object(cur))
480 error_set(error, line,
481 "Only strings may be used as keys!");
486 obj = json_object_get(cur, key);
490 else if(json_is_array(cur))
492 obj = json_array_get(cur, array_index);
498 error_set(error, line,
499 "Unsure how to retrieve JSON object '%c'",
508 if(!json_is_string(obj))
510 error_set(error, line,
511 "Type mismatch! Object wasn't a string.");
515 *va_arg(ap, const char**) = json_string_value(obj);
519 if(!json_is_integer(obj))
521 error_set(error, line,
522 "Type mismatch! Object wasn't an integer.");
526 *va_arg(ap, int*) = json_integer_value(obj);
530 if(!json_is_boolean(obj))
532 error_set(error, line,
533 "Type mismatch! Object wasn't a boolean.");
537 *va_arg(ap, int*) = json_is_true(obj);
541 if(!json_is_number(obj))
543 error_set(error, line,
544 "Type mismatch! Object wasn't a real.");
548 *va_arg(ap, double*) = json_number_value(obj);
556 *va_arg(ap, json_t**) = obj;
560 /* Don't actually assign anything; we're just happy
561 * the null turned up as promised in the format
566 error_set(error, line,
567 "Unknown format character '%c'", *fmt);
575 /* Return 0 if everything was matched; otherwise the number of JSON
576 * objects we didn't get to. */
588 /* vim: ts=4:expandtab:sw=4