From 22f703cab05b7cd368f4de9e03991b7664dc5022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 13:56:46 +0200 Subject: Initial import of argyll version 1.5.1-8 --- jcnf/Jamfile | 32 + jcnf/Makefile.am | 15 + jcnf/Readme.txt | 22 + jcnf/afiles | 7 + jcnf/jcnf.c | 1248 ++++++++++++ jcnf/jcnf.h | 199 ++ jcnf/test.c | 161 ++ jcnf/test.jcnf | 33 + jcnf/yajl/COPYING | 29 + jcnf/yajl/ChangeLog | 88 + jcnf/yajl/Jamfile | 30 + jcnf/yajl/Makefile.am | 13 + jcnf/yajl/README | 68 + jcnf/yajl/TODO | 9 + jcnf/yajl/YAJL.dxy | 1258 ++++++++++++ jcnf/yajl/YAJLDoc.cmake | 26 + jcnf/yajl/afiles | 84 + jcnf/yajl/cases/array.json | 6 + jcnf/yajl/cases/array.json.gold | 22 + jcnf/yajl/cases/bogus_char.json | 4 + jcnf/yajl/cases/bogus_char.json.gold | 9 + jcnf/yajl/cases/codepoints_from_unicode_org.json | 1 + .../cases/codepoints_from_unicode_org.json.gold | 1 + jcnf/yajl/cases/dc_simple_with_comments.json | 11 + jcnf/yajl/cases/dc_simple_with_comments.json.gold | 4 + jcnf/yajl/cases/deep_arrays.json | 1 + jcnf/yajl/cases/deep_arrays.json.gold | 2048 ++++++++++++++++++++ jcnf/yajl/cases/difficult_json_c_test_case.json | 1 + .../cases/difficult_json_c_test_case.json.gold | 35 + .../difficult_json_c_test_case_with_comments.json | 1 + ...ficult_json_c_test_case_with_comments.json.gold | 35 + jcnf/yajl/cases/doubles.json | 1 + jcnf/yajl/cases/doubles.json.gold | 6 + jcnf/yajl/cases/empty_array.json | 1 + jcnf/yajl/cases/empty_array.json.gold | 2 + jcnf/yajl/cases/escaped_bulgarian.json | 4 + jcnf/yajl/cases/escaped_bulgarian.json.gold | 6 + jcnf/yajl/cases/escaped_foobar.json | 1 + jcnf/yajl/cases/escaped_foobar.json.gold | 1 + jcnf/yajl/cases/integers.json | 3 + jcnf/yajl/cases/integers.json.gold | 13 + jcnf/yajl/cases/invalid_utf8.json | 1 + jcnf/yajl/cases/invalid_utf8.json.gold | 2 + jcnf/yajl/cases/isolated_surrogate_marker.json | 1 + .../yajl/cases/isolated_surrogate_marker.json.gold | 1 + jcnf/yajl/cases/leading_zero_in_number.json | 1 + jcnf/yajl/cases/leading_zero_in_number.json.gold | 4 + jcnf/yajl/cases/lonely_minus_sign.json | 7 + jcnf/yajl/cases/lonely_minus_sign.json.gold | 8 + .../cases/missing_integer_after_decimal_point.json | 1 + .../missing_integer_after_decimal_point.json.gold | 1 + .../yajl/cases/missing_integer_after_exponent.json | 1 + .../cases/missing_integer_after_exponent.json.gold | 1 + jcnf/yajl/cases/non_utf8_char_in_string.json | 1 + jcnf/yajl/cases/non_utf8_char_in_string.json.gold | 7 + jcnf/yajl/cases/nulls_and_bools.json | 5 + jcnf/yajl/cases/nulls_and_bools.json.gold | 8 + jcnf/yajl/cases/simple.json | 5 + jcnf/yajl/cases/simple.json.gold | 8 + jcnf/yajl/cases/simple_with_comments.json | 11 + jcnf/yajl/cases/simple_with_comments.json.gold | 8 + jcnf/yajl/cases/string_invalid_escape.json | 1 + jcnf/yajl/cases/string_invalid_escape.json.gold | 2 + jcnf/yajl/cases/string_invalid_hex_char.json | 1 + jcnf/yajl/cases/string_invalid_hex_char.json.gold | 1 + jcnf/yajl/cases/string_with_escapes.json | 3 + jcnf/yajl/cases/string_with_escapes.json.gold | 6 + jcnf/yajl/cases/string_with_invalid_newline.json | 2 + .../cases/string_with_invalid_newline.json.gold | 1 + jcnf/yajl/cases/unescaped_bulgarian.json | 1 + jcnf/yajl/cases/unescaped_bulgarian.json.gold | 3 + jcnf/yajl/configure | 94 + jcnf/yajl/json_reformat.c | 204 ++ jcnf/yajl/json_verify.c | 129 ++ jcnf/yajl/rfc4627.txt | 3 + jcnf/yajl/run_tests.sh | 61 + jcnf/yajl/yajl.c | 152 ++ jcnf/yajl/yajl_alloc.c | 65 + jcnf/yajl/yajl_alloc.h | 50 + jcnf/yajl/yajl_buf.c | 119 ++ jcnf/yajl/yajl_buf.h | 73 + jcnf/yajl/yajl_bytestack.h | 85 + jcnf/yajl/yajl_common.h | 85 + jcnf/yajl/yajl_encode.c | 179 ++ jcnf/yajl/yajl_encode.h | 44 + jcnf/yajl/yajl_gen.c | 381 ++++ jcnf/yajl/yajl_gen.h | 129 ++ jcnf/yajl/yajl_lex.c | 753 +++++++ jcnf/yajl/yajl_lex.h | 135 ++ jcnf/yajl/yajl_parse.h | 184 ++ jcnf/yajl/yajl_parser.c | 505 +++++ jcnf/yajl/yajl_parser.h | 79 + jcnf/yajl/yajl_test.c | 293 +++ 93 files changed, 9444 insertions(+) create mode 100644 jcnf/Jamfile create mode 100644 jcnf/Makefile.am create mode 100644 jcnf/Readme.txt create mode 100644 jcnf/afiles create mode 100644 jcnf/jcnf.c create mode 100644 jcnf/jcnf.h create mode 100644 jcnf/test.c create mode 100644 jcnf/test.jcnf create mode 100644 jcnf/yajl/COPYING create mode 100644 jcnf/yajl/ChangeLog create mode 100644 jcnf/yajl/Jamfile create mode 100644 jcnf/yajl/Makefile.am create mode 100644 jcnf/yajl/README create mode 100644 jcnf/yajl/TODO create mode 100644 jcnf/yajl/YAJL.dxy create mode 100644 jcnf/yajl/YAJLDoc.cmake create mode 100644 jcnf/yajl/afiles create mode 100644 jcnf/yajl/cases/array.json create mode 100644 jcnf/yajl/cases/array.json.gold create mode 100644 jcnf/yajl/cases/bogus_char.json create mode 100644 jcnf/yajl/cases/bogus_char.json.gold create mode 100644 jcnf/yajl/cases/codepoints_from_unicode_org.json create mode 100644 jcnf/yajl/cases/codepoints_from_unicode_org.json.gold create mode 100644 jcnf/yajl/cases/dc_simple_with_comments.json create mode 100644 jcnf/yajl/cases/dc_simple_with_comments.json.gold create mode 100644 jcnf/yajl/cases/deep_arrays.json create mode 100644 jcnf/yajl/cases/deep_arrays.json.gold create mode 100644 jcnf/yajl/cases/difficult_json_c_test_case.json create mode 100644 jcnf/yajl/cases/difficult_json_c_test_case.json.gold create mode 100644 jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json create mode 100644 jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold create mode 100644 jcnf/yajl/cases/doubles.json create mode 100644 jcnf/yajl/cases/doubles.json.gold create mode 100644 jcnf/yajl/cases/empty_array.json create mode 100644 jcnf/yajl/cases/empty_array.json.gold create mode 100644 jcnf/yajl/cases/escaped_bulgarian.json create mode 100644 jcnf/yajl/cases/escaped_bulgarian.json.gold create mode 100644 jcnf/yajl/cases/escaped_foobar.json create mode 100644 jcnf/yajl/cases/escaped_foobar.json.gold create mode 100644 jcnf/yajl/cases/integers.json create mode 100644 jcnf/yajl/cases/integers.json.gold create mode 100644 jcnf/yajl/cases/invalid_utf8.json create mode 100644 jcnf/yajl/cases/invalid_utf8.json.gold create mode 100644 jcnf/yajl/cases/isolated_surrogate_marker.json create mode 100644 jcnf/yajl/cases/isolated_surrogate_marker.json.gold create mode 100644 jcnf/yajl/cases/leading_zero_in_number.json create mode 100644 jcnf/yajl/cases/leading_zero_in_number.json.gold create mode 100644 jcnf/yajl/cases/lonely_minus_sign.json create mode 100644 jcnf/yajl/cases/lonely_minus_sign.json.gold create mode 100644 jcnf/yajl/cases/missing_integer_after_decimal_point.json create mode 100644 jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold create mode 100644 jcnf/yajl/cases/missing_integer_after_exponent.json create mode 100644 jcnf/yajl/cases/missing_integer_after_exponent.json.gold create mode 100644 jcnf/yajl/cases/non_utf8_char_in_string.json create mode 100644 jcnf/yajl/cases/non_utf8_char_in_string.json.gold create mode 100644 jcnf/yajl/cases/nulls_and_bools.json create mode 100644 jcnf/yajl/cases/nulls_and_bools.json.gold create mode 100644 jcnf/yajl/cases/simple.json create mode 100644 jcnf/yajl/cases/simple.json.gold create mode 100644 jcnf/yajl/cases/simple_with_comments.json create mode 100644 jcnf/yajl/cases/simple_with_comments.json.gold create mode 100644 jcnf/yajl/cases/string_invalid_escape.json create mode 100644 jcnf/yajl/cases/string_invalid_escape.json.gold create mode 100644 jcnf/yajl/cases/string_invalid_hex_char.json create mode 100644 jcnf/yajl/cases/string_invalid_hex_char.json.gold create mode 100644 jcnf/yajl/cases/string_with_escapes.json create mode 100644 jcnf/yajl/cases/string_with_escapes.json.gold create mode 100644 jcnf/yajl/cases/string_with_invalid_newline.json create mode 100644 jcnf/yajl/cases/string_with_invalid_newline.json.gold create mode 100644 jcnf/yajl/cases/unescaped_bulgarian.json create mode 100644 jcnf/yajl/cases/unescaped_bulgarian.json.gold create mode 100644 jcnf/yajl/configure create mode 100644 jcnf/yajl/json_reformat.c create mode 100644 jcnf/yajl/json_verify.c create mode 100644 jcnf/yajl/rfc4627.txt create mode 100644 jcnf/yajl/run_tests.sh create mode 100644 jcnf/yajl/yajl.c create mode 100644 jcnf/yajl/yajl_alloc.c create mode 100644 jcnf/yajl/yajl_alloc.h create mode 100644 jcnf/yajl/yajl_buf.c create mode 100644 jcnf/yajl/yajl_buf.h create mode 100644 jcnf/yajl/yajl_bytestack.h create mode 100644 jcnf/yajl/yajl_common.h create mode 100644 jcnf/yajl/yajl_encode.c create mode 100644 jcnf/yajl/yajl_encode.h create mode 100644 jcnf/yajl/yajl_gen.c create mode 100644 jcnf/yajl/yajl_gen.h create mode 100644 jcnf/yajl/yajl_lex.c create mode 100644 jcnf/yajl/yajl_lex.h create mode 100644 jcnf/yajl/yajl_parse.h create mode 100644 jcnf/yajl/yajl_parser.c create mode 100644 jcnf/yajl/yajl_parser.h create mode 100644 jcnf/yajl/yajl_test.c (limited to 'jcnf') diff --git a/jcnf/Jamfile b/jcnf/Jamfile new file mode 100644 index 0000000..cc9df79 --- /dev/null +++ b/jcnf/Jamfile @@ -0,0 +1,32 @@ + +# JAM style makefile for yajl + +#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on +PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags +#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags +PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags + +SubInclude yajl ; + +#Products +Libraries = libjcnf ; +Executables = ; +Headers = jcnf.h ; + +#Install +#InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ; +#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ; +#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ; + +# config parser based on yajl +Library libjcnf : jcnf.c ; + +# Link all utilities here with libicc +LINKLIBS = libjcnf yajl/libyajl ../numlib/libnum ; + +# All utils are made from a single source file +MainsFromSources test.c ; + + + + diff --git a/jcnf/Makefile.am b/jcnf/Makefile.am new file mode 100644 index 0000000..1914fce --- /dev/null +++ b/jcnf/Makefile.am @@ -0,0 +1,15 @@ +include $(top_srcdir)/Makefile.shared + +SUBDIRS = $(YAJL_SUBDIRS) + +privatelib_LTLIBRARIES = libjcnf.la +privatelibdir = $(pkglibdir) + +libjcnf_la_SOURCES = jcnf.h jcnf.c +libjcnf_la_LIBADD = $(YAJL_LIBS) + +LDADD = ./libjcnf.la $(YAJL_LIBS) + +check_PROGRAMS = test + +EXTRA_DIST = Readme.txt diff --git a/jcnf/Readme.txt b/jcnf/Readme.txt new file mode 100644 index 0000000..295c026 --- /dev/null +++ b/jcnf/Readme.txt @@ -0,0 +1,22 @@ + +This is a library supporting system and application configuration stored in +a flat file format based on the JSON format. + +JSON (JavaScript Object Notation) is a lightweight data-interchange format. +It is easy for humans to read and write. It is easy for machines to parse +and generate. It is based on a subset of the JavaScript Programming Language, +Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is +completely language independent but uses conventions that are familiar to +programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, +Perl, Python, and many others. These properties make JSON an ideal data-interchange +language. + +The jcnf library is designed to be used stand alone by applications, +or as a template for a back end to Elektra, as an alternative to other +simple flat file formats such as .ini + +It makes use of Lloyd Hilaiel's YAJL to do the generation +and parsing of the JSON configuration files. + +- Graeme Gill. + diff --git a/jcnf/afiles b/jcnf/afiles new file mode 100644 index 0000000..39508fa --- /dev/null +++ b/jcnf/afiles @@ -0,0 +1,7 @@ +Jamfile +Readme.txt +afiles +jcnf.c +jcnf.h +test.c +test.jcnf diff --git a/jcnf/jcnf.c b/jcnf/jcnf.c new file mode 100644 index 0000000..c2fd4cc --- /dev/null +++ b/jcnf/jcnf.c @@ -0,0 +1,1248 @@ + +/* + * JSON based configuration format class. + */ + +/************************************************************************* + Copyright 2008 Graeme W. Gill + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + *************************************************************************/ + +#define LOCK_RETRIES 5 + +/* We convert JSON arrays to numerical sub paths on reading, */ +/* but they get converted back to maps on writing. */ +/* Paths are grouped under common paths on writing, */ +/* but aren't sorted. */ + +#include +#include +#include +#ifndef NT +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "yajl/yajl_common.h" +#include "yajl/yajl_gen.h" +#include "yajl/yajl_parse.h" + +#include "jcnf.h" + +#define BUF_SIZE 2048 + +/* - - - - - - - - - - - - - - - - */ +/* Utilities */ + +/* Construct a string that represents the current key path */ +/* Return NULL on error (malloc fail) */ +/* Free the returned string when done */ +static char *cur_keypath(jcnf *p) { + char *ckey = NULL; + int i, len; + + if (p->nrecd <= 0) { + return strdup(""); + } + for (len = i = 0; i < p->nrecd; i++) { + if (p->recds[i].aix > -2) { + len += 3 + (int)log10((double)p->recds[p->nrecd-1].aix); + } else { + len += strlen(p->recds[i].key) + 1; + } + } + + if ((ckey = malloc(len)) == NULL) + return NULL; + + for (len = i = 0; i < p->nrecd; i++) { + int sl; + + if (p->recds[i].aix > -2) { + char num[13]; + sprintf(num, "%d",p->recds[i].aix); + sl = strlen(num); + memmove(ckey + len, num, sl); + } else { + sl = strlen(p->recds[i].key); + memmove(ckey + len, p->recds[i].key, sl); + } + len += sl; + + if ((i+1) >= p->nrecd) + ckey[len] = '\000'; + else + ckey[len] = '/'; + len++; + } + return ckey; +} + +/* Diagnostic - Print the value of a key */ +static jc_error jcnf_print_key(jcnf *p, int ix, FILE *fp) { + jc_key *kp; + + if (ix < 0 || ix >= p->nkeys) + return jc_ix_oorange; + + kp = p->keys[ix]; + + fprintf(fp,"Key '%s' has value",kp->key); + + switch(kp->type) { + case jc_null: { + fprintf(fp," null"); + break; + } + case jc_boolean: { + fprintf(fp," %s",*((int *)kp->data) ? "true" : "false"); + break; + } + case jc_real: { + fprintf(fp," %lf",*((double *)kp->data)); + break; + } + case jc_integer: { + fprintf(fp," %ld",*((long *)kp->data)); + break; + } + case jc_string: { + fprintf(fp," '%s'",kp->data); + break; + } + default: { + fprintf(fp," unknown type %d",kp->type); + break; + } + } + if (kp->c_comment != NULL) { + fprintf(fp," C comment = '%s'",kp->c_comment); + } + if (kp->cpp_comment != NULL) { + fprintf(fp," C++ comment = '%s'",kp->cpp_comment); + } + fprintf(fp,"\n"); + return jc_ok; +} + +/* - - - - - - - - - - - - - - - - */ +/* Free keys contents */ +static void free_key_contents(jc_key *p) { + if (p->key != NULL) { + free(p->key); + p->key = NULL; + } + if (p->c_comment != NULL) { + free(p->c_comment); + p->c_comment = NULL; + } + if (p->cpp_comment != NULL) { + free(p->cpp_comment); + p->cpp_comment = NULL; + } + if (p->data != NULL) { + free(p->data); + p->data = NULL; + } + p->type = -1; +} + +/* Free key and its contents */ +static void free_key(jc_key *p) { + free_key_contents(p); + free(p); +} + +/* Set a keyvalues (internal) */ +/* All parameters are copied */ +/* return NZ on error */ +static jc_error jcnf_set_key_internal( + jcnf *p, + jc_key *kp, /* Pointer to key */ + char *key, /* Key path name */ + jc_type type, + void *data, + size_t dataSize, /* Data size (including string nul) */ + char *comment /* C++ style comment */ +) { + free_key_contents(kp); + + if ((kp->key = strdup(key)) == NULL) + return jc_malloc; + kp->type = type; + + if (type != jc_null) { + if (type == jc_string && ((char *)data)[dataSize-1] != '\000') + return jc_string_not_terminated; + if ((kp->data = malloc(dataSize)) == NULL) + return jc_malloc; + kp->dataSize = dataSize; + memmove(kp->data, data, dataSize); + } + + if (comment != NULL) { + if ((kp->cpp_comment = strdup(comment)) == NULL) + return jc_malloc; + } + return jc_ok; +} + +/* Add a key value to the jcnf (internal) */ +/* All parameters are copied */ +/* return NZ on error */ +static jc_error jcnf_add_key_internal( + jcnf *p, + char *key, /* Key path name */ + jc_type type, + void *data, + size_t dataSize, /* Data size (including string nul) */ + char *comment +) { + jc_error ev; + jc_key *kp; + + if (key == NULL || (type != jc_null && (data == NULL || dataSize == 0))) + return jc_bad_addkey_params; + + if (p->nkeys >= p->akeys) { /* Need more pointer space */ + p->akeys = p->akeys ? 2 * p->akeys : 10; + if ((p->keys = realloc(p->keys, p->akeys * sizeof(jc_key*))) == NULL) { + return jc_malloc; + } + } + if ((kp = p->keys[p->nkeys] = calloc(1, sizeof(jc_key))) == NULL) { + return jc_malloc; + } + p->nkeys++; + + if ((ev = jcnf_set_key_internal(p, kp, key, type, data, dataSize, comment)) != jc_ok) + return ev; + p->lk = kp; + return jc_ok; +} + +/* Locate the index of the next key matching the key name, starting */ +/* at the given index. Update the index to the matching key. */ +/* Look for an exact match if exact != 0, or leading match if exact = 0 */ +/* Search backwards if bwd != 0 or forwards if bwd = 0 */ +/* Set *ix = -1 to begin search from the start/end for fwd/bwd. */ +/* Return jc_ix_oorange if no more match. */ +static jc_error jcnf_locate_key( + jcnf *p, + int *pix, + char *key, + int exact, + int bwd +) { + int ix = *pix; + int sl; + + if (ix == -1) { + if (bwd) + ix = p->nkeys-1; + else + ix = 0; + } + + if (ix < 0 || ix >= p->nkeys) + return jc_ix_oorange; + + if (key == NULL) + return jc_no_keyname; + + sl = strlen(key); + + /* We're doing a simple linear search */ + for (; ix >= 0 && ix < p->nkeys; ix += bwd ? -1 : 1) { + if (exact) { + if (strcmp(key, p->keys[ix]->key) == 0) + break; + } else { + if (strncmp(key, p->keys[ix]->key, sl) == 0) + break; + } + } + + if (ix < 0 || ix >= p->nkeys) + return jc_ix_oorange; + + *pix = ix; + return jc_ok; +} + +/* Retrieve a keys information. Return pointers may be NULL. */ +/* If ix >= 0, return the key of the given index. */ +/* If ix == -1, return the first from the beginning exactly matching key name. */ +/* jc_ix_oorange is returned when past end. */ +/* (Do not modify anything returned) */ +static jc_error jcnf_get_key( + jcnf *p, + int ix, + char **key, + jc_type *type, + unsigned char **data, + size_t *dataSize, /* Data size (including string nul) */ + char **comment +) { + jc_error ev; + + if (ix == -1) { + if (key == NULL || *key == NULL) + return jc_no_keyname; + if ((ev = jcnf_locate_key(p, &ix, *key, 1, 0)) != jc_ok) + return ev; + } else if (ix < 0 || ix >= p->nkeys) + return jc_ix_oorange; + + if (key != NULL) + *key = p->keys[ix]->key; + if (type != NULL) + *type = p->keys[ix]->type; + if (data != NULL) + *data = p->keys[ix]->data; + if (dataSize != NULL) + *dataSize = p->keys[ix]->dataSize; + if (comment != NULL) + *comment = p->keys[ix]->cpp_comment; + + return jc_ok; +} + +/* Set a keys information. */ +/* If ix >= 0, set the key of the given index. */ +/* jc_ix_oorange is returned when past end. */ +/* If ix == -1, overwrite an existing key with the same name, */ +/* or add a new key with that name at the end if there is no existing key. */ +static jc_error jcnf_set_key( + jcnf *p, + int ix, + char *key, + jc_type type, + unsigned char *data, + size_t dataSize, /* Data size (including string nul) */ + char *comment +) { + jc_error ev; + + if (ix == -1) { + if (key == NULL) + return jc_no_keyname; + if ((ev = jcnf_locate_key(p, &ix, key, 1, 0)) != jc_ok) { + if (ev != jc_ix_oorange) + return ev; + if (p->modify == 0) + return jc_update_nomod; + p->modified = 1; + return jcnf_add_key_internal(p, key, type, data, dataSize, comment); + } + } else if (ix < 0 || ix >= p->nkeys) + return jc_ix_oorange; + + if (p->modify == 0) + return jc_update_nomod; + p->modified = 1; + return jcnf_set_key_internal(p, p->keys[ix], key, type, data, dataSize, comment); +} + +/* Add a key value to the jcnf at the end, irrespective of whether there is */ +/* an existing key with that name. */ +static jc_error jcnf_add_key( + jcnf *p, + char *key, + jc_type type, + unsigned char *data, + size_t dataSize, /* Data size (including string nul) */ + char *comment +) { + jc_error ev; + if (p->modify == 0) + return jc_update_nomod; + if ((ev = jcnf_add_key_internal(p,key,type,data,dataSize,comment)) == jc_ok) { + p->modified = 1; + } + return ev; +} + +/* Delete a key. */ +/* If ix >= 0, delete the key of the given index. */ +/* jc_ix_oorange is returned when past end. */ +/* If ix == -1, delete the key with the given name. */ +static jc_error jcnf_delete_key( + jcnf *p, + int ix, + char *key +) { + jc_error ev; + + if (ix == -1) { + if (key == NULL) + return jc_no_keyname; + if ((ev = jcnf_locate_key(p, &ix, key, 1, 0)) != jc_ok) + return ev; + } else if (ix < 0 || ix >= p->nkeys) + return jc_ix_oorange; + + if (p->modify == 0) + return jc_update_nomod; + free_key_contents(p->keys[ix]); + + if ((ix+1) < p->nkeys) { + memmove(p->keys+ix, p->keys+ix+1,sizeof(jc_key *) * p->nkeys-ix-1); + } + p->nkeys--; + p->modified = 1; + + return jc_ok; +} + +/* - - - - - - - - - - - - - - - - */ +/* yajl parser callbacks */ + +static int jcnf_yajl_null(void *ctx) { + jcnf *p = (jcnf *)ctx; + char *t1; + +// printf("null\n"); + + /* If current level is an array, bump the index */ + if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2) + p->recds[p->nrecd-1].aix++; + if ((t1 = cur_keypath(p)) == NULL) + return 0; + + if (jcnf_add_key_internal(p, t1, jc_null, NULL, 0, NULL) != jc_ok) { + free(t1); + return 0; + } + free(t1); + + return 1; +} + +static int jcnf_yajl_boolean(void * ctx, int boolVal) { + jcnf *p = (jcnf *)ctx; + char *t1; + +// printf("bool: %s\n", boolVal ? "true" : "false"); + + /* If current level is an array, bump the index */ + if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2) + p->recds[p->nrecd-1].aix++; + if ((t1 = cur_keypath(p)) == NULL) + return 0; + + if (jcnf_add_key_internal(p, t1, jc_boolean, (void *)&boolVal, sizeof(int), NULL) != jc_ok) { + free(t1); + return 0; + } + free(t1); + + return 1; +} + +static int jcnf_yajl_integer(void *ctx, long integerVal) { + jcnf *p = (jcnf *)ctx; + char *t1; + +// printf("integer: %lld\n", integerVal); + + /* If current level is an array, bump the index */ + if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2) + p->recds[p->nrecd-1].aix++; + if ((t1 = cur_keypath(p)) == NULL) + return 0; + + if (jcnf_add_key_internal(p, t1, jc_integer, (void *)&integerVal, sizeof(long), NULL) != jc_ok) { + free(t1); + return 0; + } + free(t1); + + return 1; +} + +static int jcnf_yajl_double(void *ctx, double doubleVal) { + jcnf *p = (jcnf *)ctx; + char *t1; + +// printf("double: %lf\n", doubleVal); + + /* If current level is an array, bump the index */ + if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2) + p->recds[p->nrecd-1].aix++; + if ((t1 = cur_keypath(p)) == NULL) + return 0; + + if (jcnf_add_key_internal(p, t1, jc_real, (void *)&doubleVal, sizeof(double), NULL) != jc_ok) { + free(t1); + return 0; + } + free(t1); + + return 1; +} + +static int jcnf_yajl_string(void *ctx, const unsigned char *stringVal, + unsigned int stringLen) { + jcnf *p = (jcnf *)ctx; + char *t1, *t2; + +// printf("string: '"); +// fwrite(stringVal, 1, stringLen, stdout); +// printf("'\n"); + + /* If current level is an array, bump the index */ + if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2) + p->recds[p->nrecd-1].aix++; + if ((t1 = cur_keypath(p)) == NULL) + return 0; + + if ((t2 = malloc(stringLen + 1)) == NULL) /* Room to add implicit nul */ + return 0; + memmove(t2, stringVal, stringLen); + t2[stringLen] = 0; + + if (jcnf_add_key_internal(p, t1, jc_string, (void *)t2, stringLen+1, NULL) != jc_ok) { + free(t2); + free(t1); + return 0; + } + free(t2); + free(t1); + + return 1; +} + +static int jcnf_yajl_c_comment(void *ctx, const unsigned char * stringVal, + unsigned int stringLen) { + jcnf *p = (jcnf *)ctx; + +// printf("c_comment: '"); +// fwrite(stringVal, 1, stringLen, stdout); +// printf("'\n"); + + if (p->lk != NULL && p->lk->c_comment == NULL) { + char *t1; + if ((t1 = malloc(stringLen + 1)) == NULL) + return 0; + memmove(t1, stringVal, stringLen); + t1[stringLen] = 0; + + p->lk->c_comment = t1; + } + + return 1; +} + +static int jcnf_yajl_cpp_comment(void *ctx, const unsigned char * stringVal, + unsigned int stringLen) { + jcnf *p = (jcnf *)ctx; + +// printf("cpp_comment: '"); +// fwrite(stringVal, 1, stringLen, stdout); +// printf("'\n"); + + if (p->lk != NULL && p->lk->cpp_comment == NULL) { + char *t1; + if ((t1 = malloc(stringLen + 1)) == NULL) + return 0; + memmove(t1, stringVal, stringLen); + t1[stringLen] = 0; + + p->lk->cpp_comment = t1; + } + + return 1; +} + +static int jcnf_yajl_start_map(void *ctx) { + jcnf *p = (jcnf *)ctx; + + /* Start another recursion level */ + if (p->nrecd >= p->arecd) { + p->arecd *= 2; + if ((p->recds = (jc_recd *)realloc(p->recds, p->arecd * sizeof(jc_recd))) == NULL) { + /* realloc failed */ + return 0; + } + } + + /* If current level is an array, bump the index */ + if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2) + p->recds[p->nrecd-1].aix++; + + /* Move to new level */ + p->recds[p->nrecd].key = NULL; + p->recds[p->nrecd].aix = -2; + p->nrecd++; + +#ifdef NEVER + printf("map open '{'\n"); +#endif + + return 1; +} + +static int jcnf_yajl_map_key(void *ctx, const unsigned char * stringVal, + unsigned int stringLen) { + jcnf *p = (jcnf *)ctx; + int i; + + if (stringLen == 0) { + /* Zero length key */ + return 0; + } + + if (p->recds[p->nrecd-1].key != NULL) { + free(p->recds[p->nrecd-1].key); + p->recds[p->nrecd-1].key = NULL; + p->recds[p->nrecd-1].aix = -2; + } + if ((p->recds[p->nrecd-1].key = malloc(stringLen + 1)) == NULL) + return 0; + + p->recds[p->nrecd-1].key[stringLen] = 0; + memmove(p->recds[p->nrecd-1].key, stringVal, stringLen); + +#ifdef NEVER + { + char *tt; + + printf("Added path = '%s'\n", p->recds[p->nrecd-1].key); + if ((tt = cur_keypath(p)) != NULL) { + printf("Current path = '%s'\n",tt); + free(tt); + } + } +#endif + + return 1; +} + +static int jcnf_yajl_end_map(void *ctx) { + jcnf *p = (jcnf *)ctx; + + if (p->nrecd == 0) { + /* End of map without start of map */ + return 0; + } + p->nrecd--; + +#ifdef NEVER + { + char *tt; + printf("map close '}'\n"); + if ((tt = cur_keypath(p)) != NULL) + printf("Current path = '%s'\n",tt); + free(tt); + } +#endif + + return 1; +} + +static int jcnf_yajl_start_array(void *ctx) { + jcnf *p = (jcnf *)ctx; + +#ifdef NEVER + printf("array open '['\n"); +#endif + + /* Start another recursion level */ + if (p->nrecd >= p->arecd) { + p->arecd *= 2; + if ((p->recds = (jc_recd *)realloc(p->recds, p->arecd * sizeof(jc_recd))) == NULL) { + /* realloc failed */ + return 0; + } + } + + /* If current level is an array, bump the index */ + if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2) + p->recds[p->nrecd-1].aix++; + + /* Move to new level */ + p->recds[p->nrecd].key = NULL; + p->recds[p->nrecd].aix = -1; + p->nrecd++; + + return 1; +} + +static int jcnf_yajl_end_array(void *ctx) { + jcnf *p = (jcnf *)ctx; + +#ifdef NEVER + printf("array close ']'\n"); +#endif + if (p->nrecd == 0) { + /* End of map without start of map */ + return 0; + } + p->nrecd--; + + return 1; +} + +static yajl_callbacks callbacks = { + jcnf_yajl_null, + jcnf_yajl_boolean, + jcnf_yajl_integer, + jcnf_yajl_double, + NULL, /* number */ + jcnf_yajl_string, + jcnf_yajl_c_comment, + jcnf_yajl_cpp_comment, + jcnf_yajl_start_map, + jcnf_yajl_map_key, + jcnf_yajl_end_map, + jcnf_yajl_start_array, + jcnf_yajl_end_array +}; + +/* - - - - - - - - - - - - - - - - */ +/* Lock the open fp */ +static jc_error jcnf_lock_file(jcnf *p) { +#ifndef NT + int i, fh; + int lop; + + fh = fileno(p->fp); + + if (p->modify) { + lop = LOCK_EX | LOCK_NB; + } else { + lop = LOCK_SH | LOCK_NB; + } + + for (i = 0; i < LOCK_RETRIES; i++) { + if (flock(fh, lop) == 0) + break; + sleep(1); + } + if (i >= LOCK_RETRIES) + return jc_locked; +#endif + p->locked = 1; + + return jc_ok; +} + +/* Read a file into the object. */ +/* (Doesn't do locking) */ +/* Return NZ on error */ +static jc_error jcnf_read( + jcnf *p +) { + jc_error ev; + yajl_handle hand; + yajl_parser_config cfg = { 0, 1 }; /* Validate UTF8 strings ? */ + unsigned char buf[BUF_SIZE]; + struct stat sbuf; + + cfg.allowComments = 1; + + if ((p->fp = fopen(p->fname, p->modify ? "r+" : "r")) == NULL) { + if (!p->modify) + return jc_noexisting; + + if ((p->fp = fopen(p->fname, "w")) == NULL) + return jc_write_open; + if ((ev = jcnf_lock_file(p)) != jc_ok) + return ev; + return jc_ok; + } + + if ((ev = jcnf_lock_file(p)) != jc_ok) + return ev; + + hand = yajl_alloc(&callbacks, &cfg, NULL, (void *)p); + + /* Parse the file */ + for(;;) { + size_t rd; + + rd = fread(buf, 1, BUF_SIZE, p->fp); + + if (rd == 0) { + if (!feof(p->fp)) { + fprintf(stderr, "error reading from '%s'\n", p->fname); + return jc_read_fail; + } + break; + } else { + yajl_status stat; + + /* read file data, pass to parser */ + stat = yajl_parse(hand, buf, rd); + if (stat != yajl_status_insufficient_data && + stat != yajl_status_ok) + { + unsigned char * str = yajl_get_error(hand, 1, buf, rd); + fflush(stdout); + fprintf(stderr, "%s", (char *) str); + yajl_free_error(hand, str); + return jc_parse_fail; + } + } + } + + /* Record some things about the file so that we can */ + /* recognized if it's been modified */ + if (stat(p->fname, &sbuf) != 0) { + return jc_stat; + } + p->rsize = sbuf.st_size; + p->rtime = time(NULL); + + yajl_free(hand); + + /* We're not modifying it, so close it */ + if (!p->modify) { + fclose(p->fp); + p->fp = NULL; + p->locked = 0; + } + + return jc_ok; +} + +/* Write an object into a file */ +/* Unlock it & close it afterwards. */ +/* Return NZ on error */ +static jc_error jcnf_write( + jcnf *p +) { + FILE *fp; /* For temporary file */ + char *tname = NULL; + yajl_gen_config conf = { 1, " " }; + yajl_gen g; + yajl_status stat; + const unsigned char * buf; + unsigned int len; + int clevel = 0; /* Current level */ + char *pkey = ""; /* Previous key */ + char *ckey; /* Current key */ + int i; + + if (!p->locked && p->fp != NULL) { + return jc_update_nomod; + } + +#ifndef NT + { + int fh; + + if ((tname = malloc(strlen(p->fname) + 8)) == NULL) + return jc_malloc; + + /* Create temporary file, open it and lock it LOCK_EX */ + strcpy(tname, p->fname); + strcat(tname,"-XXXXXX"); + if ((fh = mkstemp(tname)) == -1) { + free(tname); + return jc_write_open; + } + if (fchmod(fh, 0644) != 0) { + free(tname); + return jc_write_open; + } + if ((fp = fdopen(fh, "w")) == NULL) { + free(tname); + return jc_write_open; + } + } +#else + /* Open a temporary file in the same directory to write to */ + if ((tname = malloc(strlen(p->fname) + 8)) == NULL) + return jc_malloc; + + if (tmpnam(tname) == NULL) { + free(tname); + return jc_write_open; + } + if ((fp = fopen(tname, "w")) == NULL) { + free(tname); + return jc_write_open; + } +#endif + + g = yajl_gen_alloc(&conf, NULL); + + /* Generate the file */ + for (i = 0; i < p->nkeys; i++, pkey = ckey) { + char *pc, *cc, *dc; + int nplev; /* Number of previous different levels */ + int ndlev; /* Number of new different levels */ + int same; + + ckey = p->keys[i]->key; + + /* See how many keys are not in common */ + nplev = ndlev = 0; + same = 1; + for(pc = pkey, dc = cc = ckey; *pc != '\000' || *cc != '\000';) { + +//printf("~1 pc = '%c', cc = '%c', same = %d\n",*pc,*cc,same); + if (same == 0 || *pc != *cc) { + same = 0; + if (*cc == '/') { + ndlev++; +//printf("~1 ndlev now %d\n",ndlev); + } + if (*pc == '/') { + nplev++; +//printf("~1 ndlev now %d\n",ndlev); + } + + } else { + if (*cc == '/') { + dc = cc+1; + } + } + if (*pc != '\000') { + pc++; + if (same == 0 && *pc == '\000') { + nplev++; +//printf("~1 nplev now %d\n",nplev); + } + } + if (*cc != '\000') { + cc++; + if (same == 0 && *cc == '\000') { + ndlev++; +//printf("~1 ndlev now %d\n",ndlev); + } + } + } +//printf("~1 Prev = '%s'\n",pkey); +//printf("~1 Curr = '%s'\n",ckey); +//printf("~1 New = '%s'\n",dc); +//printf("~1 Old different = %d, new different = %d\n\n",nplev,ndlev); + + while(nplev > 0) { + if (nplev > 1) + yajl_gen_map_close(g); + nplev--; + clevel--; + } + while(ndlev > 0) { + yajl_gen_map_open(g); + for (cc = dc; *cc != '\000' && *cc != '/'; cc++) + ; + yajl_gen_string(g, dc, cc-dc); + if (*cc != '\000') + dc = cc + 1; + ndlev--; + clevel++; + } + + switch(p->keys[i]->type) { +//printf("~1 key %d = type %d\n",i,p->keys[i]->type); + case jc_null: + yajl_gen_null(g); + break; + + case jc_boolean: + yajl_gen_bool(g, *((int *)p->keys[i]->data)); + break; + + case jc_real: + yajl_gen_double(g, *((double *)p->keys[i]->data)); + break; + + case jc_integer: + yajl_gen_integer(g, *((long *)p->keys[i]->data)); + break; + + case jc_string: + yajl_gen_string(g, (char *)p->keys[i]->data, p->keys[i]->dataSize-1); + break; + + default: { + free(tname); + return jc_unknown_key_type; + } + } + + if (p->keys[i]->cpp_comment != NULL) { + yajl_gen_cpp_comment(g, p->keys[i]->cpp_comment, strlen(p->keys[i]->cpp_comment)); + } + if (p->keys[i]->c_comment != NULL) { + yajl_gen_c_comment(g, p->keys[i]->c_comment, strlen(p->keys[i]->c_comment), 1); + } + +#ifdef NEVER + yajl_gen_map_open(g); + yajl_gen_string(g, "test", strlen("test")); + yajl_gen_string(g, "test value", strlen("test value")); + yajl_gen_c_comment(g, " A comment ", strlen(" A comment ")); + yajl_gen_map_close(g); +#endif + + /* Do some writing */ + yajl_gen_get_buf(g, &buf, &len); + if (len >= BUF_SIZE) { + if (fwrite(buf, 1, len, fp) != len) + return jc_write_fail; + yajl_gen_clear(g); + } + } + + while(clevel > 0) { + yajl_gen_map_close(g); + clevel--; + } + + yajl_gen_get_buf(g, &buf, &len); + if (len > 0) { + if (fwrite(buf, 1, len, fp) != len) + return jc_write_fail; + yajl_gen_clear(g); + } + yajl_gen_free(g); + if (fflush(fp) != 0) { + free(tname); + return jc_write_close; + } + +#ifdef NT + /* MSWindows rename won't replace existing or open files. */ + /* Lucky this is just for testing, as this leaves a window */ + if (fp != NULL) { + fclose(fp); + fp = NULL; + } + if (p->fp != NULL) { + fclose(p->fp); + p->fp = NULL; + } + unlink(p->fname); +#endif + +//printf("~1 about to rename '%s' to '%s'\n",tname,p->fname); + /* Now atomicaly rename the file to replace the file we read */ + if (rename(tname, p->fname) != 0) { + free(tname); + return jc_write_close; + } + +//printf("~1 closing files\n"); + /* Close our files and release the locks */ + if (fp != NULL && fclose(fp) != 0) { + free(tname); + return jc_write_close; + } + if (p->fp != NULL && fclose(p->fp) != 0) { + free(tname); + return jc_write_close; + } + p->fp = NULL; + p->locked = 0; + p->modify = 0; + + free(tname); + return jc_ok; +} + +/* Switch from read only to update of the config. */ +static jc_error jcnf_enable_modify(jcnf *p) { + jc_error ev; + struct stat sbuf; + + if (p->modify) + return jc_ok; /* Nothing to do */ + + /* We need to re-open the file and lock it for modification */ + if ((p->fp = fopen(p->fname, "r+")) == NULL) { + return jc_changed; + } + p->modify = 1; + + if ((ev = jcnf_lock_file(p)) != jc_ok) { + p->modify = 0; + fclose(p->fp); + p->fp = NULL; + return ev; + } + + /* Check that it hasn't been modified since it was first read */ + if (stat(p->fname, &sbuf) != 0) { + p->modify = 0; + fclose(p->fp); + p->fp = NULL; + return jc_stat; + } + + if (sbuf.st_size != p->rsize + || sbuf.st_mtime > p->rtime) { + p->modify = 0; + fclose(p->fp); + p->fp = NULL; + return jc_changed; + } + + return jc_ok; +} + + +/* Update the file that was opened for modification, and unlock it. */ +static jc_error jcnf_update(jcnf *p) { + jc_error ev; + struct stat sbuf; + + if (p->modified) { + if (p->modify == 0 || p->locked == 0) { + + return jc_update_nomod; /* File wasn't opened for modification */ + } + if ((ev = jcnf_write(p)) != jc_ok) { + return ev; + } + p->modified = 0; + } + p->modify = 0; + + return jc_ok; +} + +/* free the object */ +static void jcnf_del(jcnf *p) { + + if (p->fp) + fclose(p->fp); + + if (p->keys != NULL) { + int i; + for (i = 0; i < p->nkeys; i++) { + free_key(p->keys[i]); + } + free(p->keys); + } + + if (p->recds != NULL) { + int i; + for (i = 0; i < p->nrecd; i++) { + free(p->recds[i].key); + } + free(p->recds); + } + + if (p->fname) + free(p->fname); + + free(p); +} + +/* Create a new jconf. */ +/* Return NULL on error */ +jcnf *new_jcnf( + jc_error *pev, /* return error code on error */ + char *fname, /* Corresponding filename */ + jc_mod modify, /* Flag, nz to open for modification */ + jc_crte create /* Flag, nz to create if it doesn't exist (modify must be set) */ +) { + jcnf *p; + jc_error ev; + + if ((p = (jcnf *) calloc(1, sizeof(jcnf))) == NULL) { + if (pev != NULL) *pev = jc_malloc; + return NULL; + } + + p->arecd = 10; + if ((p->recds = (jc_recd *) calloc(p->arecd, sizeof(jc_recd))) == NULL) { + if (pev != NULL) *pev = jc_malloc; + p->del(p); + return NULL; + } + + if ((p->fname = strdup(fname)) == NULL) { + if (pev != NULL) *pev = jc_malloc; + p->del(p); + return NULL; + } + + p->modify = modify == jc_modify ? 1 : 0; + p->create = create == jc_create ? 1 : 0; + + p->locate_key = jcnf_locate_key; + p->get_key = jcnf_get_key; + p->set_key = jcnf_set_key; + p->add_key = jcnf_add_key; + p->delete_key = jcnf_delete_key; + p->print_key = jcnf_print_key; + + p->enable_modify = jcnf_enable_modify; + p->update = jcnf_update; + p->del = jcnf_del; + + if ((ev = jcnf_read(p)) != jc_ok) { + if (ev != jc_noexisting) { + if (pev != NULL) *pev = ev; + p->del(p); + return NULL; + } + } + + if (pev != NULL) *pev = jc_ok; + + return p; +} + +/* ------------------------------- */ +/* Return a pointer to the nth element of the key name. */ +/* Return null if it is out of range or malloc failed. */ +/* Free the returned value when done. */ +char *jc_get_nth_elem(char *path, int n) { + int i; + char *p1, *p2, *rv; + + if (path == NULL) + return NULL; + + p1 = path; + if (*p1 == '/') + p1++; + + for (i = 0; *p1 != '\000'; p1 = p2 + 1, i++) { + if ((p2 = strchr(p1, '/')) == NULL) + p2 = p1 + strlen(p1); + if (i >= n) { + if ((rv = malloc(p2 - p1 + 1)) == NULL) + return NULL; + strncpy(rv, p1, p2 - p1); + rv[p2-p1] = '\000'; + return rv; + } + if (*p2 == '\000') + break; + } + return NULL; +} + + diff --git a/jcnf/jcnf.h b/jcnf/jcnf.h new file mode 100644 index 0000000..d861d3d --- /dev/null +++ b/jcnf/jcnf.h @@ -0,0 +1,199 @@ + +#ifndef JCONF_H +#define JCONF_H + +/* + * JSON based configuration format class. + */ + +/************************************************************************* + Copyright 2008 Graeme W. Gill + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + *************************************************************************/ + + +/* General description: + + Key names are UNIX style '/' separated paths, stored + in UTF8 format. The paths should not start with a '/'. + + Duplicate key names are supported, but typically + will be avoided by the library user. + + Five types are supported, NULL, 32 bit boolean, 64 bit real, + 64 bit integer and string. Strings are always nul terminated. + + */ + +/* jcnf error codes */ +typedef enum { + jc_ok = 0, /* No error */ + jc_malloc, /* malloc, calloc or realloc failed */ + jc_lock_error, /* Error opening lock file */ + jc_locked, /* File is locked by someone else */ + jc_unlock, /* Unlock failed */ + jc_noexisting, /* No existing file to read */ + jc_stat, /* Unable to stat file */ + jc_changed, /* File has changed since it was read */ + jc_read_fail, /* Failure to read from the file */ + jc_parse_fail, /* Failure to parse from the file */ + jc_write_open, /* Failed to open file for writing */ + jc_write_fail, /* Failed to write to file */ + jc_write_close, /* Failed to close file after writing */ + jc_update_nomod, /* Attempt to update file that wasn't opened for modifications */ + jc_bad_addkey_params, /* Bad add_key() parameters */ + jc_unknown_key_type, /* An unrecognisd key type was encountered */ + jc_ix_oorange, /* Key index is out of range */ + jc_no_keyname, /* No key name provided when it is expected */ + jc_string_not_terminated /* String doesn't include nul */ +} jc_error; + +/* Argument types */ +typedef enum { + jc_read = 0, /* Just read the config file */ + jc_modify = 1 /* Read the config file in preparation to write it */ +} jc_mod; + +typedef enum { + jc_no_create = 0, /* Don't create the config if it doesn't exist */ + jc_create = 1 /* Create the config if it doesn't exist */ +} jc_crte; + +/* Internal jcnf structure */ + +/* The different type of values supported */ +typedef enum { + jc_null = 0, /* Null value */ + jc_boolean = 1, /* Boolean */ + jc_real = 2, /* double floating point */ + jc_integer = 3, /* 64 bit integer */ + jc_string = 4 /* UTF8 string, nul terminated */ +} jc_type; + +/* A value */ +struct _jc_key { + char *key; /* Key path */ + jc_type type; /* Type of value */ + char *c_comment; /* C Comment */ + char *cpp_comment; /* C++ Comment */ + unsigned char *data; /* Pointer to data */ + size_t dataSize; /* Size of data */ +}; typedef struct _jc_key jc_key; + +/* A recursion depth record used during parsing */ +struct _jc_recd { + char *key; /* Key name, or */ + int aix; /* Array index, -2 = no array */ +}; typedef struct _jc_recd jc_recd; + +/* jcnf Object, representing the keys in a jcnf file */ +struct _jcnf { + jc_key **keys; /* Array of pointers to keys */ + int nkeys; /* Number of valid key pointers */ + int akeys; /* Number of allocated key poiters */ + jc_key *lk; /* Last key created */ + + /* Parsing support, key recursion depth */ + jc_recd *recds; + int nrecd; /* Number of ised recd */ + int arecd; /* Allocate rec depth */ + + /* Config & status */ + char *fname; /* filename */ + FILE *fp; /* opened, locked file */ + off_t rsize; /* Size of file when read */ + time_t rtime; /* Time the file was read */ + int modify; /* Opened for modifications */ + int create; /* Create if it doesn't exist */ + int locked; /* nz if file is locked */ + int modified; /* nz if keys have been modified */ + + /* Locate the index of the next key matching the key name, starting */ + /* at the given index. Update the index to the matching key. */ + /* Look for an exact match if exact != 0, or leading match if exact = 0 */ + /* Search backwards if bwd != 0 or forwards if bwd = 0 */ + /* Set *ix = -1 to begin search from the end. */ + /* Return jc_ix_oorange if no more matchs. */ + jc_error (*locate_key)(struct _jcnf *p, int *ix, char *key, int exact, int bwd); + + /* Retrieve a keys information. Return pointers may be NULL. */ + /* If ix >= 0, return the key of the given index. */ + /* jc_ix_oorange is returned when past end. */ + /* If ix == -1, return the first from the beginning matching key name. */ + /* (Returned data is internal to jcnf object, so call must copy it). */ + jc_error (*get_key)(struct _jcnf *p, int ix, char **key, jc_type *type, unsigned char **data, + size_t *dataSize, char **comment); + + /* Set a keys information. */ + /* If ix >= 0, set the key of the given index. */ + /* jc_ix_oorange is returned when past end. */ + /* If ix == -1, overwrite an existing key with the same name, */ + /* or add a new key with that name at the end if there is no existing key. */ + jc_error (*set_key)(struct _jcnf *p, int ix, char *key, jc_type type, unsigned char *data, + size_t dataSize, char *comment); + + /* Add a key value to the jcnf at the end, irrespective of whether there is */ + /* an existing key with that name. */ + jc_error (*add_key)(struct _jcnf *p, char *key, jc_type type, unsigned char *data, + size_t dataSize, char *comment); + + /* Delete a key. */ + /* If ix >= 0, delete the key of the given index. */ + /* jc_ix_oorange is returned when past end. */ + /* If ix == -1, delete the key with the given name. */ + jc_error (*delete_key)(struct _jcnf *p, int ix, char *key); + + /* Diagnostic - Print the value of a key */ + jc_error (*print_key)(struct _jcnf *p, int ix, FILE *fp); + + /* Switch from read only to update of the config file. */ + /* (This re-opens the file and checks that it hasn't been */ + /* modified since it was read) */ + jc_error (*enable_modify)(struct _jcnf *p); + + /* Save and changes out to the file, unlock it and and close it. */ + /* It can't be udated again after this. */ + jc_error (*update)(struct _jcnf *p); + + /* Delete this object */ + void (*del)(struct _jcnf *p); + +}; typedef struct _jcnf jcnf; + +/* Create a new jcnf and read it's keys from the file. */ +/* Return NULL on error */ +jcnf *new_jcnf( + jc_error *pev, /* return error code on error */ + char *fname, /* Corresponding filename */ + jc_mod modify, /* Flag, nz to open for modification */ + jc_crte create /* Flag, nz to create if it doesn't exist (modify must be set) */ +); + +/* Utilities */ + +/* Return a pointer to the nth element of the key name. */ +/* Return null if it is out of range or malloc failed. */ +/* Free the returned value when done. */ +char *jc_get_nth_elem(char *path, int n); + +#endif /* JCNF_H */ + + diff --git a/jcnf/test.c b/jcnf/test.c new file mode 100644 index 0000000..ddf4f5b --- /dev/null +++ b/jcnf/test.c @@ -0,0 +1,161 @@ + + +/* Test out the jcnf object */ + +/* Reads the file test.jcnf, and copies it to testo.jcnf */ + +/************************************************************************* + Copyright 2008 Graeme W. Gill + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + *************************************************************************/ + + +#include +#include +#include +#include +#include + +#include "jcnf.h" + +#undef TEST_PATH_PARSING +#define TEST_ENABLE_MODIFY + +void error(char *fmt, ...); + +int +main(int argc, char *argv[]) { + int fa,nfa; /* argument we're looking at */ + + jcnf *jci, *jco; + jc_error ev; + int ix; + + printf("Hi there\n"); + +#ifdef TEST_PATH_PARSING + { + char *str; + int i, j; + + for (i = 0; i < 4; i++) { + if (i == 0) + str = "this/is/a/test"; + else if (i == 1) + str = "/this/is/another//test/"; + else if (i == 2) + str = "/"; + else + str = ""; + + printf("String = '%s'\n",str); + for (j = 0; j < 10; j++) { + char *s; + + s = jc_get_nth_elem(str, j); + if (s == NULL) + break; + printf("%d th element = '%s'\n",j,s); + free(s); + } + } + return 0; + } +#endif /* TEST_PATH_PARSING */ + + if ((jci = new_jcnf(&ev, "test.jcnf",jc_read,jc_no_create)) == NULL) { + error("new_jcnf '%s' failed with error %d\n","test.jcnf",ev); + } + +#ifdef TEST_ENABLE_MODIFY + if ((jco = new_jcnf(&ev, "testo.jcnf",jc_read,jc_no_create)) == NULL) { + jci->del(jci); + error("new_jcnf '%s' failed with error %d\n","testo.jcnf",ev); + } + printf("Read output file, hit return to continue\n"); + getchar(); + if ((ev = jco->enable_modify(jco)) != jc_ok) { + jci->del(jci); + error("enable_modify '%s' failed with error %d\n","testo.jcnf",ev); + } +#else + if ((jco = new_jcnf(&ev, "testo.jcnf",jc_modify,jc_create)) == NULL) { + jci->del(jci); + error("new_jcnf '%s' failed with error %d\n","testo.jcnf",ev); + } +#endif + + /* Delete everything from the second file */ + for (ix = jco->nkeys-1; ix >= 0; ix--) { + if ((ev = jco->delete_key(jco, ix, NULL)) != jc_ok) { + jco->del(jco); + jci->del(jci); + error("deleting keys from '%s' failed with error %d\n","testo.jcnf",ev); + } + } + + for (ix = 0; ; ix++) { + char *key; + jc_type type; + unsigned char *data; + size_t dataSize; + char *comment; + + if ((ev = jci->get_key(jci, ix, &key, &type, &data, &dataSize, &comment)) != jc_ok) { + if (ev != jc_ix_oorange) { + jco->del(jco); + jci->del(jci); + error("get_key failed with %d\n",ev); + } + break; + } + jci->print_key(jci,ix, stderr); + if ((ev = jci->add_key(jco, key, type, data, dataSize, comment)) != jc_ok) { + jco->del(jco); + jci->del(jci); + error("add_key failed with %d\n",ev); + } + } + if ((ev = jco->update(jco)) != 0) { + jco->del(jco); + jci->del(jci); + error("jcnf write failed with error %d\n",ev); + } + + jci->del(jci); + jco->del(jco); + + printf("We're done\n"); + return 0; +} + +void +error(char *fmt, ...) +{ + va_list args; + + fprintf(stderr,"test: Error - "); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + exit (-1); +} diff --git a/jcnf/test.jcnf b/jcnf/test.jcnf new file mode 100644 index 0000000..d37b286 --- /dev/null +++ b/jcnf/test.jcnf @@ -0,0 +1,33 @@ + +{ "store": { /* First comment */ + "book": [ + { "category": "reference", /* Another comment */ + "author": "Nigel Rees", /* A third comment */ + "title": "Sayings of the Century", + "price": 8.95 + }, + { "category": "fiction", + "author": "Evelyn Waugh", + "title": "Sword of Honour", + "price": 12.99 + }, + { "category": "fiction", + "author": "Herman Melville", + "title": "Moby Dick", + "isbn": "0-553-21311-3", + "price": 8.99 + }, + { "category": "fiction", + "author": "J. R. R. Tolkien", + "title": "The Lord of the Rings", + "isbn": "0-395-19395-8", + "price": 22.99 + } + ], + "bicycle": { + "color": "red", + "price": 19.95, + "price" : { "test1" : "test1 value", "test2" : "test2 value" } + } + } +} diff --git a/jcnf/yajl/COPYING b/jcnf/yajl/COPYING new file mode 100644 index 0000000..fac48ba --- /dev/null +++ b/jcnf/yajl/COPYING @@ -0,0 +1,29 @@ +Copyright 2007-2009, Lloyd Hilaiel. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. Neither the name of Lloyd Hilaiel nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/jcnf/yajl/ChangeLog b/jcnf/yajl/ChangeLog new file mode 100644 index 0000000..9acb334 --- /dev/null +++ b/jcnf/yajl/ChangeLog @@ -0,0 +1,88 @@ +1.0.5 mod ArgyllCMS + + Flattened source code layout + Removed cmake files, and added Jamfile + Added support for reading and writing comments + + (Graeme Gill) + +1.0.5 + * lth several performance improvements related to function + inlinin' + +1.0.4 + * lth fix broken utf8 validation for three & four byte represenations. + thanks to http://github.com/brianmario and + http://github.com/technoweenie + +1.0.3 + * lth fix syntax error in cplusplus extern "C" statements for wider + compiler support + +1.0.2 + * lth update doxygen documentation with new sample code, passing NULL + for allocation functions added in 1.0.0 + +1.0.1 + * lth resolve crash in json_reformatter due to incorrectly ordered + parameters. + +1.0.0 + * lth add 'make install' rules, thaks to Andrei Soroker for the + contribution. + * lth client may override allocation routines at generator or parser + allocation time + * tjw add yajl_parse_complete routine to allow client to explicitly + specify end-of-input, solving the "lonely number" case, where + json text consists only of an element with no explicit syntactic + end. + * tjw many new test cases + * tjw cleanup of code for symmetry and ease of reading + * lth integration of patches from Robert Varga which cleanup + compilation warnings on 64 bit linux + +0.4.0 + * lth buffer overflow bug in yajl_gen_double s/%lf/%g/ - thanks to + Eric Bergstrome + * lth yajl_number callback to allow passthrough of arbitrary precision + numbers to client. Thanks to Hatem Nassrat. + * lth yajl_integer now deals in long, instead of long long. This + combined with yajl_number improves compiler compatibility while + maintaining precision. + * lth better ./configure && make experience (still requires cmake and + ruby) + * lth fix handling of special characters hex 0F and 1F in yajl_encode + (thanks to Robert Geiger) + * lth allow leading zeros in exponents (thanks to Hatem Nassrat) + +0.3.0 + * lth doxygen documentation (html & man) generated as part of the + build + * lth many documentation updates. + * lth fix to work with older versions of cmake (don't use LOOSE_LOOP + constructs) + * lth work around different behavior of freebsd 4 scanf. initialize + parameter to scanf to zero. + * lth all tests run 32x with ranging buffer sizes to stress stream + parsing + * lth yajl_test accepts -b option to allow read buffer size to be + set + * lth option to validate UTF8 added to parser (argument in + yajl_parser_cfg) + * lth fix buffer overrun when chunk ends inside \u escaped text + * lth support client cancelation + +0.2.2 + * lth on windows build debug with C7 symbols and no pdb files. + +0.2.1 + * fix yajl_reformat and yajl_verify to work on arbitrarily sized + inputs. + * fix win32 build break, clean up all errors and warnings. + * fix optimized build flags. + +0.2.0 + * optionally support comments in input text + +0.1.0 + * Initial release diff --git a/jcnf/yajl/Jamfile b/jcnf/yajl/Jamfile new file mode 100644 index 0000000..122253f --- /dev/null +++ b/jcnf/yajl/Jamfile @@ -0,0 +1,30 @@ + +# JAM style makefile for yajl + +#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on +PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags +#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags +PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags + +#Products +Libraries = libyajl ; +Executables = ; +Headers = yajl_common.h yajl_gen.h yajl_parse.h ; # API headers + +#Install +#InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ; +#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ; +#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ; + +# config parser based on yajl +Library libyajl : yajl.c yajl_alloc.c yajl_buf.c yajl_encode.c yajl_gen.c yajl_lex.c yajl_parser.c ; + +# Link all utilities here with libicc +LINKLIBS = libyajl ; + +# All utils are made from a single source file +MainsFromSources yajl_test.c json_verify.c ; + + + + diff --git a/jcnf/yajl/Makefile.am b/jcnf/yajl/Makefile.am new file mode 100644 index 0000000..5f477a9 --- /dev/null +++ b/jcnf/yajl/Makefile.am @@ -0,0 +1,13 @@ +include $(top_srcdir)/Makefile.shared + +privatelib_LTLIBRARIES = libyajl.la +privatelibdir = $(pkglibdir) + +libyajl_la_SOURCES = yajl_common.h yajl_gen.h yajl_parse.h yajl.c \ + yajl_alloc.c yajl_alloc.h yajl_buf.c yajl_buf.h yajl_encode.c \ + yajl_encode.h yajl_gen.c yajl_lex.c yajl_lex.h yajl_parser.c \ + yajl_parser.h + +LDADD = ./libyajl.la + +check_PROGRAMS = yajl_test json_verify diff --git a/jcnf/yajl/README b/jcnf/yajl/README new file mode 100644 index 0000000..93b3a1a --- /dev/null +++ b/jcnf/yajl/README @@ -0,0 +1,68 @@ +Welcome to Yet Another JSON Library (YAJL) + +## Why does the world need another C library for parsing JSON? + +Good question. In a review of current C JSON parsing libraries I was +unable to find one that satisfies my requirements. Those are, +0. written in C +1. portable +2. robust -- as close to "crash proof" as possible +3. data representation independent +4. fast +5. generates verbose, useful error messages including context of where + the error occurs in the input text. +6. can parse JSON data off a stream, incrementally +7. simple to use +8. tiny + +Numbers 3, 5, 6, and 7 where particularly hard to find, and were what +caused me to ultimately create YAJL. This document is a tour of some +of the more important aspects of YAJL. + +## YAJL is Free. + +BSD licensing means you can use it in open source and commercial products +alike. My request beyond the licensing is that if you find bugs drop +me a email, or better yet, fork me on git and fix it! + +Porting YAJL should be trivial, the implementation is ANSI C. If you +port to new systems I'd love to hear of it and integrate your patches. + +## YAJL is data representation independent. + +BYODR! Many JSON libraries impose a structure based data representation +on you. This is a benefit in some cases and a drawback in others. +YAJL uses callbacks to remain agnostic of the in-memory representation. +So if you wish to build up an in-memory representation, you may do so +using YAJL, but you must bring the code that defines and populates the +in memory structure. + +This also means that YAJL can be used by other (higher level) JSON +libraries if so desired. + +## YAJL supports stream parsing + +This means you do not need to hold the whole JSON representation in +textual form in memory. This makes YAJL ideal for filtering projects, +where you're converting YAJL from one form to another (i.e. XML). The +included JSON pretty printer is an example of such a filter program. + +## YAJL is fast + +Minimal memory copying is performed. YAJL, when possible, returns +pointers into the client provided text (i.e. for strings that have no +embedded escape chars, hopefully the common case). I've put a lot of +effort into profiling and tuning performance, but I have ignored a +couple possible performance improvements to keep the interface clean, +small, and flexible. My hope is that YAJL will perform comparably to +the fastest JSON parser out there. + +YAJL should impose both minimal CPU and memory requirements on your +application. + +## YAJL is tiny. + +Fat free. No whip. + +enjoy, +Lloyd - July, 2007 diff --git a/jcnf/yajl/TODO b/jcnf/yajl/TODO new file mode 100644 index 0000000..56c3dc0 --- /dev/null +++ b/jcnf/yajl/TODO @@ -0,0 +1,9 @@ +* add a test for 0x1F bug +* numeric overflow in integers and double +* line and char offsets in the lexer and in error messages +* testing: + a. the permuter + b. some performance comparison against json_checker. +* investigate pull instead of push parsing +* Handle memory allocation failures gracefully +* cygwin/msys support on win32 diff --git a/jcnf/yajl/YAJL.dxy b/jcnf/yajl/YAJL.dxy new file mode 100644 index 0000000..680eb43 --- /dev/null +++ b/jcnf/yajl/YAJL.dxy @@ -0,0 +1,1258 @@ +# Doxyfile 1.5.2 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file that +# follow. The default is UTF-8 which is also the encoding used for all text before +# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into +# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of +# possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = YAJL + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @YAJL_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = yajl-@YAJL_VERSION@/share + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, +# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, +# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, +# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = YES + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to +# include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = NO + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from the +# version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning + +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../src/yajl ../src/api + +# This tag can be used to specify the character encoding of the source files that +# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default +# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. +# See http://www.gnu.org/software/libiconv for the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the output. +# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, +# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentstion. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = doc/yajl-@YAJL_VERSION@ + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to +# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to +# specify the directory where the mscgen tool resides. If left empty the tool is assumed to +# be found in the default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a caller dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen will always +# show the root nodes and its direct children regardless of this setting. + +DOT_GRAPH_MAX_NODES = 50 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, which results in a white background. +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/jcnf/yajl/YAJLDoc.cmake b/jcnf/yajl/YAJLDoc.cmake new file mode 100644 index 0000000..049cdef --- /dev/null +++ b/jcnf/yajl/YAJLDoc.cmake @@ -0,0 +1,26 @@ +FIND_PROGRAM(doxygenPath doxygen) + +IF (doxygenPath) + SET (YAJL_VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO}) + SET(yajlDirName yajl-${YAJL_VERSION}) + SET(docPath + "${CMAKE_CURRENT_BINARY_DIR}/${yajlDirName}/share/doc/${yajlDirName}") + MESSAGE("** using doxygen at: ${doxygenPath}") + MESSAGE("** documentation output to: ${docPath}") + + CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/src/YAJL.dxy + ${CMAKE_CURRENT_BINARY_DIR}/YAJL.dxy @ONLY) + + FILE(MAKE_DIRECTORY "${docPath}") + + ADD_CUSTOM_TARGET(doc + ${doxygenPath} YAJL.dxy + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + +ELSE (doxygenPath) + MESSAGE("!! doxygen not found, not generating documentation") + ADD_CUSTOM_TARGET( + doc + echo doxygen not installed, not generating documentation + ) +ENDIF (doxygenPath) diff --git a/jcnf/yajl/afiles b/jcnf/yajl/afiles new file mode 100644 index 0000000..23cf626 --- /dev/null +++ b/jcnf/yajl/afiles @@ -0,0 +1,84 @@ +afiles +COPYING +ChangeLog +Jamfile +README +TODO +YAJL.dxy +YAJLDoc.cmake +configure +json_reformat.c +json_verify.c +rfc4627.txt +run_tests.sh +yajl.c +yajl_alloc.c +yajl_alloc.h +yajl_buf.c +yajl_buf.h +yajl_bytestack.h +yajl_common.h +yajl_encode.c +yajl_encode.h +yajl_gen.c +yajl_gen.h +yajl_lex.c +yajl_lex.h +yajl_parse.h +yajl_parser.c +yajl_parser.h +yajl_test.c +cases/array.json +cases/array.json.gold +cases/bogus_char.json +cases/bogus_char.json.gold +cases/codepoints_from_unicode_org.json +cases/codepoints_from_unicode_org.json.gold +cases/dc_simple_with_comments.json +cases/dc_simple_with_comments.json.gold +cases/deep_arrays.json +cases/deep_arrays.json.gold +cases/difficult_json_c_test_case.json +cases/difficult_json_c_test_case.json.gold +cases/difficult_json_c_test_case_with_comments.json +cases/difficult_json_c_test_case_with_comments.json.gold +cases/doubles.json +cases/doubles.json.gold +cases/empty_array.json +cases/empty_array.json.gold +cases/escaped_bulgarian.json +cases/escaped_bulgarian.json.gold +cases/escaped_foobar.json +cases/escaped_foobar.json.gold +cases/integers.json +cases/integers.json.gold +cases/invalid_utf8.json +cases/invalid_utf8.json.gold +cases/isolated_surrogate_marker.json +cases/isolated_surrogate_marker.json.gold +cases/leading_zero_in_number.json +cases/leading_zero_in_number.json.gold +cases/lonely_minus_sign.json +cases/lonely_minus_sign.json.gold +cases/missing_integer_after_decimal_point.json +cases/missing_integer_after_decimal_point.json.gold +cases/missing_integer_after_exponent.json +cases/missing_integer_after_exponent.json.gold +cases/non_utf8_char_in_string.json +cases/non_utf8_char_in_string.json.gold +cases/nulls_and_bools.json +cases/nulls_and_bools.json.gold +cases/simple.json +cases/simple.json.gold +cases/simple_with_comments.json +cases/simple_with_comments.json.gold +cases/string_invalid_escape.json +cases/string_invalid_escape.json.gold +cases/string_invalid_hex_char.json +cases/string_invalid_hex_char.json.gold +cases/string_with_escapes.json +cases/string_with_escapes.json.gold +cases/string_with_invalid_newline.json +cases/string_with_invalid_newline.json.gold +cases/unescaped_bulgarian.json +cases/unescaped_bulgarian.json.gold diff --git a/jcnf/yajl/cases/array.json b/jcnf/yajl/cases/array.json new file mode 100644 index 0000000..f76058d --- /dev/null +++ b/jcnf/yajl/cases/array.json @@ -0,0 +1,6 @@ +["foo", + "bar", "baz", + true,false,null,{"key":"value"}, + [null,null,null,[]], + "\n\r\\" +] diff --git a/jcnf/yajl/cases/array.json.gold b/jcnf/yajl/cases/array.json.gold new file mode 100644 index 0000000..d77e716 --- /dev/null +++ b/jcnf/yajl/cases/array.json.gold @@ -0,0 +1,22 @@ +array open '[' +string: 'foo' +string: 'bar' +string: 'baz' +bool: true +bool: false +null +map open '{' +key: 'key' +string: 'value' +map close '}' +array open '[' +null +null +null +array open '[' +array close ']' +array close ']' +string: ' + +\' +array close ']' diff --git a/jcnf/yajl/cases/bogus_char.json b/jcnf/yajl/cases/bogus_char.json new file mode 100644 index 0000000..8163bd8 --- /dev/null +++ b/jcnf/yajl/cases/bogus_char.json @@ -0,0 +1,4 @@ +["this","is","what","should","be", + "a happy bit of json", + "but someone, misspelled \"true\"", ture, + "who says JSON is easy for humans to generate?"] diff --git a/jcnf/yajl/cases/bogus_char.json.gold b/jcnf/yajl/cases/bogus_char.json.gold new file mode 100644 index 0000000..ccbeed5 --- /dev/null +++ b/jcnf/yajl/cases/bogus_char.json.gold @@ -0,0 +1,9 @@ +array open '[' +string: 'this' +string: 'is' +string: 'what' +string: 'should' +string: 'be' +string: 'a happy bit of json' +string: 'but someone, misspelled "true"' +lexical error: invalid string in json text. diff --git a/jcnf/yajl/cases/codepoints_from_unicode_org.json b/jcnf/yajl/cases/codepoints_from_unicode_org.json new file mode 100644 index 0000000..f91f3be --- /dev/null +++ b/jcnf/yajl/cases/codepoints_from_unicode_org.json @@ -0,0 +1 @@ +"\u004d\u0430\u4e8c\ud800\udf02" diff --git a/jcnf/yajl/cases/codepoints_from_unicode_org.json.gold b/jcnf/yajl/cases/codepoints_from_unicode_org.json.gold new file mode 100644 index 0000000..12b358a --- /dev/null +++ b/jcnf/yajl/cases/codepoints_from_unicode_org.json.gold @@ -0,0 +1 @@ +string: 'Mа二ðŒ‚' diff --git a/jcnf/yajl/cases/dc_simple_with_comments.json b/jcnf/yajl/cases/dc_simple_with_comments.json new file mode 100644 index 0000000..3b79bba --- /dev/null +++ b/jcnf/yajl/cases/dc_simple_with_comments.json @@ -0,0 +1,11 @@ +{ + "this": "is", // ignore this + "really": "simple", + /* ignore +this +too * / +** // +(/ +******/ + "json": "right?" +} diff --git a/jcnf/yajl/cases/dc_simple_with_comments.json.gold b/jcnf/yajl/cases/dc_simple_with_comments.json.gold new file mode 100644 index 0000000..92be7a5 --- /dev/null +++ b/jcnf/yajl/cases/dc_simple_with_comments.json.gold @@ -0,0 +1,4 @@ +map open '{' +key: 'this' +string: 'is' +lexical error: probable comment found in input text, comments are not enabled. diff --git a/jcnf/yajl/cases/deep_arrays.json b/jcnf/yajl/cases/deep_arrays.json new file mode 100644 index 0000000..82d1b0d --- /dev/null +++ b/jcnf/yajl/cases/deep_arrays.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/jcnf/yajl/cases/deep_arrays.json.gold b/jcnf/yajl/cases/deep_arrays.json.gold new file mode 100644 index 0000000..e549637 --- /dev/null +++ b/jcnf/yajl/cases/deep_arrays.json.gold @@ -0,0 +1,2048 @@ +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array open '[' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' +array close ']' diff --git a/jcnf/yajl/cases/difficult_json_c_test_case.json b/jcnf/yajl/cases/difficult_json_c_test_case.json new file mode 100644 index 0000000..6998f55 --- /dev/null +++ b/jcnf/yajl/cases/difficult_json_c_test_case.json @@ -0,0 +1 @@ +{ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML", "markup"] } ] } } } diff --git a/jcnf/yajl/cases/difficult_json_c_test_case.json.gold b/jcnf/yajl/cases/difficult_json_c_test_case.json.gold new file mode 100644 index 0000000..eaaf41a --- /dev/null +++ b/jcnf/yajl/cases/difficult_json_c_test_case.json.gold @@ -0,0 +1,35 @@ +map open '{' +key: 'glossary' +map open '{' +key: 'title' +string: 'example glossary' +key: 'GlossDiv' +map open '{' +key: 'title' +string: 'S' +key: 'GlossList' +array open '[' +map open '{' +key: 'ID' +string: 'SGML' +key: 'SortAs' +string: 'SGML' +key: 'GlossTerm' +string: 'Standard Generalized Markup Language' +key: 'Acronym' +string: 'SGML' +key: 'Abbrev' +string: 'ISO 8879:1986' +key: 'GlossDef' +string: 'A meta-markup language, used to create markup languages such as DocBook.' +key: 'GlossSeeAlso' +array open '[' +string: 'GML' +string: 'XML' +string: 'markup' +array close ']' +map close '}' +array close ']' +map close '}' +map close '}' +map close '}' diff --git a/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json new file mode 100644 index 0000000..2463c71 --- /dev/null +++ b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json @@ -0,0 +1 @@ +{ "glossary": { /* you */ "title": /**/ "example glossary", /*should*/"GlossDiv": { "title": /*never*/"S", /*ever*/"GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", /*see*/"GlossSeeAlso"/*this*/:/*coming*/[/*out*/"GML"/*of*/,/*the*/"XML"/*parser!*/, "markup"] /*hey*/}/*ho*/]/*hey*/}/*ho*/} } // and the parser won't even get this far, so chill. /* hah! diff --git a/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold new file mode 100644 index 0000000..eaaf41a --- /dev/null +++ b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold @@ -0,0 +1,35 @@ +map open '{' +key: 'glossary' +map open '{' +key: 'title' +string: 'example glossary' +key: 'GlossDiv' +map open '{' +key: 'title' +string: 'S' +key: 'GlossList' +array open '[' +map open '{' +key: 'ID' +string: 'SGML' +key: 'SortAs' +string: 'SGML' +key: 'GlossTerm' +string: 'Standard Generalized Markup Language' +key: 'Acronym' +string: 'SGML' +key: 'Abbrev' +string: 'ISO 8879:1986' +key: 'GlossDef' +string: 'A meta-markup language, used to create markup languages such as DocBook.' +key: 'GlossSeeAlso' +array open '[' +string: 'GML' +string: 'XML' +string: 'markup' +array close ']' +map close '}' +array close ']' +map close '}' +map close '}' +map close '}' diff --git a/jcnf/yajl/cases/doubles.json b/jcnf/yajl/cases/doubles.json new file mode 100644 index 0000000..626f21c --- /dev/null +++ b/jcnf/yajl/cases/doubles.json @@ -0,0 +1 @@ +[ 0.1e2, 1e1, 3.141569, 10000000000000e-10] diff --git a/jcnf/yajl/cases/doubles.json.gold b/jcnf/yajl/cases/doubles.json.gold new file mode 100644 index 0000000..ab5f212 --- /dev/null +++ b/jcnf/yajl/cases/doubles.json.gold @@ -0,0 +1,6 @@ +array open '[' +double: 10.000000 +double: 10.000000 +double: 3.141569 +double: 1000.000000 +array close ']' diff --git a/jcnf/yajl/cases/empty_array.json b/jcnf/yajl/cases/empty_array.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/jcnf/yajl/cases/empty_array.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/jcnf/yajl/cases/empty_array.json.gold b/jcnf/yajl/cases/empty_array.json.gold new file mode 100644 index 0000000..45924af --- /dev/null +++ b/jcnf/yajl/cases/empty_array.json.gold @@ -0,0 +1,2 @@ +array open '[' +array close ']' diff --git a/jcnf/yajl/cases/escaped_bulgarian.json b/jcnf/yajl/cases/escaped_bulgarian.json new file mode 100644 index 0000000..9ce1d1c --- /dev/null +++ b/jcnf/yajl/cases/escaped_bulgarian.json @@ -0,0 +1,4 @@ +["\u0414\u0430", + "\u041c\u0443", + "\u0415\u0431\u0430", + "\u041c\u0430\u0439\u043a\u0430\u0442\u0430"] diff --git a/jcnf/yajl/cases/escaped_bulgarian.json.gold b/jcnf/yajl/cases/escaped_bulgarian.json.gold new file mode 100644 index 0000000..9f2aa00 --- /dev/null +++ b/jcnf/yajl/cases/escaped_bulgarian.json.gold @@ -0,0 +1,6 @@ +array open '[' +string: 'Да' +string: 'Му' +string: 'Еба' +string: 'Майката' +array close ']' diff --git a/jcnf/yajl/cases/escaped_foobar.json b/jcnf/yajl/cases/escaped_foobar.json new file mode 100644 index 0000000..2c0e25f --- /dev/null +++ b/jcnf/yajl/cases/escaped_foobar.json @@ -0,0 +1 @@ +"\u0066\u006f\u006f\u0062\u0061\u0072" diff --git a/jcnf/yajl/cases/escaped_foobar.json.gold b/jcnf/yajl/cases/escaped_foobar.json.gold new file mode 100644 index 0000000..774e867 --- /dev/null +++ b/jcnf/yajl/cases/escaped_foobar.json.gold @@ -0,0 +1 @@ +string: 'foobar' diff --git a/jcnf/yajl/cases/integers.json b/jcnf/yajl/cases/integers.json new file mode 100644 index 0000000..ca1393a --- /dev/null +++ b/jcnf/yajl/cases/integers.json @@ -0,0 +1,3 @@ +[ 1,2,3,4,5,6,7, + 123456789 , -123456789, + 9223372036854775807, -9223372036854775807 ] diff --git a/jcnf/yajl/cases/integers.json.gold b/jcnf/yajl/cases/integers.json.gold new file mode 100644 index 0000000..f44b283 --- /dev/null +++ b/jcnf/yajl/cases/integers.json.gold @@ -0,0 +1,13 @@ +array open '[' +integer: 1 +integer: 2 +integer: 3 +integer: 4 +integer: 5 +integer: 6 +integer: 7 +integer: 123456789 +integer: -123456789 +integer: 9223372036854775807 +integer: -9223372036854775807 +array close ']' diff --git a/jcnf/yajl/cases/invalid_utf8.json b/jcnf/yajl/cases/invalid_utf8.json new file mode 100644 index 0000000..12f1718 --- /dev/null +++ b/jcnf/yajl/cases/invalid_utf8.json @@ -0,0 +1 @@ +["Да ÐœÑ Ð•Ð±Ð° Майката"] diff --git a/jcnf/yajl/cases/invalid_utf8.json.gold b/jcnf/yajl/cases/invalid_utf8.json.gold new file mode 100644 index 0000000..0cabb13 --- /dev/null +++ b/jcnf/yajl/cases/invalid_utf8.json.gold @@ -0,0 +1,2 @@ +array open '[' +lexical error: invalid bytes in UTF8 string. diff --git a/jcnf/yajl/cases/isolated_surrogate_marker.json b/jcnf/yajl/cases/isolated_surrogate_marker.json new file mode 100644 index 0000000..36959f4 --- /dev/null +++ b/jcnf/yajl/cases/isolated_surrogate_marker.json @@ -0,0 +1 @@ +"\ud800" diff --git a/jcnf/yajl/cases/isolated_surrogate_marker.json.gold b/jcnf/yajl/cases/isolated_surrogate_marker.json.gold new file mode 100644 index 0000000..1ad9e8b --- /dev/null +++ b/jcnf/yajl/cases/isolated_surrogate_marker.json.gold @@ -0,0 +1 @@ +string: '?' diff --git a/jcnf/yajl/cases/leading_zero_in_number.json b/jcnf/yajl/cases/leading_zero_in_number.json new file mode 100644 index 0000000..959f5ba --- /dev/null +++ b/jcnf/yajl/cases/leading_zero_in_number.json @@ -0,0 +1 @@ +{ "bad thing": 01 } diff --git a/jcnf/yajl/cases/leading_zero_in_number.json.gold b/jcnf/yajl/cases/leading_zero_in_number.json.gold new file mode 100644 index 0000000..828aec8 --- /dev/null +++ b/jcnf/yajl/cases/leading_zero_in_number.json.gold @@ -0,0 +1,4 @@ +map open '{' +key: 'bad thing' +integer: 0 +parse error: after key and value, inside map, I expect ',' or '}' diff --git a/jcnf/yajl/cases/lonely_minus_sign.json b/jcnf/yajl/cases/lonely_minus_sign.json new file mode 100644 index 0000000..85f69bd --- /dev/null +++ b/jcnf/yajl/cases/lonely_minus_sign.json @@ -0,0 +1,7 @@ +[ + "foo", true, + true, "blue", + "baby where are you?", "oh boo hoo!", + - +] + diff --git a/jcnf/yajl/cases/lonely_minus_sign.json.gold b/jcnf/yajl/cases/lonely_minus_sign.json.gold new file mode 100644 index 0000000..4b23c61 --- /dev/null +++ b/jcnf/yajl/cases/lonely_minus_sign.json.gold @@ -0,0 +1,8 @@ +array open '[' +string: 'foo' +bool: true +bool: true +string: 'blue' +string: 'baby where are you?' +string: 'oh boo hoo!' +lexical error: malformed number, a digit is required after the minus sign. diff --git a/jcnf/yajl/cases/missing_integer_after_decimal_point.json b/jcnf/yajl/cases/missing_integer_after_decimal_point.json new file mode 100644 index 0000000..2369f4b --- /dev/null +++ b/jcnf/yajl/cases/missing_integer_after_decimal_point.json @@ -0,0 +1 @@ +10.e2 diff --git a/jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold b/jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold new file mode 100644 index 0000000..1d85c91 --- /dev/null +++ b/jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold @@ -0,0 +1 @@ +lexical error: malformed number, a digit is required after the decimal point. diff --git a/jcnf/yajl/cases/missing_integer_after_exponent.json b/jcnf/yajl/cases/missing_integer_after_exponent.json new file mode 100644 index 0000000..a62b45d --- /dev/null +++ b/jcnf/yajl/cases/missing_integer_after_exponent.json @@ -0,0 +1 @@ +10e diff --git a/jcnf/yajl/cases/missing_integer_after_exponent.json.gold b/jcnf/yajl/cases/missing_integer_after_exponent.json.gold new file mode 100644 index 0000000..b9f184f --- /dev/null +++ b/jcnf/yajl/cases/missing_integer_after_exponent.json.gold @@ -0,0 +1 @@ +lexical error: malformed number, a digit is required after the exponent. diff --git a/jcnf/yajl/cases/non_utf8_char_in_string.json b/jcnf/yajl/cases/non_utf8_char_in_string.json new file mode 100644 index 0000000..253a664 --- /dev/null +++ b/jcnf/yajl/cases/non_utf8_char_in_string.json @@ -0,0 +1 @@ +{"CoreletAPIVersion":2,"CoreletType":"standalone","documentation":"A corelet that provides the capability to upload a folder’s contents into a user’s locker.","functions":[{"documentation":"Displays a dialog box that allows user to select a folder on the local system.","name":"ShowBrowseDialog","parameters":[{"documentation":"The callback function for results.","name":"callback","required":true,"type":"callback"}]},{"documentation":"Uploads all mp3 files in the folder provided.","name":"UploadFolder","parameters":[{"documentation":"The path to upload mp3 files from.","name":"path","required":true,"type":"string"},{"documentation":"The callback function for progress.","name":"callback","required":true,"type":"callback"}]},{"documentation":"Returns the server name to the current locker service.","name":"GetLockerService","parameters":[]},{"documentation":"Changes the name of the locker service.","name":"SetLockerService","parameters":[{"documentation":"The value of the locker service to set active.","name":"LockerService","required":true,"type":"string"}]},{"documentation":"Downloads locker files to the suggested folder.","name":"DownloadFile","parameters":[{"documentation":"The origin path of the locker file.","name":"path","required":true,"type":"string"},{"documentation":"The Window destination path of the locker file.","name":"destination","required":true,"type":"integer"},{"documentation":"The callback function for progress.","name":"callback","required":true,"type":"callback"}]}],"name":"LockerUploader","version":{"major":0,"micro":1,"minor":0},"versionString":"0.0.1"} \ No newline at end of file diff --git a/jcnf/yajl/cases/non_utf8_char_in_string.json.gold b/jcnf/yajl/cases/non_utf8_char_in_string.json.gold new file mode 100644 index 0000000..b3780ae --- /dev/null +++ b/jcnf/yajl/cases/non_utf8_char_in_string.json.gold @@ -0,0 +1,7 @@ +map open '{' +key: 'CoreletAPIVersion' +integer: 2 +key: 'CoreletType' +string: 'standalone' +key: 'documentation' +lexical error: invalid bytes in UTF8 string. diff --git a/jcnf/yajl/cases/nulls_and_bools.json b/jcnf/yajl/cases/nulls_and_bools.json new file mode 100644 index 0000000..65eb01f --- /dev/null +++ b/jcnf/yajl/cases/nulls_and_bools.json @@ -0,0 +1,5 @@ +{ + "boolean, true": true, + "boolean, false": false, + "null": null +} diff --git a/jcnf/yajl/cases/nulls_and_bools.json.gold b/jcnf/yajl/cases/nulls_and_bools.json.gold new file mode 100644 index 0000000..8dc173c --- /dev/null +++ b/jcnf/yajl/cases/nulls_and_bools.json.gold @@ -0,0 +1,8 @@ +map open '{' +key: 'boolean, true' +bool: true +key: 'boolean, false' +bool: false +key: 'null' +null +map close '}' diff --git a/jcnf/yajl/cases/simple.json b/jcnf/yajl/cases/simple.json new file mode 100644 index 0000000..9ed80c9 --- /dev/null +++ b/jcnf/yajl/cases/simple.json @@ -0,0 +1,5 @@ +{ + "this": "is", + "really": "simple", + "json": "right?" +} diff --git a/jcnf/yajl/cases/simple.json.gold b/jcnf/yajl/cases/simple.json.gold new file mode 100644 index 0000000..59b7d6a --- /dev/null +++ b/jcnf/yajl/cases/simple.json.gold @@ -0,0 +1,8 @@ +map open '{' +key: 'this' +string: 'is' +key: 'really' +string: 'simple' +key: 'json' +string: 'right?' +map close '}' diff --git a/jcnf/yajl/cases/simple_with_comments.json b/jcnf/yajl/cases/simple_with_comments.json new file mode 100644 index 0000000..3b79bba --- /dev/null +++ b/jcnf/yajl/cases/simple_with_comments.json @@ -0,0 +1,11 @@ +{ + "this": "is", // ignore this + "really": "simple", + /* ignore +this +too * / +** // +(/ +******/ + "json": "right?" +} diff --git a/jcnf/yajl/cases/simple_with_comments.json.gold b/jcnf/yajl/cases/simple_with_comments.json.gold new file mode 100644 index 0000000..59b7d6a --- /dev/null +++ b/jcnf/yajl/cases/simple_with_comments.json.gold @@ -0,0 +1,8 @@ +map open '{' +key: 'this' +string: 'is' +key: 'really' +string: 'simple' +key: 'json' +string: 'right?' +map close '}' diff --git a/jcnf/yajl/cases/string_invalid_escape.json b/jcnf/yajl/cases/string_invalid_escape.json new file mode 100644 index 0000000..c554182 --- /dev/null +++ b/jcnf/yajl/cases/string_invalid_escape.json @@ -0,0 +1 @@ +["\n foo \/ bar \r\f\\\uffff\t\b\"\\ and you can't escape thi\s"] diff --git a/jcnf/yajl/cases/string_invalid_escape.json.gold b/jcnf/yajl/cases/string_invalid_escape.json.gold new file mode 100644 index 0000000..bdc473e --- /dev/null +++ b/jcnf/yajl/cases/string_invalid_escape.json.gold @@ -0,0 +1,2 @@ +array open '[' +lexical error: inside a string, '\' occurs before a character which it may not. diff --git a/jcnf/yajl/cases/string_invalid_hex_char.json b/jcnf/yajl/cases/string_invalid_hex_char.json new file mode 100644 index 0000000..bde7ee9 --- /dev/null +++ b/jcnf/yajl/cases/string_invalid_hex_char.json @@ -0,0 +1 @@ +"foo foo, blah blah \u0123 \u4567 \u89ab \uc/ef \uABCD \uEFFE bar baz bing" diff --git a/jcnf/yajl/cases/string_invalid_hex_char.json.gold b/jcnf/yajl/cases/string_invalid_hex_char.json.gold new file mode 100644 index 0000000..d8b535e --- /dev/null +++ b/jcnf/yajl/cases/string_invalid_hex_char.json.gold @@ -0,0 +1 @@ +lexical error: invalid (non-hex) character occurs after '\u' inside string. diff --git a/jcnf/yajl/cases/string_with_escapes.json b/jcnf/yajl/cases/string_with_escapes.json new file mode 100644 index 0000000..59cc940 --- /dev/null +++ b/jcnf/yajl/cases/string_with_escapes.json @@ -0,0 +1,3 @@ +["\n foo \/ bar \r\f\\\uffff\t\b\"\\", + "\"and this string has an escape at the beginning", + "and this string has no escapes" ] diff --git a/jcnf/yajl/cases/string_with_escapes.json.gold b/jcnf/yajl/cases/string_with_escapes.json.gold new file mode 100644 index 0000000..ac878a2 --- /dev/null +++ b/jcnf/yajl/cases/string_with_escapes.json.gold @@ -0,0 +1,6 @@ +array open '[' +string: ' + foo / bar \ï¿¿ "\' +string: '"and this string has an escape at the beginning' +string: 'and this string has no escapes' +array close ']' diff --git a/jcnf/yajl/cases/string_with_invalid_newline.json b/jcnf/yajl/cases/string_with_invalid_newline.json new file mode 100644 index 0000000..0e3ea0d --- /dev/null +++ b/jcnf/yajl/cases/string_with_invalid_newline.json @@ -0,0 +1,2 @@ +"la di dah. this is a string, and I can do this, \n, but not this +" diff --git a/jcnf/yajl/cases/string_with_invalid_newline.json.gold b/jcnf/yajl/cases/string_with_invalid_newline.json.gold new file mode 100644 index 0000000..80c1b8a --- /dev/null +++ b/jcnf/yajl/cases/string_with_invalid_newline.json.gold @@ -0,0 +1 @@ +lexical error: invalid character inside string. diff --git a/jcnf/yajl/cases/unescaped_bulgarian.json b/jcnf/yajl/cases/unescaped_bulgarian.json new file mode 100644 index 0000000..f9a70a6 --- /dev/null +++ b/jcnf/yajl/cases/unescaped_bulgarian.json @@ -0,0 +1 @@ +["Да Му Еба Майката"] diff --git a/jcnf/yajl/cases/unescaped_bulgarian.json.gold b/jcnf/yajl/cases/unescaped_bulgarian.json.gold new file mode 100644 index 0000000..ac34442 --- /dev/null +++ b/jcnf/yajl/cases/unescaped_bulgarian.json.gold @@ -0,0 +1,3 @@ +array open '[' +string: 'Да Му Еба Майката' +array close ']' diff --git a/jcnf/yajl/configure b/jcnf/yajl/configure new file mode 100644 index 0000000..bed8c28 --- /dev/null +++ b/jcnf/yajl/configure @@ -0,0 +1,94 @@ +#!/usr/bin/env ruby +# Copyright 2007-2009, Lloyd Hilaiel. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# 3. Neither the name of Lloyd Hilaiel nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +require 'fileutils' +require 'optparse' + +prefix = "/usr/local" +options = {} +OptionParser.new do |opts| + opts.banner = "Usage: configure [options]" + opts.on("-p", "--prefix PATH", "Set installation prefix") do |p| + prefix = p + end + opts.on_tail("-h", "--help", "Output usage summary") do + puts opts + exit + end + + opts.parse!(ARGV) +end + +puts "== removing old build files" +FileUtils.rm_rf("build") +FileUtils.rm_f("Makefile") +puts "== running CMake in build directory" +FileUtils.mkdir("build") +FileUtils.cd("build") do + if (!system("cmake ..")) + puts "The \"cmake\" program is required to configure yajl. It's" + puts "available from most ports/packaging systems and http://cmake.org" + exit 1 + end +end + +# now generate a Makefile +puts "== Generating Makefile" +File.open("Makefile", "w+") do |f| + f.puts ".PHONY: all clean distclean install package test distro" + f.puts "all: distro doc test" + f.puts + f.puts "distro:" + f.puts " @cd build && make" + f.puts + f.puts "doc:" + f.puts " @cd build && make doc" + f.puts + f.puts "test:" + f.puts " @cd build && make test" + f.puts + f.puts "clean:" + f.puts " @cd build && make clean" + f.puts + f.puts "distclean:" + f.puts " @rm -rf Makefile build" + f.puts " @rm -f yajl-*.tgz" + f.puts + f.puts "install: all" + f.puts " @cd build && make install" + f.puts + f.puts "package: all" + f.puts " @echo \"compressing to `basename build/yajl-*`.tgz\"" + f.puts " @cd build && tar czf ../`basename yajl-*`.tgz yajl-*" +end + +puts "== Configured with installation prefix: #{prefix}" + diff --git a/jcnf/yajl/json_reformat.c b/jcnf/yajl/json_reformat.c new file mode 100644 index 0000000..156a61b --- /dev/null +++ b/jcnf/yajl/json_reformat.c @@ -0,0 +1,204 @@ +/* + * Copyright 2007, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_parse.h" +#include "yajl_gen.h" + +#include +#include +#include + +int reformat_null(void * ctx) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_null(g); + return 1; +} + +int reformat_boolean(void * ctx, int boolVal) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_bool(g, boolVal); + return 1; +} + +int reformat_integer(void * ctx, long long integerVal) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_integer(g, integerVal); + return 1; +} + +int reformat_double(void * ctx, double doubleVal) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_double(g, doubleVal); + return 1; +} + +int reformat_string(void * ctx, const unsigned char * stringVal, + unsigned int stringLen) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_string(g, stringVal, stringLen); + return 1; +} + +int reformat_map_key(void * ctx, const unsigned char * stringVal, + unsigned int stringLen) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_string(g, stringVal, stringLen); + return 1; +} + +int reformat_start_map(void * ctx) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_map_open(g); + return 1; +} + + +int reformat_end_map(void * ctx) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_map_close(g); + return 1; +} + +int reformat_start_array(void * ctx) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_array_open(g); + return 1; +} + +int reformat_end_array(void * ctx) +{ + yajl_gen g = (yajl_gen) ctx; + yajl_gen_array_close(g); + return 1; +} + +static yajl_callbacks callbacks = { + reformat_null, + reformat_boolean, + reformat_integer, + reformat_double, + reformat_string, + reformat_start_map, + reformat_map_key, + reformat_end_map, + reformat_start_array, + reformat_end_array +}; + +static void +usage(const char * progname) +{ + fprintf(stderr, "usage: %s \n" + " -m minimize json rather than beautify (default)\n" + " -u allow invalid UTF8 inside strings during parsing\n", + progname); + exit(1); + +} + +int +main(int argc, char ** argv) +{ + yajl_handle hand; + static unsigned char fileData[65536]; + /* generator config */ + yajl_gen_config conf = { 1, " " }; + yajl_gen g; + yajl_status stat; + size_t rd; + /* allow comments */ + yajl_parser_config cfg = { 1, 1 }; + + /* check arguments. We expect exactly one! */ + if (argc == 2) { + if (!strcmp("-m", argv[1])) { + conf.beautify = 0; + + } else if (!strcmp("-u", argv[1])) { + cfg.checkUTF8 = 0; + } else { + usage(argv[0]); + } + } else if (argc != 1) { + usage(argv[0]); + } + + g = yajl_gen_alloc(&conf); + + /* ok. open file. let's read and parse */ + hand = yajl_alloc(&callbacks, &cfg, (void *) g); + + for (;;) { + rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); + + if (rd == 0) { + if (feof(stdin)) { + break; + } else { + fprintf(stderr, "error on file read.\n"); + break; + } + } else { + fileData[rd] = 0; + + /* read file data, pass to parser */ + stat = yajl_parse(hand, fileData, rd); + if (stat != yajl_status_ok && + stat != yajl_status_insufficient_data) + { + unsigned char * str = yajl_get_error(hand, 1, fileData, rd); + fprintf(stderr, (const char *) str); + yajl_free_error(str); + } else { + const unsigned char * buf; + unsigned int len; + yajl_gen_get_buf(g, &buf, &len); + fwrite(buf, 1, len, stdout); + yajl_gen_clear(g); + } + } + } + + yajl_gen_free(g); + yajl_free(hand); + + return 0; +} diff --git a/jcnf/yajl/json_verify.c b/jcnf/yajl/json_verify.c new file mode 100644 index 0000000..42b57a9 --- /dev/null +++ b/jcnf/yajl/json_verify.c @@ -0,0 +1,129 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_parse.h" + +#include +#include +#include + +static void +usage(const char * progname) +{ + fprintf(stderr, "%s: validate json from stdin\n" + "usage: json_verify [options]\n" + " -q quiet mode\n" + " -c allow comments\n" + " -u allow invalid utf8 inside strings\n", + progname); + exit(1); +} + +int +main(int argc, char ** argv) +{ + yajl_status stat; + size_t rd; + yajl_handle hand; + static unsigned char fileData[65536]; + int quiet = 0; + int retval = 0, done = 0; + yajl_parser_config cfg = { 0, 1 }; + + /* check arguments.*/ + if (argc > 1 && argc < 4) { + int i; + + for (i=1; i < argc;i++) { + if (!strcmp("-q", argv[i])) { + quiet = 1; + } else if (!strcmp("-c", argv[i])) { + cfg.allowComments = 1; + } else if (!strcmp("-u", argv[i])) { + cfg.checkUTF8 = 0; + } else { + fprintf(stderr, "unrecognized option: '%s'\n\n", argv[i]); + usage(argv[0]); + } + } + } else if (argc != 1) { + usage(argv[0]); + } + + /* allocate a parser */ + hand = yajl_alloc(NULL, &cfg, NULL, NULL); + + while (!done) { + rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin); + + retval = 0; + + if (rd == 0) { + if (!feof(stdin)) { + if (!quiet) { + fprintf(stderr, "error encountered on file read\n"); + } + retval = 1; + break; + } + done = 1; + } + fileData[rd] = 0; + + if (done) + /* parse any remaining buffered data */ + stat = yajl_parse_complete(hand); + else + /* read file data, pass to parser */ + stat = yajl_parse(hand, fileData, rd); + + if (stat != yajl_status_ok && + stat != yajl_status_insufficient_data) + { + if (!quiet) { + unsigned char * str = yajl_get_error(hand, 1, fileData, rd); + fprintf(stderr, "%s", (const char *) str); + yajl_free_error(hand, str); + } + retval = 1; + break; + } + } + + yajl_free(hand); + + if (!quiet) { + printf("JSON is %s\n", retval ? "invalid" : "valid"); + } + + return retval; +} diff --git a/jcnf/yajl/rfc4627.txt b/jcnf/yajl/rfc4627.txt new file mode 100644 index 0000000..c3325a9 --- /dev/null +++ b/jcnf/yajl/rfc4627.txt @@ -0,0 +1,3 @@ + +See + diff --git a/jcnf/yajl/run_tests.sh b/jcnf/yajl/run_tests.sh new file mode 100644 index 0000000..174932f --- /dev/null +++ b/jcnf/yajl/run_tests.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +DIFF_FLAGS="-u" +if [[ `uname` == *W32* ]] ; then + DIFF_FLAGS="-wu" +fi + +# find test binary on both platforms. allow the caller to force a +# particular test binary (useful for non-cmake build systems). +if [ -z "$testBin" ]; then + testBin="../build/test/Debug/yajl_test.exe" + if [[ ! -x $testBin ]] ; then + testBin="../build/test/yajl_test" + if [[ ! -x $testBin ]] ; then + echo "cannot execute test binary: '$testBin'" + exit 1; + fi + fi +fi + +echo "using test binary: $testBin" + +let testsSucceeded=0 +let testsTotal=0 + +for file in cases/*.json ; do + allowComments="-c" + + # if the filename starts with dc_, we disallow comments for this test + if [[ $(basename $file) == dc_* ]] ; then + allowComments="" + fi + echo -n " test case: '$file': " + let iter=1 + success="success" + + # parse with a read buffer size ranging from 1-31 to stress stream parsing + while (( $iter < 32 )) && [ $success == "success" ] ; do + $testBin $allowComments -b $iter < $file > ${file}.test 2>&1 + diff ${DIFF_FLAGS} ${file}.gold ${file}.test + if [[ $? == 0 ]] ; then + if (( $iter == 31 )) ; then let testsSucceeded+=1 ; fi + else + success="FAILURE" + let iter=32 + fi + let iter+=1 + rm ${file}.test + done + + echo $success + let testsTotal+=1 +done + +echo $testsSucceeded/$testsTotal tests successful + +if [[ $testsSucceeded != $testsTotal ]] ; then + exit 1 +fi + +exit 0 diff --git a/jcnf/yajl/yajl.c b/jcnf/yajl/yajl.c new file mode 100644 index 0000000..b0dc991 --- /dev/null +++ b/jcnf/yajl/yajl.c @@ -0,0 +1,152 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_parse.h" +#include "yajl_lex.h" +#include "yajl_parser.h" +#include "yajl_alloc.h" + +#include +#include +#include + +const char * +yajl_status_to_string(yajl_status stat) +{ + const char * statStr = "unknown"; + switch (stat) { + case yajl_status_ok: + statStr = "ok, no error"; + break; + case yajl_status_client_canceled: + statStr = "client canceled parse"; + break; + case yajl_status_insufficient_data: + statStr = "eof was met before the parse could complete"; + break; + case yajl_status_error: + statStr = "parse error"; + break; + } + return statStr; +} + +yajl_handle +yajl_alloc(const yajl_callbacks * callbacks, + const yajl_parser_config * config, + const yajl_alloc_funcs * afs, + void * ctx) +{ + unsigned int allowComments = 0; + unsigned int validateUTF8 = 0; + yajl_handle hand = NULL; + yajl_alloc_funcs afsBuffer; + + /* first order of business is to set up memory allocation routines */ + if (afs != NULL) { + if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) + { + return NULL; + } + } else { + yajl_set_default_alloc_funcs(&afsBuffer); + afs = &afsBuffer; + } + + hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t)); + + /* copy in pointers to allocation routines */ + memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); + + if (config != NULL) { + allowComments = config->allowComments; + validateUTF8 = config->checkUTF8; + } + + hand->callbacks = callbacks; + hand->ctx = ctx; + hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8); + hand->errorOffset = 0; + hand->decodeBuf = yajl_buf_alloc(&(hand->alloc)); + yajl_bs_init(hand->stateStack, &(hand->alloc)); + + yajl_bs_push(hand->stateStack, yajl_state_start); + + return hand; +} + +void +yajl_free(yajl_handle handle) +{ + yajl_bs_free(handle->stateStack); + yajl_buf_free(handle->decodeBuf); + yajl_lex_free(handle->lexer); + YA_FREE(&(handle->alloc), handle); +} + +yajl_status +yajl_parse(yajl_handle hand, const unsigned char * jsonText, + unsigned int jsonTextLen) +{ + unsigned int offset = 0; + yajl_status status; + status = yajl_do_parse(hand, &offset, jsonText, jsonTextLen); + return status; +} + +yajl_status +yajl_parse_complete(yajl_handle hand) +{ + /* The particular case we want to handle is a trailing number. + * Further input consisting of digits could cause our interpretation + * of the number to change (buffered "1" but "2" comes in). + * A very simple approach to this is to inject whitespace to terminate + * any number in the lex buffer. + */ + return yajl_parse(hand, (const unsigned char *)" ", 1); +} + +unsigned char * +yajl_get_error(yajl_handle hand, int verbose, + const unsigned char * jsonText, unsigned int jsonTextLen) +{ + return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose); +} + +void +yajl_free_error(yajl_handle hand, unsigned char * str) +{ + /* use memory allocation functions if set */ + YA_FREE(&(hand->alloc), str); +} + +/* XXX: add utility routines to parse from file */ diff --git a/jcnf/yajl/yajl_alloc.c b/jcnf/yajl/yajl_alloc.c new file mode 100644 index 0000000..0b4bf37 --- /dev/null +++ b/jcnf/yajl/yajl_alloc.c @@ -0,0 +1,65 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file yajl_alloc.h + * default memory allocation routines for yajl which use malloc/realloc and + * free + */ + +#include "yajl_alloc.h" +#include + +static void * yajl_internal_malloc(void *ctx, unsigned int sz) +{ + return malloc(sz); +} + +static void * yajl_internal_realloc(void *ctx, void * previous, + unsigned int sz) +{ + return realloc(previous, sz); +} + +static void yajl_internal_free(void *ctx, void * ptr) +{ + free(ptr); +} + +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf) +{ + yaf->malloc = yajl_internal_malloc; + yaf->free = yajl_internal_free; + yaf->realloc = yajl_internal_realloc; + yaf->ctx = NULL; +} + diff --git a/jcnf/yajl/yajl_alloc.h b/jcnf/yajl/yajl_alloc.h new file mode 100644 index 0000000..988a6c5 --- /dev/null +++ b/jcnf/yajl/yajl_alloc.h @@ -0,0 +1,50 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file yajl_alloc.h + * default memory allocation routines for yajl which use malloc/realloc and + * free + */ + +#ifndef __YAJL_ALLOC_H__ +#define __YAJL_ALLOC_H__ + +#include "yajl_common.h" + +#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz)) +#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr)) +#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz)) + +void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf); + +#endif diff --git a/jcnf/yajl/yajl_buf.c b/jcnf/yajl/yajl_buf.c new file mode 100644 index 0000000..97f1ced --- /dev/null +++ b/jcnf/yajl/yajl_buf.c @@ -0,0 +1,119 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_buf.h" + +#include +#include +#include + +#define YAJL_BUF_INIT_SIZE 2048 + +struct yajl_buf_t { + unsigned int len; + unsigned int used; + unsigned char * data; + yajl_alloc_funcs * alloc; +}; + +static +void yajl_buf_ensure_available(yajl_buf buf, unsigned int want) +{ + unsigned int need; + + assert(buf != NULL); + + /* first call */ + if (buf->data == NULL) { + buf->len = YAJL_BUF_INIT_SIZE; + buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len); + buf->data[0] = 0; + } + + need = buf->len; + + while (want >= (need - buf->used)) need <<= 1; + + if (need != buf->len) { + buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need); + buf->len = need; + } +} + +yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc) +{ + yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t)); + memset((void *) b, 0, sizeof(struct yajl_buf_t)); + b->alloc = alloc; + return b; +} + +void yajl_buf_free(yajl_buf buf) +{ + assert(buf != NULL); + if (buf->data) YA_FREE(buf->alloc, buf->data); + YA_FREE(buf->alloc, buf); +} + +void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len) +{ + yajl_buf_ensure_available(buf, len); + if (len > 0) { + assert(data != NULL); + memcpy(buf->data + buf->used, data, len); + buf->used += len; + buf->data[buf->used] = 0; + } +} + +void yajl_buf_clear(yajl_buf buf) +{ + buf->used = 0; + if (buf->data) buf->data[buf->used] = 0; +} + +const unsigned char * yajl_buf_data(yajl_buf buf) +{ + return buf->data; +} + +unsigned int yajl_buf_len(yajl_buf buf) +{ + return buf->used; +} + +void +yajl_buf_truncate(yajl_buf buf, unsigned int len) +{ + assert(len <= buf->used); + buf->used = len; +} diff --git a/jcnf/yajl/yajl_buf.h b/jcnf/yajl/yajl_buf.h new file mode 100644 index 0000000..e5b2c82 --- /dev/null +++ b/jcnf/yajl/yajl_buf.h @@ -0,0 +1,73 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __YAJL_BUF_H__ +#define __YAJL_BUF_H__ + +#include "yajl_common.h" +#include "yajl_alloc.h" + +/* + * Implementation/performance notes. If this were moved to a header + * only implementation using #define's where possible we might be + * able to sqeeze a little performance out of the guy by killing function + * call overhead. YMMV. + */ + +/** + * yajl_buf is a buffer with exponential growth. the buffer ensures that + * you are always null padded. + */ +typedef struct yajl_buf_t * yajl_buf; + +/* allocate a new buffer */ +yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc); + +/* free the buffer */ +void yajl_buf_free(yajl_buf buf); + +/* append a number of bytes to the buffer */ +void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len); + +/* empty the buffer */ +void yajl_buf_clear(yajl_buf buf); + +/* get a pointer to the beginning of the buffer */ +const unsigned char * yajl_buf_data(yajl_buf buf); + +/* get the length of the buffer */ +unsigned int yajl_buf_len(yajl_buf buf); + +/* truncate the buffer */ +void yajl_buf_truncate(yajl_buf buf, unsigned int len); + +#endif diff --git a/jcnf/yajl/yajl_bytestack.h b/jcnf/yajl/yajl_bytestack.h new file mode 100644 index 0000000..9ce192f --- /dev/null +++ b/jcnf/yajl/yajl_bytestack.h @@ -0,0 +1,85 @@ +/* + * Copyright 2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * A header only implementation of a simple stack of bytes, used in YAJL + * to maintain parse state. + */ + +#ifndef __YAJL_BYTESTACK_H__ +#define __YAJL_BYTESTACK_H__ + +#include "yajl_common.h" + +#define YAJL_BS_INC 128 + +typedef struct yajl_bytestack_t +{ + unsigned char * stack; + unsigned int size; + unsigned int used; + yajl_alloc_funcs * yaf; +} yajl_bytestack; + +/* initialize a bytestack */ +#define yajl_bs_init(obs, _yaf) { \ + (obs).stack = NULL; \ + (obs).size = 0; \ + (obs).used = 0; \ + (obs).yaf = (_yaf); \ + } \ + + +/* initialize a bytestack */ +#define yajl_bs_free(obs) \ + if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack); + +#define yajl_bs_current(obs) \ + (assert((obs).used > 0), (obs).stack[(obs).used - 1]) + +#define yajl_bs_push(obs, byte) { \ + if (((obs).size - (obs).used) == 0) { \ + (obs).size += YAJL_BS_INC; \ + (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\ + (void *) (obs).stack, (obs).size);\ + } \ + (obs).stack[((obs).used)++] = (byte); \ +} + +/* removes the top item of the stack, returns nothing */ +#define yajl_bs_pop(obs) { ((obs).used)--; } + +#define yajl_bs_set(obs, byte) \ + (obs).stack[((obs).used) - 1] = (byte); + + +#endif diff --git a/jcnf/yajl/yajl_common.h b/jcnf/yajl/yajl_common.h new file mode 100644 index 0000000..9ad5eb4 --- /dev/null +++ b/jcnf/yajl/yajl_common.h @@ -0,0 +1,85 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __YAJL_COMMON_H__ +#define __YAJL_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define YAJL_MAX_DEPTH 128 + +/* msft dll export gunk. To build a DLL on windows, you + * must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared + * DLL, you must define YAJL_SHARED and WIN32 */ +#if defined(WIN32) && defined(YAJL_SHARED) +# ifdef YAJL_BUILD +# define YAJL_API __declspec(dllexport) +# else +# define YAJL_API __declspec(dllimport) +# endif +#else +# define YAJL_API +#endif + +/** pointer to a malloc function, supporting client overriding memory + * allocation routines */ +typedef void * (*yajl_malloc_func)(void *ctx, unsigned int sz); + +/** pointer to a free function, supporting client overriding memory + * allocation routines */ +typedef void (*yajl_free_func)(void *ctx, void * ptr); + +/** pointer to a realloc function which can resize an allocation. */ +typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, unsigned int sz); + +/** A structure which can be passed to yajl_*_alloc routines to allow the + * client to specify memory allocation functions to be used. */ +typedef struct +{ + /** pointer to a function that can allocate uninitialized memory */ + yajl_malloc_func malloc; + /** pointer to a function that can resize memory allocations */ + yajl_realloc_func realloc; + /** pointer to a function that can free memory allocated using + * reallocFunction or mallocFunction */ + yajl_free_func free; + /** a context pointer that will be passed to above allocation routines */ + void * ctx; +} yajl_alloc_funcs; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/jcnf/yajl/yajl_encode.c b/jcnf/yajl/yajl_encode.c new file mode 100644 index 0000000..184277b --- /dev/null +++ b/jcnf/yajl/yajl_encode.c @@ -0,0 +1,179 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_encode.h" + +#include +#include +#include +#include + +static void CharToHex(unsigned char c, char * hexBuf) +{ + const char * hexchar = "0123456789ABCDEF"; + hexBuf[0] = hexchar[c >> 4]; + hexBuf[1] = hexchar[c & 0x0F]; +} + +void +yajl_string_encode(yajl_buf buf, const unsigned char * str, + unsigned int len) +{ + unsigned int beg = 0; + unsigned int end = 0; + char hexBuf[7]; + hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0'; + hexBuf[6] = 0; + + while (end < len) { + const char * escaped = NULL; + switch (str[end]) { + case '\r': escaped = "\\r"; break; + case '\n': escaped = "\\n"; break; + case '\\': escaped = "\\\\"; break; + /* case '/': escaped = "\\/"; break; */ + case '"': escaped = "\\\""; break; + case '\f': escaped = "\\f"; break; + case '\b': escaped = "\\b"; break; + case '\t': escaped = "\\t"; break; + default: + if ((unsigned char) str[end] < 32) { + CharToHex(str[end], hexBuf + 4); + escaped = hexBuf; + } + break; + } + if (escaped != NULL) { + yajl_buf_append(buf, str + beg, end - beg); + yajl_buf_append(buf, escaped, strlen(escaped)); + beg = ++end; + } else { + ++end; + } + } + yajl_buf_append(buf, str + beg, end - beg); +} + +static void hexToDigit(unsigned int * val, const unsigned char * hex) +{ + unsigned int i; + for (i=0;i<4;i++) { + unsigned char c = hex[i]; + if (c >= 'A') c = (c & ~0x20) - 7; + c -= '0'; + assert(!(c & 0xF0)); + *val = (*val << 4) | c; + } +} + +static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf) +{ + if (codepoint < 0x80) { + utf8Buf[0] = (char) codepoint; + utf8Buf[1] = 0; + } else if (codepoint < 0x0800) { + utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0); + utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80); + utf8Buf[2] = 0; + } else if (codepoint < 0x10000) { + utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0); + utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80); + utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80); + utf8Buf[3] = 0; + } else if (codepoint < 0x200000) { + utf8Buf[0] =(char)((codepoint >> 18) | 0xF0); + utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80); + utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80); + utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80); + utf8Buf[4] = 0; + } else { + utf8Buf[0] = '?'; + utf8Buf[1] = 0; + } +} + +void yajl_string_decode(yajl_buf buf, const unsigned char * str, + unsigned int len) +{ + unsigned int beg = 0; + unsigned int end = 0; + + while (end < len) { + if (str[end] == '\\') { + char utf8Buf[5]; + const char * unescaped = "?"; + yajl_buf_append(buf, str + beg, end - beg); + switch (str[++end]) { + case 'r': unescaped = "\r"; break; + case 'n': unescaped = "\n"; break; + case '\\': unescaped = "\\"; break; + case '/': unescaped = "/"; break; + case '"': unescaped = "\""; break; + case 'f': unescaped = "\f"; break; + case 'b': unescaped = "\b"; break; + case 't': unescaped = "\t"; break; + case 'u': { + unsigned int codepoint = 0; + hexToDigit(&codepoint, str + ++end); + end+=3; + /* check if this is a surrogate */ + if ((codepoint & 0xFC00) == 0xD800) { + end++; + if (str[end] == '\\' && str[end + 1] == 'u') { + unsigned int surrogate = 0; + hexToDigit(&surrogate, str + end + 2); + codepoint = + (((codepoint & 0x3F) << 10) | + ((((codepoint >> 6) & 0xF) + 1) << 16) | + (surrogate & 0x3FF)); + end += 5; + } else { + unescaped = "?"; + break; + } + } + + Utf32toUtf8(codepoint, utf8Buf); + unescaped = utf8Buf; + break; + } + default: + assert("this should never happen" == NULL); + } + yajl_buf_append(buf, unescaped, strlen(unescaped)); + beg = ++end; + } else { + end++; + } + } + yajl_buf_append(buf, str + beg, end - beg); +} diff --git a/jcnf/yajl/yajl_encode.h b/jcnf/yajl/yajl_encode.h new file mode 100644 index 0000000..8bd01af --- /dev/null +++ b/jcnf/yajl/yajl_encode.h @@ -0,0 +1,44 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __YAJL_ENCODE_H__ +#define __YAJL_ENCODE_H__ + +#include "yajl_buf.h" + +void yajl_string_encode(yajl_buf buf, const unsigned char * str, + unsigned int length); + +void yajl_string_decode(yajl_buf buf, const unsigned char * str, + unsigned int length); + +#endif diff --git a/jcnf/yajl/yajl_gen.c b/jcnf/yajl/yajl_gen.c new file mode 100644 index 0000000..a400176 --- /dev/null +++ b/jcnf/yajl/yajl_gen.c @@ -0,0 +1,381 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_gen.h" +#include "yajl_buf.h" +#include "yajl_encode.h" + +#include +#include +#include + +typedef enum { + yajl_gen_start, + yajl_gen_map_start, + yajl_gen_map_key, + yajl_gen_map_val, + yajl_gen_array_start, + yajl_gen_in_array, + yajl_gen_complete, + yajl_gen_error +} yajl_gen_state; + +struct yajl_gen_t +{ + unsigned int depth; + unsigned int pretty; + const char * indentString; + yajl_gen_state state[YAJL_MAX_DEPTH]; + yajl_buf buf; + unsigned char *pendingComment; + unsigned int pendingLen; /* Length of pending comment */ + int pendingCpp; /* NZ if comment is C++ style, Z if C */ + /* memory allocation routines */ + yajl_alloc_funcs alloc; +}; + +yajl_gen +yajl_gen_alloc(const yajl_gen_config * config, + const yajl_alloc_funcs * afs) +{ + yajl_gen g = NULL; + yajl_alloc_funcs afsBuffer; + + /* first order of business is to set up memory allocation routines */ + if (afs != NULL) { + if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL) + { + return NULL; + } + } else { + yajl_set_default_alloc_funcs(&afsBuffer); + afs = &afsBuffer; + } + + g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t)); + memset((void *) g, 0, sizeof(struct yajl_gen_t)); + /* copy in pointers to allocation routines */ + memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs)); + + if (config) { + g->pretty = config->beautify; + g->indentString = config->indentString ? config->indentString : " "; + } + g->buf = yajl_buf_alloc(&(g->alloc)); + + return g; +} + +void +yajl_gen_free(yajl_gen g) +{ + yajl_buf_free(g->buf); + YA_FREE(&(g->alloc), g); +} + +#define INSERT_EOL \ + if (g->pretty || g->pendingComment != NULL) \ + yajl_insert_eol(g); + +#define INSERT_SEP \ + if (g->state[g->depth] == yajl_gen_map_key || \ + g->state[g->depth] == yajl_gen_in_array) { \ + yajl_buf_append(g->buf, ",", 1); \ + INSERT_EOL; \ + } else if (g->state[g->depth] == yajl_gen_map_val) { \ + yajl_buf_append(g->buf, ":", 1); \ + if (g->pretty) yajl_buf_append(g->buf, " ", 1); \ + } + +#define INSERT_WHITESPACE \ + if (g->pretty) { \ + if (g->state[g->depth] != yajl_gen_map_val) { \ + unsigned int _i; \ + for (_i=0;_idepth;_i++) \ + yajl_buf_append(g->buf, g->indentString, \ + strlen(g->indentString)); \ + } \ + } + +#define INSERT_SOME_WHITESPACE \ + if (g->pretty) { \ + if (g->state[g->depth] != yajl_gen_map_val) { \ + yajl_buf_append(g->buf, g->indentString, \ + strlen(g->indentString)); \ + } \ + } + +#define ENSURE_NOT_KEY \ + if (g->state[g->depth] == yajl_gen_map_key) { \ + return yajl_gen_keys_must_be_strings; \ + } \ + +/* check that we're not complete, or in error state. in a valid state + * to be generating */ +#define ENSURE_VALID_STATE \ + if (g->state[g->depth] == yajl_gen_error) { \ + return yajl_gen_in_error_state;\ + } else if (g->state[g->depth] == yajl_gen_complete) { \ + return yajl_gen_generation_complete; \ + } + +#define INCREMENT_DEPTH \ + if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded; + +#define APPENDED_ATOM \ + switch (g->state[g->depth]) { \ + case yajl_gen_start: \ + g->state[g->depth] = yajl_gen_complete; \ + break; \ + case yajl_gen_map_start: \ + case yajl_gen_map_key: \ + g->state[g->depth] = yajl_gen_map_val; \ + break; \ + case yajl_gen_array_start: \ + g->state[g->depth] = yajl_gen_in_array; \ + break; \ + case yajl_gen_map_val: \ + g->state[g->depth] = yajl_gen_map_key; \ + break; \ + default: \ + break; \ + } \ + +#define FINAL_NEWLINE \ + if (g->pretty && g->state[g->depth] == yajl_gen_complete) \ + INSERT_EOL + +/* Insert an end of line, and take care of any */ +/* pending comments */ +static void yajl_insert_eol(yajl_gen g) { + if (g->pendingComment != NULL) { + INSERT_SOME_WHITESPACE; + if (g->pendingCpp) + yajl_buf_append(g->buf, "//", 2); + else + yajl_buf_append(g->buf, "/*", 2); + yajl_string_encode(g->buf, g->pendingComment, g->pendingLen); + if (!g->pendingCpp) + yajl_buf_append(g->buf, "*/", 2); + free(g->pendingComment); + g->pendingComment = NULL; + g->pendingLen = 0; + g->pendingCpp = 0; + } + yajl_buf_append(g->buf, "\n", 1); +} + +/* Insert a comment at the end of the line. Append if there is already */ +/* one pending. */ +static void yajl_insert_pending_comment( +yajl_gen g, const unsigned char * str, unsigned int len, int cpp) { + if (g->pendingComment != NULL) { + unsigned int tlen = g->pendingLen + 0 + len; + unsigned char *pendingComment; + pendingComment = (unsigned char *) realloc(g->pendingComment, sizeof(char) * tlen); + memcpy(pendingComment + g->pendingLen + 0, str, len); + g->pendingComment = pendingComment; + g->pendingLen = tlen; + } else { + g->pendingComment = (unsigned char *) malloc(sizeof(char) * len); + memcpy(g->pendingComment, str, len); + g->pendingLen = len; + } + g->pendingCpp = cpp; +} + +yajl_gen_status +yajl_gen_integer(yajl_gen g, long int number) +{ + char i[32]; + ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + sprintf(i, "%ld", number); + yajl_buf_append(g->buf, i, strlen(i)); + APPENDED_ATOM; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_double(yajl_gen g, double number) +{ + char i[32]; + ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + sprintf(i, "%g", number); + yajl_buf_append(g->buf, i, strlen(i)); + APPENDED_ATOM; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_number(yajl_gen g, const char * s, unsigned int l) +{ + ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + yajl_buf_append(g->buf, s, l); + APPENDED_ATOM; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_string(yajl_gen g, const unsigned char * str, + unsigned int len) +{ + ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE; + yajl_buf_append(g->buf, "\"", 1); + yajl_string_encode(g->buf, str, len); + yajl_buf_append(g->buf, "\"", 1); + APPENDED_ATOM; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_null(yajl_gen g) +{ + ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + yajl_buf_append(g->buf, "null", strlen("null")); + APPENDED_ATOM; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_bool(yajl_gen g, int boolean) +{ + const char * val = boolean ? "true" : "false"; + + ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + yajl_buf_append(g->buf, val, strlen(val)); + APPENDED_ATOM; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_map_open(yajl_gen g) +{ + ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + INCREMENT_DEPTH; + + g->state[g->depth] = yajl_gen_map_start; + yajl_buf_append(g->buf, "{", 1); + INSERT_EOL; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_map_close(yajl_gen g) +{ + ENSURE_VALID_STATE; + (g->depth)--; + INSERT_EOL; + APPENDED_ATOM; + INSERT_WHITESPACE; + yajl_buf_append(g->buf, "}", 1); + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_array_open(yajl_gen g) +{ + ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE; + INCREMENT_DEPTH; + g->state[g->depth] = yajl_gen_array_start; + yajl_buf_append(g->buf, "[", 1); + INSERT_EOL; + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_array_close(yajl_gen g) +{ + ENSURE_VALID_STATE; + INSERT_EOL; + (g->depth)--; + APPENDED_ATOM; + INSERT_WHITESPACE; + yajl_buf_append(g->buf, "]", 1); + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_c_comment(yajl_gen g, const unsigned char * str, + unsigned int len, int dlytoeol) +{ + ENSURE_VALID_STATE; + if (dlytoeol) { + yajl_insert_pending_comment(g, str, len, 0); + } else { + if (g->pretty) + yajl_buf_append(g->buf, " /*", 3); + else + yajl_buf_append(g->buf, "/*", 2); + yajl_string_encode(g->buf, str, len); + if (g->pretty) + yajl_buf_append(g->buf, "*/ ", 3); + else + yajl_buf_append(g->buf, "*/", 2); + } + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_cpp_comment(yajl_gen g, const unsigned char * str, + unsigned int len) +{ + ENSURE_VALID_STATE; + yajl_insert_pending_comment(g, str, len, 1); + FINAL_NEWLINE; + return yajl_gen_status_ok; +} + +yajl_gen_status +yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf, + unsigned int * len) +{ + *buf = yajl_buf_data(g->buf); + *len = yajl_buf_len(g->buf); + return yajl_gen_status_ok; +} + +void +yajl_gen_clear(yajl_gen g) +{ + yajl_buf_clear(g->buf); +} diff --git a/jcnf/yajl/yajl_gen.h b/jcnf/yajl/yajl_gen.h new file mode 100644 index 0000000..5bde0e8 --- /dev/null +++ b/jcnf/yajl/yajl_gen.h @@ -0,0 +1,129 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file yajl_gen.h + * Interface to YAJL's JSON generation facilities. + */ + +#include "yajl_common.h" + +#ifndef __YAJL_GEN_H__ +#define __YAJL_GEN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + /** generator status codes */ + typedef enum { + /** no error */ + yajl_gen_status_ok = 0, + /** at a point where a map key is generated, a function other than + * yajl_gen_string was called */ + yajl_gen_keys_must_be_strings, + /** YAJL's maximum generation depth was exceeded. see + * YAJL_MAX_DEPTH */ + yajl_max_depth_exceeded, + /** A generator function (yajl_gen_XXX) was called while in an error + * state */ + yajl_gen_in_error_state, + /** A complete JSON document has been generated */ + yajl_gen_generation_complete + } yajl_gen_status; + + /** an opaque handle to a generator */ + typedef struct yajl_gen_t * yajl_gen; + + /** configuration structure for the generator */ + typedef struct { + /** generate indented (beautiful) output */ + unsigned int beautify; + /** an opportunity to define an indent string. such as \\t or + * some number of spaces. default is four spaces ' '. This + * member is only relevant when beautify is true */ + const char * indentString; + } yajl_gen_config; + + /** allocate a generator handle + * \param config a pointer to a structure containing parameters which + * configure the behavior of the json generator + * \param allocFuncs an optional pointer to a structure which allows + * the client to overide the memory allocation + * used by yajl. May be NULL, in which case + * malloc/free/realloc will be used. + * + * \returns an allocated handle on success, NULL on failure (bad params) + */ + yajl_gen YAJL_API yajl_gen_alloc(const yajl_gen_config * config, + const yajl_alloc_funcs * allocFuncs); + + /** free a generator handle */ + void YAJL_API yajl_gen_free(yajl_gen handle); + + yajl_gen_status YAJL_API yajl_gen_integer(yajl_gen hand, long int number); + yajl_gen_status YAJL_API yajl_gen_double(yajl_gen hand, double number); + yajl_gen_status YAJL_API yajl_gen_number(yajl_gen hand, + const char * num, + unsigned int len); + yajl_gen_status YAJL_API yajl_gen_string(yajl_gen hand, + const unsigned char * str, + unsigned int len); + yajl_gen_status YAJL_API yajl_gen_null(yajl_gen hand); + yajl_gen_status YAJL_API yajl_gen_bool(yajl_gen hand, int boolean); + yajl_gen_status YAJL_API yajl_gen_map_open(yajl_gen hand); + yajl_gen_status YAJL_API yajl_gen_map_close(yajl_gen hand); + yajl_gen_status YAJL_API yajl_gen_array_open(yajl_gen hand); + yajl_gen_status YAJL_API yajl_gen_array_close(yajl_gen hand); + yajl_gen_status YAJL_API yajl_gen_c_comment(yajl_gen hand, + const unsigned char * str, + unsigned int len, int dlytoeol); + yajl_gen_status YAJL_API yajl_gen_cpp_comment(yajl_gen hand, + const unsigned char * str, + unsigned int len); + + /** access the null terminated generator buffer. If incrementally + * outputing JSON, one should call yajl_gen_clear to clear the + * buffer. This allows stream generation. */ + yajl_gen_status YAJL_API yajl_gen_get_buf(yajl_gen hand, + const unsigned char ** buf, + unsigned int * len); + + /** clear yajl's output buffer, but maintain all internal generation + * state. This function will not "reset" the generator state, and is + * intended to enable incremental JSON outputing. */ + void YAJL_API yajl_gen_clear(yajl_gen hand); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/jcnf/yajl/yajl_lex.c b/jcnf/yajl/yajl_lex.c new file mode 100644 index 0000000..56e563e --- /dev/null +++ b/jcnf/yajl/yajl_lex.c @@ -0,0 +1,753 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_lex.h" +#include "yajl_buf.h" + +#include +#include +#include +#include + +#ifdef YAJL_LEXER_DEBUG +static const char * +tokToStr(yajl_tok tok) +{ + switch (tok) { + case yajl_tok_bool: return "bool"; + case yajl_tok_colon: return "colon"; + case yajl_tok_comma: return "comma"; + case yajl_tok_eof: return "eof"; + case yajl_tok_error: return "error"; + case yajl_tok_left_brace: return "brace"; + case yajl_tok_left_bracket: return "bracket"; + case yajl_tok_null: return "null"; + case yajl_tok_integer: return "integer"; + case yajl_tok_double: return "double"; + case yajl_tok_right_brace: return "brace"; + case yajl_tok_right_bracket: return "bracket"; + case yajl_tok_string: return "string"; + case yajl_tok_string_with_escapes: return "string_with_escapes"; + case yajl_tok_c_comment: return "C comment"; + case yajl_tok_cpp_comment: return "C++ comment"; + } + return "unknown"; +} +#endif + +/* Impact of the stream parsing feature on the lexer: + * + * YAJL support stream parsing. That is, the ability to parse the first + * bits of a chunk of JSON before the last bits are available (still on + * the network or disk). This makes the lexer more complex. The + * responsibility of the lexer is to handle transparently the case where + * a chunk boundary falls in the middle of a token. This is + * accomplished is via a buffer and a character reading abstraction. + * + * Overview of implementation + * + * When we lex to end of input string before end of token is hit, we + * copy all of the input text composing the token into our lexBuf. + * + * Every time we read a character, we do so through the readChar function. + * readChar's responsibility is to handle pulling all chars from the buffer + * before pulling chars from input text + */ + +struct yajl_lexer_t { + /* the overal line and char offset into the data */ + unsigned int lineOff; + unsigned int charOff; + + /* error */ + yajl_lex_error error; + + /* a input buffer to handle the case where a token is spread over + * multiple chunks */ + yajl_buf buf; + + /* in the case where we have data in the lexBuf, bufOff holds + * the current offset into the lexBuf. */ + unsigned int bufOff; + + /* are we using the lex buf? */ + unsigned int bufInUse; + + /* shall we allow comments? */ + unsigned int allowComments; + + /* shall we validate utf8 inside strings? */ + unsigned int validateUTF8; + + yajl_alloc_funcs * alloc; +}; + +#define readChar(lxr, txt, off) \ + (((lxr)->bufInUse && yajl_buf_len((lxr)->buf) && lxr->bufOff < yajl_buf_len((lxr)->buf)) ? \ + (*((const unsigned char *) yajl_buf_data((lxr)->buf) + ((lxr)->bufOff)++)) : \ + ((txt)[(*(off))++])) + +#define unreadChar(lxr, off) ((*(off) > 0) ? (*(off))-- : ((lxr)->bufOff--)) + +yajl_lexer +yajl_lex_alloc(yajl_alloc_funcs * alloc, + unsigned int allowComments, unsigned int validateUTF8) +{ + yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t)); + memset((void *) lxr, 0, sizeof(struct yajl_lexer_t)); + lxr->buf = yajl_buf_alloc(alloc); + lxr->allowComments = allowComments; + lxr->validateUTF8 = validateUTF8; + lxr->alloc = alloc; + return lxr; +} + +void +yajl_lex_free(yajl_lexer lxr) +{ + yajl_buf_free(lxr->buf); + YA_FREE(lxr->alloc, lxr); + return; +} + +/* a lookup table which lets us quickly determine three things: + * VEC - valid escaped conrol char + * IJC - invalid json char + * VHC - valid hex char + * note. the solidus '/' may be escaped or not. + * note. the + */ +#define VEC 1 +#define IJC 2 +#define VHC 4 +static const char charLookupTable[256] = +{ +/*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , +/*08*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , +/*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , +/*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC , + +/*20*/ 0 , 0 , VEC|IJC, 0 , 0 , 0 , 0 , 0 , +/*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC , +/*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC , +/*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 , + +/*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 , +/*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , +/*58*/ 0 , 0 , 0 , 0 , VEC|IJC, 0 , 0 , 0 , + +/*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 , +/*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 , +/*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 , +/*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + +/* include these so we don't have to always check the range of the char */ + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , + 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 +}; + +/** process a variable length utf8 encoded codepoint. + * + * returns: + * yajl_tok_string - if valid utf8 char was parsed and offset was + * advanced + * yajl_tok_eof - if end of input was hit before validation could + * complete + * yajl_tok_error - if invalid utf8 was encountered + * + * NOTE: on error the offset will point to the first char of the + * invalid utf8 */ +#define UTF8_CHECK_EOF if (*offset >= jsonTextLen) { return yajl_tok_eof; } + +static yajl_tok +yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int * offset, + unsigned char curChar) +{ + if (curChar <= 0x7f) { + /* single byte */ + return yajl_tok_string; + } else if ((curChar >> 5) == 0x6) { + /* two byte */ + UTF8_CHECK_EOF; + curChar = readChar(lexer, jsonText, offset); + if ((curChar >> 6) == 0x2) return yajl_tok_string; + } else if ((curChar >> 4) == 0x0e) { + /* three byte */ + UTF8_CHECK_EOF; + curChar = readChar(lexer, jsonText, offset); + if ((curChar >> 6) == 0x2) { + UTF8_CHECK_EOF; + curChar = readChar(lexer, jsonText, offset); + if ((curChar >> 6) == 0x2) return yajl_tok_string; + } + } else if ((curChar >> 3) == 0x1e) { + /* four byte */ + UTF8_CHECK_EOF; + curChar = readChar(lexer, jsonText, offset); + if ((curChar >> 6) == 0x2) { + UTF8_CHECK_EOF; + curChar = readChar(lexer, jsonText, offset); + if ((curChar >> 6) == 0x2) { + UTF8_CHECK_EOF; + curChar = readChar(lexer, jsonText, offset); + if ((curChar >> 6) == 0x2) return yajl_tok_string; + } + } + } + + return yajl_tok_error; +} + +/* lex a string. input is the lexer, pointer to beginning of + * json text, and start of string (offset). + * a token is returned which has the following meanings: + * yajl_tok_string: lex of string was successful. offset points to + * terminating '"'. + * yajl_tok_eof: end of text was encountered before we could complete + * the lex. + * yajl_tok_error: embedded in the string were unallowable chars. offset + * points to the offending char + */ +#define STR_CHECK_EOF \ +if (*offset >= jsonTextLen) { \ + tok = yajl_tok_eof; \ + goto finish_string_lex; \ +} + +static yajl_tok +yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int * offset) +{ + yajl_tok tok = yajl_tok_error; + int hasEscapes = 0; + + for (;;) { + unsigned char curChar; + + STR_CHECK_EOF; + + curChar = readChar(lexer, jsonText, offset); + + /* quote terminates */ + if (curChar == '"') { + tok = yajl_tok_string; + break; + } + /* backslash escapes a set of control chars, */ + else if (curChar == '\\') { + hasEscapes = 1; + STR_CHECK_EOF; + + /* special case \u */ + curChar = readChar(lexer, jsonText, offset); + if (curChar == 'u') { + unsigned int i = 0; + + for (i=0;i<4;i++) { + STR_CHECK_EOF; + curChar = readChar(lexer, jsonText, offset); + if (!(charLookupTable[curChar] & VHC)) { + /* back up to offending char */ + unreadChar(lexer, offset); + lexer->error = yajl_lex_string_invalid_hex_char; + goto finish_string_lex; + } + } + } else if (!(charLookupTable[curChar] & VEC)) { + /* back up to offending char */ + unreadChar(lexer, offset); + lexer->error = yajl_lex_string_invalid_escaped_char; + goto finish_string_lex; + } + } + /* when not validating UTF8 it's a simple table lookup to determine + * if the present character is invalid */ + else if(charLookupTable[curChar] & IJC) { + /* back up to offending char */ + unreadChar(lexer, offset); + lexer->error = yajl_lex_string_invalid_json_char; + goto finish_string_lex; + } + /* when in validate UTF8 mode we need to do some extra work */ + else if (lexer->validateUTF8) { + yajl_tok t = yajl_lex_utf8_char(lexer, jsonText, jsonTextLen, + offset, curChar); + + if (t == yajl_tok_eof) { + tok = yajl_tok_eof; + goto finish_string_lex; + } else if (t == yajl_tok_error) { + lexer->error = yajl_lex_string_invalid_utf8; + goto finish_string_lex; + } + } + /* accept it, and move on */ + } + finish_string_lex: + /* tell our buddy, the parser, wether he needs to process this string + * again */ + if (hasEscapes && tok == yajl_tok_string) { + tok = yajl_tok_string_with_escapes; + } + + return tok; +} + +#define RETURN_IF_EOF if (*offset >= jsonTextLen) return yajl_tok_eof; + +static yajl_tok +yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int * offset) +{ + /** XXX: numbers are the only entities in json that we must lex + * _beyond_ in order to know that they are complete. There + * is an ambiguous case for integers at EOF. */ + + unsigned char c; + + yajl_tok tok = yajl_tok_integer; + + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + + /* optional leading minus */ + if (c == '-') { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + } + + /* a single zero, or a series of integers */ + if (c == '0') { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + } else if (c >= '1' && c <= '9') { + do { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + } while (c >= '0' && c <= '9'); + } else { + unreadChar(lexer, offset); + lexer->error = yajl_lex_missing_integer_after_minus; + return yajl_tok_error; + } + + /* optional fraction (indicates this is floating point) */ + if (c == '.') { + int numRd = 0; + + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + + while (c >= '0' && c <= '9') { + numRd++; + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + } + + if (!numRd) { + unreadChar(lexer, offset); + lexer->error = yajl_lex_missing_integer_after_decimal; + return yajl_tok_error; + } + tok = yajl_tok_double; + } + + /* optional exponent (indicates this is floating point) */ + if (c == 'e' || c == 'E') { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + + /* optional sign */ + if (c == '+' || c == '-') { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + } + + if (c >= '0' && c <= '9') { + do { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + } while (c >= '0' && c <= '9'); + } else { + unreadChar(lexer, offset); + lexer->error = yajl_lex_missing_integer_after_exponent; + return yajl_tok_error; + } + tok = yajl_tok_double; + } + + /* we always go "one too far" */ + unreadChar(lexer, offset); + + return tok; +} + +static yajl_tok +yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int * offset) +{ + unsigned char c; + + yajl_tok tok; + + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + + /* either slash or star expected */ + if (c == '/') { + tok = yajl_tok_cpp_comment; + /* now we throw away until end of line */ + do { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + } while (c != '\n'); + } else if (c == '*') { + tok = yajl_tok_c_comment; + /* now we throw away until end of comment */ + for (;;) { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + if (c == '*') { + RETURN_IF_EOF; + c = readChar(lexer, jsonText, offset); + if (c == '/') { + break; + } else { + unreadChar(lexer, offset); + } + } + } + } else { + lexer->error = yajl_lex_invalid_char; + tok = yajl_tok_error; + } + + return tok; +} + +yajl_tok +yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int * offset, + const unsigned char ** outBuf, unsigned int * outLen) +{ + yajl_tok tok = yajl_tok_error; + unsigned char c; + unsigned int startOffset = *offset; + + *outBuf = NULL; + *outLen = 0; + + for (;;) { + assert(*offset <= jsonTextLen); + + if (*offset >= jsonTextLen) { + tok = yajl_tok_eof; + goto lexed; + } + + c = readChar(lexer, jsonText, offset); + + switch (c) { + case '{': + tok = yajl_tok_left_bracket; + goto lexed; + case '}': + tok = yajl_tok_right_bracket; + goto lexed; + case '[': + tok = yajl_tok_left_brace; + goto lexed; + case ']': + tok = yajl_tok_right_brace; + goto lexed; + case ',': + tok = yajl_tok_comma; + goto lexed; + case ':': + tok = yajl_tok_colon; + goto lexed; + case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': + startOffset++; + break; + case 't': { + const char * want = "rue"; + do { + if (*offset >= jsonTextLen) { + tok = yajl_tok_eof; + goto lexed; + } + c = readChar(lexer, jsonText, offset); + if (c != *want) { + unreadChar(lexer, offset); + lexer->error = yajl_lex_invalid_string; + tok = yajl_tok_error; + goto lexed; + } + } while (*(++want)); + tok = yajl_tok_bool; + goto lexed; + } + case 'f': { + const char * want = "alse"; + do { + if (*offset >= jsonTextLen) { + tok = yajl_tok_eof; + goto lexed; + } + c = readChar(lexer, jsonText, offset); + if (c != *want) { + unreadChar(lexer, offset); + lexer->error = yajl_lex_invalid_string; + tok = yajl_tok_error; + goto lexed; + } + } while (*(++want)); + tok = yajl_tok_bool; + goto lexed; + } + case 'n': { + const char * want = "ull"; + do { + if (*offset >= jsonTextLen) { + tok = yajl_tok_eof; + goto lexed; + } + c = readChar(lexer, jsonText, offset); + if (c != *want) { + unreadChar(lexer, offset); + lexer->error = yajl_lex_invalid_string; + tok = yajl_tok_error; + goto lexed; + } + } while (*(++want)); + tok = yajl_tok_null; + goto lexed; + } + case '"': { + tok = yajl_lex_string(lexer, (const unsigned char *) jsonText, + jsonTextLen, offset); + goto lexed; + } + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + /* integer parsing wants to start from the beginning */ + unreadChar(lexer, offset); + tok = yajl_lex_number(lexer, (const unsigned char *) jsonText, + jsonTextLen, offset); + goto lexed; + } + case '/': + /* hey, look, a probable comment! If comments are disabled + * it's an error. */ + if (!lexer->allowComments) { + unreadChar(lexer, offset); + lexer->error = yajl_lex_unallowed_comment; + tok = yajl_tok_error; + goto lexed; + } + /* if comments are enabled, then we should try to lex + * the thing. possible outcomes are + * - successful lex (tok_comment, which means continue), + * - malformed comment opening (slash not followed by + * '*' or '/') (tok_error) + * - eof hit. (tok_eof) */ + tok = yajl_lex_comment(lexer, (const unsigned char *) jsonText, + jsonTextLen, offset); + if (tok == yajl_tok_c_comment + || tok == yajl_tok_cpp_comment) { + goto lexed; + } + /* hit error or eof, bail */ + goto lexed; + default: + lexer->error = yajl_lex_invalid_char; + tok = yajl_tok_error; + goto lexed; + } + } + + + lexed: + /* need to append to buffer if the buffer is in use or + * if it's an EOF token */ + if (tok == yajl_tok_eof || lexer->bufInUse) { + if (!lexer->bufInUse) yajl_buf_clear(lexer->buf); + lexer->bufInUse = 1; + yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset); + lexer->bufOff = 0; + + if (tok != yajl_tok_eof) { + *outBuf = yajl_buf_data(lexer->buf); + *outLen = yajl_buf_len(lexer->buf); + lexer->bufInUse = 0; + } + } else if (tok != yajl_tok_error) { + *outBuf = jsonText + startOffset; + *outLen = *offset - startOffset; + } + + /* special case for strings. skip the quotes. */ + if (tok == yajl_tok_string || tok == yajl_tok_string_with_escapes) + { + assert(*outLen >= 2); + (*outBuf)++; + *outLen -= 2; + } + + /* remove comment delimeters */ + if (tok == yajl_tok_c_comment) + { + assert(*outLen >= 4); + (*outBuf)+= 2; + *outLen -= 4; + } + if (tok == yajl_tok_cpp_comment) + { + assert(*outLen >= 2); + (*outBuf)+= 2; + *outLen -= 2; + + if (*outLen >= 1 && (*outBuf)[(*outLen)-1] == 0x0a) + *outLen -= 1; + } + + +#ifdef YAJL_LEXER_DEBUG + if (tok == yajl_tok_error) { + printf("lexical error: %s\n", + yajl_lex_error_to_string(yajl_lex_get_error(lexer))); + } else if (tok == yajl_tok_eof) { + printf("EOF hit\n"); + } else { + printf("lexed %s: '", tokToStr(tok)); + fwrite(*outBuf, 1, *outLen, stdout); + printf("'\n"); + } +#endif + + return tok; +} + +const char * +yajl_lex_error_to_string(yajl_lex_error error) +{ + switch (error) { + case yajl_lex_e_ok: + return "ok, no error"; + case yajl_lex_string_invalid_utf8: + return "invalid bytes in UTF8 string."; + case yajl_lex_string_invalid_escaped_char: + return "inside a string, '\\' occurs before a character " + "which it may not."; + case yajl_lex_string_invalid_json_char: + return "invalid character inside string."; + case yajl_lex_string_invalid_hex_char: + return "invalid (non-hex) character occurs after '\\u' inside " + "string."; + case yajl_lex_invalid_char: + return "invalid char in json text."; + case yajl_lex_invalid_string: + return "invalid string in json text."; + case yajl_lex_missing_integer_after_exponent: + return "malformed number, a digit is required after the exponent."; + case yajl_lex_missing_integer_after_decimal: + return "malformed number, a digit is required after the " + "decimal point."; + case yajl_lex_missing_integer_after_minus: + return "malformed number, a digit is required after the " + "minus sign."; + case yajl_lex_unallowed_comment: + return "probable comment found in input text, comments are " + "not enabled."; + } + return "unknown error code"; +} + + +/** allows access to more specific information about the lexical + * error when yajl_lex_lex returns yajl_tok_error. */ +yajl_lex_error +yajl_lex_get_error(yajl_lexer lexer) +{ + if (lexer == NULL) return (yajl_lex_error) -1; + return lexer->error; +} + +unsigned int yajl_lex_current_line(yajl_lexer lexer) +{ + return lexer->lineOff; +} + +unsigned int yajl_lex_current_char(yajl_lexer lexer) +{ + return lexer->charOff; +} + +yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int offset) +{ + const unsigned char * outBuf; + unsigned int outLen; + unsigned int bufLen = yajl_buf_len(lexer->buf); + unsigned int bufOff = lexer->bufOff; + unsigned int bufInUse = lexer->bufInUse; + yajl_tok tok; + + tok = yajl_lex_lex(lexer, jsonText, jsonTextLen, &offset, + &outBuf, &outLen); + + lexer->bufOff = bufOff; + lexer->bufInUse = bufInUse; + yajl_buf_truncate(lexer->buf, bufLen); + + return tok; +} diff --git a/jcnf/yajl/yajl_lex.h b/jcnf/yajl/yajl_lex.h new file mode 100644 index 0000000..e1268ea --- /dev/null +++ b/jcnf/yajl/yajl_lex.h @@ -0,0 +1,135 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __YAJL_LEX_H__ +#define __YAJL_LEX_H__ + +#include "yajl_common.h" + +typedef enum { + yajl_tok_bool, + yajl_tok_colon, + yajl_tok_comma, + yajl_tok_eof, + yajl_tok_error, + yajl_tok_left_brace, + yajl_tok_left_bracket, + yajl_tok_null, + yajl_tok_right_brace, + yajl_tok_right_bracket, + + /* we differentiate between integers and doubles to allow the + * parser to interpret the number without re-scanning */ + yajl_tok_integer, + yajl_tok_double, + + /* we differentiate between strings which require further processing, + * and strings that do not */ + yajl_tok_string, + yajl_tok_string_with_escapes, + + /* we return the two types of comment tokens as well */ + yajl_tok_c_comment, + yajl_tok_cpp_comment + +} yajl_tok; + +typedef struct yajl_lexer_t * yajl_lexer; + +yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc, + unsigned int allowComments, + unsigned int validateUTF8); + +void yajl_lex_free(yajl_lexer lexer); + +/** + * run/continue a lex. "offset" is an input/output parameter. + * It should be initialized to zero for a + * new chunk of target text, and upon subsetquent calls with the same + * target text should passed with the value of the previous invocation. + * + * the client may be interested in the value of offset when an error is + * returned from the lexer. This allows the client to render useful +n * error messages. + * + * When you pass the next chunk of data, context should be reinitialized + * to zero. + * + * Finally, the output buffer is usually just a pointer into the jsonText, + * however in cases where the entity being lexed spans multiple chunks, + * the lexer will buffer the entity and the data returned will be + * a pointer into that buffer. + * + * This behavior is abstracted from client code except for the performance + * implications which require that the client choose a reasonable chunk + * size to get adequate performance. + */ +yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int * offset, + const unsigned char ** outBuf, unsigned int * outLen); + +/** have a peek at the next token, but don't move the lexer forward */ +yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText, + unsigned int jsonTextLen, unsigned int offset); + + +typedef enum { + yajl_lex_e_ok = 0, + yajl_lex_string_invalid_utf8, + yajl_lex_string_invalid_escaped_char, + yajl_lex_string_invalid_json_char, + yajl_lex_string_invalid_hex_char, + yajl_lex_invalid_char, + yajl_lex_invalid_string, + yajl_lex_missing_integer_after_decimal, + yajl_lex_missing_integer_after_exponent, + yajl_lex_missing_integer_after_minus, + yajl_lex_unallowed_comment +} yajl_lex_error; + +const char * yajl_lex_error_to_string(yajl_lex_error error); + +/** allows access to more specific information about the lexical + * error when yajl_lex_lex returns yajl_tok_error. */ +yajl_lex_error yajl_lex_get_error(yajl_lexer lexer); + +/** get the current offset into the most recently lexed json string. */ +unsigned int yajl_lex_current_offset(yajl_lexer lexer); + +/** get the number of lines lexed by this lexer instance */ +unsigned int yajl_lex_current_line(yajl_lexer lexer); + +/** get the number of chars lexed by this lexer instance since the last + * \n or \r */ +unsigned int yajl_lex_current_char(yajl_lexer lexer); + +#endif diff --git a/jcnf/yajl/yajl_parse.h b/jcnf/yajl/yajl_parse.h new file mode 100644 index 0000000..250d3e1 --- /dev/null +++ b/jcnf/yajl/yajl_parse.h @@ -0,0 +1,184 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file yajl_parse.h + * Interface to YAJL's JSON parsing facilities. + */ + +#include "yajl_common.h" + +#ifndef __YAJL_PARSE_H__ +#define __YAJL_PARSE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + /** error codes returned from this interface */ + typedef enum { + /** no error was encountered */ + yajl_status_ok, + /** a client callback returned zero, stopping the parse */ + yajl_status_client_canceled, + /** The parse cannot yet complete because more json input text + * is required, call yajl_parse with the next buffer of input text. + * (pertinent only when stream parsing) */ + yajl_status_insufficient_data, + /** An error occured during the parse. Call yajl_get_error for + * more information about the encountered error */ + yajl_status_error + } yajl_status; + + /** attain a human readable, english, string for an error */ + const char * YAJL_API yajl_status_to_string(yajl_status code); + + /** an opaque handle to a parser */ + typedef struct yajl_handle_t * yajl_handle; + + /** yajl is an event driven parser. this means as json elements are + * parsed, you are called back to do something with the data. The + * functions in this table indicate the various events for which + * you will be called back. Each callback accepts a "context" + * pointer, this is a void * that is passed into the yajl_parse + * function which the client code may use to pass around context. + * + * All callbacks return an integer. If non-zero, the parse will + * continue. If zero, the parse will be canceled and + * yajl_status_client_canceled will be returned from the parse. + * + * Note about handling of numbers: + * yajl will only convert numbers that can be represented in a double + * or a long int. All other numbers will be passed to the client + * in string form using the yajl_number callback. Furthermore, if + * yajl_number is not NULL, it will always be used to return numbers, + * that is yajl_integer and yajl_double will be ignored. If + * yajl_number is NULL but one of yajl_integer or yajl_double are + * defined, parsing of a number larger than is representable + * in a double or long int will result in a parse error. + */ + typedef struct { + int (* yajl_null)(void * ctx); + int (* yajl_boolean)(void * ctx, int boolVal); + int (* yajl_integer)(void * ctx, long integerVal); + int (* yajl_double)(void * ctx, double doubleVal); + /** A callback which passes the string representation of the number + * back to the client. Will be used for all numbers when present */ + int (* yajl_number)(void * ctx, const char * numberVal, + unsigned int numberLen); + + /** strings are returned as pointers into the JSON text when, + * possible, as a result, they are _not_ null padded */ + int (* yajl_string)(void * ctx, const unsigned char * stringVal, + unsigned int stringLen); + int (* yajl_c_comment)(void * ctx, const unsigned char * stringVal, + unsigned int stringLen); + + int (* yajl_cpp_comment)(void * ctx, const unsigned char * stringVal, + unsigned int stringLen); + + int (* yajl_start_map)(void * ctx); + int (* yajl_map_key)(void * ctx, const unsigned char * key, + unsigned int stringLen); + int (* yajl_end_map)(void * ctx); + + int (* yajl_start_array)(void * ctx); + int (* yajl_end_array)(void * ctx); + } yajl_callbacks; + + /** configuration structure for the generator */ + typedef struct { + /** if nonzero, javascript style comments will be allowed in + * the json input, both slash star and slash slash */ + unsigned int allowComments; + /** if nonzero, invalid UTF8 strings will cause a parse + * error */ + unsigned int checkUTF8; + } yajl_parser_config; + + /** allocate a parser handle + * \param callbacks a yajl callbacks structure specifying the + * functions to call when different JSON entities + * are encountered in the input text. May be NULL, + * which is only useful for validation. + * \param config configuration parameters for the parse. + * \param ctx a context pointer that will be passed to callbacks. + */ + yajl_handle YAJL_API yajl_alloc(const yajl_callbacks * callbacks, + const yajl_parser_config * config, + const yajl_alloc_funcs * allocFuncs, + void * ctx); + + /** free a parser handle */ + void YAJL_API yajl_free(yajl_handle handle); + + /** Parse some json! + * \param hand - a handle to the json parser allocated with yajl_alloc + * \param jsonText - a pointer to the UTF8 json text to be parsed + * \param jsonTextLength - the length, in bytes, of input text + */ + yajl_status YAJL_API yajl_parse(yajl_handle hand, + const unsigned char * jsonText, + unsigned int jsonTextLength); + + /** Parse any remaining buffered json. + * Since yajl is a stream-based parser, without an explicit end of + * input, yajl sometimes can't decide if content at the end of the + * stream is valid or not. For example, if "1" has been fed in, + * yajl can't know whether another digit is next or some character + * that would terminate the integer token. + * + * \param hand - a handle to the json parser allocated with yajl_alloc + */ + yajl_status yajl_parse_complete(yajl_handle hand); + + /** get an error string describing the state of the + * parse. + * + * If verbose is non-zero, the message will include the JSON + * text where the error occured, along with an arrow pointing to + * the specific char. + * + * A dynamically allocated string will be returned which should + * be freed with yajl_free_error + */ + unsigned char * YAJL_API yajl_get_error(yajl_handle hand, int verbose, + const unsigned char * jsonText, + unsigned int jsonTextLength); + + /** free an error returned from yajl_get_error */ + void YAJL_API yajl_free_error(yajl_handle hand, unsigned char * str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/jcnf/yajl/yajl_parser.c b/jcnf/yajl/yajl_parser.c new file mode 100644 index 0000000..3d0f07f --- /dev/null +++ b/jcnf/yajl/yajl_parser.c @@ -0,0 +1,505 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_lex.h" +#include "yajl_parser.h" +#include "yajl_encode.h" +#include "yajl_bytestack.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned char * +yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, + unsigned int jsonTextLen, int verbose) +{ + unsigned int offset = hand->errorOffset; + unsigned char * str; + const char * errorType = NULL; + const char * errorText = NULL; + char text[72]; + const char * arrow = " (right here) ------^\n"; + + if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) { + errorType = "parse"; + errorText = hand->parseError; + } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) { + errorType = "lexical"; + errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer)); + } else { + errorType = "unknown"; + } + + { + unsigned int memneeded = 0; + memneeded += strlen(errorType); + memneeded += strlen(" error"); + if (errorText != NULL) { + memneeded += strlen(": "); + memneeded += strlen(errorText); + } + str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); + str[0] = 0; + strcat((char *) str, errorType); + strcat((char *) str, " error"); + if (errorText != NULL) { + strcat((char *) str, ": "); + strcat((char *) str, errorText); + } + strcat((char *) str, "\n"); + } + + /* now we append as many spaces as needed to make sure the error + * falls at char 41, if verbose was specified */ + if (verbose) { + unsigned int start, end, i; + unsigned int spacesNeeded; + + spacesNeeded = (offset < 30 ? 40 - offset : 10); + start = (offset >= 30 ? offset - 30 : 0); + end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30); + + for (i=0;ialloc), (strlen((char *) str) + + strlen((char *) text) + + strlen(arrow) + 1)); + newStr[0] = 0; + strcat((char *) newStr, (char *) str); + strcat((char *) newStr, text); + strcat((char *) newStr, arrow); + YA_FREE(&(hand->alloc), str); + str = (unsigned char *) newStr; + } + } + return str; +} + +/* check for client cancelation */ +#define _CC_CHK(x) \ + if (!(x)) { \ + yajl_bs_set(hand->stateStack, yajl_state_parse_error); \ + hand->parseError = \ + "client cancelled parse via callback return value"; \ + return yajl_status_client_canceled; \ + } + + +yajl_status +yajl_do_parse(yajl_handle hand, unsigned int * offset, + const unsigned char * jsonText, unsigned int jsonTextLen) +{ + yajl_tok tok; + const unsigned char * buf; + unsigned int bufLen; + + around_again: + switch (yajl_bs_current(hand->stateStack)) { + case yajl_state_parse_complete: + return yajl_status_ok; + case yajl_state_lexical_error: + case yajl_state_parse_error: + hand->errorOffset = *offset; + return yajl_status_error; + case yajl_state_start: + case yajl_state_map_need_val: + case yajl_state_array_need_val: + case yajl_state_array_start: { + /* for arrays and maps, we advance the state for this + * depth, then push the state of the next depth. + * If an error occurs during the parsing of the nesting + * enitity, the state at this level will not matter. + * a state that needs pushing will be anything other + * than state_start */ + yajl_state stateToPush = yajl_state_start; + + tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, + offset, &buf, &bufLen); + + switch (tok) { + case yajl_tok_eof: + return yajl_status_insufficient_data; + case yajl_tok_error: + yajl_bs_set(hand->stateStack, yajl_state_lexical_error); + goto around_again; + case yajl_tok_c_comment: + if (hand->callbacks && hand->callbacks->yajl_c_comment) { + _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_cpp_comment: + if (hand->callbacks && hand->callbacks->yajl_cpp_comment) { + _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_string: + if (hand->callbacks && hand->callbacks->yajl_string) { + _CC_CHK(hand->callbacks->yajl_string(hand->ctx, + buf, bufLen)); + } + break; + case yajl_tok_string_with_escapes: + if (hand->callbacks && hand->callbacks->yajl_string) { + yajl_buf_clear(hand->decodeBuf); + yajl_string_decode(hand->decodeBuf, buf, bufLen); + _CC_CHK(hand->callbacks->yajl_string( + hand->ctx, yajl_buf_data(hand->decodeBuf), + yajl_buf_len(hand->decodeBuf))); + } + break; + case yajl_tok_bool: + if (hand->callbacks && hand->callbacks->yajl_boolean) { + _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx, + *buf == 't')); + } + break; + case yajl_tok_null: + if (hand->callbacks && hand->callbacks->yajl_null) { + _CC_CHK(hand->callbacks->yajl_null(hand->ctx)); + } + break; + case yajl_tok_left_bracket: + if (hand->callbacks && hand->callbacks->yajl_start_map) { + _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx)); + } + stateToPush = yajl_state_map_start; + break; + case yajl_tok_left_brace: + if (hand->callbacks && hand->callbacks->yajl_start_array) { + _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx)); + } + stateToPush = yajl_state_array_start; + break; + case yajl_tok_integer: + /* + * note. strtol does not respect the length of + * the lexical token. in a corner case where the + * lexed number is a integer with a trailing zero, + * immediately followed by the end of buffer, + * sscanf could run off into oblivion and cause a + * crash. for this reason we copy the integer + * (and doubles), into our parse buffer (the same + * one used for unescaping strings), before + * calling strtol. yajl_buf ensures null padding, + * so we're safe. + */ + if (hand->callbacks) { + if (hand->callbacks->yajl_number) { + _CC_CHK(hand->callbacks->yajl_number( + hand->ctx,(const char *) buf, bufLen)); + } else if (hand->callbacks->yajl_integer) { + long int i = 0; + yajl_buf_clear(hand->decodeBuf); + yajl_buf_append(hand->decodeBuf, buf, bufLen); + buf = yajl_buf_data(hand->decodeBuf); + i = strtol((const char *) buf, NULL, 10); + if ((i == LONG_MIN || i == LONG_MAX) && + errno == ERANGE) + { + yajl_bs_set(hand->stateStack, + yajl_state_parse_error); + hand->parseError = "integer overflow" ; + /* try to restore error offset */ + if (*offset >= bufLen) *offset -= bufLen; + else *offset = 0; + goto around_again; + } + _CC_CHK(hand->callbacks->yajl_integer(hand->ctx, + i)); + } + } + break; + case yajl_tok_double: + if (hand->callbacks) { + if (hand->callbacks->yajl_number) { + _CC_CHK(hand->callbacks->yajl_number( + hand->ctx, (const char *) buf, bufLen)); + } else if (hand->callbacks->yajl_double) { + double d = 0.0; + yajl_buf_clear(hand->decodeBuf); + yajl_buf_append(hand->decodeBuf, buf, bufLen); + buf = yajl_buf_data(hand->decodeBuf); + d = strtod((char *) buf, NULL); + if ((d == HUGE_VAL || d == -HUGE_VAL) && + errno == ERANGE) + { + yajl_bs_set(hand->stateStack, + yajl_state_parse_error); + hand->parseError = "numeric (floating point) " + "overflow"; + /* try to restore error offset */ + if (*offset >= bufLen) *offset -= bufLen; + else *offset = 0; + goto around_again; + } + _CC_CHK(hand->callbacks->yajl_double(hand->ctx, + d)); + } + } + break; + case yajl_tok_right_brace: { + if (yajl_bs_current(hand->stateStack) == + yajl_state_array_start) + { + if (hand->callbacks && + hand->callbacks->yajl_end_array) + { + _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); + } + yajl_bs_pop(hand->stateStack); + goto around_again; + } + /* intentional fall-through */ + } + case yajl_tok_colon: + case yajl_tok_comma: + case yajl_tok_right_bracket: + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = + "unallowed token at this point in JSON text"; + goto around_again; + default: + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = "invalid token, internal error"; + goto around_again; + } + /* got a value. transition depends on the state we're in. */ + { + yajl_state s = yajl_bs_current(hand->stateStack); + if (s == yajl_state_start) { + yajl_bs_set(hand->stateStack, yajl_state_parse_complete); + } else if (s == yajl_state_map_need_val) { + yajl_bs_set(hand->stateStack, yajl_state_map_got_val); + } else { + yajl_bs_set(hand->stateStack, yajl_state_array_got_val); + } + } + if (stateToPush != yajl_state_start) { + yajl_bs_push(hand->stateStack, stateToPush); + } + + goto around_again; + } + case yajl_state_map_start: + case yajl_state_map_need_key: { + /* only difference between these two states is that in + * start '}' is valid, whereas in need_key, we've parsed + * a comma, and a string key _must_ follow */ + tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, + offset, &buf, &bufLen); + switch (tok) { + case yajl_tok_eof: + return yajl_status_insufficient_data; + case yajl_tok_error: + yajl_bs_set(hand->stateStack, yajl_state_lexical_error); + goto around_again; + case yajl_tok_string_with_escapes: + if (hand->callbacks && hand->callbacks->yajl_map_key) { + yajl_buf_clear(hand->decodeBuf); + yajl_string_decode(hand->decodeBuf, buf, bufLen); + buf = yajl_buf_data(hand->decodeBuf); + bufLen = yajl_buf_len(hand->decodeBuf); + } + /* intentional fall-through */ + case yajl_tok_string: + if (hand->callbacks && hand->callbacks->yajl_map_key) { + _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf, + bufLen)); + } + yajl_bs_set(hand->stateStack, yajl_state_map_sep); + goto around_again; + case yajl_tok_c_comment: + if (hand->callbacks && hand->callbacks->yajl_c_comment) { + _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_cpp_comment: + if (hand->callbacks && hand->callbacks->yajl_cpp_comment) { + _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_right_bracket: + if (yajl_bs_current(hand->stateStack) == + yajl_state_map_start) + { + if (hand->callbacks && hand->callbacks->yajl_end_map) { + _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); + } + yajl_bs_pop(hand->stateStack); + goto around_again; + } + default: + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = + "invalid object key (must be a string)"; + goto around_again; + } + } + case yajl_state_map_sep: { + tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, + offset, &buf, &bufLen); + switch (tok) { + case yajl_tok_c_comment: + if (hand->callbacks && hand->callbacks->yajl_c_comment) { + _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_cpp_comment: + if (hand->callbacks && hand->callbacks->yajl_cpp_comment) { + _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_colon: + yajl_bs_set(hand->stateStack, yajl_state_map_need_val); + goto around_again; + case yajl_tok_eof: + return yajl_status_insufficient_data; + case yajl_tok_error: + yajl_bs_set(hand->stateStack, yajl_state_lexical_error); + goto around_again; + default: + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = "object key and value must " + "be separated by a colon (':')"; + goto around_again; + } + } + case yajl_state_map_got_val: { + tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, + offset, &buf, &bufLen); + switch (tok) { + case yajl_tok_c_comment: + if (hand->callbacks && hand->callbacks->yajl_c_comment) { + _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_cpp_comment: + if (hand->callbacks && hand->callbacks->yajl_cpp_comment) { + _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_right_bracket: + if (hand->callbacks && hand->callbacks->yajl_end_map) { + _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx)); + } + yajl_bs_pop(hand->stateStack); + goto around_again; + case yajl_tok_comma: + yajl_bs_set(hand->stateStack, yajl_state_map_need_key); + goto around_again; + case yajl_tok_eof: + return yajl_status_insufficient_data; + case yajl_tok_error: + yajl_bs_set(hand->stateStack, yajl_state_lexical_error); + goto around_again; + default: + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = "after key and value, inside map, " + "I expect ',' or '}'"; + /* try to restore error offset */ + if (*offset >= bufLen) *offset -= bufLen; + else *offset = 0; + goto around_again; + } + } + case yajl_state_array_got_val: { + tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen, + offset, &buf, &bufLen); + switch (tok) { + case yajl_tok_c_comment: + if (hand->callbacks && hand->callbacks->yajl_c_comment) { + _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_cpp_comment: + if (hand->callbacks && hand->callbacks->yajl_cpp_comment) { + _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx, + buf, bufLen)); + } + goto around_again; + case yajl_tok_right_brace: + if (hand->callbacks && hand->callbacks->yajl_end_array) { + _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx)); + } + yajl_bs_pop(hand->stateStack); + goto around_again; + case yajl_tok_comma: + yajl_bs_set(hand->stateStack, yajl_state_array_need_val); + goto around_again; + case yajl_tok_eof: + return yajl_status_insufficient_data; + case yajl_tok_error: + yajl_bs_set(hand->stateStack, yajl_state_lexical_error); + goto around_again; + default: + yajl_bs_set(hand->stateStack, yajl_state_parse_error); + hand->parseError = + "after array element, I expect ',' or ']'"; + goto around_again; + } + } + } + + abort(); + return yajl_status_error; +} + diff --git a/jcnf/yajl/yajl_parser.h b/jcnf/yajl/yajl_parser.h new file mode 100644 index 0000000..f8bc8ee --- /dev/null +++ b/jcnf/yajl/yajl_parser.h @@ -0,0 +1,79 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __YAJL_PARSER_H__ +#define __YAJL_PARSER_H__ + +#include "yajl_parse.h" +#include "yajl_bytestack.h" +#include "yajl_buf.h" + + +typedef enum { + yajl_state_start = 0, + yajl_state_parse_complete, + yajl_state_parse_error, + yajl_state_lexical_error, + yajl_state_map_start, + yajl_state_map_sep, + yajl_state_map_need_val, + yajl_state_map_got_val, + yajl_state_map_need_key, + yajl_state_array_start, + yajl_state_array_got_val, + yajl_state_array_need_val +} yajl_state; + +struct yajl_handle_t { + const yajl_callbacks * callbacks; + void * ctx; + yajl_lexer lexer; + const char * parseError; + unsigned int errorOffset; + /* temporary storage for decoded strings */ + yajl_buf decodeBuf; + /* a stack of states. access with yajl_state_XXX routines */ + yajl_bytestack stateStack; + /* memory allocation routines */ + yajl_alloc_funcs alloc; +}; + +yajl_status +yajl_do_parse(yajl_handle handle, unsigned int * offset, + const unsigned char * jsonText, unsigned int jsonTextLen); + +unsigned char * +yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, + unsigned int jsonTextLen, int verbose); + + +#endif diff --git a/jcnf/yajl/yajl_test.c b/jcnf/yajl/yajl_test.c new file mode 100644 index 0000000..de43570 --- /dev/null +++ b/jcnf/yajl/yajl_test.c @@ -0,0 +1,293 @@ +/* + * Copyright 2007-2009, Lloyd Hilaiel. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. Neither the name of Lloyd Hilaiel nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "yajl_parse.h" +#include "yajl_gen.h" + +#include +#include +#include + +#include + +/* memory debugging routines */ +typedef struct +{ + unsigned int numFrees; + unsigned int numMallocs; + /* XXX: we really need a hash table here with per-allocation + * information */ +} yajlTestMemoryContext; + +/* cast void * into context */ +#define TEST_CTX(vptr) ((yajlTestMemoryContext *) (vptr)) + +static void yajlTestFree(void * ctx, void * ptr) +{ + assert(ptr != NULL); + TEST_CTX(ctx)->numFrees++; + free(ptr); +} + +static void * yajlTestMalloc(void * ctx, unsigned int sz) +{ + assert(sz != 0); + TEST_CTX(ctx)->numMallocs++; + return malloc(sz); +} + +static void * yajlTestRealloc(void * ctx, void * ptr, unsigned int sz) +{ + if (ptr == NULL) { + assert(sz != 0); + TEST_CTX(ctx)->numMallocs++; + } else if (sz == 0) { + TEST_CTX(ctx)->numFrees++; + } + + return realloc(ptr, sz); +} + + +/* begin parsing callback routines */ +#define BUF_SIZE 2048 + +static int test_yajl_null(void *ctx) +{ + printf("null\n"); + return 1; +} + +static int test_yajl_boolean(void * ctx, int boolVal) +{ + printf("bool: %s\n", boolVal ? "true" : "false"); + return 1; +} + +static int test_yajl_integer(void *ctx, long integerVal) +{ + printf("integer: %ld\n", integerVal); + return 1; +} + +static int test_yajl_double(void *ctx, double doubleVal) +{ + printf("double: %g\n", doubleVal); + return 1; +} + +static int test_yajl_string(void *ctx, const unsigned char * stringVal, + unsigned int stringLen) +{ + printf("string: '"); + fwrite(stringVal, 1, stringLen, stdout); + printf("'\n"); + return 1; +} + +static int test_yajl_map_key(void *ctx, const unsigned char * stringVal, + unsigned int stringLen) +{ + char * str = (char *) malloc(stringLen + 1); + str[stringLen] = 0; + memcpy(str, stringVal, stringLen); + printf("key: '%s'\n", str); + free(str); + return 1; +} + +static int test_yajl_start_map(void *ctx) +{ + printf("map open '{'\n"); + return 1; +} + + +static int test_yajl_end_map(void *ctx) +{ + printf("map close '}'\n"); + return 1; +} + +static int test_yajl_start_array(void *ctx) +{ + printf("array open '['\n"); + return 1; +} + +static int test_yajl_end_array(void *ctx) +{ + printf("array close ']'\n"); + return 1; +} + +static yajl_callbacks callbacks = { + test_yajl_null, + test_yajl_boolean, + test_yajl_integer, + test_yajl_double, + NULL, + test_yajl_string, + NULL, + NULL, + test_yajl_start_map, + test_yajl_map_key, + test_yajl_end_map, + test_yajl_start_array, + test_yajl_end_array +}; + +static void usage(const char * progname) +{ + fprintf(stderr, + "usage: %s [options] \n" + " -c allow comments\n" + " -b set the read buffer size\n", + progname); + exit(1); +} + +int +main(int argc, char ** argv) +{ + yajl_handle hand; + const char * fileName; + static unsigned char * fileData = NULL; + unsigned int bufSize = BUF_SIZE; + yajl_status stat; + size_t rd; + yajl_parser_config cfg = { 0, 1 }; + int i, j, done; + + /* memory allocation debugging: allocate a structure which collects + * statistics */ + yajlTestMemoryContext memCtx = { 0,0 }; + + /* memory allocation debugging: allocate a structure which holds + * allocation routines */ + yajl_alloc_funcs allocFuncs = { + yajlTestMalloc, + yajlTestRealloc, + yajlTestFree, + (void *) NULL + }; + + allocFuncs.ctx = (void *) &memCtx; + + /* check arguments. We expect exactly one! */ + for (i=1;i= argc) usage(argv[0]); + + /* validate integer */ + for (j=0;j<(int)strlen(argv[i]);j++) { + if (argv[i][j] <= '9' && argv[i][j] >= '0') continue; + fprintf(stderr, "-b requires an integer argument. '%s' " + "is invalid\n", argv[i]); + usage(argv[0]); + } + + bufSize = atoi(argv[i]); + if (!bufSize) { + fprintf(stderr, "%d is an invalid buffer size\n", + bufSize); + } + } else { + fprintf(stderr, "invalid command line option: '%s'\n", + argv[i]); + usage(argv[0]); + } + } + + fileData = (unsigned char *) malloc(bufSize); + + if (fileData == NULL) { + fprintf(stderr, + "failed to allocate read buffer of %u bytes, exiting.", + bufSize); + exit(2); + } + + fileName = argv[argc-1]; + + /* ok. open file. let's read and parse */ + hand = yajl_alloc(&callbacks, &cfg, &allocFuncs, NULL); + + done = 0; + while (!done) { + rd = fread((void *) fileData, 1, bufSize, stdin); + + if (rd == 0) { + if (!feof(stdin)) { + fprintf(stderr, "error reading from '%s'\n", fileName); + break; + } + done = 1; + } + + if (done) + /* parse any remaining buffered data */ + stat = yajl_parse_complete(hand); + else + /* read file data, pass to parser */ + stat = yajl_parse(hand, fileData, rd); + + if (stat != yajl_status_insufficient_data && + stat != yajl_status_ok) + { + unsigned char * str = yajl_get_error(hand, 0, fileData, rd); + fflush(stdout); + fprintf(stderr, "%s", (char *) str); + yajl_free_error(hand, str); + break; + } + } + + yajl_free(hand); + free(fileData); + + /* finally, print out some memory statistics */ + +/* (lth) only print leaks here, as allocations and frees may vary depending + * on read buffer size, causing false failures. + * + * printf("allocations:\t%u\n", memCtx.numMallocs); + * printf("frees:\t\t%u\n", memCtx.numFrees); +*/ + fflush(stderr); + fflush(stdout); + printf("memory leaks:\t%u\n", memCtx.numMallocs - memCtx.numFrees); + + return 0; +} -- cgit v1.2.3