To: vim_dev@googlegroups.com Subject: Patch 8.2.3320 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3320 Problem: Some local functions are not static. Solution: Add "static". Move snprintf() related code to strings.c. (Yegappan Lakshmanan, closes #8734) Files: src/alloc.c, src/channel.c, src/dict.c, src/digraph.c, src/edit.c, src/ex_docmd.c, src/getchar.c, src/job.c, src/list.c, src/message.c, src/profiler.c, src/proto/channel.pro, src/proto/dict.pro, src/proto/digraph.pro, src/proto/edit.pro, src/proto/ex_docmd.pro, src/proto/getchar.pro, src/proto/job.pro, src/proto/list.pro, src/proto/profiler.pro, src/proto/spell.pro, src/proto/vim9compile.pro, src/proto/vim9script.pro, src/proto/vim9type.pro, src/spell.c, src/strings.c, src/vim9compile.c, src/vim9script.c, src/vim9type.c, src/window.c *** ../vim-8.2.3319/src/alloc.c 2021-08-06 21:51:33.892689095 +0200 --- src/alloc.c 2021-08-09 19:56:02.947236101 +0200 *************** *** 232,250 **** mem_pre_alloc_l(&size); #endif ! /* ! * Loop when out of memory: Try to release some memfile blocks and ! * if some blocks are released call malloc again. ! */ for (;;) { ! /* ! * Handle three kind of systems: ! * 1. No check for available memory: Just return. ! * 2. Slow check for available memory: call mch_avail_mem() after ! * allocating KEEP_ROOM amount of memory. ! * 3. Strict check for available memory: call mch_avail_mem() ! */ if ((p = malloc(size)) != NULL) { #ifndef HAVE_AVAIL_MEM --- 232,246 ---- mem_pre_alloc_l(&size); #endif ! // Loop when out of memory: Try to release some memfile blocks and ! // if some blocks are released call malloc again. for (;;) { ! // Handle three kind of systems: ! // 1. No check for available memory: Just return. ! // 2. Slow check for available memory: call mch_avail_mem() after ! // allocating KEEP_ROOM amount of memory. ! // 3. Strict check for available memory: call mch_avail_mem() if ((p = malloc(size)) != NULL) { #ifndef HAVE_AVAIL_MEM *************** *** 268,277 **** goto theend; #endif } ! /* ! * Remember that mf_release_all() is being called to avoid an endless ! * loop, because mf_release_all() may call alloc() recursively. ! */ if (releasing) break; releasing = TRUE; --- 264,271 ---- goto theend; #endif } ! // Remember that mf_release_all() is being called to avoid an endless ! // loop, because mf_release_all() may call alloc() recursively. if (releasing) break; releasing = TRUE; *** ../vim-8.2.3319/src/channel.c 2021-08-02 18:07:15.186473836 +0200 --- src/channel.c 2021-08-09 19:56:02.947236101 +0200 *************** *** 3025,3031 **** * Return a string indicating the status of the channel. * If "req_part" is not negative check that part. */ ! char * channel_status(channel_T *channel, int req_part) { ch_part_T part; --- 3025,3031 ---- * Return a string indicating the status of the channel. * If "req_part" is not negative check that part. */ ! static char * channel_status(channel_T *channel, int req_part) { ch_part_T part; *** ../vim-8.2.3319/src/dict.c 2021-07-27 22:00:39.737712414 +0200 --- src/dict.c 2021-08-09 19:56:02.947236101 +0200 *************** *** 805,811 **** * Advance over a literal key, including "-". If the first character is not a * literal key character then "key" is returned. */ ! char_u * skip_literal_key(char_u *key) { char_u *p; --- 805,811 ---- * Advance over a literal key, including "-". If the first character is not a * literal key character then "key" is returned. */ ! static char_u * skip_literal_key(char_u *key) { char_u *p; *** ../vim-8.2.3319/src/digraph.c 2021-07-27 22:00:39.741712405 +0200 --- src/digraph.c 2021-08-09 19:56:02.947236101 +0200 *************** *** 2029,2035 **** * If they are valid, returns TRUE; otherwise, give an error message and * returns FALSE. */ ! int check_digraph_chars_valid(int char1, int char2) { if (char2 == 0) --- 2029,2035 ---- * If they are valid, returns TRUE; otherwise, give an error message and * returns FALSE. */ ! static int check_digraph_chars_valid(int char1, int char2) { if (char2 == 0) *************** *** 2193,2199 **** li2->li_tv.vval.v_string = vim_strsave(buf); } ! void digraph_getlist_common(int list_all, typval_T *rettv) { int i; --- 2193,2199 ---- li2->li_tv.vval.v_string = vim_strsave(buf); } ! static void digraph_getlist_common(int list_all, typval_T *rettv) { int i; *** ../vim-8.2.3319/src/edit.c 2021-07-26 22:19:05.376122583 +0200 --- src/edit.c 2021-08-09 19:56:02.947236101 +0200 *************** *** 1587,1593 **** * Note that this doesn't wait for characters, they must be in the typeahead * buffer already. */ ! int decodeModifyOtherKeys(int c) { char_u *p = typebuf.tb_buf + typebuf.tb_off; --- 1587,1593 ---- * Note that this doesn't wait for characters, they must be in the typeahead * buffer already. */ ! static int decodeModifyOtherKeys(int c) { char_u *p = typebuf.tb_buf + typebuf.tb_off; *** ../vim-8.2.3319/src/ex_docmd.c 2021-08-05 21:17:28.755789462 +0200 --- src/ex_docmd.c 2021-08-09 19:56:02.947236101 +0200 *************** *** 598,604 **** * Execute the "+cmd" argument of "edit +cmd fname" and the like. * This allows for using a range without ":" in Vim9 script. */ ! int do_cmd_argument(char_u *cmd) { return do_cmdline(cmd, NULL, NULL, --- 598,604 ---- * Execute the "+cmd" argument of "edit +cmd fname" and the like. * This allows for using a range without ":" in Vim9 script. */ ! static int do_cmd_argument(char_u *cmd) { return do_cmdline(cmd, NULL, NULL, *** ../vim-8.2.3319/src/getchar.c 2021-07-27 22:00:39.745712396 +0200 --- src/getchar.c 2021-08-09 19:56:02.951236093 +0200 *************** *** 631,637 **** add_buff(&readbuf2, s, -1L); } ! void stuffReadbuffLen(char_u *s, long len) { add_buff(&readbuf1, s, len); --- 631,637 ---- add_buff(&readbuf2, s, -1L); } ! static void stuffReadbuffLen(char_u *s, long len) { add_buff(&readbuf1, s, len); *** ../vim-8.2.3319/src/job.c 2021-07-27 22:00:39.745712396 +0200 --- src/job.c 2021-08-09 19:56:02.951236093 +0200 *************** *** 1582,1588 **** /* * Return the effective prompt for the specified buffer. */ ! char_u * buf_prompt_text(buf_T* buf) { if (buf->b_prompt_text == NULL) --- 1582,1588 ---- /* * Return the effective prompt for the specified buffer. */ ! static char_u * buf_prompt_text(buf_T* buf) { if (buf->b_prompt_text == NULL) *** ../vim-8.2.3319/src/list.c 2021-08-04 19:25:50.614808524 +0200 --- src/list.c 2021-08-09 19:56:02.951236093 +0200 *************** *** 620,626 **** * As list_append_tv() but move the value instead of copying it. * Return FAIL when out of memory. */ ! int list_append_tv_move(list_T *l, typval_T *tv) { listitem_T *li = listitem_alloc(); --- 620,626 ---- * As list_append_tv() but move the value instead of copying it. * Return FAIL when out of memory. */ ! static int list_append_tv_move(list_T *l, typval_T *tv) { listitem_T *li = listitem_alloc(); *** ../vim-8.2.3319/src/message.c 2021-07-11 19:12:00.045760328 +0200 --- src/message.c 2021-08-09 19:56:02.951236093 +0200 *************** *** 12,18 **** */ #define MESSAGE_FILE // don't include prototype for smsg() - #define USING_FLOAT_STUFF #include "vim.h" --- 12,17 ---- *************** *** 4108,5219 **** } #endif // FEAT_GUI_DIALOG || FEAT_CON_DIALOG - - #if defined(FEAT_EVAL) - static char *e_printf = N_("E766: Insufficient arguments for printf()"); - - /* - * Get number argument from "idxp" entry in "tvs". First entry is 1. - */ - static varnumber_T - tv_nr(typval_T *tvs, int *idxp) - { - int idx = *idxp - 1; - varnumber_T n = 0; - int err = FALSE; - - if (tvs[idx].v_type == VAR_UNKNOWN) - emsg(_(e_printf)); - else - { - ++*idxp; - n = tv_get_number_chk(&tvs[idx], &err); - if (err) - n = 0; - } - return n; - } - - /* - * Get string argument from "idxp" entry in "tvs". First entry is 1. - * If "tofree" is NULL tv_get_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 *)tv_get_string_chk(&tvs[idx]); - } - return s; - } - - # ifdef FEAT_FLOAT - /* - * Get float argument from "idxp" entry in "tvs". First entry is 1. - */ - static double - tv_float(typval_T *tvs, int *idxp) - { - int idx = *idxp - 1; - double f = 0; - - if (tvs[idx].v_type == VAR_UNKNOWN) - emsg(_(e_printf)); - else - { - ++*idxp; - if (tvs[idx].v_type == VAR_FLOAT) - f = tvs[idx].vval.v_float; - else if (tvs[idx].v_type == VAR_NUMBER) - f = (double)tvs[idx].vval.v_number; - else - emsg(_("E807: Expected Float argument for printf()")); - } - return f; - } - # endif - #endif - - #ifdef FEAT_FLOAT - /* - * Return the representation of infinity for printf() function: - * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF". - */ - static const char * - infinity_str(int positive, - char fmt_spec, - int force_sign, - int space_for_positive) - { - static const char *table[] = - { - "-inf", "inf", "+inf", " inf", - "-INF", "INF", "+INF", " INF" - }; - int idx = positive * (1 + force_sign + force_sign * space_for_positive); - - if (ASCII_ISUPPER(fmt_spec)) - idx += 4; - return table[idx]; - } - #endif - - /* - * This code was included to provide a portable vsnprintf() and snprintf(). - * Some systems may provide their own, but we always use this one for - * consistency. - * - * This code is based on snprintf.c - a portable implementation of snprintf - * by Mark Martinec , Version 2.2, 2000-10-06. - * Included with permission. It was heavily modified to fit in Vim. - * The original code, including useful comments, can be found here: - * http://www.ijs.si/software/snprintf/ - * - * This snprintf() only supports the following conversion specifiers: - * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) - * with flags: '-', '+', ' ', '0' and '#'. - * An asterisk is supported for field width as well as precision. - * - * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'. - * - * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int) - * are supported. NOTE: for 'll' the argument is varnumber_T or uvarnumber_T. - * - * The locale is not used, the string is used as a byte string. This is only - * relevant for double-byte encodings where the second byte may be '%'. - * - * It is permitted for "str_m" to be zero, and it is permitted to specify NULL - * pointer for resulting string argument if "str_m" is zero (as per ISO C99). - * - * The return value is the number of characters which would be generated - * for the given input, excluding the trailing NUL. If this value - * is greater or equal to "str_m", not all characters from the result - * have been stored in str, output bytes beyond the ("str_m"-1) -th character - * are discarded. If "str_m" is greater than zero it is guaranteed - * the resulting string will be NUL-terminated. - */ - - /* - * When va_list is not supported we only define vim_snprintf(). - * - * vim_vsnprintf_typval() can be invoked with either "va_list" or a list of - * "typval_T". When the latter is not used it must be NULL. - */ - - // When generating prototypes all of this is skipped, cproto doesn't - // understand this. - #ifndef PROTO - - // Like vim_vsnprintf() but append to the string. - int - vim_snprintf_add(char *str, size_t str_m, const char *fmt, ...) - { - va_list ap; - int str_l; - size_t len = STRLEN(str); - size_t space; - - if (str_m <= len) - space = 0; - else - space = str_m - len; - va_start(ap, fmt); - str_l = vim_vsnprintf(str + len, space, fmt, ap); - va_end(ap); - return str_l; - } - - int - vim_snprintf(char *str, size_t str_m, const char *fmt, ...) - { - va_list ap; - int str_l; - - va_start(ap, fmt); - str_l = vim_vsnprintf(str, str_m, fmt, ap); - va_end(ap); - return str_l; - } - - int - vim_vsnprintf( - char *str, - size_t str_m, - const char *fmt, - va_list ap) - { - return vim_vsnprintf_typval(str, str_m, fmt, ap, NULL); - } - - int - vim_vsnprintf_typval( - char *str, - size_t str_m, - const char *fmt, - va_list ap, - typval_T *tvs) - { - size_t str_l = 0; - const char *p = fmt; - int arg_idx = 1; - - if (p == NULL) - p = ""; - while (*p != NUL) - { - if (*p != '%') - { - char *q = strchr(p + 1, '%'); - size_t n = (q == NULL) ? STRLEN(p) : (size_t)(q - p); - - // Copy up to the next '%' or NUL without any changes. - if (str_l < str_m) - { - size_t avail = str_m - str_l; - - mch_memmove(str + str_l, p, n > avail ? avail : n); - } - p += n; - str_l += n; - } - else - { - size_t min_field_width = 0, precision = 0; - int zero_padding = 0, precision_specified = 0, justify_left = 0; - int alternate_form = 0, force_sign = 0; - - // If both the ' ' and '+' flags appear, the ' ' flag should be - // ignored. - int space_for_positive = 1; - - // allowed values: \0, h, l, L - char length_modifier = '\0'; - - // temporary buffer for simple numeric->string conversion - # 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. - # else - # define TMP_LEN 66 - # endif - char tmp[TMP_LEN]; - - // string address in case of string argument - const char *str_arg = NULL; - - // natural field width of arg without padding and sign - size_t str_arg_l; - - // unsigned char argument value - only defined for c conversion. - // N.B. standard explicitly states the char argument for the c - // conversion is unsigned - unsigned char uchar_arg; - - // number of zeros to be inserted for numeric conversions as - // required by the precision or minimal field width - size_t number_of_zeros_to_pad = 0; - - // index into tmp where zero padding is to be inserted - size_t zero_padding_insertion_ind = 0; - - // current conversion specifier character - char fmt_spec = '\0'; - - // buffer for 's' and 'S' specs - char_u *tofree = NULL; - - - p++; // skip '%' - - // parse flags - while (*p == '0' || *p == '-' || *p == '+' || *p == ' ' - || *p == '#' || *p == '\'') - { - switch (*p) - { - case '0': zero_padding = 1; break; - case '-': justify_left = 1; break; - case '+': force_sign = 1; space_for_positive = 0; break; - case ' ': force_sign = 1; - // If both the ' ' and '+' flags appear, the ' ' - // flag should be ignored - break; - case '#': alternate_form = 1; break; - case '\'': break; - } - p++; - } - // If the '0' and '-' flags both appear, the '0' flag should be - // ignored. - - // parse field width - if (*p == '*') - { - int j; - - p++; - j = - # if defined(FEAT_EVAL) - tvs != NULL ? tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, int); - if (j >= 0) - min_field_width = j; - else - { - min_field_width = -j; - justify_left = 1; - } - } - else if (VIM_ISDIGIT((int)(*p))) - { - // size_t could be wider than unsigned int; make sure we treat - // argument like common implementations do - unsigned int uj = *p++ - '0'; - - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); - min_field_width = uj; - } - - // parse precision - if (*p == '.') - { - p++; - precision_specified = 1; - if (*p == '*') - { - int j; - - j = - # if defined(FEAT_EVAL) - tvs != NULL ? tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, int); - p++; - if (j >= 0) - precision = j; - else - { - precision_specified = 0; - precision = 0; - } - } - else if (VIM_ISDIGIT((int)(*p))) - { - // size_t could be wider than unsigned int; make sure we - // treat argument like common implementations do - unsigned int uj = *p++ - '0'; - - while (VIM_ISDIGIT((int)(*p))) - uj = 10 * uj + (unsigned int)(*p++ - '0'); - precision = uj; - } - } - - // parse 'h', 'l' and 'll' length modifiers - if (*p == 'h' || *p == 'l') - { - length_modifier = *p; - p++; - if (length_modifier == 'l' && *p == 'l') - { - // double l = __int64 / varnumber_T - length_modifier = 'L'; - p++; - } - } - fmt_spec = *p; - - // common synonyms: - switch (fmt_spec) - { - case 'i': fmt_spec = 'd'; break; - case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; - case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; - case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; - default: break; - } - - # if defined(FEAT_EVAL) - switch (fmt_spec) - { - case 'd': case 'u': case 'o': case 'x': case 'X': - if (tvs != NULL && length_modifier == '\0') - length_modifier = 'L'; - } - # endif - - // get parameter value, do initial processing - switch (fmt_spec) - { - // '%' and 'c' behave similar to 's' regarding flags and field - // widths - case '%': - case 'c': - case 's': - case 'S': - str_arg_l = 1; - switch (fmt_spec) - { - case '%': - str_arg = p; - break; - - case 'c': - { - int j; - - j = - # if defined(FEAT_EVAL) - tvs != NULL ? tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, int); - // standard demands unsigned char - uchar_arg = (unsigned char)j; - str_arg = (char *)&uchar_arg; - break; - } - - case 's': - 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) - { - str_arg = "[NULL]"; - str_arg_l = 6; - } - // make sure not to address string beyond the specified - // precision !!! - else if (!precision_specified) - str_arg_l = strlen(str_arg); - // truncate string if necessary as requested by precision - else if (precision == 0) - str_arg_l = 0; - else - { - // Don't put the #if inside memchr(), it can be a - // macro. - // memchr on HP does not like n > 2^31 !!! - char *q = memchr(str_arg, '\0', - precision <= (size_t)0x7fffffffL ? precision - : (size_t)0x7fffffffL); - str_arg_l = (q == NULL) ? precision - : (size_t)(q - str_arg); - } - if (fmt_spec == 'S') - { - if (min_field_width != 0) - min_field_width += STRLEN(str_arg) - - mb_string2cells((char_u *)str_arg, -1); - if (precision) - { - char_u *p1; - size_t i = 0; - - for (p1 = (char_u *)str_arg; *p1; - p1 += mb_ptr2len(p1)) - { - i += (size_t)mb_ptr2cells(p1); - if (i > precision) - break; - } - str_arg_l = precision = p1 - (char_u *)str_arg; - } - } - break; - - default: - break; - } - break; - - case 'd': case 'u': - case 'b': case 'B': - case 'o': - case 'x': case 'X': - case 'p': - { - // NOTE: the u, b, o, x, X and p conversion specifiers - // imply the value is unsigned; d implies a signed - // value - - // 0 if numeric argument is zero (or if pointer is - // NULL for 'p'), +1 if greater than zero (or nonzero - // for unsigned arguments), -1 if negative (unsigned - // argument is never negative) - int arg_sign = 0; - - // only set for length modifier h, or for no length - // modifiers - int int_arg = 0; - unsigned int uint_arg = 0; - - // only set for length modifier l - long int long_arg = 0; - unsigned long int ulong_arg = 0; - - // only set for length modifier ll - varnumber_T llong_arg = 0; - uvarnumber_T ullong_arg = 0; - - // only set for b conversion - uvarnumber_T bin_arg = 0; - - // pointer argument value -only defined for p - // conversion - void *ptr_arg = NULL; - - if (fmt_spec == 'p') - { - 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) - 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 - switch (length_modifier) - { - case '\0': - case 'h': - // char and short arguments are passed as int. - int_arg = - # if defined(FEAT_EVAL) - tvs != NULL ? tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, int); - if (int_arg > 0) - arg_sign = 1; - else if (int_arg < 0) - arg_sign = -1; - break; - case 'l': - long_arg = - # if defined(FEAT_EVAL) - tvs != NULL ? tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, long int); - if (long_arg > 0) - arg_sign = 1; - else if (long_arg < 0) - arg_sign = -1; - break; - case 'L': - llong_arg = - # if defined(FEAT_EVAL) - tvs != NULL ? tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, varnumber_T); - if (llong_arg > 0) - arg_sign = 1; - else if (llong_arg < 0) - arg_sign = -1; - break; - } - } - else - { - // unsigned - switch (length_modifier) - { - case '\0': - case 'h': - uint_arg = - # if defined(FEAT_EVAL) - tvs != NULL ? (unsigned) - tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, unsigned int); - if (uint_arg != 0) - arg_sign = 1; - break; - case 'l': - ulong_arg = - # if defined(FEAT_EVAL) - tvs != NULL ? (unsigned long) - tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, unsigned long int); - if (ulong_arg != 0) - arg_sign = 1; - break; - case 'L': - ullong_arg = - # if defined(FEAT_EVAL) - tvs != NULL ? (uvarnumber_T) - tv_nr(tvs, &arg_idx) : - # endif - va_arg(ap, uvarnumber_T); - if (ullong_arg != 0) - arg_sign = 1; - break; - } - } - - str_arg = tmp; - str_arg_l = 0; - - // NOTE: - // For d, i, u, o, x, and X conversions, if precision is - // specified, the '0' flag should be ignored. This is so - // with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux, - // FreeBSD, NetBSD; but not with Perl. - if (precision_specified) - zero_padding = 0; - if (fmt_spec == 'd') - { - if (force_sign && arg_sign >= 0) - tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; - // leave negative numbers for sprintf to handle, to - // avoid handling tricky cases like (short int)-32768 - } - else if (alternate_form) - { - if (arg_sign != 0 - && (fmt_spec == 'b' || fmt_spec == 'B' - || fmt_spec == 'x' || fmt_spec == 'X') ) - { - tmp[str_arg_l++] = '0'; - tmp[str_arg_l++] = fmt_spec; - } - // alternate form should have no effect for p - // conversion, but ... - } - - zero_padding_insertion_ind = str_arg_l; - if (!precision_specified) - precision = 1; // default precision is 1 - if (precision == 0 && arg_sign == 0) - { - // When zero value is formatted with an explicit - // precision 0, the resulting formatted string is - // empty (d, i, u, b, B, o, x, X, p). - } - else - { - char f[6]; - int f_l = 0; - - // construct a simple format string for sprintf - f[f_l++] = '%'; - if (!length_modifier) - ; - else if (length_modifier == 'L') - { - # ifdef MSWIN - f[f_l++] = 'I'; - f[f_l++] = '6'; - f[f_l++] = '4'; - # else - f[f_l++] = 'l'; - f[f_l++] = 'l'; - # endif - } - else - f[f_l++] = length_modifier; - f[f_l++] = fmt_spec; - f[f_l++] = '\0'; - - 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 - switch (length_modifier) - { - case '\0': str_arg_l += sprintf( - tmp + str_arg_l, f, - int_arg); - break; - case 'h': str_arg_l += sprintf( - tmp + str_arg_l, f, - (short)int_arg); - break; - case 'l': str_arg_l += sprintf( - tmp + str_arg_l, f, long_arg); - break; - case 'L': str_arg_l += sprintf( - tmp + str_arg_l, f, llong_arg); - break; - } - } - else - { - // unsigned - switch (length_modifier) - { - case '\0': str_arg_l += sprintf( - tmp + str_arg_l, f, - uint_arg); - break; - case 'h': str_arg_l += sprintf( - tmp + str_arg_l, f, - (unsigned short)uint_arg); - break; - case 'l': str_arg_l += sprintf( - tmp + str_arg_l, f, ulong_arg); - break; - case 'L': str_arg_l += sprintf( - tmp + str_arg_l, f, ullong_arg); - break; - } - } - - // include the optional minus sign and possible - // "0x" in the region before the zero padding - // insertion point - if (zero_padding_insertion_ind < str_arg_l - && tmp[zero_padding_insertion_ind] == '-') - zero_padding_insertion_ind++; - if (zero_padding_insertion_ind + 1 < str_arg_l - && tmp[zero_padding_insertion_ind] == '0' - && (tmp[zero_padding_insertion_ind + 1] == 'x' - || tmp[zero_padding_insertion_ind + 1] == 'X')) - zero_padding_insertion_ind += 2; - } - - { - size_t num_of_digits = str_arg_l - - zero_padding_insertion_ind; - - if (alternate_form && fmt_spec == 'o' - // unless zero is already the first - // character - && !(zero_padding_insertion_ind < str_arg_l - && tmp[zero_padding_insertion_ind] == '0')) - { - // assure leading zero for alternate-form - // octal numbers - if (!precision_specified - || precision < num_of_digits + 1) - { - // precision is increased to force the - // first character to be zero, except if a - // zero value is formatted with an - // explicit precision of zero - precision = num_of_digits + 1; - } - } - // zero padding to specified precision? - if (num_of_digits < precision) - number_of_zeros_to_pad = precision - num_of_digits; - } - // zero padding to specified minimal field width? - if (!justify_left && zero_padding) - { - int n = (int)(min_field_width - (str_arg_l - + number_of_zeros_to_pad)); - if (n > 0) - number_of_zeros_to_pad += n; - } - break; - } - - # ifdef FEAT_FLOAT - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - { - // Floating point. - double f; - double abs_f; - char format[40]; - int l; - int remove_trailing_zeroes = FALSE; - - f = - # if defined(FEAT_EVAL) - tvs != NULL ? tv_float(tvs, &arg_idx) : - # endif - va_arg(ap, double); - abs_f = f < 0 ? -f : f; - - if (fmt_spec == 'g' || fmt_spec == 'G') - { - // Would be nice to use %g directly, but it prints - // "1.0" as "1", we don't want that. - if ((abs_f >= 0.001 && abs_f < 10000000.0) - || abs_f == 0.0) - fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f'; - else - fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; - remove_trailing_zeroes = TRUE; - } - - if ((fmt_spec == 'f' || fmt_spec == 'F') && - # ifdef VAX - abs_f > 1.0e38 - # else - abs_f > 1.0e307 - # endif - ) - { - // Avoid a buffer overflow - STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, - force_sign, space_for_positive)); - str_arg_l = STRLEN(tmp); - zero_padding = 0; - } - else - { - if (isnan(f)) - { - // Not a number: nan or NAN - STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" - : "nan"); - str_arg_l = 3; - zero_padding = 0; - } - else if (isinf(f)) - { - STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, - force_sign, space_for_positive)); - str_arg_l = STRLEN(tmp); - zero_padding = 0; - } - else - { - // Regular float number - format[0] = '%'; - l = 1; - if (force_sign) - format[l++] = space_for_positive ? ' ' : '+'; - if (precision_specified) - { - size_t max_prec = TMP_LEN - 10; - - // Make sure we don't get more digits than we - // have room for. - if ((fmt_spec == 'f' || fmt_spec == 'F') - && abs_f > 1.0) - max_prec -= (size_t)log10(abs_f); - if (precision > max_prec) - precision = max_prec; - l += sprintf(format + l, ".%d", (int)precision); - } - format[l] = fmt_spec == 'F' ? 'f' : fmt_spec; - format[l + 1] = NUL; - - str_arg_l = sprintf(tmp, format, f); - } - - if (remove_trailing_zeroes) - { - int i; - char *tp; - - // Using %g or %G: remove superfluous zeroes. - if (fmt_spec == 'f' || fmt_spec == 'F') - tp = tmp + str_arg_l - 1; - else - { - tp = (char *)vim_strchr((char_u *)tmp, - fmt_spec == 'e' ? 'e' : 'E'); - if (tp != NULL) - { - // Remove superfluous '+' and leading - // zeroes from the exponent. - if (tp[1] == '+') - { - // Change "1.0e+07" to "1.0e07" - STRMOVE(tp + 1, tp + 2); - --str_arg_l; - } - i = (tp[1] == '-') ? 2 : 1; - while (tp[i] == '0') - { - // Change "1.0e07" to "1.0e7" - STRMOVE(tp + i, tp + i + 1); - --str_arg_l; - } - --tp; - } - } - - if (tp != NULL && !precision_specified) - // Remove trailing zeroes, but keep the one - // just after a dot. - while (tp > tmp + 2 && *tp == '0' - && tp[-1] != '.') - { - STRMOVE(tp, tp + 1); - --tp; - --str_arg_l; - } - } - else - { - char *tp; - - // Be consistent: some printf("%e") use 1.0e+12 - // and some 1.0e+012. Remove one zero in the last - // case. - tp = (char *)vim_strchr((char_u *)tmp, - fmt_spec == 'e' ? 'e' : 'E'); - if (tp != NULL && (tp[1] == '+' || tp[1] == '-') - && tp[2] == '0' - && vim_isdigit(tp[3]) - && vim_isdigit(tp[4])) - { - STRMOVE(tp + 2, tp + 3); - --str_arg_l; - } - } - } - if (zero_padding && min_field_width > str_arg_l - && (tmp[0] == '-' || force_sign)) - { - // padding 0's should be inserted after the sign - number_of_zeros_to_pad = min_field_width - str_arg_l; - zero_padding_insertion_ind = 1; - } - str_arg = tmp; - break; - } - # endif - - default: - // unrecognized conversion specifier, keep format string - // as-is - zero_padding = 0; // turn zero padding off for non-numeric - // conversion - justify_left = 1; - min_field_width = 0; // reset flags - - // discard the unrecognized conversion, just keep * - // the unrecognized conversion character - str_arg = p; - str_arg_l = 0; - if (*p != NUL) - str_arg_l++; // include invalid conversion specifier - // unchanged if not at end-of-string - break; - } - - if (*p != NUL) - p++; // step over the just processed conversion specifier - - // insert padding to the left as requested by min_field_width; - // this does not include the zero padding in case of numerical - // conversions - if (!justify_left) - { - // left padding with blank or zero - int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad)); - - if (pn > 0) - { - if (str_l < str_m) - { - size_t avail = str_m - str_l; - - vim_memset(str + str_l, zero_padding ? '0' : ' ', - (size_t)pn > avail ? avail - : (size_t)pn); - } - str_l += pn; - } - } - - // zero padding as requested by the precision or by the minimal - // field width for numeric conversions required? - if (number_of_zeros_to_pad == 0) - { - // will not copy first part of numeric right now, * - // force it to be copied later in its entirety - zero_padding_insertion_ind = 0; - } - else - { - // insert first part of numerics (sign or '0x') before zero - // padding - int zn = (int)zero_padding_insertion_ind; - - if (zn > 0) - { - if (str_l < str_m) - { - size_t avail = str_m - str_l; - - mch_memmove(str + str_l, str_arg, - (size_t)zn > avail ? avail - : (size_t)zn); - } - str_l += zn; - } - - // insert zero padding as requested by the precision or min - // field width - zn = (int)number_of_zeros_to_pad; - if (zn > 0) - { - if (str_l < str_m) - { - size_t avail = str_m - str_l; - - vim_memset(str + str_l, '0', - (size_t)zn > avail ? avail - : (size_t)zn); - } - str_l += zn; - } - } - - // insert formatted string - // (or as-is conversion specifier for unknown conversions) - { - int sn = (int)(str_arg_l - zero_padding_insertion_ind); - - if (sn > 0) - { - if (str_l < str_m) - { - size_t avail = str_m - str_l; - - mch_memmove(str + str_l, - str_arg + zero_padding_insertion_ind, - (size_t)sn > avail ? avail : (size_t)sn); - } - str_l += sn; - } - } - - // insert right padding - if (justify_left) - { - // right blank padding to the field width - int pn = (int)(min_field_width - - (str_arg_l + number_of_zeros_to_pad)); - - if (pn > 0) - { - if (str_l < str_m) - { - size_t avail = str_m - str_l; - - vim_memset(str + str_l, ' ', - (size_t)pn > avail ? avail - : (size_t)pn); - } - str_l += pn; - } - } - vim_free(tofree); - } - } - - if (str_m > 0) - { - // make sure the string is nul-terminated even at the expense of - // overwriting the last character (shouldn't happen, but just in case) - // - str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0'; - } - - if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN) - emsg(_("E767: Too many arguments to printf()")); - - // Return the number of characters formatted (excluding trailing nul - // character), that is, the number of characters that would have been - // written to the buffer if it were large enough. - return (int)str_l; - } - - #endif // PROTO --- 4107,4109 ---- *** ../vim-8.2.3319/src/profiler.c 2021-02-19 19:13:13.083904350 +0100 --- src/profiler.c 2021-08-09 19:56:02.951236093 +0200 *************** *** 555,560 **** --- 555,578 ---- } /* + * Save time when starting to invoke another script or function. + */ + static void + script_prof_save( + proftime_T *tm) // place to store wait time + { + scriptitem_T *si; + + if (SCRIPT_ID_VALID(current_sctx.sc_sid)) + { + si = SCRIPT_ITEM(current_sctx.sc_sid); + if (si->sn_prof_on && si->sn_pr_nest++ == 0) + profile_start(&si->sn_pr_child); + } + profile_get_wait(tm); + } + + /* * When calling a function: may initialize for profiling. */ void *************** *** 793,816 **** } /* - * Save time when starting to invoke another script or function. - */ - void - script_prof_save( - proftime_T *tm) // place to store wait time - { - scriptitem_T *si; - - if (SCRIPT_ID_VALID(current_sctx.sc_sid)) - { - si = SCRIPT_ITEM(current_sctx.sc_sid); - if (si->sn_prof_on && si->sn_pr_nest++ == 0) - profile_start(&si->sn_pr_child); - } - profile_get_wait(tm); - } - - /* * Count time spent in children after invoking another script or function. */ void --- 811,816 ---- *** ../vim-8.2.3319/src/proto/channel.pro 2021-06-05 20:51:34.737122348 +0200 --- src/proto/channel.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 24,30 **** int channel_collapse(channel_T *channel, ch_part_T part, int want_nl); int channel_can_write_to(channel_T *channel); int channel_is_open(channel_T *channel); - char *channel_status(channel_T *channel, int req_part); void channel_close(channel_T *channel, int invoke_close_cb); void channel_clear(channel_T *channel); void channel_free_all(void); --- 24,29 ---- *** ../vim-8.2.3319/src/proto/dict.pro 2021-07-22 14:58:43.469967322 +0200 --- src/proto/dict.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 34,40 **** varnumber_T dict_get_number_check(dict_T *d, char_u *key); varnumber_T dict_get_bool(dict_T *d, char_u *key, int def); char_u *dict2string(typval_T *tv, int copyID, int restore_copyID); - char_u *skip_literal_key(char_u *key); char_u *get_literal_key(char_u **arg); int eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal); void dict_extend(dict_T *d1, dict_T *d2, char_u *action, char *func_name); --- 34,39 ---- *** ../vim-8.2.3319/src/proto/digraph.pro 2021-07-26 21:54:00.055491571 +0200 --- src/proto/digraph.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 3,12 **** char_u *get_digraph_for_char(int val_arg); int get_digraph(int cmdline); int digraph_get(int char1, int char2, int meta_char); - int check_digraph_chars_valid(int char1, int char2); void putdigraph(char_u *str); void listdigraphs(int use_headers); - void digraph_getlist_common(int list_all, typval_T *rettv); void f_digraph_get(typval_T *argvars, typval_T *rettv); void f_digraph_getlist(typval_T *argvars, typval_T *rettv); void f_digraph_set(typval_T *argvars, typval_T *rettv); --- 3,10 ---- *** ../vim-8.2.3319/src/proto/edit.pro 2020-12-03 19:54:38.177924280 +0100 --- src/proto/edit.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 2,8 **** int edit(int cmdchar, int startln, long count); int ins_need_undo_get(void); void ins_redraw(int ready); - int decodeModifyOtherKeys(int c); void edit_putchar(int c, int highlight); void set_insstart(linenr_T lnum, int col); void edit_unputchar(void); --- 2,7 ---- *** ../vim-8.2.3319/src/proto/ex_docmd.pro 2021-08-05 20:39:59.346053681 +0200 --- src/proto/ex_docmd.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 1,7 **** /* ex_docmd.c */ void do_exmode(int improved); int do_cmdline_cmd(char_u *cmd); - int do_cmd_argument(char_u *cmd); int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie, int flags); void handle_did_throw(void); int getline_equal(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie, char_u *(*func)(int, void *, int, getline_opt_T)); --- 1,6 ---- *** ../vim-8.2.3319/src/proto/getchar.pro 2021-06-07 22:04:48.402620082 +0200 --- src/proto/getchar.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 15,21 **** void AppendNumberToRedobuff(long n); void stuffReadbuff(char_u *s); void stuffRedoReadbuff(char_u *s); - void stuffReadbuffLen(char_u *s, long len); void stuffReadbuffSpec(char_u *s); void stuffcharReadbuff(int c); void stuffnumReadbuff(long n); --- 15,20 ---- *** ../vim-8.2.3319/src/proto/job.pro 2021-06-05 20:51:34.737122348 +0200 --- src/proto/job.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 20,26 **** int job_stop(job_T *job, typval_T *argvars, char *type); void invoke_prompt_callback(void); int invoke_prompt_interrupt(void); - char_u *buf_prompt_text(buf_T *buf); char_u *prompt_text(void); void init_prompt(int cmdchar_todo); int prompt_curpos_editable(void); --- 20,25 ---- *** ../vim-8.2.3319/src/proto/list.pro 2021-02-20 17:03:57.984112613 +0100 --- src/proto/list.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 24,30 **** long list_idx_of_item(list_T *l, listitem_T *item); void list_append(list_T *l, listitem_T *item); int list_append_tv(list_T *l, typval_T *tv); - int list_append_tv_move(list_T *l, typval_T *tv); int list_append_dict(list_T *list, dict_T *dict); int list_append_list(list_T *list1, list_T *list2); int list_append_string(list_T *l, char_u *str, int len); --- 24,29 ---- *** ../vim-8.2.3319/src/proto/profiler.pro 2021-02-19 19:13:13.083904350 +0100 --- src/proto/profiler.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 27,33 **** void func_line_exec(void *cookie); void func_line_end(void *cookie); void script_do_profile(scriptitem_T *si); - void script_prof_save(proftime_T *tm); void script_prof_restore(proftime_T *tm); void profile_dump(void); void script_line_start(void); --- 27,32 ---- *** ../vim-8.2.3319/src/proto/spell.pro 2021-06-11 19:07:36.734247944 +0200 --- src/proto/spell.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 5,11 **** int match_compoundrule(slang_T *slang, char_u *compflags); int valid_word_prefix(int totprefcnt, int arridx, int flags, char_u *word, slang_T *slang, int cond_req); int spell_valid_case(int wordflags, int treeflags); - int no_spell_checking(win_T *wp); int spell_move_to(win_T *wp, int dir, int allwords, int curline, hlf_T *attrp); void spell_cat_line(char_u *buf, char_u *line, int maxlen); char_u *spell_enc(void); --- 5,10 ---- *** ../vim-8.2.3319/src/proto/vim9compile.pro 2021-07-19 22:19:25.690972401 +0200 --- src/proto/vim9compile.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 1,7 **** /* vim9compile.c */ int check_defined(char_u *p, size_t len, cctx_T *cctx, int is_arg); int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2); - int use_typecheck(type_T *actual, type_T *expected); int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const); int func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type); int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx); --- 1,6 ---- *************** *** 9,15 **** imported_T *find_imported_in_script(char_u *name, size_t len, int sid); char_u *peek_next_line_from_context(cctx_T *cctx); char_u *next_line_from_context(cctx_T *cctx, int skip_comment); - char_u *to_name_end(char_u *arg, int use_namespace); char_u *to_name_const_end(char_u *arg); int get_lambda_tv_and_compile(char_u **arg, typval_T *rettv, int types_optional, evalarg_T *evalarg); exprtype_T get_compare_type(char_u *p, int *len, int *type_is); --- 8,13 ---- *** ../vim-8.2.3319/src/proto/vim9script.pro 2021-07-08 21:38:45.339232318 +0200 --- src/proto/vim9script.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 11,21 **** void mark_imports_for_reload(int sid); void ex_import(exarg_T *eap); int find_exported(int sid, char_u *name, ufunc_T **ufunc, type_T **type, cctx_T *cctx, int verbose); - char_u *handle_import(char_u *arg_start, garray_T *gap, int import_sid, evalarg_T *evalarg, void *cctx); char_u *vim9_declare_scriptvar(exarg_T *eap, char_u *arg); void update_vim9_script_var(int create, dictitem_T *di, int flags, typval_T *tv, type_T **type, int do_member); void hide_script_var(scriptitem_T *si, int idx, int func_defined); - void free_all_script_vars(scriptitem_T *si); svar_T *find_typval_in_script(typval_T *dest); int check_script_var_type(typval_T *dest, typval_T *value, char_u *name, where_T where); int check_reserved_name(char_u *name); --- 11,19 ---- *** ../vim-8.2.3319/src/proto/vim9type.pro 2021-07-29 22:48:50.103129907 +0200 --- src/proto/vim9type.pro 2021-08-09 19:56:02.951236093 +0200 *************** *** 1,5 **** /* vim9type.c */ - type_T *get_type_ptr(garray_T *type_gap); void clear_type_list(garray_T *gap); type_T *alloc_type(type_T *type); void free_type(type_T *type); --- 1,4 ---- *** ../vim-8.2.3319/src/spell.c 2021-07-20 21:07:32.968058851 +0200 --- src/spell.c 2021-08-09 19:56:02.951236093 +0200 *************** *** 1240,1246 **** /* * Return TRUE if spell checking is not enabled. */ ! int no_spell_checking(win_T *wp) { if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL --- 1240,1246 ---- /* * Return TRUE if spell checking is not enabled. */ ! static int no_spell_checking(win_T *wp) { if (!wp->w_p_spell || *wp->w_s->b_p_spl == NUL *** ../vim-8.2.3319/src/strings.c 2021-07-27 22:00:39.749712387 +0200 --- src/strings.c 2021-08-09 19:56:02.951236093 +0200 *************** *** 11,16 **** --- 11,17 ---- * strings.c: string manipulation functions */ + #define USING_FLOAT_STUFF #include "vim.h" /* *************** *** 77,86 **** unsigned length; int l; ! /* ! * First count the number of backslashes required. ! * Then allocate the memory and insert them. ! */ length = 1; // count the trailing NUL for (p = string; *p; p++) { --- 78,85 ---- unsigned length; int l; ! // First count the number of backslashes required. ! // Then allocate the memory and insert them. length = 1; // count the trailing NUL for (p = string; *p; p++) { *************** *** 1265,1274 **** len = slen - nbyte; // default: all bytes that are available. } ! /* ! * Only return the overlap between the specified part and the actual ! * string. ! */ if (nbyte < 0) { len += nbyte; --- 1264,1271 ---- len = slen - nbyte; // default: all bytes that are available. } ! // Only return the overlap between the specified part and the actual ! // string. if (nbyte < 0) { len += nbyte; *************** *** 1668,1670 **** --- 1665,2776 ---- } #endif + + #if defined(FEAT_EVAL) + static char *e_printf = N_("E766: Insufficient arguments for printf()"); + + /* + * Get number argument from "idxp" entry in "tvs". First entry is 1. + */ + static varnumber_T + tv_nr(typval_T *tvs, int *idxp) + { + int idx = *idxp - 1; + varnumber_T n = 0; + int err = FALSE; + + if (tvs[idx].v_type == VAR_UNKNOWN) + emsg(_(e_printf)); + else + { + ++*idxp; + n = tv_get_number_chk(&tvs[idx], &err); + if (err) + n = 0; + } + return n; + } + + /* + * Get string argument from "idxp" entry in "tvs". First entry is 1. + * If "tofree" is NULL tv_get_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 *)tv_get_string_chk(&tvs[idx]); + } + return s; + } + + # ifdef FEAT_FLOAT + /* + * Get float argument from "idxp" entry in "tvs". First entry is 1. + */ + static double + tv_float(typval_T *tvs, int *idxp) + { + int idx = *idxp - 1; + double f = 0; + + if (tvs[idx].v_type == VAR_UNKNOWN) + emsg(_(e_printf)); + else + { + ++*idxp; + if (tvs[idx].v_type == VAR_FLOAT) + f = tvs[idx].vval.v_float; + else if (tvs[idx].v_type == VAR_NUMBER) + f = (double)tvs[idx].vval.v_number; + else + emsg(_("E807: Expected Float argument for printf()")); + } + return f; + } + # endif + #endif + + #ifdef FEAT_FLOAT + /* + * Return the representation of infinity for printf() function: + * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF". + */ + static const char * + infinity_str(int positive, + char fmt_spec, + int force_sign, + int space_for_positive) + { + static const char *table[] = + { + "-inf", "inf", "+inf", " inf", + "-INF", "INF", "+INF", " INF" + }; + int idx = positive * (1 + force_sign + force_sign * space_for_positive); + + if (ASCII_ISUPPER(fmt_spec)) + idx += 4; + return table[idx]; + } + #endif + + /* + * This code was included to provide a portable vsnprintf() and snprintf(). + * Some systems may provide their own, but we always use this one for + * consistency. + * + * This code is based on snprintf.c - a portable implementation of snprintf + * by Mark Martinec , Version 2.2, 2000-10-06. + * Included with permission. It was heavily modified to fit in Vim. + * The original code, including useful comments, can be found here: + * http://www.ijs.si/software/snprintf/ + * + * This snprintf() only supports the following conversion specifiers: + * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below) + * with flags: '-', '+', ' ', '0' and '#'. + * An asterisk is supported for field width as well as precision. + * + * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'. + * + * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int) + * are supported. NOTE: for 'll' the argument is varnumber_T or uvarnumber_T. + * + * The locale is not used, the string is used as a byte string. This is only + * relevant for double-byte encodings where the second byte may be '%'. + * + * It is permitted for "str_m" to be zero, and it is permitted to specify NULL + * pointer for resulting string argument if "str_m" is zero (as per ISO C99). + * + * The return value is the number of characters which would be generated + * for the given input, excluding the trailing NUL. If this value + * is greater or equal to "str_m", not all characters from the result + * have been stored in str, output bytes beyond the ("str_m"-1) -th character + * are discarded. If "str_m" is greater than zero it is guaranteed + * the resulting string will be NUL-terminated. + */ + + /* + * When va_list is not supported we only define vim_snprintf(). + * + * vim_vsnprintf_typval() can be invoked with either "va_list" or a list of + * "typval_T". When the latter is not used it must be NULL. + */ + + // When generating prototypes all of this is skipped, cproto doesn't + // understand this. + #ifndef PROTO + + // Like vim_vsnprintf() but append to the string. + int + vim_snprintf_add(char *str, size_t str_m, const char *fmt, ...) + { + va_list ap; + int str_l; + size_t len = STRLEN(str); + size_t space; + + if (str_m <= len) + space = 0; + else + space = str_m - len; + va_start(ap, fmt); + str_l = vim_vsnprintf(str + len, space, fmt, ap); + va_end(ap); + return str_l; + } + + int + vim_snprintf(char *str, size_t str_m, const char *fmt, ...) + { + va_list ap; + int str_l; + + va_start(ap, fmt); + str_l = vim_vsnprintf(str, str_m, fmt, ap); + va_end(ap); + return str_l; + } + + int + vim_vsnprintf( + char *str, + size_t str_m, + const char *fmt, + va_list ap) + { + return vim_vsnprintf_typval(str, str_m, fmt, ap, NULL); + } + + int + vim_vsnprintf_typval( + char *str, + size_t str_m, + const char *fmt, + va_list ap, + typval_T *tvs) + { + size_t str_l = 0; + const char *p = fmt; + int arg_idx = 1; + + if (p == NULL) + p = ""; + while (*p != NUL) + { + if (*p != '%') + { + char *q = strchr(p + 1, '%'); + size_t n = (q == NULL) ? STRLEN(p) : (size_t)(q - p); + + // Copy up to the next '%' or NUL without any changes. + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + mch_memmove(str + str_l, p, n > avail ? avail : n); + } + p += n; + str_l += n; + } + else + { + size_t min_field_width = 0, precision = 0; + int zero_padding = 0, precision_specified = 0, justify_left = 0; + int alternate_form = 0, force_sign = 0; + + // If both the ' ' and '+' flags appear, the ' ' flag should be + // ignored. + int space_for_positive = 1; + + // allowed values: \0, h, l, L + char length_modifier = '\0'; + + // temporary buffer for simple numeric->string conversion + # 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. + # else + # define TMP_LEN 66 + # endif + char tmp[TMP_LEN]; + + // string address in case of string argument + const char *str_arg = NULL; + + // natural field width of arg without padding and sign + size_t str_arg_l; + + // unsigned char argument value - only defined for c conversion. + // N.B. standard explicitly states the char argument for the c + // conversion is unsigned + unsigned char uchar_arg; + + // number of zeros to be inserted for numeric conversions as + // required by the precision or minimal field width + size_t number_of_zeros_to_pad = 0; + + // index into tmp where zero padding is to be inserted + size_t zero_padding_insertion_ind = 0; + + // current conversion specifier character + char fmt_spec = '\0'; + + // buffer for 's' and 'S' specs + char_u *tofree = NULL; + + + p++; // skip '%' + + // parse flags + while (*p == '0' || *p == '-' || *p == '+' || *p == ' ' + || *p == '#' || *p == '\'') + { + switch (*p) + { + case '0': zero_padding = 1; break; + case '-': justify_left = 1; break; + case '+': force_sign = 1; space_for_positive = 0; break; + case ' ': force_sign = 1; + // If both the ' ' and '+' flags appear, the ' ' + // flag should be ignored + break; + case '#': alternate_form = 1; break; + case '\'': break; + } + p++; + } + // If the '0' and '-' flags both appear, the '0' flag should be + // ignored. + + // parse field width + if (*p == '*') + { + int j; + + p++; + j = + # if defined(FEAT_EVAL) + tvs != NULL ? tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, int); + if (j >= 0) + min_field_width = j; + else + { + min_field_width = -j; + justify_left = 1; + } + } + else if (VIM_ISDIGIT((int)(*p))) + { + // size_t could be wider than unsigned int; make sure we treat + // argument like common implementations do + unsigned int uj = *p++ - '0'; + + while (VIM_ISDIGIT((int)(*p))) + uj = 10 * uj + (unsigned int)(*p++ - '0'); + min_field_width = uj; + } + + // parse precision + if (*p == '.') + { + p++; + precision_specified = 1; + if (*p == '*') + { + int j; + + j = + # if defined(FEAT_EVAL) + tvs != NULL ? tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, int); + p++; + if (j >= 0) + precision = j; + else + { + precision_specified = 0; + precision = 0; + } + } + else if (VIM_ISDIGIT((int)(*p))) + { + // size_t could be wider than unsigned int; make sure we + // treat argument like common implementations do + unsigned int uj = *p++ - '0'; + + while (VIM_ISDIGIT((int)(*p))) + uj = 10 * uj + (unsigned int)(*p++ - '0'); + precision = uj; + } + } + + // parse 'h', 'l' and 'll' length modifiers + if (*p == 'h' || *p == 'l') + { + length_modifier = *p; + p++; + if (length_modifier == 'l' && *p == 'l') + { + // double l = __int64 / varnumber_T + length_modifier = 'L'; + p++; + } + } + fmt_spec = *p; + + // common synonyms: + switch (fmt_spec) + { + case 'i': fmt_spec = 'd'; break; + case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; + case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; + case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; + default: break; + } + + # if defined(FEAT_EVAL) + switch (fmt_spec) + { + case 'd': case 'u': case 'o': case 'x': case 'X': + if (tvs != NULL && length_modifier == '\0') + length_modifier = 'L'; + } + # endif + + // get parameter value, do initial processing + switch (fmt_spec) + { + // '%' and 'c' behave similar to 's' regarding flags and field + // widths + case '%': + case 'c': + case 's': + case 'S': + str_arg_l = 1; + switch (fmt_spec) + { + case '%': + str_arg = p; + break; + + case 'c': + { + int j; + + j = + # if defined(FEAT_EVAL) + tvs != NULL ? tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, int); + // standard demands unsigned char + uchar_arg = (unsigned char)j; + str_arg = (char *)&uchar_arg; + break; + } + + case 's': + 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) + { + str_arg = "[NULL]"; + str_arg_l = 6; + } + // make sure not to address string beyond the specified + // precision !!! + else if (!precision_specified) + str_arg_l = strlen(str_arg); + // truncate string if necessary as requested by precision + else if (precision == 0) + str_arg_l = 0; + else + { + // Don't put the #if inside memchr(), it can be a + // macro. + // memchr on HP does not like n > 2^31 !!! + char *q = memchr(str_arg, '\0', + precision <= (size_t)0x7fffffffL ? precision + : (size_t)0x7fffffffL); + str_arg_l = (q == NULL) ? precision + : (size_t)(q - str_arg); + } + if (fmt_spec == 'S') + { + if (min_field_width != 0) + min_field_width += STRLEN(str_arg) + - mb_string2cells((char_u *)str_arg, -1); + if (precision) + { + char_u *p1; + size_t i = 0; + + for (p1 = (char_u *)str_arg; *p1; + p1 += mb_ptr2len(p1)) + { + i += (size_t)mb_ptr2cells(p1); + if (i > precision) + break; + } + str_arg_l = precision = p1 - (char_u *)str_arg; + } + } + break; + + default: + break; + } + break; + + case 'd': case 'u': + case 'b': case 'B': + case 'o': + case 'x': case 'X': + case 'p': + { + // NOTE: the u, b, o, x, X and p conversion specifiers + // imply the value is unsigned; d implies a signed + // value + + // 0 if numeric argument is zero (or if pointer is + // NULL for 'p'), +1 if greater than zero (or nonzero + // for unsigned arguments), -1 if negative (unsigned + // argument is never negative) + int arg_sign = 0; + + // only set for length modifier h, or for no length + // modifiers + int int_arg = 0; + unsigned int uint_arg = 0; + + // only set for length modifier l + long int long_arg = 0; + unsigned long int ulong_arg = 0; + + // only set for length modifier ll + varnumber_T llong_arg = 0; + uvarnumber_T ullong_arg = 0; + + // only set for b conversion + uvarnumber_T bin_arg = 0; + + // pointer argument value -only defined for p + // conversion + void *ptr_arg = NULL; + + if (fmt_spec == 'p') + { + 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) + 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 + switch (length_modifier) + { + case '\0': + case 'h': + // char and short arguments are passed as int. + int_arg = + # if defined(FEAT_EVAL) + tvs != NULL ? tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, int); + if (int_arg > 0) + arg_sign = 1; + else if (int_arg < 0) + arg_sign = -1; + break; + case 'l': + long_arg = + # if defined(FEAT_EVAL) + tvs != NULL ? tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, long int); + if (long_arg > 0) + arg_sign = 1; + else if (long_arg < 0) + arg_sign = -1; + break; + case 'L': + llong_arg = + # if defined(FEAT_EVAL) + tvs != NULL ? tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, varnumber_T); + if (llong_arg > 0) + arg_sign = 1; + else if (llong_arg < 0) + arg_sign = -1; + break; + } + } + else + { + // unsigned + switch (length_modifier) + { + case '\0': + case 'h': + uint_arg = + # if defined(FEAT_EVAL) + tvs != NULL ? (unsigned) + tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, unsigned int); + if (uint_arg != 0) + arg_sign = 1; + break; + case 'l': + ulong_arg = + # if defined(FEAT_EVAL) + tvs != NULL ? (unsigned long) + tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, unsigned long int); + if (ulong_arg != 0) + arg_sign = 1; + break; + case 'L': + ullong_arg = + # if defined(FEAT_EVAL) + tvs != NULL ? (uvarnumber_T) + tv_nr(tvs, &arg_idx) : + # endif + va_arg(ap, uvarnumber_T); + if (ullong_arg != 0) + arg_sign = 1; + break; + } + } + + str_arg = tmp; + str_arg_l = 0; + + // NOTE: + // For d, i, u, o, x, and X conversions, if precision is + // specified, the '0' flag should be ignored. This is so + // with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux, + // FreeBSD, NetBSD; but not with Perl. + if (precision_specified) + zero_padding = 0; + if (fmt_spec == 'd') + { + if (force_sign && arg_sign >= 0) + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; + // leave negative numbers for sprintf to handle, to + // avoid handling tricky cases like (short int)-32768 + } + else if (alternate_form) + { + if (arg_sign != 0 + && (fmt_spec == 'b' || fmt_spec == 'B' + || fmt_spec == 'x' || fmt_spec == 'X') ) + { + tmp[str_arg_l++] = '0'; + tmp[str_arg_l++] = fmt_spec; + } + // alternate form should have no effect for p + // conversion, but ... + } + + zero_padding_insertion_ind = str_arg_l; + if (!precision_specified) + precision = 1; // default precision is 1 + if (precision == 0 && arg_sign == 0) + { + // When zero value is formatted with an explicit + // precision 0, the resulting formatted string is + // empty (d, i, u, b, B, o, x, X, p). + } + else + { + char f[6]; + int f_l = 0; + + // construct a simple format string for sprintf + f[f_l++] = '%'; + if (!length_modifier) + ; + else if (length_modifier == 'L') + { + # ifdef MSWIN + f[f_l++] = 'I'; + f[f_l++] = '6'; + f[f_l++] = '4'; + # else + f[f_l++] = 'l'; + f[f_l++] = 'l'; + # endif + } + else + f[f_l++] = length_modifier; + f[f_l++] = fmt_spec; + f[f_l++] = '\0'; + + 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 + switch (length_modifier) + { + case '\0': str_arg_l += sprintf( + tmp + str_arg_l, f, + int_arg); + break; + case 'h': str_arg_l += sprintf( + tmp + str_arg_l, f, + (short)int_arg); + break; + case 'l': str_arg_l += sprintf( + tmp + str_arg_l, f, long_arg); + break; + case 'L': str_arg_l += sprintf( + tmp + str_arg_l, f, llong_arg); + break; + } + } + else + { + // unsigned + switch (length_modifier) + { + case '\0': str_arg_l += sprintf( + tmp + str_arg_l, f, + uint_arg); + break; + case 'h': str_arg_l += sprintf( + tmp + str_arg_l, f, + (unsigned short)uint_arg); + break; + case 'l': str_arg_l += sprintf( + tmp + str_arg_l, f, ulong_arg); + break; + case 'L': str_arg_l += sprintf( + tmp + str_arg_l, f, ullong_arg); + break; + } + } + + // include the optional minus sign and possible + // "0x" in the region before the zero padding + // insertion point + if (zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '-') + zero_padding_insertion_ind++; + if (zero_padding_insertion_ind + 1 < str_arg_l + && tmp[zero_padding_insertion_ind] == '0' + && (tmp[zero_padding_insertion_ind + 1] == 'x' + || tmp[zero_padding_insertion_ind + 1] == 'X')) + zero_padding_insertion_ind += 2; + } + + { + size_t num_of_digits = str_arg_l + - zero_padding_insertion_ind; + + if (alternate_form && fmt_spec == 'o' + // unless zero is already the first + // character + && !(zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '0')) + { + // assure leading zero for alternate-form + // octal numbers + if (!precision_specified + || precision < num_of_digits + 1) + { + // precision is increased to force the + // first character to be zero, except if a + // zero value is formatted with an + // explicit precision of zero + precision = num_of_digits + 1; + } + } + // zero padding to specified precision? + if (num_of_digits < precision) + number_of_zeros_to_pad = precision - num_of_digits; + } + // zero padding to specified minimal field width? + if (!justify_left && zero_padding) + { + int n = (int)(min_field_width - (str_arg_l + + number_of_zeros_to_pad)); + if (n > 0) + number_of_zeros_to_pad += n; + } + break; + } + + # ifdef FEAT_FLOAT + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + { + // Floating point. + double f; + double abs_f; + char format[40]; + int l; + int remove_trailing_zeroes = FALSE; + + f = + # if defined(FEAT_EVAL) + tvs != NULL ? tv_float(tvs, &arg_idx) : + # endif + va_arg(ap, double); + abs_f = f < 0 ? -f : f; + + if (fmt_spec == 'g' || fmt_spec == 'G') + { + // Would be nice to use %g directly, but it prints + // "1.0" as "1", we don't want that. + if ((abs_f >= 0.001 && abs_f < 10000000.0) + || abs_f == 0.0) + fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f'; + else + fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; + remove_trailing_zeroes = TRUE; + } + + if ((fmt_spec == 'f' || fmt_spec == 'F') && + # ifdef VAX + abs_f > 1.0e38 + # else + abs_f > 1.0e307 + # endif + ) + { + // Avoid a buffer overflow + STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, + force_sign, space_for_positive)); + str_arg_l = STRLEN(tmp); + zero_padding = 0; + } + else + { + if (isnan(f)) + { + // Not a number: nan or NAN + STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" + : "nan"); + str_arg_l = 3; + zero_padding = 0; + } + else if (isinf(f)) + { + STRCPY(tmp, infinity_str(f > 0.0, fmt_spec, + force_sign, space_for_positive)); + str_arg_l = STRLEN(tmp); + zero_padding = 0; + } + else + { + // Regular float number + format[0] = '%'; + l = 1; + if (force_sign) + format[l++] = space_for_positive ? ' ' : '+'; + if (precision_specified) + { + size_t max_prec = TMP_LEN - 10; + + // Make sure we don't get more digits than we + // have room for. + if ((fmt_spec == 'f' || fmt_spec == 'F') + && abs_f > 1.0) + max_prec -= (size_t)log10(abs_f); + if (precision > max_prec) + precision = max_prec; + l += sprintf(format + l, ".%d", (int)precision); + } + format[l] = fmt_spec == 'F' ? 'f' : fmt_spec; + format[l + 1] = NUL; + + str_arg_l = sprintf(tmp, format, f); + } + + if (remove_trailing_zeroes) + { + int i; + char *tp; + + // Using %g or %G: remove superfluous zeroes. + if (fmt_spec == 'f' || fmt_spec == 'F') + tp = tmp + str_arg_l - 1; + else + { + tp = (char *)vim_strchr((char_u *)tmp, + fmt_spec == 'e' ? 'e' : 'E'); + if (tp != NULL) + { + // Remove superfluous '+' and leading + // zeroes from the exponent. + if (tp[1] == '+') + { + // Change "1.0e+07" to "1.0e07" + STRMOVE(tp + 1, tp + 2); + --str_arg_l; + } + i = (tp[1] == '-') ? 2 : 1; + while (tp[i] == '0') + { + // Change "1.0e07" to "1.0e7" + STRMOVE(tp + i, tp + i + 1); + --str_arg_l; + } + --tp; + } + } + + if (tp != NULL && !precision_specified) + // Remove trailing zeroes, but keep the one + // just after a dot. + while (tp > tmp + 2 && *tp == '0' + && tp[-1] != '.') + { + STRMOVE(tp, tp + 1); + --tp; + --str_arg_l; + } + } + else + { + char *tp; + + // Be consistent: some printf("%e") use 1.0e+12 + // and some 1.0e+012. Remove one zero in the last + // case. + tp = (char *)vim_strchr((char_u *)tmp, + fmt_spec == 'e' ? 'e' : 'E'); + if (tp != NULL && (tp[1] == '+' || tp[1] == '-') + && tp[2] == '0' + && vim_isdigit(tp[3]) + && vim_isdigit(tp[4])) + { + STRMOVE(tp + 2, tp + 3); + --str_arg_l; + } + } + } + if (zero_padding && min_field_width > str_arg_l + && (tmp[0] == '-' || force_sign)) + { + // padding 0's should be inserted after the sign + number_of_zeros_to_pad = min_field_width - str_arg_l; + zero_padding_insertion_ind = 1; + } + str_arg = tmp; + break; + } + # endif + + default: + // unrecognized conversion specifier, keep format string + // as-is + zero_padding = 0; // turn zero padding off for non-numeric + // conversion + justify_left = 1; + min_field_width = 0; // reset flags + + // discard the unrecognized conversion, just keep * + // the unrecognized conversion character + str_arg = p; + str_arg_l = 0; + if (*p != NUL) + str_arg_l++; // include invalid conversion specifier + // unchanged if not at end-of-string + break; + } + + if (*p != NUL) + p++; // step over the just processed conversion specifier + + // insert padding to the left as requested by min_field_width; + // this does not include the zero padding in case of numerical + // conversions + if (!justify_left) + { + // left padding with blank or zero + int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad)); + + if (pn > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + vim_memset(str + str_l, zero_padding ? '0' : ' ', + (size_t)pn > avail ? avail + : (size_t)pn); + } + str_l += pn; + } + } + + // zero padding as requested by the precision or by the minimal + // field width for numeric conversions required? + if (number_of_zeros_to_pad == 0) + { + // will not copy first part of numeric right now, * + // force it to be copied later in its entirety + zero_padding_insertion_ind = 0; + } + else + { + // insert first part of numerics (sign or '0x') before zero + // padding + int zn = (int)zero_padding_insertion_ind; + + if (zn > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + mch_memmove(str + str_l, str_arg, + (size_t)zn > avail ? avail + : (size_t)zn); + } + str_l += zn; + } + + // insert zero padding as requested by the precision or min + // field width + zn = (int)number_of_zeros_to_pad; + if (zn > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + vim_memset(str + str_l, '0', + (size_t)zn > avail ? avail + : (size_t)zn); + } + str_l += zn; + } + } + + // insert formatted string + // (or as-is conversion specifier for unknown conversions) + { + int sn = (int)(str_arg_l - zero_padding_insertion_ind); + + if (sn > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + mch_memmove(str + str_l, + str_arg + zero_padding_insertion_ind, + (size_t)sn > avail ? avail : (size_t)sn); + } + str_l += sn; + } + } + + // insert right padding + if (justify_left) + { + // right blank padding to the field width + int pn = (int)(min_field_width + - (str_arg_l + number_of_zeros_to_pad)); + + if (pn > 0) + { + if (str_l < str_m) + { + size_t avail = str_m - str_l; + + vim_memset(str + str_l, ' ', + (size_t)pn > avail ? avail + : (size_t)pn); + } + str_l += pn; + } + } + vim_free(tofree); + } + } + + if (str_m > 0) + { + // make sure the string is nul-terminated even at the expense of + // overwriting the last character (shouldn't happen, but just in case) + // + str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0'; + } + + if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN) + emsg(_("E767: Too many arguments to printf()")); + + // Return the number of characters formatted (excluding trailing nul + // character), that is, the number of characters that would have been + // written to the buffer if it were large enough. + return (int)str_l; + } + + #endif // PROTO *** ../vim-8.2.3319/src/vim9compile.c 2021-08-08 14:41:48.723930691 +0200 --- src/vim9compile.c 2021-08-09 19:56:02.955236082 +0200 *************** *** 1012,1018 **** * Return TRUE if "actual" could be "expected" and a runtime typecheck is to be * used. Return FALSE if the types will never match. */ ! int use_typecheck(type_T *actual, type_T *expected) { if (actual->tt_type == VAR_ANY --- 1012,1018 ---- * Return TRUE if "actual" could be "expected" and a runtime typecheck is to be * used. Return FALSE if the types will never match. */ ! static int use_typecheck(type_T *actual, type_T *expected) { if (actual->tt_type == VAR_ANY *************** *** 3579,3585 **** * Return a pointer to just after the name. Equal to "arg" if there is no * valid name. */ ! char_u * to_name_end(char_u *arg, int use_namespace) { char_u *p; --- 3579,3585 ---- * Return a pointer to just after the name. Equal to "arg" if there is no * valid name. */ ! static char_u * to_name_end(char_u *arg, int use_namespace) { char_u *p; *** ../vim-8.2.3319/src/vim9script.c 2021-08-05 20:39:59.354053658 +0200 --- src/vim9script.c 2021-08-09 19:56:02.955236082 +0200 *************** *** 246,251 **** --- 246,293 ---- } /* + * Free the script variables from "sn_all_vars". + */ + static void + free_all_script_vars(scriptitem_T *si) + { + int todo; + hashtab_T *ht = &si->sn_all_vars.dv_hashtab; + hashitem_T *hi; + sallvar_T *sav; + sallvar_T *sav_next; + + hash_lock(ht); + todo = (int)ht->ht_used; + for (hi = ht->ht_array; todo > 0; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + + // Free the variable. Don't remove it from the hashtab, ht_array + // might change then. hash_clear() takes care of it later. + sav = HI2SAV(hi); + while (sav != NULL) + { + sav_next = sav->sav_next; + if (sav->sav_di == NULL) + clear_tv(&sav->sav_tv); + vim_free(sav); + sav = sav_next; + } + } + } + hash_clear(ht); + hash_init(ht); + + ga_clear(&si->sn_var_vals); + + // existing commands using script variable indexes are no longer valid + si->sn_script_seq = current_sctx.sc_seq; + } + + /* * Free all imported items in script "sid". */ void *************** *** 286,400 **** } /* - * ":import Item from 'filename'" - * ":import Item as Alias from 'filename'" - * ":import {Item} from 'filename'". - * ":import {Item as Alias} from 'filename'" - * ":import {Item, Item} from 'filename'" - * ":import {Item, Item as Alias} from 'filename'" - * - * ":import * as Name from 'filename'" - */ - void - ex_import(exarg_T *eap) - { - char_u *cmd_end; - evalarg_T evalarg; - - if (!getline_equal(eap->getline, eap->cookie, getsourceline)) - { - emsg(_(e_import_can_only_be_used_in_script)); - return; - } - fill_evalarg_from_eap(&evalarg, eap, eap->skip); - - cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, - &evalarg, NULL); - if (cmd_end != NULL) - set_nextcmd(eap, cmd_end); - clear_evalarg(&evalarg, eap); - } - - /* - * Find an exported item in "sid" matching the name at "*argp". - * When it is a variable return the index. - * When it is a user function return "*ufunc". - * When not found returns -1 and "*ufunc" is NULL. - */ - int - find_exported( - int sid, - char_u *name, - ufunc_T **ufunc, - type_T **type, - cctx_T *cctx, - int verbose) - { - int idx = -1; - svar_T *sv; - scriptitem_T *script = SCRIPT_ITEM(sid); - - // Find name in "script". - idx = get_script_item_idx(sid, name, 0, cctx); - if (idx >= 0) - { - sv = ((svar_T *)script->sn_var_vals.ga_data) + idx; - if (!sv->sv_export) - { - if (verbose) - semsg(_(e_item_not_exported_in_script_str), name); - return -1; - } - *type = sv->sv_type; - *ufunc = NULL; - } - else - { - char_u buffer[200]; - char_u *funcname; - - // it could be a user function. - if (STRLEN(name) < sizeof(buffer) - 15) - funcname = buffer; - else - { - funcname = alloc(STRLEN(name) + 15); - if (funcname == NULL) - return -1; - } - funcname[0] = K_SPECIAL; - funcname[1] = KS_EXTRA; - funcname[2] = (int)KE_SNR; - sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); - *ufunc = find_func(funcname, FALSE, NULL); - if (funcname != buffer) - vim_free(funcname); - - if (*ufunc == NULL) - { - if (verbose) - semsg(_(e_item_not_found_in_script_str), name); - return -1; - } - else if (((*ufunc)->uf_flags & FC_EXPORT) == 0) - { - if (verbose) - semsg(_(e_item_not_exported_in_script_str), name); - *ufunc = NULL; - return -1; - } - } - - return idx; - } - - /* * Handle an ":import" command and add the resulting imported_T to "gap", when * not NULL, or script "import_sid" sn_imports. * "cctx" is NULL at the script level. * Returns a pointer to after the command or NULL in case of failure */ ! char_u * handle_import( char_u *arg_start, garray_T *gap, --- 328,339 ---- } /* * Handle an ":import" command and add the resulting imported_T to "gap", when * not NULL, or script "import_sid" sn_imports. * "cctx" is NULL at the script level. * Returns a pointer to after the command or NULL in case of failure */ ! static char_u * handle_import( char_u *arg_start, garray_T *gap, *************** *** 676,681 **** --- 615,723 ---- } /* + * ":import Item from 'filename'" + * ":import Item as Alias from 'filename'" + * ":import {Item} from 'filename'". + * ":import {Item as Alias} from 'filename'" + * ":import {Item, Item} from 'filename'" + * ":import {Item, Item as Alias} from 'filename'" + * + * ":import * as Name from 'filename'" + */ + void + ex_import(exarg_T *eap) + { + char_u *cmd_end; + evalarg_T evalarg; + + if (!getline_equal(eap->getline, eap->cookie, getsourceline)) + { + emsg(_(e_import_can_only_be_used_in_script)); + return; + } + fill_evalarg_from_eap(&evalarg, eap, eap->skip); + + cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, + &evalarg, NULL); + if (cmd_end != NULL) + set_nextcmd(eap, cmd_end); + clear_evalarg(&evalarg, eap); + } + + /* + * Find an exported item in "sid" matching the name at "*argp". + * When it is a variable return the index. + * When it is a user function return "*ufunc". + * When not found returns -1 and "*ufunc" is NULL. + */ + int + find_exported( + int sid, + char_u *name, + ufunc_T **ufunc, + type_T **type, + cctx_T *cctx, + int verbose) + { + int idx = -1; + svar_T *sv; + scriptitem_T *script = SCRIPT_ITEM(sid); + + // Find name in "script". + idx = get_script_item_idx(sid, name, 0, cctx); + if (idx >= 0) + { + sv = ((svar_T *)script->sn_var_vals.ga_data) + idx; + if (!sv->sv_export) + { + if (verbose) + semsg(_(e_item_not_exported_in_script_str), name); + return -1; + } + *type = sv->sv_type; + *ufunc = NULL; + } + else + { + char_u buffer[200]; + char_u *funcname; + + // it could be a user function. + if (STRLEN(name) < sizeof(buffer) - 15) + funcname = buffer; + else + { + funcname = alloc(STRLEN(name) + 15); + if (funcname == NULL) + return -1; + } + funcname[0] = K_SPECIAL; + funcname[1] = KS_EXTRA; + funcname[2] = (int)KE_SNR; + sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); + *ufunc = find_func(funcname, FALSE, NULL); + if (funcname != buffer) + vim_free(funcname); + + if (*ufunc == NULL) + { + if (verbose) + semsg(_(e_item_not_found_in_script_str), name); + return -1; + } + else if (((*ufunc)->uf_flags & FC_EXPORT) == 0) + { + if (verbose) + semsg(_(e_item_not_exported_in_script_str), name); + *ufunc = NULL; + return -1; + } + } + + return idx; + } + + /* * Declare a script-local variable without init: "let var: type". * "const" is an error since the value is missing. * Returns a pointer to after the type. *************** *** 904,951 **** } /* - * Free the script variables from "sn_all_vars". - */ - void - free_all_script_vars(scriptitem_T *si) - { - int todo; - hashtab_T *ht = &si->sn_all_vars.dv_hashtab; - hashitem_T *hi; - sallvar_T *sav; - sallvar_T *sav_next; - - hash_lock(ht); - todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) - { - if (!HASHITEM_EMPTY(hi)) - { - --todo; - - // Free the variable. Don't remove it from the hashtab, ht_array - // might change then. hash_clear() takes care of it later. - sav = HI2SAV(hi); - while (sav != NULL) - { - sav_next = sav->sav_next; - if (sav->sav_di == NULL) - clear_tv(&sav->sav_tv); - vim_free(sav); - sav = sav_next; - } - } - } - hash_clear(ht); - hash_init(ht); - - ga_clear(&si->sn_var_vals); - - // existing commands using script variable indexes are no longer valid - si->sn_script_seq = current_sctx.sc_seq; - } - - /* * Find the script-local variable that links to "dest". * Returns NULL if not found and give an internal error. */ --- 946,951 ---- *** ../vim-8.2.3319/src/vim9type.c 2021-08-01 15:40:24.648232770 +0200 --- src/vim9type.c 2021-08-09 19:56:02.955236082 +0200 *************** *** 24,30 **** * Allocate memory for a type_T and add the pointer to type_gap, so that it can * be easily freed later. */ ! type_T * get_type_ptr(garray_T *type_gap) { type_T *type; --- 24,30 ---- * Allocate memory for a type_T and add the pointer to type_gap, so that it can * be easily freed later. */ ! static type_T * get_type_ptr(garray_T *type_gap) { type_T *type; *** ../vim-8.2.3319/src/window.c 2021-08-07 22:35:49.034237954 +0200 --- src/window.c 2021-08-09 19:56:02.955236082 +0200 *************** *** 4475,4481 **** #endif } ! #if defined(FEAT_PERL) || defined(FEAT_LUA) || defined(PROTO) /* * Find window number "winnr" (counting top to bottom). */ --- 4475,4481 ---- #endif } ! #if defined(FEAT_PERL) || defined(PROTO) /* * Find window number "winnr" (counting top to bottom). */ *** ../vim-8.2.3319/src/version.c 2021-08-09 13:20:30.198002335 +0200 --- src/version.c 2021-08-09 19:58:29.930887032 +0200 *************** *** 757,758 **** --- 757,760 ---- { /* Add new patch number below this line */ + /**/ + 3320, /**/ -- BLACK KNIGHT: I move for no man. ARTHUR: So be it! [hah] [parry thrust] [ARTHUR chops the BLACK KNIGHT's left arm off] ARTHUR: Now stand aside, worthy adversary. BLACK KNIGHT: 'Tis but a scratch. The Quest for the Holy Grail (Monty Python) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///