From 2f80360e9acdb32f63633e8408c00de2ef972b3b Mon Sep 17 00:00:00 2001 From: Jurica Bradaric Date: Sun, 5 Mar 2017 22:20:48 +0100 Subject: vim-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) https://github.com/vim/vim/commit/e5a8f35b4286135f3469f3b00a6c2220553d9658 --- src/nvim/strings.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src/nvim/strings.c') diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 5b6fbf75a9..6bfb63251c 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -45,6 +45,7 @@ #include "nvim/window.h" #include "nvim/os/os.h" #include "nvim/os/shell.h" +#include "nvim/eval/encode.h" /* * Copy "string" into newly allocated memory. @@ -588,18 +589,30 @@ static varnumber_T tv_nr(typval_T *tvs, int *idxp) /// value. /// @param[in,out] idxp Index in a list. Will be incremented. /// +/// @param[out] tofree 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 encode_tv2echo() is used. All +/// types are converted to a string with the same format as +/// ":echo". The caller must free "*tofree". +/// /// @return String value or NULL in case of error. -static char *tv_str(typval_T *tvs, int *idxp) - FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +static char *tv_str(typval_T *tvs, int *idxp, char_u **tofree) + FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) + FUNC_ATTR_WARN_UNUSED_RESULT { int idx = *idxp - 1; - char *s = NULL; + char *s = NULL; if (tvs[idx].v_type == VAR_UNKNOWN) { EMSG(_(e_printf)); } else { (*idxp)++; - s = (char *)get_tv_string_chk(&tvs[idx]); + if (tofree != NULL) { + s = encode_tv2echo(&tvs[idx], NULL); + *tofree = (char_u *)s; + } else { + s = (char *)get_tv_string_chk(&tvs[idx]); + } } return s; } @@ -813,6 +826,9 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, // current conversion specifier character char fmt_spec = '\0'; + // buffer for 's' and 'S' specs + char_u *tofree = NULL; + p++; // skip '%' // parse flags @@ -919,7 +935,8 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, case 's': case 'S': - str_arg = tvs ? tv_str(tvs, &arg_idx) : va_arg(ap, char *); + str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree) + : va_arg(ap, char *); if (!str_arg) { str_arg = "[NULL]"; str_arg_l = 6; @@ -1370,6 +1387,8 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, str_l += pn; } } + + xfree(tofree); } } -- cgit From 04b91d6b89f12df314e0d209afe2d5f872c5caf2 Mon Sep 17 00:00:00 2001 From: Jurica Bradaric Date: Mon, 6 Mar 2017 21:33:55 +0100 Subject: strings.c: Fix problems found during code review. --- src/nvim/strings.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'src/nvim/strings.c') diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 6bfb63251c..0dc27061f4 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -588,17 +588,14 @@ static varnumber_T tv_nr(typval_T *tvs, int *idxp) /// @param[in] tvs List of VimL values. List is terminated by VAR_UNKNOWN /// value. /// @param[in,out] idxp Index in a list. Will be incremented. -/// -/// @param[out] tofree 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 encode_tv2echo() is used. All -/// types are converted to a string with the same format as -/// ":echo". The caller must free "*tofree". +/// @param[out] tofree If the idxp entry in tvs is not a String or a Number, +/// it will be converted to String in the same format +/// as ":echo" and stored in "*tofree". The caller must +/// free "*tofree". /// /// @return String value or NULL in case of error. -static char *tv_str(typval_T *tvs, int *idxp, char_u **tofree) - FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2) - FUNC_ATTR_WARN_UNUSED_RESULT +static char *tv_str(typval_T *tvs, int *idxp, char ** const tofree) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { int idx = *idxp - 1; char *s = NULL; @@ -607,11 +604,12 @@ static char *tv_str(typval_T *tvs, int *idxp, char_u **tofree) EMSG(_(e_printf)); } else { (*idxp)++; - if (tofree != NULL) { - s = encode_tv2echo(&tvs[idx], NULL); - *tofree = (char_u *)s; - } else { + if (tvs[idx].v_type == VAR_STRING || tvs[idx].v_type == VAR_NUMBER) { s = (char *)get_tv_string_chk(&tvs[idx]); + *tofree = NULL; + } else { + s = encode_tv2echo(&tvs[idx], NULL); + *tofree = s; } } return s; @@ -827,7 +825,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, char fmt_spec = '\0'; // buffer for 's' and 'S' specs - char_u *tofree = NULL; + char *tofree = NULL; p++; // skip '%' -- cgit