To: vim_dev@googlegroups.com Subject: Patch 7.4.2220 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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) Files: runtime/doc/eval.txt, src/message.c, src/testdir/test_expr.vim *** ../vim-7.4.2219/runtime/doc/eval.txt 2016-08-15 22:16:21.557888355 +0200 --- runtime/doc/eval.txt 2016-08-16 21:22:55.590093669 +0200 *************** *** 5960,5965 **** --- 5989,5998 ---- s The text of the String argument is used. If a precision is specified, no more bytes than the number specified are used. + If the argument is not a String type, it is + automatically converted to text with the same format + as ":echo". + *printf-S* S The text of the String argument is used. If a precision is specified, no more display cells than the number specified are used. Without the |+multi_byte| *** ../vim-7.4.2219/src/message.c 2016-07-30 16:40:34.780374612 +0200 --- src/message.c 2016-08-16 21:22:55.590093669 +0200 *************** *** 3887,3893 **** 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); # ifdef FEAT_FLOAT static double tv_float(typval_T *tvs, int *idxp); # endif --- 3887,3893 ---- 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, char_u **tofree); # ifdef FEAT_FLOAT static double tv_float(typval_T *tvs, int *idxp); # endif *************** *** 3916,3935 **** /* * Get string argument from "idxp" entry in "tvs". First entry is 1. * Returns NULL for an error. */ static char * ! tv_str(typval_T *tvs, int *idxp) { ! int idx = *idxp - 1; ! char *s = NULL; if (tvs[idx].v_type == VAR_UNKNOWN) EMSG(_(e_printf)); else { ++*idxp; ! s = (char *)get_tv_string_chk(&tvs[idx]); } return s; } --- 3916,3943 ---- /* * 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, char_u **tofree) { ! int idx = *idxp - 1; ! char *s = NULL; ! static char_u numbuf[NUMBUFLEN]; if (tvs[idx].v_type == VAR_UNKNOWN) EMSG(_(e_printf)); else { ++*idxp; ! 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,4118 **** --- 4121,4130 ---- /* current conversion specifier character */ char fmt_spec = '\0'; + /* buffer for 's' and 'S' specs */ + char_u *tofree = NULL; + + str_arg = NULL; p++; /* skip '%' */ *************** *** 4276,4282 **** case 'S': str_arg = # if defined(FEAT_EVAL) ! tvs != NULL ? tv_str(tvs, &arg_idx) : # endif va_arg(ap, char *); if (str_arg == NULL) --- 4288,4294 ---- case 'S': str_arg = # if defined(FEAT_EVAL) ! tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) : # endif va_arg(ap, char *); if (str_arg == NULL) *************** *** 4367,4373 **** length_modifier = '\0'; ptr_arg = # if defined(FEAT_EVAL) ! tvs != NULL ? (void *)tv_str(tvs, &arg_idx) : # endif va_arg(ap, void *); if (ptr_arg != NULL) --- 4379,4386 ---- length_modifier = '\0'; ptr_arg = # if defined(FEAT_EVAL) ! tvs != NULL ? (void *)tv_str(tvs, &arg_idx, ! NULL) : # endif va_arg(ap, void *); if (ptr_arg != NULL) *************** *** 4877,4882 **** --- 4890,4896 ---- str_l += pn; } } + vim_free(tofree); } } *** ../vim-7.4.2219/src/testdir/test_expr.vim 2016-08-05 22:51:09.597156984 +0200 --- src/testdir/test_expr.vim 2016-08-16 21:26:27.244199354 +0200 *************** *** 136,141 **** --- 136,168 ---- 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', '')) *** ../vim-7.4.2219/src/version.c 2016-08-16 21:04:37.827952367 +0200 --- src/version.c 2016-08-16 21:23:31.233775243 +0200 *************** *** 765,766 **** --- 765,768 ---- { /* Add new patch number below this line */ + /**/ + 2220, /**/ -- How To Keep A Healthy Level Of Insanity: 13. Go to a poetry recital and ask why the poems don't rhyme. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///