summaryrefslogtreecommitdiff
path: root/jcnf
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-09-01 13:56:46 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-09-01 13:56:46 +0200
commit22f703cab05b7cd368f4de9e03991b7664dc5022 (patch)
tree6f4d50beaa42328e24b1c6b56b6ec059e4ef21a5 /jcnf
Initial import of argyll version 1.5.1-8debian/1.5.1-8
Diffstat (limited to 'jcnf')
-rw-r--r--jcnf/Jamfile32
-rw-r--r--jcnf/Makefile.am15
-rw-r--r--jcnf/Readme.txt22
-rw-r--r--jcnf/afiles7
-rw-r--r--jcnf/jcnf.c1248
-rw-r--r--jcnf/jcnf.h199
-rw-r--r--jcnf/test.c161
-rw-r--r--jcnf/test.jcnf33
-rw-r--r--jcnf/yajl/COPYING29
-rw-r--r--jcnf/yajl/ChangeLog88
-rw-r--r--jcnf/yajl/Jamfile30
-rw-r--r--jcnf/yajl/Makefile.am13
-rw-r--r--jcnf/yajl/README68
-rw-r--r--jcnf/yajl/TODO9
-rw-r--r--jcnf/yajl/YAJL.dxy1258
-rw-r--r--jcnf/yajl/YAJLDoc.cmake26
-rw-r--r--jcnf/yajl/afiles84
-rw-r--r--jcnf/yajl/cases/array.json6
-rw-r--r--jcnf/yajl/cases/array.json.gold22
-rw-r--r--jcnf/yajl/cases/bogus_char.json4
-rw-r--r--jcnf/yajl/cases/bogus_char.json.gold9
-rw-r--r--jcnf/yajl/cases/codepoints_from_unicode_org.json1
-rw-r--r--jcnf/yajl/cases/codepoints_from_unicode_org.json.gold1
-rw-r--r--jcnf/yajl/cases/dc_simple_with_comments.json11
-rw-r--r--jcnf/yajl/cases/dc_simple_with_comments.json.gold4
-rw-r--r--jcnf/yajl/cases/deep_arrays.json1
-rw-r--r--jcnf/yajl/cases/deep_arrays.json.gold2048
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case.json1
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case.json.gold35
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json1
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold35
-rw-r--r--jcnf/yajl/cases/doubles.json1
-rw-r--r--jcnf/yajl/cases/doubles.json.gold6
-rw-r--r--jcnf/yajl/cases/empty_array.json1
-rw-r--r--jcnf/yajl/cases/empty_array.json.gold2
-rw-r--r--jcnf/yajl/cases/escaped_bulgarian.json4
-rw-r--r--jcnf/yajl/cases/escaped_bulgarian.json.gold6
-rw-r--r--jcnf/yajl/cases/escaped_foobar.json1
-rw-r--r--jcnf/yajl/cases/escaped_foobar.json.gold1
-rw-r--r--jcnf/yajl/cases/integers.json3
-rw-r--r--jcnf/yajl/cases/integers.json.gold13
-rw-r--r--jcnf/yajl/cases/invalid_utf8.json1
-rw-r--r--jcnf/yajl/cases/invalid_utf8.json.gold2
-rw-r--r--jcnf/yajl/cases/isolated_surrogate_marker.json1
-rw-r--r--jcnf/yajl/cases/isolated_surrogate_marker.json.gold1
-rw-r--r--jcnf/yajl/cases/leading_zero_in_number.json1
-rw-r--r--jcnf/yajl/cases/leading_zero_in_number.json.gold4
-rw-r--r--jcnf/yajl/cases/lonely_minus_sign.json7
-rw-r--r--jcnf/yajl/cases/lonely_minus_sign.json.gold8
-rw-r--r--jcnf/yajl/cases/missing_integer_after_decimal_point.json1
-rw-r--r--jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold1
-rw-r--r--jcnf/yajl/cases/missing_integer_after_exponent.json1
-rw-r--r--jcnf/yajl/cases/missing_integer_after_exponent.json.gold1
-rw-r--r--jcnf/yajl/cases/non_utf8_char_in_string.json1
-rw-r--r--jcnf/yajl/cases/non_utf8_char_in_string.json.gold7
-rw-r--r--jcnf/yajl/cases/nulls_and_bools.json5
-rw-r--r--jcnf/yajl/cases/nulls_and_bools.json.gold8
-rw-r--r--jcnf/yajl/cases/simple.json5
-rw-r--r--jcnf/yajl/cases/simple.json.gold8
-rw-r--r--jcnf/yajl/cases/simple_with_comments.json11
-rw-r--r--jcnf/yajl/cases/simple_with_comments.json.gold8
-rw-r--r--jcnf/yajl/cases/string_invalid_escape.json1
-rw-r--r--jcnf/yajl/cases/string_invalid_escape.json.gold2
-rw-r--r--jcnf/yajl/cases/string_invalid_hex_char.json1
-rw-r--r--jcnf/yajl/cases/string_invalid_hex_char.json.gold1
-rw-r--r--jcnf/yajl/cases/string_with_escapes.json3
-rw-r--r--jcnf/yajl/cases/string_with_escapes.json.gold6
-rw-r--r--jcnf/yajl/cases/string_with_invalid_newline.json2
-rw-r--r--jcnf/yajl/cases/string_with_invalid_newline.json.gold1
-rw-r--r--jcnf/yajl/cases/unescaped_bulgarian.json1
-rw-r--r--jcnf/yajl/cases/unescaped_bulgarian.json.gold3
-rw-r--r--jcnf/yajl/configure94
-rw-r--r--jcnf/yajl/json_reformat.c204
-rw-r--r--jcnf/yajl/json_verify.c129
-rw-r--r--jcnf/yajl/rfc4627.txt3
-rw-r--r--jcnf/yajl/run_tests.sh61
-rw-r--r--jcnf/yajl/yajl.c152
-rw-r--r--jcnf/yajl/yajl_alloc.c65
-rw-r--r--jcnf/yajl/yajl_alloc.h50
-rw-r--r--jcnf/yajl/yajl_buf.c119
-rw-r--r--jcnf/yajl/yajl_buf.h73
-rw-r--r--jcnf/yajl/yajl_bytestack.h85
-rw-r--r--jcnf/yajl/yajl_common.h85
-rw-r--r--jcnf/yajl/yajl_encode.c179
-rw-r--r--jcnf/yajl/yajl_encode.h44
-rw-r--r--jcnf/yajl/yajl_gen.c381
-rw-r--r--jcnf/yajl/yajl_gen.h129
-rw-r--r--jcnf/yajl/yajl_lex.c753
-rw-r--r--jcnf/yajl/yajl_lex.h135
-rw-r--r--jcnf/yajl/yajl_parse.h184
-rw-r--r--jcnf/yajl/yajl_parser.c505
-rw-r--r--jcnf/yajl/yajl_parser.h79
-rw-r--r--jcnf/yajl/yajl_test.c293
93 files changed, 9444 insertions, 0 deletions
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 <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef NT
+#include <sys/file.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+
+#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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#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 <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> 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 <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> 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 folders contents into a users 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 <filename>\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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 <http://www.ietf.org/rfc/rfc4627.txt>
+
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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+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 <stdlib.h>
+
+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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+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 <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+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;_i<g->depth;_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 <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#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 <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+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;i<spacesNeeded;i++) text[i] = ' ';
+
+ for (;start < end;start++, i++) {
+ if (jsonText[start] != '\n' && jsonText[start] != '\r')
+ {
+ text[i] = jsonText[start];
+ }
+ else
+ {
+ text[i] = ' ';
+ }
+ }
+ assert(i <= 71);
+ text[i++] = '\n';
+ text[i] = 0;
+ {
+ char * newStr = (char *)
+ YA_MALLOC(&(hand->alloc), (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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+/* 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] <filename>\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;i++) {
+ if (!strcmp("-c", argv[i])) {
+ cfg.allowComments = 1;
+ } else if (!strcmp("-b", argv[i])) {
+ if (++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;
+}