aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2015-12-25 09:45:32 +0200
committerSergey Poznyakoff <gray@gnu.org>2015-12-25 09:45:32 +0200
commit8312f45f48ed9d995a15ee6707257f4c8946528d (patch)
tree1a32dcce9886c46654e7f8f3c3a7cc99413a5d9e
parentffd39f82123a582b97fdbaf61ebcb932ecc6682e (diff)
downloadgrecs-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.
-rw-r--r--src/json-gram.y219
-rw-r--r--src/json-lex.l62
-rw-r--r--src/json.h22
-rw-r--r--src/jsonfmt.c4
4 files changed, 249 insertions, 58 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;
+}
diff --git a/src/json-lex.l b/src/json-lex.l
index 2a08fd0..376ac95 100644
--- a/src/json-lex.l
+++ b/src/json-lex.l
@@ -128,9 +128,9 @@ utf8_wctomb(char *u)
}
int
-json_unescape(int c, int *o)
+json_unescape(char c, char *o)
{
- static char transtab[] = "\\\\\"\"//b\bf\fn\nr\rt\t";
+ static char transtab[] = "\\\\\"\"b\bf\fn\nr\rt\t";
char *p;
for (p = transtab; *p; p += 2) {
@@ -148,6 +148,32 @@ yywrap()
{
return 1;
}
+
+static struct grecs_txtacc *json_line_acc;
+
+static void
+json_line_begin()
+{
+ if (!json_line_acc)
+ json_line_acc = grecs_txtacc_create();
+}
+
+static char *
+json_line_finish()
+{
+ if (json_line_acc) {
+ char nil = 0;
+ grecs_txtacc_grow(json_line_acc, &nil, 1);
+ return grecs_txtacc_finish(json_line_acc, 1);
+ }
+ return NULL;
+}
+
+static void
+json_line_grow(char const *text, size_t len)
+{
+ grecs_txtacc_grow(json_line_acc, text, len);
+}
%}
D [0-9]
X [0-9a-fA-F]
@@ -157,42 +183,42 @@ X [0-9a-fA-F]
yylval.n = strtod(yytext, NULL);
return T_NUMBER;
}
-\"[^\\\"]*\" { grecs_line_begin();
- grecs_line_add(yytext + 1, yyleng - 2);
- yylval.s = grecs_line_finish();
+\"[^\\\"]*\" { json_line_begin();
+ json_line_grow(yytext + 1, yyleng - 2);
+ yylval.s = json_line_finish();
return T_STRING; }
\"[^\\\"]*\\{X}{4} { BEGIN(STR);
- grecs_line_begin();
- grecs_line_add(yytext + 1, yyleng - 5);
+ json_line_begin();
+ json_line_grow(yytext + 1, yyleng - 5);
utf8_wctomb(yytext + yyleng - 4);
}
-\"[^\\\"]*\\. { int c;
+\"[^\\\"]*\\. { char c;
BEGIN(STR);
- grecs_line_begin();
- grecs_line_acc_grow(yytext + 1, yyleng - 3);
+ json_line_begin();
+ json_line_grow(yytext + 1, yyleng - 3);
if (json_unescape(yytext[yyleng - 1], &c)) {
jsonlex_diag("invalid UTF-8 codepoint");
return T_ERR;
}
- grecs_line_acc_grow_char(c);
+ json_line_grow(&c, 1);
}
<STR>[^\\\"]*\" { BEGIN(INITIAL);
- if (yyleng > 1)
- grecs_line_acc_grow(yytext, yyleng - 1);
- yylval.s = grecs_line_finish();
+ if (yyleng > 1)
+ json_line_grow(yytext, yyleng - 1);
+ yylval.s = json_line_finish();
return T_STRING; }
<STR>[^\\\"]*\\{X}{4} {
- grecs_line_add(yytext, yyleng - 5);
+ json_line_grow(yytext, yyleng - 5);
utf8_wctomb(yytext + yyleng - 4);
}
<STR>[^\\\"]*\\. {
- int c;
- grecs_line_acc_grow(yytext, yyleng - 2);
+ char c;
+ json_line_grow(yytext, yyleng - 2);
if (json_unescape(yytext[yyleng - 1], &c)) {
jsonlex_diag("invalid UTF-8 codepoint");
return T_ERR;
}
- grecs_line_acc_grow_char(c); }
+ json_line_grow(&c, 1); }
null { return T_NULL; }
true { yylval.b = 1; return T_BOOL; }
diff --git a/src/json.h b/src/json.h
index 698d56b..7dffc4b 100644
--- a/src/json.h
+++ b/src/json.h
@@ -30,6 +30,7 @@ struct json_value;
struct json_array {
size_t oc;
struct json_value **ov;
+ struct grecs_list *ol;
};
struct json_value {
@@ -54,7 +55,7 @@ extern struct json_value *json_return_obj;
void jsonlex_setup(char const *s, size_t l);
void jsonlex_diag(const char *s);
-int json_unescape(int c, int *o);
+int json_unescape(char c, char *o);
struct json_value *json_value_create(int type);
struct grecs_symtab *json_assoc_create(void);
@@ -75,4 +76,23 @@ struct json_format
};
void json_format_value(struct json_value *obj, struct json_format *fmt);
+
+struct json_value *json_new_null(void);
+struct json_value *json_new_bool(int b);
+struct json_value *json_new_number(double n);
+struct json_value *json_new_string(char const *str);
+
+struct json_value *json_new_object(void);
+int json_object_set(struct json_value *obj, char const *name,
+ struct json_value *val);
+int json_object_get(struct json_value *obj, char const *name,
+ struct json_value **retval);
+
+struct json_value *json_new_array(void);
+size_t json_array_size(struct json_value *j);
+void json_array_flatten(struct json_value *j);
+int json_array_insert(struct json_value *j, size_t idx, struct json_value *v);
+int json_array_append(struct json_value *j, struct json_value *v);
+int json_array_get(struct json_value *j, size_t idx,
+ struct json_value **retval);
diff --git a/src/jsonfmt.c b/src/jsonfmt.c
index 75c8ac7..0687faf 100644
--- a/src/jsonfmt.c
+++ b/src/jsonfmt.c
@@ -56,7 +56,7 @@ json_format_delim(struct json_format *fmt, size_t level)
static int
escape(char c, char *o)
{
- static char transtab[] = "\\\\\"\"//b\bf\fn\nr\rt\t";
+ static char transtab[] = "\\\\\"\"b\bf\fn\nr\rt\t";
char *p;
for (p = transtab; *p; p += 2) {
@@ -155,6 +155,8 @@ json_format_array(struct json_format *fmt, struct json_value *obj,
{
size_t i;
+ json_array_flatten(obj);
+
json_writec(fmt, '[');
if (obj->v.a->oc) {
if (fmt->indent)

Return to:

Send suggestions and report system problems to the System administrator.