diff options
Diffstat (limited to 'com32/gpllib/zzjson')
-rw-r--r-- | com32/gpllib/zzjson/zzjson_create.c | 240 | ||||
-rw-r--r-- | com32/gpllib/zzjson/zzjson_free.c | 29 | ||||
-rw-r--r-- | com32/gpllib/zzjson/zzjson_parse.c | 490 | ||||
-rw-r--r-- | com32/gpllib/zzjson/zzjson_print.c | 110 | ||||
-rw-r--r-- | com32/gpllib/zzjson/zzjson_query.c | 63 |
5 files changed, 932 insertions, 0 deletions
diff --git a/com32/gpllib/zzjson/zzjson_create.c b/com32/gpllib/zzjson/zzjson_create.c new file mode 100644 index 00000000..7e6bd5bd --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_create.c @@ -0,0 +1,240 @@ +/* JSON Create ZZJSON structures + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#ifdef CONFIG_NO_ERROR_MESSAGES +#define ERROR(x...) +#else +#define ERROR(x...) config->error(config->ehandle, ##x) +#endif +#define MEMERROR() ERROR("out of memory") + +static ZZJSON *zzjson_create_templ(ZZJSON_CONFIG *config, ZZJSON_TYPE type) { + ZZJSON *zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) MEMERROR(); + else zzjson->type = type; + return zzjson; +} + +ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config) { + return zzjson_create_templ(config, ZZJSON_TRUE); +} + +ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config) { + return zzjson_create_templ(config, ZZJSON_FALSE); +} + +ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config) { + return zzjson_create_templ(config, ZZJSON_NULL); +} + +ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d) { + ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_DOUBLE); + if (zzjson) + zzjson->value.number.val.dval = d; + return zzjson; +} + +ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i) { + ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_NEGINT); + if (zzjson) { + zzjson->type = i<0LL ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT; + zzjson->value.number.val.ival = llabs(i); + } + return zzjson; +} + +/* sdup mimics strdup, but avoids having another function pointer in config */ +static char *sdup(ZZJSON_CONFIG *config, char *s) { + size_t slen = strlen(s)+1; + char *scopy = config->malloc(slen); + + if (!scopy) MEMERROR(); + else memcpy(scopy, s, slen); + return scopy; +} + +ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s) { + ZZJSON *zzjson = NULL; + char *scopy; + + if (!(scopy = sdup(config,s))) return zzjson; + + if ((zzjson = zzjson_create_templ(config, ZZJSON_STRING))) + zzjson->value.string.string = scopy; + else + config->free(scopy); + + return zzjson; +} + +ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...) { + ZZJSON *zzjson, *retval, *val; + va_list ap; + + if (!(zzjson = zzjson_create_templ(config, ZZJSON_ARRAY))) return zzjson; + retval = zzjson; + + va_start(ap, config); + val = va_arg(ap, ZZJSON *); + while (val) { + zzjson->value.array.val = val; + val = va_arg(ap, ZZJSON *); + + if (val) { + ZZJSON *next = zzjson_create_templ(config, ZZJSON_ARRAY); + if (!next) { + while (retval) { + next = retval->next; + config->free(retval); + retval = next; + } + break; + } + zzjson->next = next; + zzjson = next; + } + } + va_end(ap); + return retval; +} + +ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...) { + ZZJSON *zzjson, *retval, *val; + char *label, *labelcopy; + va_list ap; + + if (!(zzjson = zzjson_create_templ(config, ZZJSON_OBJECT))) return zzjson; + retval = zzjson; + + va_start(ap, config); + label = va_arg(ap, char *); + while (label) { + val = va_arg(ap, ZZJSON *); + labelcopy = sdup(config, label); + + if (!labelcopy) { + zzjson_free(config, retval); + retval = NULL; + break; + } + + zzjson->value.object.label = labelcopy; + zzjson->value.object.val = val; + + label = va_arg(ap, char *); + + if (label) { + ZZJSON *next = zzjson_create_templ(config, ZZJSON_OBJECT); + if (!next) { + while (retval) { + next = retval->next; + config->free(retval->value.object.label); + config->free(retval); + retval = next; + } + break; + } + zzjson->next = next; + zzjson = next; + } + } + va_end(ap); + return retval; +} + +ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array, + ZZJSON *val) { + ZZJSON *zzjson; + + if (!array->value.array.val) { /* empty array */ + array->value.array.val = val; + return array; + } + + zzjson = zzjson_create_templ(config, ZZJSON_ARRAY); + if (zzjson) { + zzjson->value.array.val = val; + zzjson->next = array; + } + return zzjson; +} + +ZZJSON *zzjson_array_append(ZZJSON_CONFIG *config, ZZJSON *array, + ZZJSON *val) { + ZZJSON *retval = array, *zzjson; + + if (!array->value.array.val) { /* empty array */ + array->value.array.val = val; + return array; + } + + zzjson = zzjson_create_templ(config, ZZJSON_ARRAY); + if (!zzjson) return NULL; + + while (array->next) array = array->next; + + zzjson->value.array.val = val; + array->next = zzjson; + + return retval; +} + +ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object, + char *label, ZZJSON *val) { + ZZJSON *zzjson = NULL; + char *labelcopy = sdup(config, label); + + if (!labelcopy) return zzjson; + + if (!object->value.object.label) { /* empty object */ + object->value.object.label = labelcopy; + object->value.object.val = val; + return object; + } + + zzjson = zzjson_create_templ(config, ZZJSON_OBJECT); + if (zzjson) { + zzjson->value.object.label = labelcopy; + zzjson->value.object.val = val; + zzjson->next = object; + } else { + config->free(labelcopy); + } + return zzjson; +} + +ZZJSON *zzjson_object_append(ZZJSON_CONFIG *config, ZZJSON *object, + char *label, ZZJSON *val) { + ZZJSON *retval = object, *zzjson = NULL; + char *labelcopy = sdup(config, label); + + if (!labelcopy) return zzjson; + + if (!object->value.object.label) { /* empty object */ + object->value.object.label = labelcopy; + object->value.object.val = val; + return object; + } + + zzjson = zzjson_create_templ(config, ZZJSON_OBJECT); + if (!zzjson) { + config->free(labelcopy); + return NULL; + } + + while (object->next) object = object->next; + + zzjson->value.object.label = labelcopy; + zzjson->value.object.val = val; + object->next = zzjson; + + return retval; +} + diff --git a/com32/gpllib/zzjson/zzjson_free.c b/com32/gpllib/zzjson/zzjson_free.c new file mode 100644 index 00000000..01dfd242 --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_free.c @@ -0,0 +1,29 @@ +/* JSON free + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" + +void zzjson_free(ZZJSON_CONFIG *config, ZZJSON *zzjson) { + while (zzjson) { + ZZJSON *next; + switch(zzjson->type) { + case ZZJSON_OBJECT: + config->free(zzjson->value.object.label); + zzjson_free(config, zzjson->value.object.val); + break; + case ZZJSON_ARRAY: + zzjson_free(config, zzjson->value.array.val); + break; + case ZZJSON_STRING: + config->free(zzjson->value.string.string); + break; + default: + break; + } + next = zzjson->next; + config->free(zzjson); + zzjson = next; + } +} diff --git a/com32/gpllib/zzjson/zzjson_parse.c b/com32/gpllib/zzjson/zzjson_parse.c new file mode 100644 index 00000000..ecb6f61e --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_parse.c @@ -0,0 +1,490 @@ +/* JSON Parser + * ZZJSON - Copyright (C) 2008-2009 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" +#include <ctype.h> +#include <string.h> +#include <math.h> +#include <stdio.h> + +#define GETC() config->getchar(config->ihandle) +#define UNGETC(c) config->ungetchar(c, config->ihandle) +#define SKIPWS() skipws(config) +#ifdef CONFIG_NO_ERROR_MESSAGES +#define ERROR(x...) +#else +#define ERROR(x...) config->error(config->ehandle, ##x) +#endif +#define MEMERROR() ERROR("out of memory") + +#define ALLOW_EXTRA_COMMA (config->strictness & ZZJSON_ALLOW_EXTRA_COMMA) +#define ALLOW_ILLEGAL_ESCAPE (config->strictness & ZZJSON_ALLOW_ILLEGAL_ESCAPE) +#define ALLOW_CONTROL_CHARS (config->strictness & ZZJSON_ALLOW_CONTROL_CHARS) +#define ALLOW_GARBAGE_AT_END (config->strictness & ZZJSON_ALLOW_GARBAGE_AT_END) +#define ALLOW_COMMENTS (config->strictness & ZZJSON_ALLOW_COMMENTS) + +static ZZJSON *parse_array(ZZJSON_CONFIG *config); +static ZZJSON *parse_object(ZZJSON_CONFIG *config); + +static void skipws(ZZJSON_CONFIG *config) { + int d, c = GETC(); +morews: + while (isspace(c)) c = GETC(); + if (!ALLOW_COMMENTS) goto endws; + if (c != '/') goto endws; + d = GETC(); + if (d != '*') goto endws; /* pushing back c will generate a parse error */ + c = GETC(); +morecomments: + while (c != '*') { + if (c == EOF) goto endws; + c = GETC(); + } + c = GETC(); + if (c != '/') goto morecomments; + c = GETC(); + if (isspace(c) || c == '/') goto morews; +endws: + UNGETC(c); +} + +static char *parse_string(ZZJSON_CONFIG *config) { + unsigned int len = 16, pos = 0; + int c; + char *str = NULL; + + SKIPWS(); + c = GETC(); + if (c != '"') { + ERROR("string: expected \" at the start"); + return NULL; + } + + str = config->malloc(len); + if (!str) { + MEMERROR(); + return NULL; + } + c = GETC(); + while (c > 0 && c != '"') { + if (!ALLOW_CONTROL_CHARS && c >= 0 && c <= 31) { + ERROR("string: control characters not allowed"); + goto errout; + } + if (c == '\\') { + c = GETC(); + switch (c) { + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'u': { + UNGETC(c); /* ignore \uHHHH, copy verbatim */ + c = '\\'; + break; + } + case '\\': case '/': case '"': + break; + default: + if (!ALLOW_ILLEGAL_ESCAPE) { + ERROR("string: illegal escape character"); + goto errout; + } + } + } + str[pos++] = c; + if (pos == len-1) { + void *tmp = str; + len *= 2; + str = config->realloc(str, len); + if (!str) { + MEMERROR(); + str = tmp; + goto errout; + } + } + c = GETC(); + } + if (c != '"') { + ERROR("string: expected \" at the end"); + goto errout; + } + str[pos] = 0; + return str; + +errout: + config->free(str); + return NULL; +} + +static ZZJSON *parse_string2(ZZJSON_CONFIG *config) { + ZZJSON *zzjson = NULL; + char *str; + + str = parse_string(config); + if (str) { + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + config->free(str); + return NULL; + } + zzjson->type = ZZJSON_STRING; + zzjson->value.string.string = str; + } + return zzjson; +} + +static ZZJSON *parse_number(ZZJSON_CONFIG *config) { + ZZJSON *zzjson; + unsigned long long ival = 0, expo = 0; + double dval = 0.0, frac = 0.0, fracshft = 10.0; + int c, dbl = 0, sign = 1, signexpo = 1; + + SKIPWS(); + c = GETC(); + if (c == '-') { + sign = -1; + c = GETC(); + } + if (c == '0') { + c = GETC(); + goto skip; + } + + if (!isdigit(c)) { + ERROR("number: digit expected"); + return NULL; + } + + while (isdigit(c)) { + ival *= 10; + ival += c - '0'; + c = GETC(); + } + +skip: + if (c != '.') goto skipfrac; + + dbl = 1; + + c = GETC(); + if (!isdigit(c)) { + ERROR("number: digit expected"); + return NULL; + } + + while (isdigit(c)) { + frac += (double)(c - '0') / fracshft; + fracshft *= 10.0; + c = GETC(); + } + +skipfrac: + if (c != 'e' && c != 'E') goto skipexpo; + + dbl = 1; + + c = GETC(); + if (c == '+') + c = GETC(); + else if (c == '-') { + signexpo = -1; + c = GETC(); + } + + if (!isdigit(c)) { + ERROR("number: digit expected"); + return NULL; + } + + while (isdigit(c)) { + expo *= 10; + expo += c - '0'; + c = GETC(); + } + +skipexpo: + UNGETC(c); + + if (dbl) { + dval = sign * (long long) ival; + dval += sign * frac; + dval *= pow(10.0, (double) signexpo * expo); + } + + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + return NULL; + } + if (dbl) { + zzjson->type = ZZJSON_NUMBER_DOUBLE; + zzjson->value.number.val.dval = dval; + } else { + zzjson->type = sign < 0 ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT; + zzjson->value.number.val.ival = ival; + } + + return zzjson; +} + +static ZZJSON *parse_literal(ZZJSON_CONFIG *config, char *s, ZZJSON_TYPE t) { + char b[strlen(s)+1]; + unsigned int i; + + for (i=0; i<strlen(s); i++) b[i] = GETC(); + b[i] = 0; + + if (!strcmp(b,s)) { + ZZJSON *zzjson; + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + return NULL; + } + zzjson->type = t; + return zzjson; + } + ERROR("literal: expected %s", s); + return NULL; +} + +static ZZJSON *parse_true(ZZJSON_CONFIG *config) { + return parse_literal(config, (char *)"true", ZZJSON_TRUE); +} + +static ZZJSON *parse_false(ZZJSON_CONFIG *config) { + return parse_literal(config, (char *)"false", ZZJSON_FALSE); +} + +static ZZJSON *parse_null(ZZJSON_CONFIG *config) { + return parse_literal(config, (char *)"null", ZZJSON_NULL); +} + +static ZZJSON *parse_value(ZZJSON_CONFIG *config) { + ZZJSON *retval = NULL; + int c; + + SKIPWS(); + c = GETC(); + UNGETC(c); + switch (c) { + case '"': retval = parse_string2(config); break; + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '-': + retval = parse_number(config); break; + case '{': retval = parse_object(config); break; + case '[': retval = parse_array(config); break; + case 't': retval = parse_true(config); break; + case 'f': retval = parse_false(config); break; + case 'n': retval = parse_null(config); break; + } + + if (!retval) { + ERROR("value: invalid value"); + return retval; + } + + return retval; +} + +static ZZJSON *parse_array(ZZJSON_CONFIG *config) { + ZZJSON *retval = NULL, **next = &retval; + int c; + + SKIPWS(); + c = GETC(); + if (c != '[') { + ERROR("array: expected '['"); + return NULL; + } + + SKIPWS(); + c = GETC(); + while (c > 0 && c != ']') { + ZZJSON *zzjson = NULL, *val = NULL; + + UNGETC(c); + + SKIPWS(); + val = parse_value(config); + if (!val) { + ERROR("array: value expected"); + goto errout; + } + + SKIPWS(); + c = GETC(); + if (c != ',' && c != ']') { + ERROR("array: expected ',' or ']'"); +errout_with_val: + zzjson_free(config, val); + goto errout; + } + if (c == ',') { + SKIPWS(); + c = GETC(); + if (c == ']' && !ALLOW_EXTRA_COMMA) { + ERROR("array: expected value after ','"); + goto errout_with_val; + } + } + UNGETC(c); + + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + zzjson_free(config, val); + goto errout_with_val; + } + zzjson->type = ZZJSON_ARRAY; + zzjson->value.array.val = val; + *next = zzjson; + next = &zzjson->next; + + c = GETC(); + } + + if (c != ']') { + ERROR("array: expected ']'"); + goto errout; + } + + if (!retval) { /* empty array, [ ] */ + retval = config->calloc(1, sizeof(ZZJSON)); + if (!retval) { + MEMERROR(); + return NULL; + } + retval->type = ZZJSON_ARRAY; + } + + return retval; + +errout: + zzjson_free(config, retval); + return NULL; +} + +static ZZJSON *parse_object(ZZJSON_CONFIG *config) { + ZZJSON *retval = NULL; + int c; + ZZJSON **next = &retval; + + SKIPWS(); + c = GETC(); + if (c != '{') { + ERROR("object: expected '{'"); + return NULL; + } + + SKIPWS(); + c = GETC(); + while (c > 0 && c != '}') { + ZZJSON *zzjson = NULL, *val = NULL; + char *str; + + UNGETC(c); + + str = parse_string(config); + if (!str) { + ERROR("object: expected string"); +errout_with_str: + config->free(str); + goto errout; + } + + SKIPWS(); + c = GETC(); + if (c != ':') { + ERROR("object: expected ':'"); + goto errout_with_str; + } + + SKIPWS(); + val = parse_value(config); + if (!val) { + ERROR("object: value expected"); + goto errout_with_str; + } + + SKIPWS(); + c = GETC(); + if (c != ',' && c != '}') { + ERROR("object: expected ',' or '}'"); +errout_with_str_and_val: + zzjson_free(config, val); + goto errout_with_str; + } + if (c == ',') { + SKIPWS(); + c = GETC(); + if (c == '}' && !ALLOW_EXTRA_COMMA) { + ERROR("object: expected pair after ','"); + goto errout_with_str_and_val; + } + } + UNGETC(c); + + zzjson = config->calloc(1, sizeof(ZZJSON)); + if (!zzjson) { + MEMERROR(); + goto errout_with_str_and_val; + } + zzjson->type = ZZJSON_OBJECT; + zzjson->value.object.label = str; + zzjson->value.object.val = val; + *next = zzjson; + next = &zzjson->next; + + c = GETC(); + } + + if (c != '}') { + ERROR("object: expected '}'"); + goto errout; + } + + if (!retval) { /* empty object, { } */ + retval = config->calloc(1, sizeof(ZZJSON)); + if (!retval) { + MEMERROR(); + return NULL; + } + retval->type = ZZJSON_OBJECT; + } + + return retval; + +errout: + zzjson_free(config, retval); + return NULL; +} + +ZZJSON *zzjson_parse(ZZJSON_CONFIG *config) { + ZZJSON *retval; + int c; + + SKIPWS(); + c = GETC(); + UNGETC(c); + if (c == '[') retval = parse_array(config); + else if (c == '{') retval = parse_object(config); + else { ERROR("expected '[' or '{'"); return NULL; } + + if (!retval) return NULL; + + SKIPWS(); + c = GETC(); + if (c >= 0 && !ALLOW_GARBAGE_AT_END) { + ERROR("parse: garbage at end of file"); + zzjson_free(config, retval); + return NULL; + } + + return retval; +} diff --git a/com32/gpllib/zzjson/zzjson_print.c b/com32/gpllib/zzjson/zzjson_print.c new file mode 100644 index 00000000..a59b3b09 --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_print.c @@ -0,0 +1,110 @@ +/* JSON Printer + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" + +#define PRINT(fmt...) if (config->print(config->ohandle, ##fmt) < 0) return -1; +//#define PUTC(c) if (config->putchar(c, config->ohandle) < 0) return -1; +#define PUTC(c) PRINT("%c",c) +#define INC 4 + +static int print_string(ZZJSON_CONFIG *config, char *s) { + int c, bs; + if (!s) return 0; + while ((c = *s++)) { + bs = 1; + switch (c) { +// case '/': // useless escape of forward slash + case '\\': + if (*s == 'u') bs = 0; // copy \uHHHH verbatim + break; + case '"': break; + case '\b': c = 'b'; break; + case '\f': c = 'f'; break; + case '\n': c = 'n'; break; + case '\r': c = 'r'; break; + case '\t': c = 't'; break; + default: bs = 0; break; + } + if (bs) PUTC('\\'); + PUTC(c); + } + return 0; +} + +static int zzjson_print2(ZZJSON_CONFIG *config, ZZJSON *zzjson, + unsigned int indent, unsigned int objval) { + char c = 0, d = 0; + if (!zzjson) return -1; + + switch(zzjson->type) { + case ZZJSON_OBJECT: c = '{'; d = '}'; break; + case ZZJSON_ARRAY: c = '['; d = ']'; break; + default: break; + } + + if (c) PRINT("%s%*s%c", indent ? "\n" : "", indent, "", c); + + while (zzjson) { + switch(zzjson->type) { + case ZZJSON_OBJECT: + if (zzjson->value.object.val) { + PRINT("\n%*s\"", indent+INC, ""); + if (print_string(config, zzjson->value.object.label) < 0) + return -1; + PRINT("\" :"); + if (zzjson_print2(config, zzjson->value.object.val, + indent+INC, 1) < 0) return -1; + } + break; + case ZZJSON_ARRAY: + if (zzjson->value.array.val) + if (zzjson_print2(config, zzjson->value.array.val, + indent+INC, 0) < 0) return -1; + break; + case ZZJSON_STRING: + PRINT(objval ? " \"" : "\n%*s\"", indent, ""); + if (print_string(config, zzjson->value.string.string)<0) return -1; + PUTC('"'); + break; + case ZZJSON_FALSE: + PRINT(objval ? " false" : "\n%*sfalse", indent, ""); + break; + case ZZJSON_NULL: + PRINT(objval ? " null" : "\n%*snull", indent, ""); + break; + case ZZJSON_TRUE: + PRINT(objval ? " true" : "\n%*strue", indent, ""); + break; + case ZZJSON_NUMBER_NEGINT: + case ZZJSON_NUMBER_POSINT: + case ZZJSON_NUMBER_DOUBLE: + PRINT(objval ? " " : "\n%*s", indent, ""); + if (zzjson->type == ZZJSON_NUMBER_DOUBLE) { + PRINT("%16.16e", zzjson->value.number.val.dval); + } else { + if (zzjson->type == ZZJSON_NUMBER_NEGINT) PUTC('-'); + PRINT("%llu", zzjson->value.number.val.ival); + } + default: + break; + } + zzjson = zzjson->next; + if (zzjson) PUTC(','); + } + + if (d) PRINT("\n%*s%c", indent, "", d); + + return 0; +} + +int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson) { + int retval = zzjson_print2(config, zzjson, 0, 0); +// if (retval >= 0) retval = config->putchar('\n', config->ohandle); +#ifndef CONFIG_NO_ERROR_MESSAGES + if (retval < 0) config->error(config->ehandle, "print: unable to print"); +#endif + return retval; +} diff --git a/com32/gpllib/zzjson/zzjson_query.c b/com32/gpllib/zzjson/zzjson_query.c new file mode 100644 index 00000000..35ba7b79 --- /dev/null +++ b/com32/gpllib/zzjson/zzjson_query.c @@ -0,0 +1,63 @@ +/* JSON query + * ZZJSON - Copyright (C) 2008 by Ivo van Poorten + * License: GNU Lesser General Public License version 2.1 + */ + +#include "zzjson.h" +#include <string.h> +#include <stdarg.h> + +ZZJSON *zzjson_object_find_label(ZZJSON *zzjson, char *label) { + if (zzjson->type != ZZJSON_OBJECT) return NULL; + + while (zzjson) { + char *string = zzjson->value.object.label; + + if (zzjson->type != ZZJSON_OBJECT) return NULL; + if (!string) return NULL; + + if (!strcmp(string, label)) + return zzjson->value.object.val; + zzjson = zzjson->next; + } + return NULL; +} + +ZZJSON *zzjson_object_find_labels(ZZJSON *zzjson, ...) { + va_list ap; + char *lbl; + + va_start(ap, zzjson); + lbl = va_arg(ap, char *); + while (lbl) { + zzjson = zzjson_object_find_label(zzjson, lbl); + if (!zzjson) break; + lbl = va_arg(ap, char *); + } + va_end(ap); + + return zzjson; +} + +unsigned int zzjson_object_count(ZZJSON *zzjson) { + unsigned int count = 1; + + if (zzjson->type != ZZJSON_OBJECT) return 0; + if (!zzjson->value.object.label) return 0; /* empty { } */ + + while ((zzjson = zzjson->next)) count++; + + return count; +} + +unsigned int zzjson_array_count(ZZJSON *zzjson) { + unsigned int count = 1; + + if (zzjson->type != ZZJSON_ARRAY) return 0; + if (!zzjson->value.array.val) return 0; /* empty [ ] */ + + while ((zzjson = zzjson->next)) count++; + + return count; +} + |