summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-08-16 21:30:54 +0200
committerBram Moolenaar <Bram@vim.org>2016-08-16 21:30:54 +0200
commite5a8f35b4286135f3469f3b00a6c2220553d9658 (patch)
treea7505fde61e414d9664d99be9136677584277521 /src
parentf5a39447a8ebe162ee62caa2ee502cd0e65eecaa (diff)
patch 7.4.2220v7.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)
Diffstat (limited to 'src')
-rw-r--r--src/message.c28
-rw-r--r--src/testdir/test_expr.vim27
-rw-r--r--src/version.c2
3 files changed, 50 insertions, 7 deletions
diff --git a/src/message.c b/src/message.c
index b4d7b65e67..513f2888da 100644
--- 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
index cd71c419a1..e835854031 100644
--- 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
index 505231fec6..bb933d2bd6 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 */
/**/
+ 2220,
+/**/
2219,
/**/
2218,