diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2015-12-25 09:45:32 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2015-12-25 09:45:32 +0200 |
commit | 8312f45f48ed9d995a15ee6707257f4c8946528d (patch) | |
tree | 1a32dcce9886c46654e7f8f3c3a7cc99413a5d9e /src/json-gram.y | |
parent | ffd39f82123a582b97fdbaf61ebcb932ecc6682e (diff) | |
download | grecs-8312f45f48ed9d995a15ee6707257f4c8946528d.tar.gz grecs-8312f45f48ed9d995a15ee6707257f4c8946528d.tar.bz2 |
Cleanup json code.
* src/json-gram.y (json_new_string)
(json_new_number,json_new_bool,json_new_null)
(json_new_object),json_new_null)
(json_new_object,json_new_array)
(json_object_set,json_object_get)
(json_array_size,json_array_flatten)
(json_array_insert,json_array_append)
(json_array_get): New functions.
* src/json.h (json_array): New member ol.
(json_unescape): Change signature.
Add new prototypes.
* src/json-lex.l: Return allocated string as T_STRING.
(json_unescape): Change signature.
* src/jsonfmt.c: Use new accessors. Don't escape / in strings.
Diffstat (limited to 'src/json-gram.y')
-rw-r--r-- | src/json-gram.y | 219 |
1 files changed, 181 insertions, 38 deletions
diff --git a/src/json-gram.y b/src/json-gram.y index e92ad35..ecfb561 100644 --- a/src/json-gram.y +++ b/src/json-gram.y @@ -21,6 +21,7 @@ #include "grecs.h" #include <grecs-locus.h> #include <string.h> +#include <errno.h> #include "json-gram.h" #include "json.h" @@ -33,7 +34,7 @@ static void pairfree(void *ptr) { struct json_pair *p = ptr; - free(p->k); + grecs_free(p->k); json_value_free(p->v); free(p); } @@ -55,17 +56,15 @@ objfree(void *ptr) %token <b> T_BOOL %token T_NULL T_ERR -%type <a> array %type <list> objects objlist pairs pairlist %type <p> pair -%type <obj> object +%type <obj> object array %type <o> assoc %union { int b; double n; char *s; - struct json_array *a; struct grecs_symtab *o; struct json_value *obj; struct grecs_list *list; @@ -75,7 +74,7 @@ objfree(void *ptr) input : object { - json_return_obj = $1; + json_return_obj = $1; } ; @@ -99,10 +98,6 @@ object : T_NUMBER $$ = json_value_create(json_null); } | array - { - $$ = json_value_create(json_arr); - $$->v.a = $1; - } | assoc { $$ = json_value_create(json_object); @@ -112,21 +107,8 @@ object : T_NUMBER array : '[' objects ']' { - struct json_array *a = grecs_malloc(sizeof(*a)); - if (!$2) { - a->oc = 0; - a->ov = NULL; - } else { - size_t i; - struct grecs_list_entry *ep; - a->oc = $2->count; - a->ov = grecs_calloc(a->oc, sizeof(a->ov)); - for (i = 0, ep = $2->head; ep; i++, ep = ep->next) { - struct json_value *p = ep->data; - a->ov[i] = p; - } - } - $$ = a; + $$ = json_new_array(); + $$->v.a->ol = $2; } ; @@ -140,7 +122,6 @@ objects : /* empty */ objlist : object { $$ = grecs_list_create(); - $$->free_entry = objfree; grecs_list_append($$, $1); } | objlist ',' object @@ -229,12 +210,16 @@ json_value_free(struct json_value *obj) case json_number: break; case json_string: - free(obj->v.s); + grecs_free(obj->v.s); break; case json_arr: for (i = 0; i < obj->v.a->oc; i++) json_value_free(obj->v.a->ov[i]); - free(obj->v.a); + if (obj->v.a->ol) { + obj->v.a->ol->free_entry = objfree; + grecs_list_free(obj->v.a->ol); + } + grecs_free(obj->v.a); break; case json_object: grecs_symtab_free(obj->v.o); @@ -322,7 +307,7 @@ json_value_lookup(struct json_value *obj, const char *ident) q = qbuf; while (*ident) { if (*ident == '\\') { - int c; + char c; ++ident; if (json_unescape(*ident, &c)) *q++ = *ident++; @@ -345,18 +330,12 @@ json_value_lookup(struct json_value *obj, const char *ident) break; case json_arr: l = strtoul(qbuf, &q, 10); - if (*q == 0 && l < obj->v.a->oc) - obj = obj->v.a->ov[l]; - else + if (*q != 0 || json_array_get(obj, l, &obj)) obj = NULL; break; - case json_object: { - struct json_pair key, *match; - key.k = qbuf; - match = grecs_symtab_lookup_or_install(obj->v.o, - &key, NULL); - obj = match ? match->v : NULL; - } + case json_object: + if (json_object_get(obj, qbuf, &obj)) + obj = NULL; } } if (*ident) @@ -364,8 +343,172 @@ json_value_lookup(struct json_value *obj, const char *ident) free(qbuf); return obj; } + +struct json_value * +json_new_string(char const *str) +{ + struct json_value *j = json_value_create(json_string); + j->v.s = grecs_strdup(str); + return j; +} +struct json_value * +json_new_number(double n) +{ + struct json_value *j = json_value_create(json_number); + j->v.n = n; + return j; +} +struct json_value * +json_new_bool(int b) +{ + struct json_value *j = json_value_create(json_bool); + j->v.b = b; + return j; +} +struct json_value * +json_new_null(void) +{ + return json_value_create(json_null); +} + +struct json_value * +json_new_object(void) +{ + struct json_value *j = json_value_create(json_object); + j->v.o = json_assoc_create(); + return j; +} + +int +json_object_set(struct json_value *obj, char const *name, + struct json_value *val) +{ + struct json_pair pair, *ret; + int install; + if (obj->type != json_object) { + errno = EINVAL; + return -1; + } + pair.k = (char*) name; + pair.v = NULL; + ret = grecs_symtab_lookup_or_install(obj->v.o, &pair, &install); + if (install) + ret->k = grecs_strdup(ret->k); + ret->v = val; + return 0; +} + +int +json_object_get(struct json_value *obj, char const *name, + struct json_value **retval) +{ + struct json_pair pair, *ret; + if (obj->type != json_object) { + errno = EINVAL; + return -1; + } + pair.k = (char*) name; + pair.v = NULL; + ret = grecs_symtab_lookup_or_install(obj->v.o, &pair, NULL); + if (ret) { + *retval = ret->v; + return 0; + } + return 1; +} +struct json_value * +json_new_array(void) +{ + struct json_value *j = json_value_create(json_arr); + j->v.a = grecs_malloc(sizeof(*j->v.a)); + j->v.a->oc = 0; + j->v.a->ov = NULL; + j->v.a->ol = NULL; + return j; +} + +size_t +json_array_size(struct json_value *j) +{ + if (j->type != json_arr) { + errno = EINVAL; + return 0; + } + return j->v.a->oc + grecs_list_size(j->v.a->ol); +} + +void +json_array_flatten(struct json_value *j) +{ + size_t size, i; + struct grecs_list_entry *ep; + + size = grecs_list_size(j->v.a->ol); + + if (size == 0) + return; + + j->v.a->ov = grecs_realloc(j->v.a->ov, + (j->v.a->oc + size) * sizeof(j->v.a->ov[0])); + + for (ep = j->v.a->ol->head, i = j->v.a->oc; ep; ep = ep->next, i++) + j->v.a->ov[i] = ep->data; + j->v.a->oc = i; + grecs_list_clear(j->v.a->ol); +} + +int +json_array_insert(struct json_value *j, size_t idx, struct json_value *v) +{ + size_t size; + if (j->type != json_arr) { + errno = EINVAL; + return -1; + } + size = json_array_size(j); + if (idx < size) { + json_array_flatten(j); + j->v.a->ov[idx] = v; + } else { + size_t i; + for (i = size; i < idx; i++) + json_array_append(j, NULL); + json_array_append(j, v); + } + return 0; +} + +int +json_array_append(struct json_value *j, struct json_value *v) +{ + if (j->type != json_arr) { + errno = EINVAL; + return -1; + } + + if (!j->v.a->ol) + j->v.a->ol = grecs_list_create(); + grecs_list_append(j->v.a->ol, v); + return 0; +} +int +json_array_get(struct json_value *j, size_t idx, struct json_value **retval) +{ + if (j->type != json_arr) { + errno = EINVAL; + return -1; + } + if (idx >= json_array_size(j)) { + errno = ENOENT; + return -1; + } + + json_array_flatten(j); + *retval = j->v.a->ov[idx]; + return 0; +} |