summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-02-23 21:26:43 +0100
committerBram Moolenaar <Bram@vim.org>2016-02-23 21:26:43 +0100
commitf1b6ac72293e658bb6e68c5cfd926c405b1b6f34 (patch)
treed6013028a0f6cdae4d19bcda1eacebe03a0b53c2 /src
parente16e5a9d8d6d3159107541a259c6823ade18fd08 (diff)
patch 7.4.1407v7.4.1407
Problem: json_encode() does not handle NaN and inf properly. (David Barnett) Solution: For JSON turn them into "null". For JS use "NaN" and "Infinity". Add isnan().
Diffstat (limited to 'src')
-rw-r--r--src/eval.c18
-rw-r--r--src/json.c51
-rw-r--r--src/testdir/test_json.vim18
-rw-r--r--src/version.c2
4 files changed, 84 insertions, 5 deletions
diff --git a/src/eval.c b/src/eval.c
index 1471568184..cf908d1d5c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -628,6 +628,9 @@ static void f_insert(typval_T *argvars, typval_T *rettv);
static void f_invert(typval_T *argvars, typval_T *rettv);
static void f_isdirectory(typval_T *argvars, typval_T *rettv);
static void f_islocked(typval_T *argvars, typval_T *rettv);
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+static void f_isnan(typval_T *argvars, typval_T *rettv);
+#endif
static void f_items(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_JOB
# ifdef FEAT_CHANNEL
@@ -8320,6 +8323,9 @@ static struct fst
{"invert", 1, 1, f_invert},
{"isdirectory", 1, 1, f_isdirectory},
{"islocked", 1, 1, f_islocked},
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+ {"isnan", 1, 1, f_isnan},
+#endif
{"items", 1, 1, f_items},
#ifdef FEAT_JOB
# ifdef FEAT_CHANNEL
@@ -14740,6 +14746,18 @@ f_islocked(typval_T *argvars, typval_T *rettv)
clear_lval(&lv);
}
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+/*
+ * "isnan()" function
+ */
+ static void
+f_isnan(typval_T *argvars, typval_T *rettv)
+{
+ rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
+ && isnan(argvars[0].vval.v_float);
+}
+#endif
+
static void dict_list(typval_T *argvars, typval_T *rettv, int what);
/*
diff --git a/src/json.c b/src/json.c
index 7b85cd251e..6eadd2e83e 100644
--- a/src/json.c
+++ b/src/json.c
@@ -16,6 +16,12 @@
#include "vim.h"
#if defined(FEAT_EVAL) || defined(PROTO)
+
+#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
+ /* for isnan() and isinf() */
+# include <math.h>
+#endif
+
static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options);
static int json_decode_item(js_read_T *reader, typval_T *res, int options);
@@ -267,8 +273,20 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
case VAR_FLOAT:
#ifdef FEAT_FLOAT
- vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
- ga_concat(gap, numbuf);
+# if defined(HAVE_MATH_H)
+ if ((options & JSON_JS) && isnan(val->vval.v_float))
+ ga_concat(gap, (char_u *)"NaN");
+ else if ((options & JSON_JS) && isinf(val->vval.v_float))
+ ga_concat(gap, (char_u *)"Infinity");
+ else if (isnan(val->vval.v_float) || isinf(val->vval.v_float))
+ ga_concat(gap, (char_u *)"null");
+ else
+# endif
+ {
+ vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
+ val->vval.v_float);
+ ga_concat(gap, numbuf);
+ }
break;
#endif
case VAR_UNKNOWN:
@@ -720,9 +738,36 @@ json_decode_item(js_read_T *reader, typval_T *res, int options)
}
return OK;
}
+#ifdef FEAT_FLOAT
+ if (STRNICMP((char *)p, "NaN", 3) == 0)
+ {
+ reader->js_used += 3;
+ if (res != NULL)
+ {
+ res->v_type = VAR_FLOAT;
+ res->vval.v_float = 0.0 / 0.0;
+ }
+ return OK;
+ }
+ if (STRNICMP((char *)p, "Infinity", 8) == 0)
+ {
+ reader->js_used += 8;
+ if (res != NULL)
+ {
+ res->v_type = VAR_FLOAT;
+ res->vval.v_float = 1.0 / 0.0;
+ }
+ return OK;
+ }
+#endif
/* check for truncated name */
len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
- if ((len < 5 && STRNICMP((char *)p, "false", len) == 0)
+ if (
+ (len < 5 && STRNICMP((char *)p, "false", len) == 0)
+#ifdef FEAT_FLOAT
+ || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
+ || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
+#endif
|| (len < 4 && (STRNICMP((char *)p, "true", len) == 0
|| STRNICMP((char *)p, "null", len) == 0)))
return MAYBE;
diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim
index 3ac936f8ad..bde7321739 100644
--- a/src/testdir/test_json.vim
+++ b/src/testdir/test_json.vim
@@ -16,8 +16,16 @@ let s:jsonmb = '"s¢cĴgё"'
let s:varmb = "s¢cĴgё"
let s:jsonnr = '1234'
let s:varnr = 1234
-let s:jsonfl = '12.34'
-let s:varfl = 12.34
+if has('float')
+ let s:jsonfl = '12.34'
+ let s:varfl = 12.34
+ let s:jsoninf = 'null'
+ let s:jsinf = 'Infinity'
+ let s:varinf = 1.0 / 0.0
+ let s:jsonnan = 'null'
+ let s:jsnan = 'NaN'
+ let s:varnan = 0.0 / 0.0
+endif
let s:jsonl1 = '[1,"a",3]'
let s:varl1 = [1, "a", 3]
@@ -68,6 +76,8 @@ func Test_json_encode()
call assert_equal(s:jsonnr, json_encode(s:varnr))
if has('float')
call assert_equal(s:jsonfl, json_encode(s:varfl))
+ call assert_equal(s:jsoninf, json_encode(s:varinf))
+ call assert_equal(s:jsonnan, json_encode(s:varnan))
endif
call assert_equal(s:jsonl1, json_encode(s:varl1))
@@ -165,6 +175,8 @@ func Test_js_encode()
call assert_equal(s:jsonnr, js_encode(s:varnr))
if has('float')
call assert_equal(s:jsonfl, js_encode(s:varfl))
+ call assert_equal(s:jsinf, js_encode(s:varinf))
+ call assert_equal(s:jsnan, js_encode(s:varnan))
endif
call assert_equal(s:jsonl1, js_encode(s:varl1))
@@ -201,6 +213,8 @@ func Test_js_decode()
call assert_equal(s:varnr, js_decode(s:jsonnr))
if has('float')
call assert_equal(s:varfl, js_decode(s:jsonfl))
+ call assert_equal(s:varinf, js_decode(s:jsinf))
+ call assert_true(isnan(js_decode(s:jsnan)))
endif
call assert_equal(s:varl1, js_decode(s:jsonl1))
diff --git a/src/version.c b/src/version.c
index a04a948c66..8d858d1051 100644
--- a/src/version.c
+++ b/src/version.c
@@ -749,6 +749,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1407,
+/**/
1406,
/**/
1405,