diff options
author | Lloyd Hilaiel <lloyd@hilaiel.com> | 2011-04-23 11:17:35 -0600 |
---|---|---|
committer | Lloyd Hilaiel <lloyd@hilaiel.com> | 2011-04-23 11:17:35 -0600 |
commit | b36a8bd294cbeeaab7149402f369fdd9be95aec1 (patch) | |
tree | 7e2ab759926148ad03d1931c8a768abe5301bff9 | |
parent | 9bf2ad882bb98710949b1e3262bddff67845bb87 (diff) | |
download | yajl-b36a8bd294cbeeaab7149402f369fdd9be95aec1.tar.gz |
update documentation and tighten API for yajl_tree.h, inline several structures so a reader can grok the structure in hopefully one pass without jumping all over the file.
-rw-r--r-- | src/api/yajl_tree.h | 110 | ||||
-rw-r--r-- | src/yajl_tree.c | 147 |
2 files changed, 108 insertions, 149 deletions
diff --git a/src/api/yajl_tree.h b/src/api/yajl_tree.h index 78ed240..f23f191 100644 --- a/src/api/yajl_tree.h +++ b/src/api/yajl_tree.h @@ -28,54 +28,7 @@ #include <yajl/yajl_common.h> -/* Forward declaration, because "yajl_val_object_t" and "yajl_val_array" - * contain "yajl_val" and "yajl_val" can be an object or an array. */ -typedef struct yajl_val_s * yajl_val; - -#define YAJL_NUMBER_INT_VALID 0x01 -#define YAJL_NUMBER_DOUBLE_VALID 0x02 -/** Structure describing a JSON number. */ -typedef struct yajl_val_number_s -{ - /** Holds the raw value of the number, in string form. */ - char *r; - /** Holds the integer value of the number, if possible. */ - long long i; - /** Holds the double value of the number, if possible. */ - double d; - /** Signals whether the \em value_int and \em value_double members are - * valid. See \c YAJL_NUMBER_INT_VALID and \c YAJL_NUMBER_DOUBLE_VALID. */ - unsigned int flags; -} yajl_val_number; - -/** - * Structure describing a JSON object. - * - * \sa yajl_val_array_s - */ -typedef struct yajl_val_object_s -{ - /** Array of keys in the JSON object. */ - const char **keys; - /** Array of values in the JSON object. */ - yajl_val *values; - /** Number of key-value-pairs in the JSON object. */ - size_t len; -} yajl_val_object; - -/** - * Structure describing a JSON array. - * - * \sa yajl_val_object_s - */ -typedef struct yajl_val_array_s -{ - /** Array of elements in the JSON array. */ - yajl_val *values; - /** Number of elements in the JSON array. */ - size_t len; -} yajl_val_array; - +/** possible data types that a yajl_val_s can hold */ typedef enum { yajl_t_string = 1, yajl_t_number = 2, @@ -84,19 +37,23 @@ typedef enum { yajl_t_true = 5, yajl_t_false = 6, yajl_t_null = 7, + /** The any type isn't valid for yajl_val_s.type, but can be + * used as an argument to routines like yajl_tree_get(). + */ yajl_t_any = 8 } yajl_type; +#define YAJL_NUMBER_INT_VALID 0x01 +#define YAJL_NUMBER_DOUBLE_VALID 0x02 + +/** A pointer to a node in the parse tree */ +typedef struct yajl_val_s * yajl_val; + /** - * Struct describing a general JSON value. - * - * Each value is one of the seven types above. For "string", "number", - * "object", and "array" additional data is available in the "data" union. Use - * the "YAJL_IS_*" and "YAJL_TO_*" macros below to check for the correct type - * and cast the struct. - * - * \sa yajl_val_string, yajl_val_number, yajl_val_object, - * yajl_val_array + * A JSON value:is one of the seven types above. For "string", "number", + * "object", and "array" additional data is available in the "data" union. + * The "YAJL_IS_*" and "YAJL_GET_*" macros below allow type checking + * and convenient value extraction. */ struct yajl_val_s { @@ -108,10 +65,25 @@ struct yajl_val_s union { char * string; - yajl_val_number number; - yajl_val_object object; - yajl_val_array array; - } data; + struct { + char *r; /*< unparsed number in string form. */ + long long i; /*< integer value, if representable. */ + double d; /*< double value, if representable. */ + /** Signals whether the \em i and \em d members are + * valid. See \c YAJL_NUMBER_INT_VALID and + * \c YAJL_NUMBER_DOUBLE_VALID. */ + unsigned int flags; + } number; + struct { + const char **keys; /*< Array of keys */ + yajl_val *values; /** Array of values. */ + size_t len; /*< Number of key-value-pairs. */ + } object; + struct { + yajl_val *values; /*< Array of elements. */ + size_t len; /*< Number of elements. */ + } array; + } u; }; /** @@ -157,8 +129,8 @@ YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type t /* Various convenience macros to check the type of a `yajl_val` */ #define YAJL_IS_STRING(v) (((v) != NULL) && ((v)->type == yajl_t_string)) #define YAJL_IS_NUMBER(v) (((v) != NULL) && ((v)->type == yajl_t_number)) -#define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->data.flags & YAJL_NUMBER_INT_VALID)) -#define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->data.flags & YAJL_NUMBER_DOUBLE_VALID)) +#define YAJL_IS_INTEGER(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_INT_VALID)) +#define YAJL_IS_DOUBLE(v) (YAJL_IS_NUMBER(v) && ((v)->u.flags & YAJL_NUMBER_DOUBLE_VALID)) #define YAJL_IS_OBJECT(v) (((v) != NULL) && ((v)->type == yajl_t_object)) #define YAJL_IS_ARRAY(v) (((v) != NULL) && ((v)->type == yajl_t_array )) #define YAJL_IS_TRUE(v) (((v) != NULL) && ((v)->type == yajl_t_true )) @@ -167,24 +139,24 @@ YAJL_API yajl_val yajl_tree_get(yajl_val parent, const char ** path, yajl_type t /** Given a yajl_val_string return a ptr to the bare string it contains, * or NULL if the value is not a string. */ -#define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->data.string : NULL) +#define YAJL_GET_STRING(v) (YAJL_IS_STRING(v) ? (v)->u.string : NULL) /** Get the string representation of a number. You should check type first, * perhaps using YAJL_IS_NUMBER */ -#define YAJL_GET_NUMBER(v) ((v)->data.number.r) +#define YAJL_GET_NUMBER(v) ((v)->u.number.r) /** Get the double representation of a number. You should check type first, * perhaps using YAJL_IS_DOUBLE */ -#define YAJL_GET_DOUBLE(v) ((v)->data.number.d) +#define YAJL_GET_DOUBLE(v) ((v)->u.number.d) /** Get the 64bit (long long) integer representation of a number. You should * check type first, perhaps using YAJL_IS_INTEGER */ -#define YAJL_GET_INTEGER(v) ((v)->data.number.i) +#define YAJL_GET_INTEGER(v) ((v)->u.number.i) /** Get a pointer to a yajl_val_object or NULL if the value is not an object. */ -#define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->data.object : NULL) +#define YAJL_GET_OBJECT(v) (YAJL_IS_OBJECT(v) ? &(v)->u.object : NULL) /** Get a pointer to a yajl_val_array or NULL if the value is not an object. */ -#define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->data.array : NULL) +#define YAJL_GET_ARRAY(v) (YAJL_IS_ARRAY(v) ? &(v)->u.array : NULL) #endif /* YAJL_TREE_H */ diff --git a/src/yajl_tree.c b/src/yajl_tree.c index 0810fdd..7a8c3e7 100644 --- a/src/yajl_tree.c +++ b/src/yajl_tree.c @@ -65,41 +65,37 @@ static yajl_val value_alloc (yajl_type type) static void yajl_object_free (yajl_val v) { - yajl_val_object *o; size_t i; - o = YAJL_GET_OBJECT(v); - if (o == NULL) return; + if (!YAJL_IS_OBJECT(v)) return; - for (i = 0; i < o->len; i++) + for (i = 0; i < v->u.object.len; i++) { - free((char *) o->keys[i]); - o->keys[i] = NULL; - yajl_tree_free (o->values[i]); - o->values[i] = NULL; + free((char *) v->u.object.keys[i]); + v->u.object.keys[i] = NULL; + yajl_tree_free (v->u.object.values[i]); + v->u.object.values[i] = NULL; } - free (o->keys); - free (o->values); - free (v); + free(v->u.object.keys); + free(v->u.object.values); + free(v); } static void yajl_array_free (yajl_val v) { - yajl_val_array *a; size_t i; - a = YAJL_GET_ARRAY (v); - if (a == NULL) return; + if (!YAJL_IS_ARRAY(v)) return; - for (i = 0; i < a->len; i++) + for (i = 0; i < v->u.array.len; i++) { - yajl_tree_free (a->values[i]); - a->values[i] = NULL; + yajl_tree_free (v->u.array.values[i]); + v->u.array.values[i] = NULL; } - free (a->values); - free (v); + free(v->u.array.values); + free(v); } /* @@ -151,7 +147,6 @@ static yajl_val context_pop(context_t *ctx) static int object_add_keyval(context_t *ctx, yajl_val obj, char *key, yajl_val value) { - yajl_val_object *o; const char **tmpk; yajl_val *tmpv; @@ -162,22 +157,21 @@ static int object_add_keyval(context_t *ctx, assert (value != NULL); /* We're assuring that "obj" is an object in "context_add_value". */ - o = YAJL_GET_OBJECT (obj); - assert (o != NULL); + assert(YAJL_IS_OBJECT(o)); - tmpk = realloc (o->keys, sizeof (*o->keys) * (o->len + 1)); + tmpk = realloc(obj->u.object.keys, sizeof(*(obj->u.object.keys)) * (obj->u.object.len + 1)); if (tmpk == NULL) - RETURN_ERROR (ctx, ENOMEM, "Out of memory"); - o->keys = tmpk; + RETURN_ERROR(ctx, ENOMEM, "Out of memory"); + obj->u.object.keys = tmpk; - tmpv = realloc (o->values, sizeof (*o->values) * (o->len + 1)); + tmpv = realloc(obj->u.object.values, sizeof (*obj->u.object.values) * (obj->u.object.len + 1)); if (tmpv == NULL) - RETURN_ERROR (ctx, ENOMEM, "Out of memory"); - o->values = tmpv; + RETURN_ERROR(ctx, ENOMEM, "Out of memory"); + obj->u.object.values = tmpv; - o->keys[o->len] = key; - o->values[o->len] = value; - o->len++; + obj->u.object.keys[obj->u.object.len] = key; + obj->u.object.values[obj->u.object.len] = value; + obj->u.object.len++; return (0); } @@ -185,7 +179,6 @@ static int object_add_keyval(context_t *ctx, static int array_add_value (context_t *ctx, yajl_val array, yajl_val value) { - yajl_val_array *a; yajl_val *tmp; /* We're checking for NULL pointers in "context_add_value" or its @@ -195,17 +188,17 @@ static int array_add_value (context_t *ctx, assert (value != NULL); /* "context_add_value" will only call us with array values. */ - a = YAJL_GET_ARRAY (array); - assert (a != NULL); - - tmp = realloc (a->values, sizeof (*a->values) * (a->len + 1)); + assert(YAJL_IS_ARRAY(array)); + + tmp = realloc(array->u.array.values, + sizeof(*(array->u.array.values)) * (array->u.array.len + 1)); if (tmp == NULL) - RETURN_ERROR (ctx, ENOMEM, "Out of memory"); - a->values = tmp; - a->values[a->len] = value; - a->len++; + RETURN_ERROR(ctx, ENOMEM, "Out of memory"); + array->u.array.values = tmp; + array->u.array.values[array->u.array.len] = value; + array->u.array.len++; - return (0); + return 0; } /* @@ -244,8 +237,8 @@ static int context_add_value (context_t *ctx, yajl_val v) "Object key is not a string (%#04"PRIx8")", v->type); - ctx->stack->key = v->data.string; - v->data.string = NULL; + ctx->stack->key = v->u.string; + v->u.string = NULL; free(v); return (0); } @@ -279,14 +272,14 @@ static int handle_string (void *ctx, if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); - v->data.string = malloc (string_length + 1); - if (v->data.string == NULL) + v->u.string = malloc (string_length + 1); + if (v->u.string == NULL) { free (v); RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); } - memcpy(v->data.string, string, string_length); - v->data.string[string_length] = 0; + memcpy(v->u.string, string, string_length); + v->u.string[string_length] = 0; return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } @@ -294,53 +287,49 @@ static int handle_string (void *ctx, static int handle_number (void *ctx, const char *string, size_t string_length) { yajl_val v; - yajl_val_number *n; char *endptr; - v = value_alloc (yajl_t_number); + v = value_alloc(yajl_t_number); if (v == NULL) - RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); - n = &(v->data.number); + RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); - n->r = malloc (string_length + 1); - if (n->r == NULL) + v->u.number.r = malloc(string_length + 1); + if (v->u.number.r == NULL) { - free (v); - RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); + free(v); + RETURN_ERROR((context_t *) ctx, STATUS_ABORT, "Out of memory"); } - memcpy (n->r, string, string_length); - n->r[string_length] = 0; + memcpy(v->u.number.r, string, string_length); + v->u.number.r[string_length] = 0; - n->flags = 0; + v->u.number.flags = 0; endptr = NULL; errno = 0; - n->i = (int64_t) strtoll (n->r, &endptr, /* base = */ 10); + v->u.number.i = (int64_t) strtoll(v->u.number.r, &endptr, /* base = */ 10); if ((errno == 0) && (endptr != NULL) && (*endptr == 0)) - n->flags |= YAJL_NUMBER_INT_VALID; + v->u.number.flags |= YAJL_NUMBER_INT_VALID; endptr = NULL; errno = 0; - n->d = strtod (n->r, &endptr); + v->u.number.d = strtod(v->u.number.r, &endptr); if ((errno == 0) && (endptr != NULL) && (*endptr == 0)) - n->flags |= YAJL_NUMBER_DOUBLE_VALID; + v->u.number.flags |= YAJL_NUMBER_DOUBLE_VALID; - return ((context_add_value (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); + return ((context_add_value(ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } static int handle_start_map (void *ctx) { yajl_val v; - yajl_val_object *o; - v = value_alloc (yajl_t_object); + v = value_alloc(yajl_t_object); if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); - o = YAJL_GET_OBJECT (v); - o->keys = NULL; - o->values = NULL; - o->len = 0; + v->u.object.keys = NULL; + v->u.object.values = NULL; + v->u.object.len = 0; return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } @@ -359,15 +348,13 @@ static int handle_end_map (void *ctx) static int handle_start_array (void *ctx) { yajl_val v; - yajl_val_array *a; - v = value_alloc (yajl_t_array); + v = value_alloc(yajl_t_array); if (v == NULL) RETURN_ERROR ((context_t *) ctx, STATUS_ABORT, "Out of memory"); - a = YAJL_GET_ARRAY (v); - a->values = NULL; - a->len = 0; + v->u.array.values = NULL; + v->u.array.len = 0; return ((context_push (ctx, v) == 0) ? STATUS_CONTINUE : STATUS_ABORT); } @@ -470,13 +457,13 @@ yajl_val yajl_tree_get(yajl_val n, const char ** path, yajl_type type) unsigned int i; if (n->type != yajl_t_object) return NULL; - for (i = 0; i < n->data.object.len; i++) { - if (!strcmp(*path, n->data.object.keys[i])) { - n = n->data.object.values[i]; + for (i = 0; i < n->u.object.len; i++) { + if (!strcmp(*path, n->u.object.keys[i])) { + n = n->u.object.values[i]; break; } } - if (i == n->data.object.len) return NULL; + if (i == n->u.object.len) return NULL; path++; } if (n && type != yajl_t_any && type != n->type) n = NULL; @@ -489,12 +476,12 @@ void yajl_tree_free (yajl_val v) if (YAJL_IS_STRING(v)) { - free(v->data.string); + free(v->u.string); free(v); } else if (YAJL_IS_NUMBER(v)) { - free(v->data.number.r); + free(v->u.number.r); free(v); } else if (YAJL_GET_OBJECT(v)) |