summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLloyd Hilaiel <lloyd@hilaiel.com>2011-04-21 09:36:26 -0600
committerLloyd Hilaiel <lloyd@hilaiel.com>2011-04-21 13:55:45 -0600
commit0858bb341280956947df1cfae33eb5ac6ecfe6f7 (patch)
tree2f61e004f7a892f00f6f34d38a8a194618400b59
parent6aefdaab38d81f33c46e33353c5a156884ea022d (diff)
downloadyajl-0858bb341280956947df1cfae33eb5ac6ecfe6f7.tar.gz
rework programmatic configuration of yajl. both generator and parser now have a yajl_XXX_config() function that accepts varargs so that configuration is simple, and new config options can be added in the future that preserve backwards binary compatibility. closes #23.
-rw-r--r--reformatter/json_reformat.c65
-rw-r--r--src/api/yajl_gen.h61
-rw-r--r--src/api/yajl_parse.h89
-rw-r--r--src/yajl.c75
-rw-r--r--src/yajl_gen.c106
-rw-r--r--src/yajl_parser.c8
-rw-r--r--src/yajl_parser.h4
-rw-r--r--test/cases/ac_difficult_json_c_test_case_with_comments.json (renamed from test/cases/difficult_json_c_test_case_with_comments.json)0
-rw-r--r--test/cases/ac_difficult_json_c_test_case_with_comments.json.gold (renamed from test/cases/difficult_json_c_test_case_with_comments.json.gold)0
-rw-r--r--test/cases/ac_simple_with_comments.json (renamed from test/cases/dc_simple_with_comments.json)0
-rw-r--r--test/cases/ac_simple_with_comments.json.gold9
-rw-r--r--test/cases/ag_false_then_garbage.json (renamed from test/cases/false_then_garbage.json)0
-rw-r--r--test/cases/ag_false_then_garbage.json.gold (renamed from test/cases/false_then_garbage.json.gold)0
-rw-r--r--test/cases/ag_null_then_garbage.json (renamed from test/cases/null_then_garbage.json)0
-rw-r--r--test/cases/ag_null_then_garbage.json.gold (renamed from test/cases/null_then_garbage.json.gold)0
-rw-r--r--test/cases/ag_true_then_garbage.json (renamed from test/cases/true_then_garbage.json)0
-rw-r--r--test/cases/ag_true_then_garbage.json.gold (renamed from test/cases/true_then_garbage.json.gold)0
-rw-r--r--test/cases/ap_array_open.json (renamed from test/cases/array_open.json)0
-rw-r--r--test/cases/ap_array_open.json.gold (renamed from test/cases/array_open.json.gold)0
-rw-r--r--test/cases/ap_eof_str.json (renamed from test/cases/eof_str.json)0
-rw-r--r--test/cases/ap_eof_str.json.gold (renamed from test/cases/eof_str.json.gold)0
-rw-r--r--test/cases/ap_map_open.json (renamed from test/cases/map_open.json)0
-rw-r--r--test/cases/ap_map_open.json.gold (renamed from test/cases/map_open.json.gold)0
-rw-r--r--test/cases/ap_partial_ok.json (renamed from test/cases/partial_ok.json)0
-rw-r--r--test/cases/ap_partial_ok.json.gold (renamed from test/cases/partial_ok.json.gold)0
-rw-r--r--test/cases/dc_simple_with_comments.json.gold5
-rw-r--r--test/cases/multiple.json.gold1
-rw-r--r--test/cases/simple_with_comments.json.gold6
-rwxr-xr-xtest/run_tests.sh43
-rw-r--r--test/yajl_test.c25
-rw-r--r--verify/json_verify.c51
31 files changed, 290 insertions, 258 deletions
diff --git a/reformatter/json_reformat.c b/reformatter/json_reformat.c
index 070ca46..ddcab01 100644
--- a/reformatter/json_reformat.c
+++ b/reformatter/json_reformat.c
@@ -119,13 +119,18 @@ main(int argc, char ** argv)
yajl_handle hand;
static unsigned char fileData[65536];
/* generator config */
- yajl_gen_config conf = { 1, " " };
- yajl_gen g;
+ yajl_gen g;
yajl_status stat;
size_t rd;
- /* allow comments */
- yajl_parser_config cfg = { 1, 1 };
- int retval = 0, done = 0;
+ int retval = 0;
+
+ g = yajl_gen_alloc(NULL);
+ yajl_gen_config(g, yajl_gen_beautify, 1);
+
+ /* ok. open file. let's read and parse */
+ hand = yajl_alloc(&callbacks, NULL, (void *) g);
+ /* and let's allow comments by default */
+ yajl_config(hand, yajl_allow_comments, 1);
/* check arguments.*/
int a = 1;
@@ -134,10 +139,10 @@ main(int argc, char ** argv)
for ( i=1; i < strlen(argv[a]); i++) {
switch (argv[a][i]) {
case 'm':
- conf.beautify = 0;
+ yajl_gen_config(g, yajl_gen_beautify, 0);
break;
case 'u':
- cfg.checkUTF8 = 0;
+ yajl_config(hand, yajl_dont_validate_strings, 1);
break;
default:
fprintf(stderr, "unrecognized option: '%c'\n\n", argv[a][i]);
@@ -149,41 +154,26 @@ main(int argc, char ** argv)
if (a < argc) {
usage(argv[0]);
}
-
- g = yajl_gen_alloc(&conf, NULL);
- /* ok. open file. let's read and parse */
- hand = yajl_alloc(&callbacks, &cfg, NULL, (void *) g);
-
- while (!done) {
+
+
+ for (;;) {
rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);
-
+
if (rd == 0) {
if (!feof(stdin)) {
fprintf(stderr, "error on file read.\n");
retval = 1;
- break;
}
- done = 1;
+ break;
}
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)
+
+ stat = yajl_parse(hand, fileData, rd);
+
+ if (stat != yajl_status_ok) break;
+
{
- unsigned char * str = yajl_get_error(hand, 1, fileData, rd);
- fprintf(stderr, "%s", (const char *) str);
- yajl_free_error(hand, str);
- retval = 1;
- break;
- } else {
const unsigned char * buf;
size_t len;
yajl_gen_get_buf(g, &buf, &len);
@@ -192,8 +182,17 @@ main(int argc, char ** argv)
}
}
+ stat = yajl_parse_complete(hand);
+
+ if (stat != yajl_status_ok) {
+ unsigned char * str = yajl_get_error(hand, 1, fileData, rd);
+ fprintf(stderr, "%s", (const char *) str);
+ yajl_free_error(hand, str);
+ retval = 1;
+ }
+
yajl_gen_free(g);
yajl_free(hand);
-
+
return retval;
}
diff --git a/src/api/yajl_gen.h b/src/api/yajl_gen.h
index 4d229ec..b7c475f 100644
--- a/src/api/yajl_gen.h
+++ b/src/api/yajl_gen.h
@@ -60,15 +60,35 @@ extern "C" {
const char * str,
size_t len);
- /** configuration structure for the generator */
- typedef struct {
+ /** configuration parameters for the parser, these may be passed to
+ * yajl_gen_config() along with option specific argument(s). In general,
+ * all configuration parameters default to *off*. */
+ typedef enum {
/** 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;
+ yajl_gen_beautify = 0x01,
+ /**
+ * Set an indent string which is used when yajl_gen_beautify
+ * is enabled. Maybe something like \\t or some number of
+ * spaces. The default is four spaces ' '.
+ */
+ yajl_gen_indent_string = 0x02,
+ /**
+ * Set a function and context argument that should be used to
+ * output generated json. the function should conform to the
+ * yajl_print_t prototype while the context argument is a
+ * void * of your choosing.
+ *
+ * example:
+ * yajl_gen_config(g, yajl_gen_print_callback, myFunc, myVoidPtr);
+ */
+ yajl_gen_print_callback = 0x04
+ } yajl_gen_option;
+
+ /** allow the modification of generator options subsequent to handle
+ * allocation (via yajl_alloc)
+ * \returns zero in case of errors, non-zero otherwise
+ */
+ YAJL_API int yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...);
/** allocate a generator handle
* \param config a pointer to a structure containing parameters which
@@ -80,30 +100,7 @@ extern "C" {
*
* \returns an allocated handle on success, NULL on failure (bad params)
*/
- YAJL_API yajl_gen yajl_gen_alloc(const yajl_gen_config * config,
- const yajl_alloc_funcs * allocFuncs);
-
- /** allocate a generator handle that will print to the specified
- * callback rather than storing the results in an internal buffer.
- * \param callback a pointer to a printer function. May be NULL
- * in which case, the results will be store in an
- * internal buffer.
- * \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.
- * \param ctx a context pointer that will be passed to the
- * printer callback.
- *
- * \returns an allocated handle on success, NULL on failure (bad params)
- */
- YAJL_API yajl_gen yajl_gen_alloc2(const yajl_print_t callback,
- const yajl_gen_config * config,
- const yajl_alloc_funcs * allocFuncs,
- void * ctx);
+ YAJL_API yajl_gen yajl_gen_alloc(const yajl_alloc_funcs * allocFuncs);
/** free a generator handle */
YAJL_API void yajl_gen_free(yajl_gen handle);
diff --git a/src/api/yajl_parse.h b/src/api/yajl_parse.h
index 9c85496..0b868db 100644
--- a/src/api/yajl_parse.h
+++ b/src/api/yajl_parse.h
@@ -35,8 +35,6 @@ extern "C" {
yajl_status_ok,
/** a client callback returned zero, stopping the parse */
yajl_status_client_canceled,
- /** not returned. here for cmpatability */
- yajl_status_insufficient_data,
/** An error occured during the parse. Call yajl_get_error for
* more information about the encountered error */
yajl_status_error
@@ -93,49 +91,74 @@ extern "C" {
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 afs memory allocation functions, may be NULL for to use
+ * C runtime library routines (malloc and friends)
* \param ctx a context pointer that will be passed to callbacks.
*/
YAJL_API yajl_handle yajl_alloc(const yajl_callbacks * callbacks,
- const yajl_parser_config * config,
- const yajl_alloc_funcs * allocFuncs,
+ yajl_alloc_funcs * afs,
void * ctx);
- /**
- * Forbid trailing garbage from following a JSON document.
- * Whitespace is not considered garbage.
- */
- YAJL_API void yajl_forbid_trailing_garbage(yajl_handle h);
-
- /**
- * Allow multiple values to be parsed by a single handle.
- * The entire text must be valid JSON, and values can be seperated
- * by any kind of whitespace.
- */
- YAJL_API void yajl_allow_multiple_values(yajl_handle h);
-
- /**
- * Setting this flag causes the handle to enter an error
- * state if yajl_parse_complete is called in the middle of
- * a value.
+ /** configuration parameters for the parser, these may be passed to
+ * yajl_config() along with option specific argument(s). In general,
+ * all configuration parameters default to *off*. */
+ typedef enum {
+ /** Ignore javascript style comments present in
+ * JSON input. Non-standard, but rather fun
+ * arguments: toggled off with integer zero, on otherwise.
+ *
+ * example:
+ * yajl_config(h, yajl_allow_comments, 1); // turn comment support on
+ */
+ yajl_allow_comments = 0x01,
+ /**
+ * When set the parser will verify that all strings in JSON input are
+ * valid UTF8 and will emit a parse error if this is not so. When set,
+ * this option makes parsing slightly more expensive (~10%) (XXX: get real numbers)
+ *
+ * example:
+ * yajl_config(h, yajl_dont_validate_strings, 1); // disable utf8 checking
+ */
+ yajl_dont_validate_strings = 0x02,
+ /**
+ * By default, upon calls to yajl_parse_complete(), yajl will
+ * ensure the entire input text was consumed and will raise an error
+ * otherwise. Enabling this flag will cause yajl to disable this
+ * check. This can be useful when parsing json out of a that contains more
+ * than a single JSON document.
+ */
+ yajl_allow_trailing_garbage = 0x04,
+ /**
+ * Allow multiple values to be parsed by a single handle. The
+ * entire text must be valid JSON, and values can be seperated
+ * by any kind of whitespace. This flag will change the
+ * behavior of the parser, and cause it continue parsing after
+ * a value is parsed, rather than transitioning into a
+ * complete state. This option can be useful when parsing multiple
+ * values from an input stream.
+ */
+ yajl_allow_multiple_values = 0x08,
+ /**
+ * When yajl_parse_complete() is called the parser will
+ * check that the top level value was completely consumed. I.E.,
+ * if called whilst in the middle of parsing a value
+ * yajl will enter an error state (premature EOF). Setting this
+ * flag suppresses that check and the corresponding error.
+ */
+ yajl_allow_partial_values = 0x10
+ } yajl_option;
+
+ /** allow the modification of parser options subsequent to handle
+ * allocation (via yajl_alloc)
+ * \returns zero in case of errors, non-zero otherwise
*/
- YAJL_API void yajl_forbid_partial_values(yajl_handle h);
+ YAJL_API int yajl_config(yajl_handle h, yajl_option opt, ...);
/** free a parser handle */
YAJL_API void yajl_free(yajl_handle handle);
diff --git a/src/yajl.c b/src/yajl.c
index d4195c3..06950e5 100644
--- a/src/yajl.c
+++ b/src/yajl.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include <assert.h>
const char *
@@ -34,9 +35,6 @@ yajl_status_to_string(yajl_status stat)
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;
@@ -46,12 +44,9 @@ yajl_status_to_string(yajl_status stat)
yajl_handle
yajl_alloc(const yajl_callbacks * callbacks,
- const yajl_parser_config * config,
- const yajl_alloc_funcs * afs,
+ yajl_alloc_funcs * afs,
void * ctx)
{
- unsigned int allowComments = 0;
- unsigned int validateUTF8 = 0;
yajl_handle hand = NULL;
yajl_alloc_funcs afsBuffer;
@@ -71,41 +66,40 @@ yajl_alloc(const yajl_callbacks * callbacks,
/* 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->lexer = NULL;
hand->bytesConsumed = 0;
hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
- hand->flags = allow_trailing_garbage | allow_partial_values;
+ hand->flags = 0;
yajl_bs_init(hand->stateStack, &(hand->alloc));
-
yajl_bs_push(hand->stateStack, yajl_state_start);
return hand;
}
-
-void
-yajl_forbid_trailing_garbage(yajl_handle h)
-{
- h->flags &= ~allow_trailing_garbage;
-}
-
-void
-yajl_allow_multiple_values(yajl_handle h)
+int
+yajl_config(yajl_handle h, yajl_option opt, ...)
{
- h->flags |= allow_multiple_values;
-}
+ int rv = 1;
+ va_list ap;
+ va_start(ap, opt);
+
+ switch(opt) {
+ case yajl_allow_comments:
+ case yajl_dont_validate_strings:
+ case yajl_allow_trailing_garbage:
+ case yajl_allow_multiple_values:
+ case yajl_allow_partial_values:
+ if (va_arg(ap, int)) h->flags |= opt;
+ else h->flags &= ~opt;
+ break;
+ default:
+ rv = 0;
+ }
+ va_end(ap);
-void
-yajl_forbid_partial_values(yajl_handle h)
-{
- h->flags &= ~allow_partial_values;
+ return rv;
}
void
@@ -113,7 +107,10 @@ yajl_free(yajl_handle handle)
{
yajl_bs_free(handle->stateStack);
yajl_buf_free(handle->decodeBuf);
- yajl_lex_free(handle->lexer);
+ if (handle->lexer) {
+ yajl_lex_free(handle->lexer);
+ handle->lexer = NULL;
+ }
YA_FREE(&(handle->alloc), handle);
}
@@ -122,6 +119,14 @@ yajl_parse(yajl_handle hand, const unsigned char * jsonText,
size_t jsonTextLen)
{
yajl_status status;
+
+ // lazy allocate the lexer
+ if (hand->lexer == NULL) {
+ hand->lexer = yajl_lex_alloc(&(hand->alloc),
+ hand->flags & yajl_allow_comments,
+ !(hand->flags & yajl_dont_validate_strings));
+ }
+
status = yajl_do_parse(hand, jsonText, jsonTextLen);
return status;
}
@@ -130,13 +135,7 @@ yajl_parse(yajl_handle hand, const unsigned char * jsonText,
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_do_finish(hand);
+ return yajl_do_finish(hand);
}
unsigned char *
diff --git a/src/yajl_gen.c b/src/yajl_gen.c
index 210a918..d50b492 100644
--- a/src/yajl_gen.c
+++ b/src/yajl_gen.c
@@ -22,6 +22,7 @@
#include <string.h>
#include <stdio.h>
#include <math.h>
+#include <stdarg.h>
typedef enum {
yajl_gen_start,
@@ -36,8 +37,8 @@ typedef enum {
struct yajl_gen_t
{
+ unsigned int flags;
unsigned int depth;
- unsigned int pretty;
const char * indentString;
yajl_gen_state state[YAJL_MAX_DEPTH];
yajl_print_t print;
@@ -46,18 +47,53 @@ struct yajl_gen_t
yajl_alloc_funcs alloc;
};
-yajl_gen
-yajl_gen_alloc(const yajl_gen_config * config,
- const yajl_alloc_funcs * afs)
+int
+yajl_gen_config(yajl_gen g, yajl_gen_option opt, ...)
{
- return yajl_gen_alloc2(NULL, config, afs, NULL);
+ int rv = 1;
+ va_list ap;
+ va_start(ap, opt);
+
+ switch(opt) {
+ case yajl_gen_beautify:
+ if (va_arg(ap, int)) g->flags |= opt;
+ else g->flags &= ~opt;
+ break;
+ case yajl_gen_indent_string: {
+ const char *indent = va_arg(ap, const char *);
+ g->indentString = indent;
+ for (; *indent; indent++) {
+ if (*indent != '\n'
+ && *indent != '\v'
+ && *indent != '\f'
+ && *indent != '\t'
+ && *indent != '\r'
+ && *indent != ' ')
+ {
+ g->indentString = NULL;
+ rv = 0;
+ }
+ }
+ break;
+ }
+ case yajl_gen_print_callback:
+ yajl_buf_free(g->ctx);
+ g->print = va_arg(ap, const yajl_print_t);
+ g->ctx = va_arg(ap, void *);
+ break;
+ default:
+ rv = 0;
+ }
+
+ va_end(ap);
+
+ return rv;
}
+
+
yajl_gen
-yajl_gen_alloc2(const yajl_print_t callback,
- const yajl_gen_config * config,
- const yajl_alloc_funcs * afs,
- void * ctx)
+yajl_gen_alloc(const yajl_alloc_funcs * afs)
{
yajl_gen g = NULL;
yajl_alloc_funcs afsBuffer;
@@ -80,35 +116,9 @@ yajl_gen_alloc2(const yajl_print_t callback,
/* copy in pointers to allocation routines */
memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
- if (config) {
- const char *indent = config->indentString;
- g->pretty = config->beautify;
- g->indentString = config->indentString;
- if (indent) {
- for (; *indent; indent++) {
- if (*indent != '\n'
- && *indent != '\v'
- && *indent != '\f'
- && *indent != '\t'
- && *indent != '\r'
- && *indent != ' ') {
- g->indentString = NULL;
- break;
- }
- }
- }
- if (!g->indentString) {
- g->indentString = " ";
- }
- }
-
- if (callback) {
- g->print = callback;
- g->ctx = ctx;
- } else {
- g->print = (yajl_print_t)&yajl_buf_append;
- g->ctx = yajl_buf_alloc(&(g->alloc));
- }
+ g->print = (yajl_print_t)&yajl_buf_append;
+ g->ctx = yajl_buf_alloc(&(g->alloc));
+ g->indentString = " ";
return g;
}
@@ -124,14 +134,14 @@ yajl_gen_free(yajl_gen g)
if (g->state[g->depth] == yajl_gen_map_key || \
g->state[g->depth] == yajl_gen_in_array) { \
g->print(g->ctx, ",", 1); \
- if (g->pretty) g->print(g->ctx, "\n", 1); \
+ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1); \
} else if (g->state[g->depth] == yajl_gen_map_val) { \
g->print(g->ctx, ":", 1); \
- if (g->pretty) g->print(g->ctx, " ", 1); \
+ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, " ", 1); \
}
#define INSERT_WHITESPACE \
- if (g->pretty) { \
+ if ((g->flags & yajl_gen_beautify)) { \
if (g->state[g->depth] != yajl_gen_map_val) { \
unsigned int _i; \
for (_i=0;_i<g->depth;_i++) \
@@ -182,9 +192,9 @@ yajl_gen_free(yajl_gen g)
} \
#define FINAL_NEWLINE \
- if (g->pretty && g->state[g->depth] == yajl_gen_complete) \
- g->print(g->ctx, "\n", 1);
-
+ if ((g->flags & yajl_gen_beautify) && g->state[g->depth] == yajl_gen_complete) \
+ g->print(g->ctx, "\n", 1);
+
yajl_gen_status
yajl_gen_integer(yajl_gen g, long long int number)
{
@@ -270,7 +280,7 @@ yajl_gen_map_open(yajl_gen g)
g->state[g->depth] = yajl_gen_map_start;
g->print(g->ctx, "{", 1);
- if (g->pretty) g->print(g->ctx, "\n", 1);
+ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
FINAL_NEWLINE;
return yajl_gen_status_ok;
}
@@ -281,7 +291,7 @@ yajl_gen_map_close(yajl_gen g)
ENSURE_VALID_STATE;
DECREMENT_DEPTH;
- if (g->pretty) g->print(g->ctx, "\n", 1);
+ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
APPENDED_ATOM;
INSERT_WHITESPACE;
g->print(g->ctx, "}", 1);
@@ -296,7 +306,7 @@ yajl_gen_array_open(yajl_gen g)
INCREMENT_DEPTH;
g->state[g->depth] = yajl_gen_array_start;
g->print(g->ctx, "[", 1);
- if (g->pretty) g->print(g->ctx, "\n", 1);
+ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
FINAL_NEWLINE;
return yajl_gen_status_ok;
}
@@ -306,7 +316,7 @@ yajl_gen_array_close(yajl_gen g)
{
ENSURE_VALID_STATE;
DECREMENT_DEPTH;
- if (g->pretty) g->print(g->ctx, "\n", 1);
+ if ((g->flags & yajl_gen_beautify)) g->print(g->ctx, "\n", 1);
APPENDED_ATOM;
INSERT_WHITESPACE;
g->print(g->ctx, "]", 1);
diff --git a/src/yajl_parser.c b/src/yajl_parser.c
index 5838be7..65d5ed6 100644
--- a/src/yajl_parser.c
+++ b/src/yajl_parser.c
@@ -14,6 +14,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "api/yajl_parse.h"
#include "yajl_lex.h"
#include "yajl_parser.h"
#include "yajl_encode.h"
@@ -161,9 +162,10 @@ yajl_do_finish(yajl_handle hand)
case yajl_state_lexical_error:
return yajl_status_error;
case yajl_state_got_value:
+ case yajl_state_parse_complete:
return yajl_status_ok;
default:
- if (!(hand->flags & allow_partial_values))
+ if (!(hand->flags & yajl_allow_partial_values))
{
yajl_bs_set(hand->stateStack, yajl_state_parse_error);
hand->parseError = "premature EOF";
@@ -187,11 +189,11 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
around_again:
switch (yajl_bs_current(hand->stateStack)) {
case yajl_state_parse_complete:
- if (hand->flags & allow_multiple_values) {
+ if (hand->flags & yajl_allow_multiple_values) {
yajl_bs_set(hand->stateStack, yajl_state_got_value);
goto around_again;
}
- if (!(hand->flags & allow_trailing_garbage)) {
+ if (!(hand->flags & yajl_allow_trailing_garbage)) {
if (*offset != jsonTextLen) {
tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
offset, &buf, &bufLen);
diff --git a/src/yajl_parser.h b/src/yajl_parser.h
index 4151b71..97ef207 100644
--- a/src/yajl_parser.h
+++ b/src/yajl_parser.h
@@ -57,10 +57,6 @@ struct yajl_handle_t {
unsigned int flags;
};
-#define allow_trailing_garbage 0x01
-#define allow_multiple_values 0x02
-#define allow_partial_values 0x04
-
yajl_status
yajl_do_parse(yajl_handle handle, const unsigned char * jsonText,
size_t jsonTextLen);
diff --git a/test/cases/difficult_json_c_test_case_with_comments.json b/test/cases/ac_difficult_json_c_test_case_with_comments.json
index 2463c71..2463c71 100644
--- a/test/cases/difficult_json_c_test_case_with_comments.json
+++ b/test/cases/ac_difficult_json_c_test_case_with_comments.json
diff --git a/test/cases/difficult_json_c_test_case_with_comments.json.gold b/test/cases/ac_difficult_json_c_test_case_with_comments.json.gold
index c3adc11..c3adc11 100644
--- a/test/cases/difficult_json_c_test_case_with_comments.json.gold
+++ b/test/cases/ac_difficult_json_c_test_case_with_comments.json.gold
diff --git a/test/cases/dc_simple_with_comments.json b/test/cases/ac_simple_with_comments.json
index 3b79bba..3b79bba 100644
--- a/test/cases/dc_simple_with_comments.json
+++ b/test/cases/ac_simple_with_comments.json
diff --git a/test/cases/ac_simple_with_comments.json.gold b/test/cases/ac_simple_with_comments.json.gold
new file mode 100644
index 0000000..80fcad2
--- /dev/null
+++ b/test/cases/ac_simple_with_comments.json.gold
@@ -0,0 +1,9 @@
+map open '{'
+key: 'this'
+string: 'is'
+key: 'really'
+string: 'simple'
+key: 'json'
+string: 'right?'
+map close '}'
+memory leaks: 0
diff --git a/test/cases/false_then_garbage.json b/test/cases/ag_false_then_garbage.json
index 78f4e96..78f4e96 100644
--- a/test/cases/false_then_garbage.json
+++ b/test/cases/ag_false_then_garbage.json
diff --git a/test/cases/false_then_garbage.json.gold b/test/cases/ag_false_then_garbage.json.gold
index e55fa1f..e55fa1f 100644
--- a/test/cases/false_then_garbage.json.gold
+++ b/test/cases/ag_false_then_garbage.json.gold
diff --git a/test/cases/null_then_garbage.json b/test/cases/ag_null_then_garbage.json
index 7b65b35..7b65b35 100644
--- a/test/cases/null_then_garbage.json
+++ b/test/cases/ag_null_then_garbage.json
diff --git a/test/cases/null_then_garbage.json.gold b/test/cases/ag_null_then_garbage.json.gold
index 94ad0fa..94ad0fa 100644
--- a/test/cases/null_then_garbage.json.gold
+++ b/test/cases/ag_null_then_garbage.json.gold
diff --git a/test/cases/true_then_garbage.json b/test/cases/ag_true_then_garbage.json
index 9151612..9151612 100644
--- a/test/cases/true_then_garbage.json
+++ b/test/cases/ag_true_then_garbage.json
diff --git a/test/cases/true_then_garbage.json.gold b/test/cases/ag_true_then_garbage.json.gold
index 0858bf7..0858bf7 100644
--- a/test/cases/true_then_garbage.json.gold
+++ b/test/cases/ag_true_then_garbage.json.gold
diff --git a/test/cases/array_open.json b/test/cases/ap_array_open.json
index 558ed37..558ed37 100644
--- a/test/cases/array_open.json
+++ b/test/cases/ap_array_open.json
diff --git a/test/cases/array_open.json.gold b/test/cases/ap_array_open.json.gold
index 478b6b9..478b6b9 100644
--- a/test/cases/array_open.json.gold
+++ b/test/cases/ap_array_open.json.gold
diff --git a/test/cases/eof_str.json b/test/cases/ap_eof_str.json
index 6a21793..6a21793 100644
--- a/test/cases/eof_str.json
+++ b/test/cases/ap_eof_str.json
diff --git a/test/cases/eof_str.json.gold b/test/cases/ap_eof_str.json.gold
index 736730b..736730b 100644
--- a/test/cases/eof_str.json.gold
+++ b/test/cases/ap_eof_str.json.gold
diff --git a/test/cases/map_open.json b/test/cases/ap_map_open.json
index 98232c6..98232c6 100644
--- a/test/cases/map_open.json
+++ b/test/cases/ap_map_open.json
diff --git a/test/cases/map_open.json.gold b/test/cases/ap_map_open.json.gold
index ab1f33d..ab1f33d 100644
--- a/test/cases/map_open.json.gold
+++ b/test/cases/ap_map_open.json.gold
diff --git a/test/cases/partial_ok.json b/test/cases/ap_partial_ok.json
index 2fbd027..2fbd027 100644
--- a/test/cases/partial_ok.json
+++ b/test/cases/ap_partial_ok.json
diff --git a/test/cases/partial_ok.json.gold b/test/cases/ap_partial_ok.json.gold
index 9f754c7..9f754c7 100644
--- a/test/cases/partial_ok.json.gold
+++ b/test/cases/ap_partial_ok.json.gold
diff --git a/test/cases/dc_simple_with_comments.json.gold b/test/cases/dc_simple_with_comments.json.gold
deleted file mode 100644
index d222e9b..0000000
--- a/test/cases/dc_simple_with_comments.json.gold
+++ /dev/null
@@ -1,5 +0,0 @@
-map open '{'
-key: 'this'
-string: 'is'
-lexical error: probable comment found in input text, comments are not enabled.
-memory leaks: 0
diff --git a/test/cases/multiple.json.gold b/test/cases/multiple.json.gold
index c687717..0f6f3df 100644
--- a/test/cases/multiple.json.gold
+++ b/test/cases/multiple.json.gold
@@ -1,3 +1,4 @@
map open '{'
map close '}'
+parse error: trailing garbage
memory leaks: 0
diff --git a/test/cases/simple_with_comments.json.gold b/test/cases/simple_with_comments.json.gold
index 80fcad2..d222e9b 100644
--- a/test/cases/simple_with_comments.json.gold
+++ b/test/cases/simple_with_comments.json.gold
@@ -1,9 +1,5 @@
map open '{'
key: 'this'
string: 'is'
-key: 'really'
-string: 'simple'
-key: 'json'
-string: 'right?'
-map close '}'
+lexical error: probable comment found in input text, comments are not enabled.
memory leaks: 0
diff --git a/test/run_tests.sh b/test/run_tests.sh
index 9a7d0fc..0d75ed3 100755
--- a/test/run_tests.sh
+++ b/test/run_tests.sh
@@ -28,47 +28,54 @@ fi
${ECHO} "using test binary: $testBin"
+testBinShort=`basename $testBin`
+
testsSucceeded=0
testsTotal=0
for file in cases/*.json ; do
- allowComments="-c"
- forbidGarbage=""
+ allowComments=""
+ allowGarbage=""
allowMultiple=""
- noPartials=""
+ allowPartials=""
# if the filename starts with dc_, we disallow comments for this test
case $(basename $file) in
- dc_*)
- allowComments=""
+ ac_*)
+ allowComments="-c "
;;
- fg_*)
- forbidGarbage="-g"
+ ag_*)
+ allowGarbage="-g "
;;
am_*)
- allowMultiple="-m";
+ allowMultiple="-m ";
;;
- np_*)
- noPartials="-p";
+ ap_*)
+ allowPartials="-p ";
;;
esac
- ${ECHO} -n " test case: '$file': "
+ fileShort=`basename $file`
+ testName=`echo $fileShort | sed -e 's/\.json$//'`
+
+ ${ECHO} -n " test ($testName): "
iter=1
- success="success"
+ success="SUCCESS"
- ${ECHO} "$testBin $noPartials $allowComments $forbidGarbage $allowMultiple -b $iter < $file > ${file}.test "
+ ${ECHO} -n "$testBinShort $allowPartials$allowComments$allowGarbage$allowMultiple-b $iter < $fileShort > ${fileShort}.test : "
# parse with a read buffer size ranging from 1-31 to stress stream parsing
- while [ $iter -lt 32 ] && [ $success = "success" ] ; do
- $testBin $noPartials $allowComments $forbidGarbage $allowMultiple -b $iter < $file > ${file}.test 2>&1
- diff ${DIFF_FLAGS} ${file}.gold ${file}.test
+ while [ $iter -lt 32 ] && [ $success = "SUCCESS" ] ; do
+ $testBin $allowPartials $allowComments $allowGarbage $allowMultiple -b $iter < $file > ${file}.test 2>&1
+ diff ${DIFF_FLAGS} ${file}.gold ${file}.test > ${file}.out
if [ $? -eq 0 ] ; then
if [ $iter -eq 31 ] ; then : $(( testsSucceeded += 1)) ; fi
- else
+ else
success="FAILURE"
iter=32
+ ${ECHO}
+ cat ${file}.out
fi
: $(( iter += 1 ))
- rm ${file}.test
+ rm ${file}.test ${file}.out
done
${ECHO} $success
diff --git a/test/yajl_test.c b/test/yajl_test.c
index 1b07f8b..7d507f8 100644
--- a/test/yajl_test.c
+++ b/test/yajl_test.c
@@ -156,10 +156,10 @@ static void usage(const char * progname)
"to stdout\n"
" -b set the read buffer size\n"
" -c allow comments\n"
- " -g forbid *g*arbage after valid JSON text\n"
+ " -g allow *g*arbage after valid JSON text\n"
" -m allows the parser to consume multiple JSON values\n"
" from a single string separated by whitespace\n"
- " -p partial JSON documents should be considered invalid\n",
+ " -p partial JSON documents should not cause errors\n",
progname);
exit(1);
}
@@ -173,9 +173,8 @@ main(int argc, char ** argv)
size_t bufSize = BUF_SIZE;
yajl_status stat;
size_t rd;
- yajl_parser_config cfg = { 0, 1 };
int i, j;
- int multiple = 0 ,trailing = 0, partial = 0;
+
/* memory allocation debugging: allocate a structure which collects
* statistics */
yajlTestMemoryContext memCtx = { 0,0 };
@@ -191,10 +190,13 @@ main(int argc, char ** argv)
allocFuncs.ctx = (void *) &memCtx;
+ /* allocate the parser */
+ hand = yajl_alloc(&callbacks, &allocFuncs, NULL);
+
/* check arguments. We expect exactly one! */
for (i=1;i<argc;i++) {
if (!strcmp("-c", argv[i])) {
- cfg.allowComments = 1;
+ yajl_config(hand, yajl_allow_comments, 1);
} else if (!strcmp("-b", argv[i])) {
if (++i >= argc) usage(argv[0]);
@@ -212,11 +214,11 @@ main(int argc, char ** argv)
bufSize);
}
} else if (!strcmp("-g", argv[i])) {
- trailing = 1;
+ yajl_config(hand, yajl_allow_trailing_garbage, 1);
} else if (!strcmp("-m", argv[i])) {
- multiple = 1; partial = 1;
+ yajl_config(hand, yajl_allow_multiple_values, 1);
} else if (!strcmp("-p", argv[i])) {
- partial = 1;
+ yajl_config(hand, yajl_allow_partial_values, 1);
} else {
fprintf(stderr, "invalid command line option: '%s'\n",
argv[i]);
@@ -230,17 +232,12 @@ main(int argc, char ** argv)
fprintf(stderr,
"failed to allocate read buffer of %zu bytes, exiting.",
bufSize);
+ yajl_free(hand);
exit(2);
}
fileName = argv[argc-1];
- /* ok. open file. let's read and parse */
- hand = yajl_alloc(&callbacks, &cfg, &allocFuncs, NULL);
- if (trailing) yajl_forbid_trailing_garbage(hand);
- if (multiple) yajl_allow_multiple_values(hand);
- if (partial) yajl_forbid_partial_values(hand);
-
for (;;) {
rd = fread((void *) fileData, 1, bufSize, stdin);
diff --git a/verify/json_verify.c b/verify/json_verify.c
index dbb6525..ea09cdf 100644
--- a/verify/json_verify.c
+++ b/verify/json_verify.c
@@ -40,9 +40,10 @@ main(int argc, char ** argv)
yajl_handle hand;
static unsigned char fileData[65536];
int quiet = 0;
- int retval = 0, done = 0;
- yajl_parser_config cfg = { 0, 1 };
-
+ int retval = 0;
+ int allowComments = 0;
+ int checkUTF8 = 1;
+
/* check arguments.*/
int a = 1;
while ((a < argc) && (argv[a][0] == '-') && (strlen(argv[a]) > 1)) {
@@ -53,10 +54,10 @@ main(int argc, char ** argv)
quiet = 1;
break;
case 'c':
- cfg.allowComments = 1;
+ allowComments = 1;
break;
case 'u':
- cfg.checkUTF8 = 0;
+ checkUTF8 = 0;
break;
default:
fprintf(stderr, "unrecognized option: '%c'\n\n", argv[a][i]);
@@ -70,9 +71,11 @@ main(int argc, char ** argv)
}
/* allocate a parser */
- hand = yajl_alloc(NULL, &cfg, NULL, NULL);
+ hand = yajl_alloc(NULL, NULL, NULL);
+ yajl_config(hand, yajl_allow_comments, allowComments);
+ yajl_config(hand, yajl_dont_validate_strings, !checkUTF8);
- while (!done) {
+ for (;;) {
rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);
retval = 0;
@@ -83,30 +86,28 @@ main(int argc, char ** argv)
fprintf(stderr, "error encountered on file read\n");
}
retval = 1;
- break;
}
- done = 1;
+ break;
}
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);
+ /* 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;
+ if (stat != yajl_status_ok) break;
+ }
+
+ /* parse any remaining buffered data */
+ stat = yajl_parse_complete(hand);
+
+ if (stat != yajl_status_ok)
+ {
+ 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;
}
yajl_free(hand);