]> granicus.if.org Git - vim/commitdiff
patch 8.1.2035: recognizing octal numbers is confusing v8.1.2035
authorBram Moolenaar <Bram@vim.org>
Sun, 15 Sep 2019 12:33:22 +0000 (14:33 +0200)
committerBram Moolenaar <Bram@vim.org>
Sun, 15 Sep 2019 12:33:22 +0000 (14:33 +0200)
Problem:    Recognizing octal numbers is confusing.
Solution:   Introduce scriptversion 4: do not use octal and allow for single
            quote inside numbers.

runtime/doc/eval.txt
src/eval.c
src/evalfunc.c
src/scriptfile.c
src/testdir/test_eval_stuff.vim
src/testdir/test_functions.vim
src/version.c
src/vim.h

index 8cb2af1e66d1dac392eddff348df132b7d1133dd..a8173175943f419c237bd7cff19bbdd4d7302c88 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*     For Vim version 8.1.  Last change: 2019 Sep 10
+*eval.txt*     For Vim version 8.1.  Last change: 2019 Sep 15
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -92,7 +92,8 @@ the Number.  Examples:
                                                        *octal*
 Conversion from a String to a Number is done by converting the first digits to
 a number.  Hexadecimal "0xf9", Octal "017", and Binary "0b10" numbers are
-recognized.  If the String doesn't start with digits, the result is zero.
+recognized (NOTE: when using |scriptversion-4| octal is not recognized).  If
+the String doesn't start with digits, the result is zero.
 Examples:
        String "456"    -->     Number 456 ~
        String "6bar"   -->     Number 6 ~
@@ -2757,7 +2758,8 @@ sqrt({expr})                      Float   square root of {expr}
 str2float({expr})              Float   convert String to Float
 str2list({expr} [, {utf8}])    List    convert each character of {expr} to
                                        ASCII/UTF8 value
-str2nr({expr} [, {base}])      Number  convert String to Number
+str2nr({expr} [, {base} [, {quoted}]])
+                               Number  convert String to Number
 strchars({expr} [, {skipcc}])  Number  character length of the String {expr}
 strcharpart({str}, {start} [, {len}])
                                String  {len} characters of {str} at {start}
@@ -9075,9 +9077,11 @@ str2list({expr} [, {utf8}])                              *str2list()*
                        GetString()->str2list()
 
 
-str2nr({expr} [, {base}])                              *str2nr()*
+str2nr({expr} [, {base} [, {quoted}]])                         *str2nr()*
                Convert string {expr} to a number.
                {base} is the conversion base, it can be 2, 8, 10 or 16.
+               When {quoted} is present and non-zero then embedded single
+               quotes are ignored, thus "1'000'000" is a million.
 
                When {base} is omitted base 10 is used.  This also means that
                a leading zero doesn't cause octal conversion to be used, as
@@ -12937,6 +12941,23 @@ instead of failing in mysterious ways.
 
        Test for support with: >
                has('vimscript-3')
+<
+                                                       *scriptversion-4*  >
+ :scriptversion 4
+<      Numbers with a leading zero are not recognized as octal.  With the
+       previous version you get: >
+               echo 017   " displays 15
+               echo 018   " displays 18
+<      with script version 4: >
+               echo 017   " displays 17
+               echo 018   " displays 18
+<      Also, it is possible to use single quotes inside numbers to make them
+       easier to read: >
+               echo 1'000'000
+<      The quotes must be surrounded by digits.
+
+       Test for support with: >
+               has('vimscript-4')
 
 ==============================================================================
 11. No +eval feature                           *no-eval-feature*
index acdfac3a330fde5d737c4f3bad2945c62428cb41..680ca1af7b65a15a840a1742185a889c74c2d12f 100644 (file)
@@ -2617,7 +2617,9 @@ eval7(
                else
                {
                    // decimal, hex or octal number
-                   vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, TRUE);
+                   vim_str2nr(*arg, NULL, &len, current_sctx.sc_version >= 4
+                                 ? STR2NR_NO_OCT + STR2NR_QUOTE
+                                 : STR2NR_ALL, &n, NULL, 0, TRUE);
                    if (len == 0)
                    {
                        semsg(_(e_invexpr2), *arg);
index 438aac8eac44ebdd62304d86869e667153498e64..67726923dcba362300d056ca2d2cfae4f4c842c7 100644 (file)
@@ -728,7 +728,7 @@ static funcentry_T global_functions[] =
     {"str2float",      1, 1, FEARG_1,    f_str2float},
 #endif
     {"str2list",       1, 2, FEARG_1,    f_str2list},
-    {"str2nr",         1, 2, FEARG_1,    f_str2nr},
+    {"str2nr",         1, 3, FEARG_1,    f_str2nr},
     {"strcharpart",    2, 3, FEARG_1,    f_strcharpart},
     {"strchars",       1, 2, FEARG_1,    f_strchars},
     {"strdisplaywidth",        1, 2, FEARG_1,    f_strdisplaywidth},
@@ -7323,7 +7323,7 @@ f_str2nr(typval_T *argvars, typval_T *rettv)
     int                base = 10;
     char_u     *p;
     varnumber_T        n;
-    int                what;
+    int                what = 0;
     int                isneg;
 
     if (argvars[1].v_type != VAR_UNKNOWN)
@@ -7334,6 +7334,8 @@ f_str2nr(typval_T *argvars, typval_T *rettv)
            emsg(_(e_invarg));
            return;
        }
+       if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
+           what |= STR2NR_QUOTE;
     }
 
     p = skipwhite(tv_get_string(&argvars[0]));
