]> granicus.if.org Git - vim/commitdiff
patch 7.4.1407 v7.4.1407
authorBram Moolenaar <Bram@vim.org>
Tue, 23 Feb 2016 20:26:43 +0000 (21:26 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 23 Feb 2016 20:26:43 +0000 (21:26 +0100)
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().

src/eval.c
src/json.c
src/testdir/test_json.vim
src/version.c

index 1471568184cb3f5e5901da257d5c680796c480b9..cf908d1d5c444cb2edbb03013fa1f7b5a7074648 100644 (file)
@@ -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);
 
 /*
index 7b85cd251e19e9ac628a735dd53d6e68391011ff..6eadd2e83e17acfb8ed04618210dc6308c829b87 100644 (file)
 #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;
index 3ac936f8adcc73a4a2ed56bb329978057d604d71..bde7321739078e71b9948852078f3994487b6c6b 100644 (file)
@@ -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))
index a04a948c668947aa3066f34a5f95094ff804a6bc..8d858d10512540811f76411c32cb97d1f4114af8 100644 (file)
@@ -748,6 +748,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1407,
 /**/
     1406,
 /**/