changeset 20665:6ff992bf4c82 v8.2.0886

patch 8.2.0886: cannot use octal numbers in scriptversion 4 Commit: https://github.com/vim/vim/commit/c17e66c5c0acd5038f1eb3d7b3049b64bb6ea30b Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jun 2 21:38:22 2020 +0200 patch 8.2.0886: cannot use octal numbers in scriptversion 4 Problem: Cannot use octal numbers in scriptversion 4. Solution: Add the "0o" notation. (Ken Takata, closes https://github.com/vim/vim/issues/5304)
author Bram Moolenaar <Bram@vim.org>
date Tue, 02 Jun 2020 21:45:03 +0200
parents 2ee305469487
children e66b9b38cfab
files runtime/doc/eval.txt src/charset.c src/evalfunc.c src/testdir/test_eval_stuff.vim src/testdir/test_functions.vim src/version.c src/vim.h
diffstat 7 files changed, 48 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -95,15 +95,17 @@ the Number.  Examples:
 	Number -1	-->	String "-1" ~
 							*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.
+a number.  Hexadecimal "0xf9", Octal "017" or "0o17", and Binary "0b10"
+numbers are recognized (NOTE: when using |scriptversion-4| octal with a
+leading "0" is not recognized).  If the String doesn't start with digits, the
+result is zero.
 Examples:
 	String "456"	-->	Number 456 ~
 	String "6bar"	-->	Number 6 ~
 	String "foo"	-->	Number 0 ~
 	String "0xf1"	-->	Number 241 ~
 	String "0100"	-->	Number 64 ~
+	String "0o100"	-->	Number 64 ~
 	String "0b101"	-->	Number 5 ~
 	String "-8"	-->	Number -8 ~
 	String "+8"	-->	Number 0 ~
@@ -1264,7 +1266,7 @@ number			number constant			*expr-number*
 				*hex-number* *octal-number* *binary-number*
 
 Decimal, Hexadecimal (starting with 0x or 0X), Binary (starting with 0b or 0B)
-and Octal (starting with 0).
+and Octal (starting with 0, 0o or 0O).
 
 						*floating-point-format*
 Floating point numbers can be written in two forms:
@@ -9642,8 +9644,8 @@ str2nr({expr} [, {base} [, {quoted}]])		
 <
 		When {base} is 16 a leading "0x" or "0X" is ignored.  With a
 		different base the result will be zero.  Similarly, when
-		{base} is 8 a leading "0" is ignored, and when {base} is 2 a
-		leading "0b" or "0B" is ignored.
+		{base} is 8 a leading "0", "0o" or "0O" is ignored, and when
+		{base} is 2 a leading "0b" or "0B" is ignored.
 		Text after the number is silently ignored.
 
 		Can also be used as a |method|: >
@@ -13593,13 +13595,16 @@ instead of failing in mysterious ways.
 <
 							*scriptversion-4*  >
  :scriptversion 4
-<	Numbers with a leading zero are not recognized as octal.  With the
+<	Numbers with a leading zero are not recognized as octal.  "0o" or "0O"
+	is still recognized as octal.  With the
 	previous version you get: >
-		echo 017   " displays 15
-		echo 018   " displays 18
+		echo 017   " displays 15 (octal)
+		echo 0o17  " displays 15 (octal)
+		echo 018   " displays 18 (decimal)
 <	with script version 4: >
-		echo 017   " displays 17
-		echo 018   " displays 18
+		echo 017   " displays 17 (decimal)
+		echo 0o17  " displays 15 (octal)
+		echo 018   " displays 18 (decimal)
 <	Also, it is possible to use single quotes inside numbers to make them
 	easier to read: >
 		echo 1'000'000
--- a/src/charset.c
+++ b/src/charset.c
@@ -1764,6 +1764,8 @@ vim_isblankline(char_u *lbuf)
  * If "prep" is not NULL, returns a flag to indicate the type of the number:
  *  0	    decimal
  *  '0'	    octal
+ *  'O'	    octal
+ *  'o'	    octal
  *  'B'	    bin
  *  'b'	    bin
  *  'X'	    hex
