Patch 8.1.2035
Problem:    Recognizing octal numbers is confusing.
Solution:   Introduce scriptversion 4: do not use octal and allow for single
            quote inside numbers.
Files:      runtime/doc/eval.txt, src/vim.h, src/eval.c, src/scriptfile.c,
            src/evalfunc.c, src/testdir/test_eval_stuff.vim,
            src/testdir/test_functions.vim


*** ../vim-8.1.2034/runtime/doc/eval.txt        2019-09-10 21:22:54.872629203 
+0200
--- runtime/doc/eval.txt        2019-09-15 14:26:28.494040912 +0200
***************
*** 92,98 ****
                                                        *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.
  Examples:
        String "456"    -->     Number 456 ~
        String "6bar"   -->     Number 6 ~
--- 92,99 ----
                                                        *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 (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 ~
***************
*** 2543,2549 ****
  len({expr})                   Number  the length of {expr}
  libcall({lib}, {func}, {arg}) String  call {func} in library {lib} with {arg}
  libcallnr({lib}, {func}, {arg})       Number  idem, but return a Number
! line({expr})                  Number  line nr of cursor, last line or mark
  line2byte({lnum})             Number  byte count of line {lnum}
  lispindent({lnum})            Number  Lisp indent for line {lnum}
  list2str({list} [, {utf8}])   String  turn numbers in {list} into a String
--- 2549,2555 ----
  len({expr})                   Number  the length of {expr}
  libcall({lib}, {func}, {arg}) String  call {func} in library {lib} with {arg}
  libcallnr({lib}, {func}, {arg})       Number  idem, but return a Number
! line({expr} [, {winid}])      Number  line nr of cursor, last line or mark
  line2byte({lnum})             Number  byte count of line {lnum}
  lispindent({lnum})            Number  Lisp indent for line {lnum}
  list2str({list} [, {utf8}])   String  turn numbers in {list} into a String
***************
*** 2752,2758 ****
  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
  strchars({expr} [, {skipcc}]) Number  character length of the String {expr}
  strcharpart({str}, {start} [, {len}])
                                String  {len} characters of {str} at {start}
--- 2758,2765 ----
  str2float({expr})             Float   convert String to Float
  str2list({expr} [, {utf8}])   List    convert each character of {expr} to
                                        ASCII/UTF8 value
! 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}
***************
*** 6376,6383 ****
                the argument to the called function: >
                        GetValue()->libcallnr("libc.so", "printf")
  <
!                                                       *line()*
! line({expr})  The result is a Number, which is the line number of the file
                position given with {expr}.  The accepted positions are:
                    .       the cursor position
                    $       the last line in the current buffer
--- 6388,6396 ----
                the argument to the called function: >
                        GetValue()->libcallnr("libc.so", "printf")
  <
! 
! line({expr} [, {winid}])                              *line()*
!               The result is a Number, which is the line number of the file
                position given with {expr}.  The accepted positions are:
                    .       the cursor position
                    $       the last line in the current buffer
***************
*** 6395,6402 ****
--- 6408,6418 ----
                then applies to another buffer.
                To get the column number use |col()|.  To get both use
                |getpos()|.
+               With the optional {winid} argument the values are obtained for
+               that window instead of the current window.
                Examples: >
                        line(".")               line number of the cursor
+                       line(".", winid)        idem, in window "winid"
                        line("'t")              line number of mark t
                        line("'" . marker)      line number of mark marker
  <
***************
*** 9061,9069 ****
                        GetString()->str2list()
  
  
! str2nr({expr} [, {base}])                             *str2nr()*
                Convert string {expr} to a number.
                {base} is the conversion base, it can be 2, 8, 10 or 16.
  
                When {base} is omitted base 10 is used.  This also means that
                a leading zero doesn't cause octal conversion to be used, as
--- 9077,9087 ----
                        GetString()->str2list()
  
  
! 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
***************
*** 12916,12921 ****
--- 12941,12963 ----
  
        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*
*** ../vim-8.1.2034/src/vim.h   2019-09-04 20:59:10.491409987 +0200
--- src/vim.h   2019-09-15 13:49:47.753458236 +0200
***************
*** 307,317 ****
  #define NUMBUFLEN 65
  
  // flags for vim_str2nr()
! #define STR2NR_BIN 1
! #define STR2NR_OCT 2
! #define STR2NR_HEX 4
  #define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX)
