changeset 9894:b01afb4e8f66 v7.4.2221

commit https://github.com/vim/vim/commit/91984b9034d3b698459622be277d963e0c6df60e Author: Bram Moolenaar <Bram@vim.org> Date: Tue Aug 16 21:58:41 2016 +0200 patch 7.4.2221 Problem: printf() does not support binary format. Solution: Add %b and %B. (Ozaki Kiichi)
author Christian Brabandt <cb@256bit.org>
date Tue, 16 Aug 2016 22:00:06 +0200
parents 0ff00d411567
children 1e88c3dd0ae2
files runtime/doc/eval.txt src/message.c src/testdir/test_expr.vim src/version.c
diffstat 4 files changed, 75 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5884,6 +5884,7 @@ printf({fmt}, {expr1} ...)				*printf()*
 		  %04x	hex number padded with zeros to at least 4 characters
 		  %X	hex number using upper case letters
 		  %o	octal number
+		  %08b	binary number padded with zeros to at least 8 chars
 		  %f	floating point number in the form 123.456
 		  %e	floating point number in the form 1.234e3
 		  %E	floating point number in the form 1.234E3
@@ -5910,6 +5911,9 @@ printf({fmt}, {expr1} ...)				*printf()*
 			      character of the output string to a zero (except
 			      if a zero value is printed with an explicit
 			      precision of zero).
+			      For b and B conversions, a non-zero result has
+			      the string "0b" (or "0B" for B conversions)
+			      prepended to it.
 			      For x and X conversions, a non-zero result has
 			      the string "0x" (or "0X" for X conversions)
 			      prepended to it.
@@ -5917,8 +5921,8 @@ printf({fmt}, {expr1} ...)				*printf()*
 		    0 (zero)  Zero padding.  For all conversions the converted
 			      value is padded on the left with zeros rather
 			      than blanks.  If a precision is given with a
-			      numeric conversion (d, o, x, and X), the 0 flag
-			      is ignored.
+			      numeric conversion (d, b, B, o, x, and X), the 0
+			      flag is ignored.
 
 		    -	      A negative field width flag; the converted value
 			      is to be left adjusted on the field boundary.
@@ -5966,12 +5970,13 @@ printf({fmt}, {expr1} ...)				*printf()*
 
 		The conversion specifiers and their meanings are:
 
-				*printf-d* *printf-o* *printf-x* *printf-X*
-		doxX	The Number argument is converted to signed decimal
-			(d), unsigned octal (o), or unsigned hexadecimal (x
-			and X) notation.  The letters "abcdef" are used for
-			x conversions; the letters "ABCDEF" are used for X
-			conversions.
+				*printf-d* *printf-b* *printf-B* *printf-o*
+				*printf-x* *printf-X*
+		dbBoxX	The Number argument is converted to signed decimal
+			(d), unsigned binary (b and B), unsigned octal (o), or
+			unsigned hexadecimal (x and X) notation.  The letters
+			"abcdef" are used for x conversions; the letters
+			"ABCDEF" are used for X conversions.
 			The precision, if any, gives the minimum number of
 			digits that must appear; if the converted value
 			requires fewer digits, it is padded on the left with
