# HG changeset patch # User Christian Brabandt # Date 1471376706 -7200 # Node ID 41c5d59e7e10cfc6592f6378e0d1d05f8032d2a9 # Parent ec73a26cd6cffc5276e310841ee2cf9a8eefbac0 commit https://github.com/vim/vim/commit/e5a8f35b4286135f3469f3b00a6c2220553d9658 Author: Bram Moolenaar Date: Tue Aug 16 21:30:54 2016 +0200 patch 7.4.2220 Problem: printf() gives an error when the argument for %s is not a string. (Ozaki Kiichi) Solution: Behave like invoking string() on the argument. (Ken Takata) diff --git a/src/message.c b/src/message.c --- a/src/message.c +++ b/src/message.c @@ -3887,7 +3887,7 @@ do_browse( static char *e_printf = N_("E766: Insufficient arguments for printf()"); static varnumber_T tv_nr(typval_T *tvs, int *idxp); -static char *tv_str(typval_T *tvs, int *idxp); +static char *tv_str(typval_T *tvs, int *idxp, char_u **tofree); # ifdef FEAT_FLOAT static double tv_float(typval_T *tvs, int *idxp); # endif @@ -3916,20 +3916,28 @@ tv_nr(typval_T *tvs, int *idxp) /* * Get string argument from "idxp" entry in "tvs". First entry is 1. + * If "tofree" is NULL get_tv_string_chk() is used. Some types (e.g. List) + * are not converted to a string. + * If "tofree" is not NULL echo_string() is used. All types are converted to + * a string with the same format as ":echo". The caller must free "*tofree". * Returns NULL for an error. */ static char * -tv_str(typval_T *tvs, int *idxp) +tv_str(typval_T *tvs, int *idxp, char_u **tofree) { - int idx = *idxp - 1; - char *s = NULL; + int idx = *idxp - 1; + char *s = NULL; + static char_u numbuf[NUMBUFLEN]; if (tvs[idx].v_type == VAR_UNKNOWN) EMSG(_(e_printf)); else { ++*idxp; - s = (char *)get_tv_string_chk(&tvs[idx]); + if (tofree != NULL) + s = (char *)echo_string(&tvs[idx], tofree, numbuf, get_copyID()); + else + s = (char *)get_tv_string_chk(&tvs[idx]); } return s; } @@ -4113,6 +4121,10 @@ vim_vsnprintf( /* current conversion specifier character */ char fmt_spec = '\0'; + /* buffer for 's' and 'S' specs */ + char_u *tofree = NULL; + + str_arg = NULL; p++; /* skip '%' */ @@ -4276,7 +4288,7 @@ vim_vsnprintf( case 'S': str_arg = # if defined(FEAT_EVAL) - tvs != NULL ? tv_str(tvs, &arg_idx) : + tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) : # endif va_arg(ap, char *); if (str_arg == NULL) @@ -4367,7 +4379,8 @@ vim_vsnprintf( length_modifier = '\0'; ptr_arg = # if defined(FEAT_EVAL) - tvs != NULL ? (void *)tv_str(tvs, &arg_idx) : + tvs != NULL ? (void *)tv_str(tvs, &arg_idx, + NULL) : # endif va_arg(ap, void *); if (ptr_arg != NULL) @@ -4877,6 +4890,7 @@ vim_vsnprintf( str_l += pn; } } + vim_free(tofree); } } 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 @@ -136,6 +136,33 @@ function Test_printf_64bit() endif endfunc +function Test_printf_spec_s() + " number + call assert_equal("1234567890", printf('%s', 1234567890)) + + " string + call assert_equal("abcdefgi", printf('%s', "abcdefgi")) + + " float + if has('float') + call assert_equal("1.23", printf('%s', 1.23)) + endif + + " list + let value = [1, 'two', ['three', 4]] + call assert_equal(string(value), printf('%s', value)) + + " dict + let value = {'key1' : 'value1', 'key2' : ['list', 'value'], 'key3' : {'dict' : 'value'}} + call assert_equal(string(value), printf('%s', value)) + + " funcref + call assert_equal('printf', printf('%s', function('printf'))) + + " partial + call assert_equal(string(function('printf', ['%s'])), printf('%s', function('printf', ['%s']))) +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 */ /**/ + 2220, +/**/ 2219, /**/ 2218,