! #define STR2NR_FORCE 8 // only when ONE of the above is used
  
  /*
   * Shorthand for unsigned variables. Many systems, but not all, have u_char
--- 307,321 ----
  #define NUMBUFLEN 65
  
  // flags for vim_str2nr()
! #define STR2NR_BIN 0x01
! #define STR2NR_OCT 0x02
! #define STR2NR_HEX 0x04
  #define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX)
! #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
*** ../vim-8.1.2034/src/eval.c  2019-09-04 15:54:23.912359700 +0200
--- src/eval.c  2019-09-15 13:50:06.149393853 +0200
***************
*** 2617,2623 ****
                else
                {
                    // decimal, hex or octal number
!                   vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0, TRUE);
                    if (len == 0)
                    {
                        semsg(_(e_invexpr2), *arg);
--- 2617,2625 ----
                else
                {
                    // decimal, hex or octal number
!                   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);
*** ../vim-8.1.2034/src/scriptfile.c    2019-09-04 20:59:10.491409987 +0200
--- src/scriptfile.c    2019-09-15 13:41:54.911081578 +0200
***************
*** 1659,1665 ****
      nr = getdigits(&eap->arg);
      if (nr == 0 || *eap->arg != NUL)
        emsg(_(e_invarg));
!     else if (nr > 3)
        semsg(_("E999: scriptversion not supported: %d"), nr);
      else
        current_sctx.sc_version = nr;
--- 1659,1665 ----
      nr = getdigits(&eap->arg);
      if (nr == 0 || *eap->arg != NUL)
        emsg(_(e_invarg));
!     else if (nr > 4)
        semsg(_("E999: scriptversion not supported: %d"), nr);
      else
        current_sctx.sc_version = nr;
*** ../vim-8.1.2034/src/evalfunc.c      2019-09-10 21:22:54.876629189 +0200
--- src/evalfunc.c      2019-09-15 14:18:51.327587656 +0200
***************
*** 728,734 ****
      {"str2float",     1, 1, FEARG_1,    f_str2float},
  #endif
      {"str2list",      1, 2, FEARG_1,    f_str2list},
!     {"str2nr",                1, 2, 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},
--- 728,734 ----
      {"str2float",     1, 1, FEARG_1,    f_str2float},
  #endif
      {"str2list",      1, 2, FEARG_1,    f_str2list},
!     {"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,7329 ****
      int               base = 10;
      char_u    *p;
      varnumber_T       n;
!     int               what;
      int               isneg;
  
      if (argvars[1].v_type != VAR_UNKNOWN)
--- 7323,7329 ----
      int               base = 10;
      char_u    *p;
      varnumber_T       n;
!     int               what = 0;
      int               isneg;
  
      if (argvars[1].v_type != VAR_UNKNOWN)
***************
*** 7334,7339 ****
--- 7334,7341 ----
            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,7351 ****
        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;
      }
      vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
      // Text after the number is silently ignored.
--- 7344,7352 ----
        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;
      }
      vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
      // Text after the number is silently ignored.
*** ../vim-8.1.2034/src/testdir/test_eval_stuff.vim     2019-09-04 
22:28:53.061026888 +0200
--- src/testdir/test_eval_stuff.vim     2019-09-15 14:08:25.701595419 +0200
***************
*** 74,80 ****
    new
    call setline(1, ['one', 'two', 'three'])
    setlocal ff=dos
!   write XReadfile
    let lines = 'XReadfile'->readfile()
    call assert_equal(['one', 'two', 'three'], lines)
    let lines = readfile('XReadfile', '', 2)
--- 74,80 ----
    new
    call setline(1, ['one', 'two', 'three'])
    setlocal ff=dos
!   silent write XReadfile
    let lines = 'XReadfile'->readfile()
    call assert_equal(['one', 'two', 'three'], lines)
    let lines = readfile('XReadfile', '', 2)
***************
*** 124,129 ****
--- 124,138 ----
    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,199 ****
    call assert_true(1 && l:x.foo)
  endfunc
  
! func Test_scriptversion()
    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
--- 192,214 ----
    call assert_true(1 && l:x.foo)
  endfunc
  
! 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
*** ../vim-8.1.2034/src/testdir/test_functions.vim      2019-09-08 
21:51:36.453843927 +0200
--- src/testdir/test_functions.vim      2019-09-15 14:16:32.940047034 +0200
***************
*** 157,162 ****
--- 157,168 ----
    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))
*** ../vim-8.1.2034/src/version.c       2019-09-15 13:16:55.208317441 +0200
--- src/version.c       2019-09-15 13:46:48.678081187 +0200
***************
*** 759,760 ****
--- 759,762 ----
  {   /* Add new patch number below this line */
+ /**/
+     2035,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
264. You turn to the teletext page "surfing report" and are surprised that it
     is about sizes of waves and a weather forecast for seaside resorts.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201909151233.x8FCXsUQ032442%40masaka.moolenaar.net.

Raspunde prin e-mail lui