--- a/src/message.c
+++ b/src/message.c
@@ -4091,12 +4091,14 @@ vim_vsnprintf(
 	    char    length_modifier = '\0';
 
 	    /* temporary buffer for simple numeric->string conversion */
-# ifdef FEAT_FLOAT
+# if defined(FEAT_FLOAT)
 #  define TMP_LEN 350	/* On my system 1e308 is the biggest number possible.
 			 * That sounds reasonable to use as the maximum
 			 * printable. */
+# elif defined(FEAT_NUM64)
+#  define TMP_LEN 66
 # else
-#  define TMP_LEN 32
+#  define TMP_LEN 34
 # endif
 	    char    tmp[TMP_LEN];
 
@@ -4343,9 +4345,13 @@ vim_vsnprintf(
 		}
 		break;
 
-	    case 'd': case 'u': case 'o': case 'x': case 'X': case 'p':
+	    case 'd': case 'u':
+	    case 'b': case 'B':
+	    case 'o':
+	    case 'x': case 'X':
+	    case 'p':
 		{
-		    /* NOTE: the u, o, x, X and p conversion specifiers
+		    /* NOTE: the u, b, o, x, X and p conversion specifiers
 		     * imply the value is unsigned;  d implies a signed
 		     * value */
 
@@ -4370,6 +4376,9 @@ vim_vsnprintf(
 		    uvarnumber_T ullong_arg = 0;
 # endif
 
+		    /* only defined for b convertion */
+		    uvarnumber_T bin_arg = 0;
+
 		    /* pointer argument value -only defined for p
 		     * conversion */
 		    void *ptr_arg = NULL;
@@ -4386,6 +4395,17 @@ vim_vsnprintf(
 			if (ptr_arg != NULL)
 			    arg_sign = 1;
 		    }
+		    else if (fmt_spec == 'b' || fmt_spec == 'B')
+		    {
+			bin_arg =
+# if defined(FEAT_EVAL)
+				    tvs != NULL ?
+					   (uvarnumber_T)tv_nr(tvs, &arg_idx) :
+# endif
+					va_arg(ap, uvarnumber_T);
+			if (bin_arg != 0)
+			    arg_sign = 1;
+		    }
 		    else if (fmt_spec == 'd')
 		    {
 			/* signed */
@@ -4492,7 +4512,8 @@ vim_vsnprintf(
 		    else if (alternate_form)
 		    {
 			if (arg_sign != 0
-				     && (fmt_spec == 'x' || fmt_spec == 'X') )
+				     && (fmt_spec == 'b' || fmt_spec == 'B'
+				      || fmt_spec == 'x' || fmt_spec == 'X') )
 			{
 			    tmp[str_arg_l++] = '0';
 			    tmp[str_arg_l++] = fmt_spec;
@@ -4508,7 +4529,7 @@ vim_vsnprintf(
 		    {
 			/* When zero value is formatted with an explicit
 			 * precision 0, the resulting formatted string is
-			 * empty (d, i, u, o, x, X, p).   */
+			 * empty (d, i, u, b, B, o, x, X, p).   */
 		    }
 		    else
 		    {
@@ -4541,6 +4562,22 @@ vim_vsnprintf(
 
 			if (fmt_spec == 'p')
 			    str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg);
+			else if (fmt_spec == 'b' || fmt_spec == 'B')
+			{
+			    char	    b[8 * sizeof(uvarnumber_T)];
+			    size_t	    b_l = 0;
+			    uvarnumber_T    bn = bin_arg;
+
+			    do
+			    {
+				b[sizeof(b) - ++b_l] = '0' + (bn & 0x1);
+				bn >>= 1;
+			    }
+			    while (bn != 0);
+
+			    memcpy(tmp + str_arg_l, b + sizeof(b) - b_l, b_l);
+			    str_arg_l += b_l;
+			}
 			else if (fmt_spec == 'd')
 			{
 			    /* signed */
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -163,6 +163,23 @@ function Test_printf_spec_s()
   call assert_equal(string(function('printf', ['%s'])), printf('%s', function('printf', ['%s'])))
 endfunc
 
+function Test_printf_spec_b()
+  call assert_equal("0", printf('%b', 0))
+  call assert_equal("00001100", printf('%08b', 12))
+  call assert_equal("11111111", printf('%08b', 0xff))
+  call assert_equal("   1111011", printf('%10b', 123))
+  call assert_equal("0001111011", printf('%010b', 123))
+  call assert_equal(" 0b1111011", printf('%#10b', 123))
+  call assert_equal("0B01111011", printf('%#010B', 123))
+  call assert_equal("1001001100101100000001011010010", printf('%b', 1234567890))
+  if has('num64')
+    call assert_equal("11100000100100010000110000011011101111101111001", printf('%b', 123456789012345))
+    call assert_equal("1111111111111111111111111111111111111111111111111111111111111111", printf('%b', -1))
+  else
+    call assert_equal("11111111111111111111111111111111", printf('%b', -1))
+  endif
+endfunc
+
 func Test_substitute_expr()
   let g:val = 'XXX'
   call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2221,
+/**/
     2220,
 /**/
     2219,