diff --git a/config.h.in b/config.h.in index f24bfbc..7c8973f 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,10 @@ /* Define if .gnu.warning accepts long strings. */ #undef HAS_GNU_WARNING_LONG +/* Define to 1 if you have the declaration of `INFINITY', and to 0 if you + don't. */ +#undef HAVE_DECL_INFINITY + /* Define to 1 if you have the declaration of `isinf', and to 0 if you don't. */ #undef HAVE_DECL_ISINF diff --git a/configure.ac b/configure.ac index 96e2466..20ad715 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,7 @@ AC_FUNC_MEMCMP AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS(strcasecmp strdup strerror snprintf vsnprintf vasprintf open vsyslog strncasecmp setlocale) +AC_CHECK_DECLS([INFINITY], [], [], [[#include ]]) AC_CHECK_DECLS([nan], [], [], [[#include ]]) AC_CHECK_DECLS([isnan], [], [], [[#include ]]) AC_CHECK_DECLS([isinf], [], [], [[#include ]]) diff --git a/json_tokener.c b/json_tokener.c index 9862f9e..e4710e4 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -57,6 +57,8 @@ static const char json_null_str[] = "null"; static const int json_null_str_len = sizeof(json_null_str) - 1; +static const char json_inf_str[] = "Infinity"; +static const int json_inf_str_len = sizeof(json_inf_str) - 1; static const char json_nan_str[] = "NaN"; static const int json_nan_str_len = sizeof(json_nan_str) - 1; static const char json_true_str[] = "true"; @@ -275,6 +277,12 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, saved_state = json_tokener_state_array; current = json_object_new_array(); break; + case 'I': + case 'i': + state = json_tokener_state_inf; + printbuf_reset(tok->pb); + tok->st_pos = 0; + goto redo_char; case 'N': case 'n': state = json_tokener_state_null; // or NaN @@ -332,7 +340,41 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, tok->depth--; goto redo_char; - case json_tokener_state_null: + case json_tokener_state_inf: /* aka starts with 'i' */ + { + int size; + int size_inf; + int is_negative = 0; + + printbuf_memappend_fast(tok->pb, &c, 1); + size = json_min(tok->st_pos+1, json_null_str_len); + size_inf = json_min(tok->st_pos+1, json_inf_str_len); + char *infbuf = tok->pb->buf; + if (*infbuf == '-') + { + infbuf++; + is_negative = 1; + } + if ((!(tok->flags & JSON_TOKENER_STRICT) && + strncasecmp(json_inf_str, infbuf, size_inf) == 0) || + (strncmp(json_inf_str, infbuf, size_inf) == 0) + ) + { + if (tok->st_pos == json_inf_str_len) + { + current = json_object_new_double(is_negative ? -INFINITY : INFINITY); + saved_state = json_tokener_state_finish; + state = json_tokener_state_eatws; + goto redo_char; + } + } else { + tok->err = json_tokener_error_parse_unexpected; + goto out; + } + tok->st_pos++; + } + break; + case json_tokener_state_null: /* aka starts with 'n' */ { int size; int size_nan; @@ -628,6 +670,14 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, } if (case_len>0) printbuf_memappend_fast(tok->pb, case_start, case_len); + + // Check for -Infinity + if (tok->pb->buf[0] == '-' && case_len == 1 && + (c == 'i' || c == 'I')) + { + state = json_tokener_state_inf; + goto redo_char; + } } { int64_t num64; diff --git a/json_tokener.h b/json_tokener.h index 08e5ff7..61f73d2 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -60,7 +60,8 @@ enum json_tokener_state { json_tokener_state_object_value_add, json_tokener_state_object_sep, json_tokener_state_array_after_sep, - json_tokener_state_object_field_start_after_sep + json_tokener_state_object_field_start_after_sep, + json_tokener_state_inf }; struct json_tokener_srec diff --git a/math_compat.h b/math_compat.h index d94a4da..f40b8fa 100644 --- a/math_compat.h +++ b/math_compat.h @@ -21,4 +21,8 @@ #error This platform does not have nan() #endif +#ifndef HAVE_DECL_INFINITY +#error This platform does not have INFINITY +#endif + #endif diff --git a/tests/test_parse.c b/tests/test_parse.c index f0f2550..8808d0f 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -51,6 +51,34 @@ static void test_basic_parse() printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); + new_obj = json_tokener_parse("-NaN"); /* non-sensical, returns null */ + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("Inf"); /* must use full string, returns null */ + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("inf"); /* must use full string, returns null */ + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("Infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("-Infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + + new_obj = json_tokener_parse("-infinity"); + printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); + json_object_put(new_obj); + new_obj = json_tokener_parse("True"); printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj)); json_object_put(new_obj); diff --git a/tests/test_parse.expected b/tests/test_parse.expected index 378a82b..d49cbbb 100644 --- a/tests/test_parse.expected +++ b/tests/test_parse.expected @@ -4,6 +4,13 @@ new_obj.to_string()="foo" new_obj.to_string()="ABC" new_obj.to_string()=null new_obj.to_string()=NaN +new_obj.to_string()=null +new_obj.to_string()=null +new_obj.to_string()=null +new_obj.to_string()=Infinity +new_obj.to_string()=Infinity +new_obj.to_string()=-Infinity +new_obj.to_string()=-Infinity new_obj.to_string()=true new_obj.to_string()=12 new_obj.to_string()=12.3