summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-08-16 21:58:41 +0200
committerBram Moolenaar <Bram@vim.org>2016-08-16 21:58:41 +0200
commit91984b9034d3b698459622be277d963e0c6df60e (patch)
tree329479725a833a6bc5ae7b42cf7c1686c6542597
parente5a8f35b4286135f3469f3b00a6c2220553d9658 (diff)
patch 7.4.2221v7.4.2221
Problem: printf() does not support binary format. Solution: Add %b and %B. (Ozaki Kiichi)
-rw-r--r--runtime/doc/eval.txt21
-rw-r--r--src/message.c49
-rw-r--r--src/testdir/test_expr.vim17
-rw-r--r--src/version.c2
4 files changed, 75 insertions, 14 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index f281f4aa81..32d8dad52e 100644
--- 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
diff --git a/src/message.c b/src/message.c
index 513f2888da..a7398f6eb0 100644
--- 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 */
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
index e835854031..a7ad65eef4 100644
--- 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', ''))
diff --git a/src/version.c b/src/version.c
index bb933d2bd6..0395201c69 100644
--- 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,