Patch 8.1.2035

26 views
Skip to first unread message

Bram Moolenaar

unread,
Sep 15, 2019, 8:34:03 AM9/15/19
to vim...@googlegroups.com

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 -- Br...@Moolenaar.net -- 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 ///

Andy Wokula

unread,
Sep 15, 2019, 1:59:21 PM9/15/19
to vim...@googlegroups.com
Am 15.09.2019 um 14:33 schrieb Bram Moolenaar:
> 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

Single quotes could be a pitfall for scripts that attempt to skip string
literals in Vim script code.

> // 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

Is 0x80 the intended value or 0x08 ?

> ! #define STR2NR_QUOTE 0x10 // ignore embedded single quotes

What happens with
:echo 1''234
:echo 1'''234
? Is it an error?

--
Andy

Bram Moolenaar

unread,
Sep 15, 2019, 3:13:08 PM9/15/19
to vim...@googlegroups.com

Andy Wokula wrote:

> Am 15.09.2019 um 14:33 schrieb Bram Moolenaar:
> > 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
>
> Single quotes could be a pitfall for scripts that attempt to skip string
> literals in Vim script code.

It's not difficult to handle this syntax.

> > // 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
>
> Is 0x80 the intended value or 0x08 ?

Doesn't matter, just wanted to make sure it's further away from the
BIN/OCT/HEX values.

> > ! #define STR2NR_QUOTE 0x10 // ignore embedded single quotes
>
> What happens with
> :echo 1''234
> :echo 1'''234
> ? Is it an error?

A double single quote is not part of the number, thus 1''234 is the same
as
:echo 1 '' 234

Should add a test for that.

--
Women are probably the main cause of free software starvation.

Andy Wokula

unread,
Sep 16, 2019, 11:06:45 AM9/16/19
to vim...@googlegroups.com
Am 15.09.2019 um 21:13 schrieb Bram Moolenaar:
> Andy Wokula wrote:
>
>> Am 15.09.2019 um 14:33 schrieb Bram Moolenaar:
>>> 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
>>
>> Single quotes could be a pitfall for scripts that attempt to skip string
>> literals in Vim script code.
>
> It's not difficult to handle this syntax.
>>
>> Is 0x80 the intended value or 0x08 ?
>
> Doesn't matter, just wanted to make sure it's further away from the
> BIN/OCT/HEX values.
>
>> What happens with
>> :echo 1''234
> Should add a test for that.

Ok ok ok ^^.

--
Andy
Reply all
Reply to author
Forward
0 new messages