@@ -1783,8 +1785,8 @@ vim_isblankline(char_u *lbuf)
 vim_str2nr(
     char_u		*start,
     int			*prep,	    // return: type of number 0 = decimal, 'x'
-				    // or 'X' is hex, '0' = octal, 'b' or 'B'
-				    // is bin
+				    // or 'X' is hex, '0', 'o' or 'O' is octal,
+				    // 'b' or 'B' is bin
     int			*len,	    // return: detected length of number
     int			what,	    // what numbers to recognize
     varnumber_T		*nptr,	    // return: signed result
@@ -1822,6 +1824,11 @@ vim_str2nr(
 		&& (maxlen == 0 || maxlen > 2))
 	    // binary
 	    ptr += 2;
+	else if ((what & STR2NR_OOCT)
+		&& (pre == 'O' || pre == 'o') && vim_isbdigit(ptr[2])
+		&& (maxlen == 0 || maxlen > 2))
+	    // octal with prefix "0o"
+	    ptr += 2;
 	else
 	{
 	    // decimal or octal, default is decimal
@@ -1869,9 +1876,12 @@ vim_str2nr(
 	    }
 	}
     }
-    else if (pre == '0' || ((what & STR2NR_OCT) && (what & STR2NR_FORCE)))
+    else if (pre == 'O' || pre == 'o' ||
+		pre == '0' || ((what & STR2NR_OCT) && (what & STR2NR_FORCE)))
     {
 	// octal
+	if (pre != 0 && pre != '0')
+	    n += 2;	    // skip over "0o"
 	while ('0' <= *ptr && *ptr <= '7')
 	{
 	    // avoid ubsan error for overflow
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -7737,7 +7737,7 @@ f_str2nr(typval_T *argvars, typval_T *re
     switch (base)
     {
 	case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
-	case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
+	case 8: what |= STR2NR_OCT + STR2NR_OOCT + STR2NR_FORCE; break;
 	case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
     }
     vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
--- a/src/testdir/test_eval_stuff.vim
+++ b/src/testdir/test_eval_stuff.vim
@@ -199,9 +199,12 @@ scriptversion 4
 func Test_vvar_scriptversion4()
   call assert_true(has('vimscript-4'))
   call assert_equal(17, 017)
+  call assert_equal(15, 0o17)
+  call assert_equal(15, 0O17)
   call assert_equal(18, 018)
   call assert_equal(64, 0b1'00'00'00)
   call assert_equal(1048576, 0x10'00'00)
+  call assert_equal(32768, 0o10'00'00)
   call assert_equal(1000000, 1'000'000)
   call assert_equal("1234", execute("echo 1'234")->trim())
   call assert_equal('1  234', execute("echo 1''234")->trim())
@@ -211,6 +214,8 @@ endfunc
 scriptversion 1
 func Test_vvar_scriptversion1()
   call assert_equal(15, 017)
+  call assert_equal(15, 0o17)
+  call assert_equal(15, 0O17)
   call assert_equal(18, 018)
 endfunc
 
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -189,6 +189,10 @@ func Test_str2nr()
   call assert_equal(65, str2nr('0101', 8))
   call assert_equal(-65, str2nr('-101', 8))
   call assert_equal(-65, str2nr('-0101', 8))
+  call assert_equal(65, str2nr('0o101', 8))
+  call assert_equal(65, str2nr('0O0101', 8))
+  call assert_equal(-65, str2nr('-0O101', 8))
+  call assert_equal(-65, str2nr('-0o0101', 8))
 
   call assert_equal(11259375, str2nr('abcdef', 16))
   call assert_equal(11259375, str2nr('ABCDEF', 16))
@@ -207,6 +211,7 @@ func Test_str2nr()
 
   call assert_equal(0, str2nr('0x10'))
   call assert_equal(0, str2nr('0b10'))
+  call assert_equal(0, str2nr('0o10'))
   call assert_equal(1, str2nr('12', 2))
   call assert_equal(1, str2nr('18', 8))
   call assert_equal(1, str2nr('1g', 16))
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    886,
+/**/
     885,
 /**/
     884,
--- a/src/vim.h
+++ b/src/vim.h
@@ -312,11 +312,12 @@
 #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_BIN  0x01
+#define STR2NR_OCT  0x02
+#define STR2NR_HEX  0x04
+#define STR2NR_OOCT 0x08    // Octal with prefix "0o": 0o777
+#define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX + STR2NR_OOCT)
+#define STR2NR_NO_OCT (STR2NR_BIN + STR2NR_HEX + STR2NR_OOCT)
 
 #define STR2NR_FORCE 0x80   // only when ONE of the above is used