@@ -7342,10 +7344,9 @@ f_str2nr(typval_T *argvars, typval_T *rettv)
        p = skipwhite(p + 1);
     switch (base)
     {
-       case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
-       case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
-       case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
-       default: what = 0;
+       case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
+       case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
+       case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
     }
     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
     // Text after the number is silently ignored.
index d46b1e0b7ca896bfad3c50fa96258282f47edd2b..92db59c2de8ed9ceb868c89874c6d90d0d6e26cd 100644 (file)
@@ -1659,7 +1659,7 @@ ex_scriptversion(exarg_T *eap UNUSED)
     nr = getdigits(&eap->arg);
     if (nr == 0 || *eap->arg != NUL)
        emsg(_(e_invarg));
-    else if (nr > 3)
+    else if (nr > 4)
        semsg(_("E999: scriptversion not supported: %d"), nr);
     else
        current_sctx.sc_version = nr;
index b518f5ae6b3712c64524ed42ee6fa15705f0182e..720f3094ef0130b32252c87cb6a6f67133807ff5 100644 (file)
@@ -74,7 +74,7 @@ func Test_readfile_binary()
   new
   call setline(1, ['one', 'two', 'three'])
   setlocal ff=dos
-  write XReadfile
+  silent write XReadfile
   let lines = 'XReadfile'->readfile()
   call assert_equal(['one', 'two', 'three'], lines)
   let lines = readfile('XReadfile', '', 2)
@@ -124,6 +124,15 @@ func Test_string_concatenation()
   call assert_equal('ab', a)
 endfunc
 
+" Test fix for issue #4507
+func Test_skip_after_throw()
+  try
+    throw 'something'
+    let x = wincol() || &ts
+  catch /something/
+  endtry
+endfunc
+
 scriptversion 2
 func Test_string_concat_scriptversion2()
   call assert_true(has('vimscript-2'))
@@ -183,17 +192,23 @@ func Test_dict_access_scriptversion2()
   call assert_true(1 && l:x.foo)
 endfunc
 
-func Test_scriptversion()
+scriptversion 4
+func Test_vvar_scriptversion4()
+  call assert_equal(17, 017)
+  call assert_equal(18, 018)
+  call assert_equal(64, 0b1'00'00'00)
+  call assert_equal(1048576, 0x10'00'00)
+  call assert_equal(1000000, 1'000'000)
+endfunc
+
+scriptversion 1
+func Test_vvar_scriptversion1()
+  call assert_equal(15, 017)
+  call assert_equal(18, 018)
+endfunc
+
+func Test_scriptversion_fail()
   call writefile(['scriptversion 9'], 'Xversionscript')
   call assert_fails('source Xversionscript', 'E999:')
   call delete('Xversionscript')
 endfunc
-
-" Test fix for issue #4507
-func Test_skip_after_throw()
-  try
-    throw 'something'
-    let x = wincol() || &ts
-  catch /something/
-  endtry
-endfunc
index 2e051bb262d58a05759e8af1c2718478725b9257..e782061886520119696c80748a705d6cd1fe46b1 100644 (file)
@@ -157,6 +157,12 @@ func Test_str2nr()
   call assert_equal(11259375, str2nr('0XABCDEF', 16))
   call assert_equal(-11259375, str2nr('-0xABCDEF', 16))
 
+  call assert_equal(1, str2nr("1'000'000", 10, 0))
+  call assert_equal(256, str2nr("1'0000'0000", 2, 1))
+  call assert_equal(262144, str2nr("1'000'000", 8, 1))
+  call assert_equal(1000000, str2nr("1'000'000", 10, 1))
+  call assert_equal(65536, str2nr("1'00'00", 16, 1))
+
   call assert_equal(0, str2nr('0x10'))
   call assert_equal(0, str2nr('0b10'))
   call assert_equal(1, str2nr('12', 2))
index 69c77d81d1c49771fa3ccc10a66f9299886a0e4f..09baa53249fcb2054bb1eecd9c585d12bdb7ac22 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2035,
 /**/
     2034,
 /**/
index 46ca6930db5fe77200ffabe91638c9bc1e5c24f5..8afa9335252faef60030230c0c18bd0ce23d1aca 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
 #define NUMBUFLEN 65
 
 // flags for vim_str2nr()
-#define STR2NR_BIN 1
-#define STR2NR_OCT 2
-#define STR2NR_HEX 4
+#define STR2NR_BIN 0x01
+#define STR2NR_OCT 0x02
+#define STR2NR_HEX 0x04
 #define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX)
-#define STR2NR_FORCE 8 // only when ONE of the above is used
+#define STR2NR_NO_OCT (STR2NR_BIN + STR2NR_HEX)
+
+#define STR2NR_FORCE 0x80   // only when ONE of the above is used
+
+#define STR2NR_QUOTE 0x10   // ignore embedded single quotes
 
 /*
  * Shorthand for unsigned variables. Many systems, but not all, have u_char