# HG changeset patch # User Christian Brabandt # Date 1471377606 -7200 # Node ID b01afb4e8f66b9779a0dd7479aae46699f71a941 # Parent 0ff00d41156752bfc04a6c8e2c3180cedaa4d995 commit https://github.com/vim/vim/commit/91984b9034d3b698459622be277d963e0c6df60e Author: Bram Moolenaar 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) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- 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 --- 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 --- 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 --- 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,