patch 9.1.1291: too many strlen() calls in buffer.c

Commit: 
https://github.com/vim/vim/commit/ec032de6465f159bd57c22d464e0f4815f3aefc7
Author: John Marriott <basil...@internode.on.net>
Date:   Thu Apr 10 21:34:19 2025 +0200

    patch 9.1.1291: too many strlen() calls in buffer.c
    
    Problem:  too many strlen() calls in buffer.c
    Solution: refactor buffer.c and remove strlen() calls
              (John Marriott)
    
    closes: #17063
    
    Signed-off-by: John Marriott <basil...@internode.on.net>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/buffer.c b/src/buffer.c
index 90ca59678..955800e3a 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -45,7 +45,7 @@ static int    buf_same_ino(buf_T *buf, stat_T *stp);
 static int     otherfile_buf(buf_T *buf, char_u *ffname);
 #endif
 static int     value_changed(char_u *str, char_u **last);
-static int     append_arg_number(win_T *wp, char_u *buf, int buflen, int 
add_file);
+static int     append_arg_number(win_T *wp, char_u *buf, size_t buflen, int 
add_file);
 static void    free_buffer(buf_T *);
 static void    free_buffer_stuff(buf_T *buf, int free_options);
 static int     bt_nofileread(buf_T *buf);
@@ -72,6 +72,19 @@ static int   buf_free_count = 0;
 static int     top_file_num = 1;       // highest file number
 static garray_T buf_reuse = GA_EMPTY;  // file numbers to recycle
 
+/*
+ * Calculate the percentage that `part` is of the `whole`.
+ */
+    static int
+calc_percentage(long part, long whole)
+{
+    // With 32 bit longs and more than 21,474,836 lines multiplying by 100
+    // causes an overflow, thus for large numbers divide instead.
+    return (part > 1000000L)
+       ? (int)(part / (whole / 100L))
+       : (int)((part * 100L) / whole);
+}
+
 /*
  * Return the highest possible buffer number.
  */
@@ -454,7 +467,7 @@ static hashtab_T buf_hashtab;
     static void
 buf_hashtab_add(buf_T *buf)
 {
-    sprintf((char *)buf->b_key, "%x", buf->b_fnum);
+    vim_snprintf((char *)buf->b_key, sizeof(buf->b_key), "%x", buf->b_fnum);
     if (hash_add(&buf_hashtab, buf->b_key, "create buffer") == FAIL)
        emsg(_(e_buffer_cannot_be_registered));
 }
@@ -3088,7 +3101,7 @@ buflist_findnr(int nr)
 
     if (nr == 0)
        nr = curwin->w_alt_fnum;
-    sprintf((char *)key, "%x", nr);
+    vim_snprintf((char *)key, sizeof(key), "%x", nr);
     hi = hash_find(&buf_hashtab, key);
 
     if (!HASHITEM_EMPTY(hi))
@@ -3385,6 +3398,8 @@ buflist_list(exarg_T *eap)
     for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
 #endif
     {
+       char_u  *name;
+
 #ifdef FEAT_TERMINAL
        job_running = term_job_running(buf->b_term);
        job_none_open = term_none_open(buf->b_term);
@@ -3413,8 +3428,9 @@ buflist_list(exarg_T *eap)
                || (vim_strchr(eap->arg, '#')
                      && (buf == curbuf || curwin->w_alt_fnum != buf->b_fnum)))
            continue;
-       if (buf_spname(buf) != NULL)
-           vim_strncpy(NameBuff, buf_spname(buf), MAXPATHL - 1);
+       name = buf_spname(buf);
+       if (name != NULL)
+           vim_strncpy(NameBuff, name, MAXPATHL - 1);
        else
            home_replace(buf, buf->b_fname, NameBuff, MAXPATHL, TRUE);
        if (message_filtered(NameBuff))
@@ -3439,7 +3455,7 @@ buflist_list(exarg_T *eap)
            ro_char = !buf->b_p_ma ? '-' : (buf->b_p_ro ? '=' : ' ');
 
        msg_putchar('
');
-       len = vim_snprintf((char *)IObuff, IOSIZE - 20, "%3d%c%c%c%c%c \"%s\"",
+       len = (int)vim_snprintf_safelen((char *)IObuff, IOSIZE - 20, 
"%3d%c%c%c%c%c \"%s\"",
                buf->b_fnum,
                buf->b_p_bl ? ' ' : 'u',
                buf == curbuf ? '%' :
@@ -3449,8 +3465,6 @@ buflist_list(exarg_T *eap)
                ro_char,
                changed_char,
                NameBuff);
-       if (len > IOSIZE - 20)
-           len = IOSIZE - 20;
 
        // put "line 999" in column 40 or after the file name
        i = 40 - vim_strsize(IObuff);
@@ -3850,83 +3864,81 @@ fileinfo(
     int        dont_truncate)
 {
     char_u     *name;
-    int                n;
-    char       *p;
     char       *buffer;
-    size_t     len;
+    size_t     bufferlen = 0;
 
     buffer = alloc(IOSIZE);
     if (buffer == NULL)
        return;
 
     if (fullname > 1)      // 2 CTRL-G: include buffer number
-    {
-       vim_snprintf(buffer, IOSIZE, "buf %d: ", curbuf->b_fnum);
-       p = buffer + STRLEN(buffer);
-    }
-    else
-       p = buffer;
+       bufferlen = vim_snprintf_safelen(buffer, IOSIZE, "buf %d: ", 
curbuf->b_fnum);
+
+    buffer[bufferlen++] = '"';
 
-    *p++ = '"';
-    if (buf_spname(curbuf) != NULL)
-       vim_strncpy((char_u *)p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1);
+    name = buf_spname(curbuf);
+    if (name != NULL)
+       bufferlen += vim_snprintf_safelen(buffer + bufferlen,
+           IOSIZE - bufferlen, "%s", name);
     else
     {
        if (!fullname && curbuf->b_fname != NULL)
            name = curbuf->b_fname;
        else
            name = curbuf->b_ffname;
-       home_replace(shorthelp ? curbuf : NULL, name, (char_u *)p,
-                                         (int)(IOSIZE - (p - buffer)), TRUE);
+       home_replace(shorthelp ? curbuf : NULL, name, (char_u *)buffer + 
bufferlen,
+                                         IOSIZE - (int)bufferlen, TRUE);
+       bufferlen += STRLEN(buffer + bufferlen);
     }
 
-    vim_snprintf_add(buffer, IOSIZE, "\"%s%s%s%s%s%s",
-           curbufIsChanged() ? (shortmess(SHM_MOD)
-                                         ?  " [+]" : _(" [Modified]")) : " ",
-           (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf)
-                                       ? _("[Not edited]") : "",
-           (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf)
-                                          ? new_file_message() : "",
-           (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
-           curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]")
-                                                     : _("[readonly]")) : "",
-           (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
-                                                         || curbuf->b_p_ro) ?
-                                                                   " " : "");
-    // With 32 bit longs and more than 21,474,836 lines multiplying by 100
-    // causes an overflow, thus for large numbers divide instead.
-    if (curwin->w_cursor.lnum > 1000000L)
-       n = (int)(((long)curwin->w_cursor.lnum) /
-                                  ((long)curbuf->b_ml.ml_line_count / 100L));
-    else
-       n = (int)(((long)curwin->w_cursor.lnum * 100L) /
-                                           (long)curbuf->b_ml.ml_line_count);
+    bufferlen += vim_snprintf_safelen(
+       buffer + bufferlen,
+       IOSIZE - bufferlen,
+       "\"%s%s%s%s%s%s",
+       curbufIsChanged() ? (shortmess(SHM_MOD)
+           ?  " [+]" : _(" [Modified]")) : " ",
+       (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf)
+           ? _("[Not edited]") : "",
+       (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf)
+           ? new_file_message() : "",
+       (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "", curbuf->b_p_ro
+           ? (shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")) : "",
+       (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK) || 
curbuf->b_p_ro)
+           ? " " : "");
+
     if (curbuf->b_ml.ml_flags & ML_EMPTY)
-       vim_snprintf_add(buffer, IOSIZE, "%s", _(no_lines_msg));
+       bufferlen += vim_snprintf_safelen(buffer + bufferlen,
+           IOSIZE - bufferlen, "%s", _(no_lines_msg));
     else if (p_ru)
        // Current line and column are already on the screen -- webb
-       vim_snprintf_add(buffer, IOSIZE,
-               NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--",
-                                                  curbuf->b_ml.ml_line_count),
-               (long)curbuf->b_ml.ml_line_count, n);
+       bufferlen += vim_snprintf_safelen(
+           buffer + bufferlen,
+           IOSIZE - bufferlen,
+           NGETTEXT("%ld line --%d%%--", "%ld lines --%d%%--", 
curbuf->b_ml.ml_line_count),
+           (long)curbuf->b_ml.ml_line_count,
+           calc_percentage(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count));
     else
     {
-       vim_snprintf_add(buffer, IOSIZE,
-               _("line %ld of %ld --%d%%-- col "),
-               (long)curwin->w_cursor.lnum,
-               (long)curbuf->b_ml.ml_line_count,
-               n);
+       bufferlen += vim_snprintf_safelen(
+           buffer + bufferlen,
+           IOSIZE - bufferlen,
+           _("line %ld of %ld --%d%%-- col "),
+           (long)curwin->w_cursor.lnum,
+           (long)curbuf->b_ml.ml_line_count,
+           calc_percentage(curwin->w_cursor.lnum, curbuf->b_ml.ml_line_count));
+
        validate_virtcol();
-       len = STRLEN(buffer);
-       (void)col_print((char_u *)buffer + len, IOSIZE - len,
+       bufferlen += col_print((char_u *)buffer + bufferlen, IOSIZE - bufferlen,
                   (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
     }
 
-    (void)append_arg_number(curwin, (char_u *)buffer, IOSIZE,
-                                                        !shortmess(SHM_FILE));
+    (void)append_arg_number(curwin, (char_u *)buffer + bufferlen,
+       IOSIZE - bufferlen, !shortmess(SHM_FILE));
 
     if (dont_truncate)
     {
+       int     n;
+
        // Temporarily set msg_scroll to avoid the message being truncated.
        // First call msg_start() to get the message in the right place.
        msg_start();
@@ -3937,7 +3949,7 @@ fileinfo(
     }
     else
     {
-       p = msg_trunc_attr(buffer, FALSE, 0);
+       char    *p = msg_trunc_attr(buffer, FALSE, 0);
        if (restart_edit != 0 || (msg_scrolled && !need_wait_return))
            // Need to repeat the message after redrawing when:
            // - When restart_edit is set (otherwise there will be a delay
@@ -3958,9 +3970,9 @@ col_print(
     int            vcol)
 {
     if (col == vcol)
-       return vim_snprintf((char *)buf, buflen, "%d", col);
+       return (int)vim_snprintf_safelen((char *)buf, buflen, "%d", col);
 
-    return vim_snprintf((char *)buf, buflen, "%d-%d", col, vcol);
+    return (int)vim_snprintf_safelen((char *)buf, buflen, "%d-%d", col, vcol);
 }
 
 static char_u *lasttitle = NULL;
@@ -3972,14 +3984,11 @@ static char_u *lasticon = NULL;
     void
 maketitle(void)
 {
-    char_u     *p;
     char_u     *title_str = NULL;
     char_u     *icon_str = NULL;
-    int                maxlen = 0;
-    int                len;
     int                mustset;
     char_u     buf[IOSIZE];
-    int                off;
+    size_t     buflen = 0;
 
     if (!redrawing())
     {
@@ -3994,6 +4003,8 @@ maketitle(void)
 
     if (p_title)
     {
+       int maxlen = 0;
+
        if (p_titlelen > 0)
        {
            maxlen = p_titlelen * Columns / 100;
@@ -4012,51 +4023,90 @@ maketitle(void)
            else
 #endif
                title_str = p_titlestring;
+           buflen = STRLEN(title_str);
        }
        else
        {
-           // format: "fname + (path) (1 of 2) - VIM"
+           char_u  *p;
+
+           // format: "<filename> [flags] <(path)> [argument info] <- 
servername>"
+           // example:
+           //      buffer.c + (/home/vim/src) (1 of 2) - VIM
+
+           // reserve some space for different parts of the title.
+           // use sizeof() to introduce 'size_t' so we don't have to
+           // cast sizes to it.
+#define SPACE_FOR_FNAME (sizeof(buf) - 100)
+#define SPACE_FOR_DIR   (sizeof(buf) - 20)
+#define SPACE_FOR_ARGNR (sizeof(buf) - 10)  // at least room for " - VIM"
 
-#define SPACE_FOR_FNAME (IOSIZE - 100)
-#define SPACE_FOR_DIR   (IOSIZE - 20)
-#define SPACE_FOR_ARGNR (IOSIZE - 10)  // at least room for " - VIM"
+           // file name
            if (curbuf->b_fname == NULL)
-               vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME);
+               buflen = vim_snprintf_safelen((char *)buf,
+                   SPACE_FOR_FNAME, "%s", _("[No Name]"));
 #ifdef FEAT_TERMINAL
            else if (curbuf->b_term != NULL)
-           {
-               vim_strncpy(buf, term_get_status_text(curbuf->b_term),
-                                                             SPACE_FOR_FNAME);
-           }
+               buflen = vim_snprintf_safelen((char *)buf,
+                   SPACE_FOR_FNAME, "%s",
+                   term_get_status_text(curbuf->b_term));
 #endif
            else
            {
-               p = transstr(gettail(curbuf->b_fname));
-               if (p != NULL)
-               {
-                   vim_strncpy(buf, p, SPACE_FOR_FNAME);
-                   vim_free(p);
-               }
-               else
-                   STRCPY(buf, "");
+               buflen = vim_snprintf_safelen((char *)buf,
+                   SPACE_FOR_FNAME, "%s",
+                   ((p = transstr(gettail(curbuf->b_fname))) != NULL)
+                       ? p
+                       : (char_u *)"");
+               vim_free(p);
            }
 
+           // flags
 #ifdef FEAT_TERMINAL
            if (curbuf->b_term == NULL)
 #endif
+           {
                switch (bufIsChanged(curbuf)
                        + (curbuf->b_p_ro * 2)
                        + (!curbuf->b_p_ma * 4))
                {
-                   case 1: STRCAT(buf, " +"); break;
-                   case 2: STRCAT(buf, " ="); break;
-                   case 3: STRCAT(buf, " =+"); break;
+                   case 1:
+                       // file was modified
+                       buflen += vim_snprintf_safelen(
+                           (char *)buf + buflen,
+                           sizeof(buf) - buflen, " +");
+                       break;
+                   case 2:
+                       // file is readonly
+                       buflen += vim_snprintf_safelen(
+                           (char *)buf + buflen,
+                           sizeof(buf) - buflen, " =");
+                       break;
+                   case 3:
+                       // file was modified and is readonly
+                       buflen += vim_snprintf_safelen(
+                           (char *)buf + buflen,
+                           sizeof(buf) - buflen, " =+");
+                       break;
                    case 4:
-                   case 6: STRCAT(buf, " -"); break;
+                   case 6:
+                       // file cannot be modified
+                       buflen += vim_snprintf_safelen(
+                           (char *)buf + buflen,
+                           sizeof(buf) - buflen, " -");
+                       break;
                    case 5:
-                   case 7: STRCAT(buf, " -+"); break;
+                   case 7:
+                       // file cannot be modified but was modified
+                       buflen += vim_snprintf_safelen(
+                           (char *)buf + buflen,
+                           sizeof(buf) - buflen, " -+");
+                       break;
+                   default:
+                       break;
                }
+           }
 
+           // path (surrounded by '()')
            if (curbuf->b_fname != NULL
 #ifdef FEAT_TERMINAL
                    && curbuf->b_term == NULL
@@ -4064,64 +4114,69 @@ maketitle(void)
                    )
            {
                // Get path of file, replace home dir with ~
-               off = (int)STRLEN(buf);
-               buf[off++] = ' ';
-               buf[off++] = '(';
+               buflen += vim_snprintf_safelen((char *)buf + buflen,
+                   sizeof(buf) - buflen, " (");
+
                home_replace(curbuf, curbuf->b_ffname,
-                                       buf + off, SPACE_FOR_DIR - off, TRUE);
+                   buf + buflen, (int)(SPACE_FOR_DIR - buflen), TRUE);
+
 #ifdef BACKSLASH_IN_FILENAME
                // avoid "c:/name" to be reduced to "c"
-               if (SAFE_isalpha(buf[off]) && buf[off + 1] == ':')
-                   off += 2;
+               if (SAFE_isalpha(buf[buflen]) && buf[buflen + 1] == ':')
+                   buflen += 2;                        // step over "c:"
 #endif
-               // remove the file name
-               p = gettail_sep(buf + off);
-               if (p == buf + off)
+
+               // determine if we have a help or normal buffer
+               p = gettail_sep(buf + buflen);
+               if (p == buf + buflen)
                {
-                   // must be a help buffer
-                   vim_strncpy(buf + off, (char_u *)_("help"),
-                                          (size_t)(SPACE_FOR_DIR - off - 1));
+                   // help buffer
+                   buflen += vim_snprintf_safelen((char *)buf + buflen,
+                       SPACE_FOR_DIR - buflen, "%s)", _("help"));
                }
                else
-                   *p = NUL;
-
-               // Translate unprintable chars and concatenate.  Keep some
-               // room for the server name.  When there is no room (very long
-               // file name) use (...).
-               if (off < SPACE_FOR_DIR)
                {
-                   p = transstr(buf + off);
-                   if (p != NULL)
+                   // normal buffer
+
+                   // Translate unprintable chars and concatenate.  Keep some
+                   // room for the server name.  When there is no room (very 
long
+                   // file name) use (...).
+                   if (buflen < SPACE_FOR_DIR)
                    {
-                       vim_strncpy(buf + off, p, (size_t)(SPACE_FOR_DIR - 
off));
+                       // remove the file name
+                       *p = NUL;
+
+                       buflen += vim_snprintf_safelen((char *)buf + buflen,
+                           SPACE_FOR_DIR - buflen, "%s)",
+                           ((p = transstr(buf + buflen)) != NULL)
+                               ? p
+                               : (char_u *)"");
                        vim_free(p);
                    }
+                   else
+                       buflen += vim_snprintf_safelen((char *)buf + buflen,
+                           SPACE_FOR_ARGNR - buflen, "...)");
                }
-               else
-               {
-                   vim_strncpy(buf + off, (char_u *)"...",
-                                            (size_t)(SPACE_FOR_ARGNR - off));
-               }
-               STRCAT(buf, ")");
            }
 
-           append_arg_number(curwin, buf, SPACE_FOR_ARGNR, FALSE);
+           // argument info
+           buflen += append_arg_number(curwin, buf + buflen,
+               SPACE_FOR_ARGNR - buflen, FALSE);
 
+           // servername
+           buflen += vim_snprintf_safelen((char *)buf + buflen,
+               sizeof(buf) - buflen, " - %s",
 #if defined(FEAT_CLIENTSERVER)
-           if (serverName != NULL)
-           {
-               STRCAT(buf, " - ");
-               vim_strcat(buf, serverName, IOSIZE);
-           }
-           else
+               (serverName != NULL)
+                   ? serverName :
 #endif
-               STRCAT(buf, " - VIM");
+                   (char_u *)"VIM");
 
            if (maxlen > 0)
            {
                // make it shorter by removing a bit in the middle
                if (vim_strsize(buf) > maxlen)
-                   trunc_string(buf, buf, maxlen, IOSIZE);
+                   trunc_string(buf, buf, maxlen, sizeof(buf));
            }
        }
     }
@@ -4142,22 +4197,23 @@ maketitle(void)
        }
        else
        {
-           if (buf_spname(curbuf) != NULL)
-               p = buf_spname(curbuf);
-           else                    // use file name only in icon
-               p = gettail(curbuf->b_ffname);
-           *icon_str = NUL;
+           char_u  *name;
+           int     namelen;
+
+           name = buf_spname(curbuf);
+           if (name == NULL)
+               name = gettail(curbuf->b_ffname);
            // Truncate name at 100 bytes.
-           len = (int)STRLEN(p);
-           if (len > 100)
+           namelen = (int)STRLEN(name);
+           if (namelen > 100)
            {
-               len -= 100;
+               namelen -= 100;
                if (has_mbyte)
-                   len += (*mb_tail_off)(p, p + len) + 1;
-               p += len;
+                   namelen += (*mb_tail_off)(name, name + namelen) + 1;
+               name += namelen;
            }
-           STRCPY(icon_str, p);
-           trans_characters(icon_str, IOSIZE);
+           STRCPY(buf, name);
+           trans_characters(buf, sizeof(buf));
        }
     }
 
@@ -4270,18 +4326,15 @@ build_stl_str_hl(
 {
     linenr_T   lnum;
     colnr_T    len;
+    size_t     outputlen;      // length of out[] used (excluding the NUL)
     char_u     *p;
     char_u     *s;
-    char_u     *t;
     int                byteval;
 #ifdef FEAT_EVAL
     int                use_sandbox;
-    win_T      *save_curwin;
-    buf_T      *save_curbuf;
     int                save_VIsual_active;
 #endif
     int                empty_line;
-    colnr_T    virtcol;
     long       l;
     long       n;
     int                prevchar_isflag;
@@ -4293,8 +4346,6 @@ build_stl_str_hl(
     int                width;
     int                itemcnt;
     int                curitem;
-    int                group_end_userhl;
-    int                group_start_userhl;
     int                groupdepth;
 #ifdef FEAT_EVAL
     int                evaldepth;
@@ -4306,7 +4357,6 @@ build_stl_str_hl(
     char_u     opt;
 #define TMPLEN 70
     char_u     buf_tmp[TMPLEN];
-    char_u     win_tmp[TMPLEN];
     char_u     *usefmt = fmt;
     stl_hlrec_T *sp;
     int                save_redraw_not_allowed = redraw_not_allowed;
@@ -4429,7 +4479,7 @@ build_stl_str_hl(
                                            sizeof(int) * new_len);
            if (new_separator_locs == NULL)
                break;
-           stl_separator_locations = new_separator_locs;;
+           stl_separator_locations = new_separator_locs;
 
            stl_items_len = new_len;
        }
@@ -4478,6 +4528,8 @@ build_stl_str_hl(
        }
        if (*s == ')')
        {
+           char_u  *t;
+
            s++;
            if (groupdepth < 1)
                continue;
@@ -4489,9 +4541,11 @@ build_stl_str_hl(
            if (curitem > stl_groupitem[groupdepth] + 1
                    && stl_items[stl_groupitem[groupdepth]].stl_minwid == 0)
            {
+               int group_start_userhl = 0;
+               int group_end_userhl = 0;
+
                // remove group if all items are empty and highlight group
                // doesn't change
-               group_start_userhl = group_end_userhl = 0;
                for (n = stl_groupitem[groupdepth] - 1; n >= 0; n--)
                {
                    if (stl_items[n].stl_type == Highlight)
@@ -4693,12 +4747,16 @@ build_stl_str_hl(
        case STL_FILEPATH:
        case STL_FULLPATH:
        case STL_FILENAME:
+       {
+           char_u  *name;
+
            fillable = FALSE;   // don't change ' ' to fillchar
-           if (buf_spname(wp->w_buffer) != NULL)
-               vim_strncpy(NameBuff, buf_spname(wp->w_buffer), MAXPATHL - 1);
+           name = buf_spname(wp->w_buffer);
+           if (name != NULL)
+               vim_strncpy(NameBuff, name, MAXPATHL - 1);
            else
            {
-               t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
+               char_u  *t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname
                                          : wp->w_buffer->b_fname;
                home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE);
            }
@@ -4708,13 +4766,17 @@ build_stl_str_hl(
            else
                str = gettail(NameBuff);
            break;
+       }
 
        case STL_VIM_EXPR: // '{'
        {
 #ifdef FEAT_EVAL
-           char_u *block_start = s - 1;
+           char_u  *block_start = s - 1;
 #endif
-           int reevaluate = (*s == '%');
+           int     reevaluate = (*s == '%');
+           char_u  *t;
+           buf_T   *save_curbuf;
+           win_T   *save_curwin;
 
            if (reevaluate)
                s++;
@@ -4727,16 +4789,16 @@ build_stl_str_hl(
                break;
            s++;
            if (reevaluate)
-               p[-1] = 0; // remove the % at the end of %{% expr %}
+               p[-1] = NUL; // remove the % at the end of %{% expr %}
            else
-               *p = 0;
+               *p = NUL;
            p = t;
 #ifdef FEAT_EVAL
            vim_snprintf((char *)buf_tmp, sizeof(buf_tmp),
                                                         "%d", curbuf->b_fnum);
            set_internal_string_var((char_u *)"g:actual_curbuf", buf_tmp);
-           vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->w_id);
-           set_internal_string_var((char_u *)"g:actual_curwin", win_tmp);
+           vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "%d", curwin->w_id);
+           set_internal_string_var((char_u *)"g:actual_curwin", buf_tmp);
 
            save_curbuf = curbuf;
            save_curwin = curwin;
@@ -4755,7 +4817,7 @@ build_stl_str_hl(
            do_unlet((char_u *)"g:actual_curbuf", TRUE);
            do_unlet((char_u *)"g:actual_curwin", TRUE);
 
-           if (str != NULL && *str != 0)
+           if (str != NULL && *str != NUL)
            {
                if (*skipdigits(str) == NUL)
                {
@@ -4767,30 +4829,19 @@ build_stl_str_hl(
 
            // If the output of the expression needs to be evaluated
            // replace the %{} block with the result of evaluation
-           if (reevaluate && str != NULL && *str != 0
+           if (reevaluate && str != NULL && *str != NUL
                    && strchr((const char *)str, '%') != NULL
                    && evaldepth < MAX_STL_EVAL_DEPTH)
            {
                size_t parsed_usefmt = (size_t)(block_start - usefmt);
-               size_t str_length = strlen((const char *)str);
-               size_t fmt_length = strlen((const char *)s);
-               size_t new_fmt_len = parsed_usefmt
-                                                + str_length + fmt_length + 3;
-               char_u *new_fmt = (char_u *)alloc(new_fmt_len * sizeof(char_u));
+               size_t new_fmt_len = (parsed_usefmt
+                       + STRLEN(str) + STRLEN(s) + 3) * sizeof(char_u);
+               char_u *new_fmt = (char_u *)alloc(new_fmt_len);
 
                if (new_fmt != NULL)
                {
-                   char_u *new_fmt_p = new_fmt;
-
-                   new_fmt_p = (char_u *)memcpy(new_fmt_p, usefmt, 
parsed_usefmt)
-                                                                  + 
parsed_usefmt;
-                   new_fmt_p = (char_u *)memcpy(new_fmt_p , str, str_length)
-                                                                     + 
str_length;
-                   new_fmt_p = (char_u *)memcpy(new_fmt_p, "%}", 2) + 2;
-                   new_fmt_p = (char_u *)memcpy(new_fmt_p , s, fmt_length)
-                                                                     + 
fmt_length;
-                   *new_fmt_p = 0;
-                   new_fmt_p = NULL;
+                   vim_snprintf((char *)new_fmt, new_fmt_len, "%.*s%s%s%s",
+                       (int)parsed_usefmt, usefmt, str, "%}", s);
 
                    if (usefmt != fmt)
                        vim_free(usefmt);
@@ -4820,7 +4871,9 @@ build_stl_str_hl(
 
        case STL_VIRTCOL:
        case STL_VIRTCOL_ALT:
-           virtcol = wp->w_virtcol + 1;
+       {
+           colnr_T virtcol = wp->w_virtcol + 1;
+
            // Don't display %V if it's the same as %c.
            if (opt == STL_VIRTCOL_ALT
                    && (virtcol == (colnr_T)((State & MODE_INSERT) == 0
@@ -4828,10 +4881,10 @@ build_stl_str_hl(
                break;
            num = (long)virtcol;
            break;
+       }
 
        case STL_PERCENTAGE:
-           num = (int)(((long)wp->w_cursor.lnum * 100L) /
-                       (long)wp->w_buffer->b_ml.ml_line_count);
+           num = calc_percentage((long)wp->w_cursor.lnum, 
(long)wp->w_buffer->b_ml.ml_line_count);
            break;
 
        case STL_ALTPERCENT:
@@ -4846,8 +4899,8 @@ build_stl_str_hl(
 
        case STL_ARGLISTSTAT:
            fillable = FALSE;
-           buf_tmp[0] = 0;
-           if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), FALSE))
+           buf_tmp[0] = NUL;
+           if (append_arg_number(wp, buf_tmp, sizeof(buf_tmp), FALSE) > 0)
                str = buf_tmp;
            break;
 
@@ -4921,6 +4974,8 @@ build_stl_str_hl(
            if (*wp->w_buffer->b_p_ft != NUL
                    && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
            {
+               char_u  *t;
+
                vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s",
                                                        wp->w_buffer->b_p_ft);
                for (t = buf_tmp; *t != 0; t++)
@@ -4963,26 +5018,30 @@ build_stl_str_hl(
            break;
 
        case STL_HIGHLIGHT:
-           t = s;
-           while (*s != '#' && *s != NUL)
-               ++s;
-           if (*s == '#')
            {
-               stl_items[curitem].stl_type = Highlight;
-               stl_items[curitem].stl_start = p;
-               stl_items[curitem].stl_minwid = -syn_namen2id(t, (int)(s - t));
-               curitem++;
+               char_u  *t = s;
+
+               while (*s != '#' && *s != NUL)
+                   ++s;
+               if (*s == '#')
+               {
+                   stl_items[curitem].stl_type = Highlight;
+                   stl_items[curitem].stl_start = p;
+                   stl_items[curitem].stl_minwid = -syn_namen2id(t, (int)(s - 
t));
+                   curitem++;
+               }
+               if (*s != NUL)
+                   ++s;
+               continue;
            }
-           if (*s != NUL)
-               ++s;
-           continue;
        }
 
        stl_items[curitem].stl_start = p;
        stl_items[curitem].stl_type = Normal;
        if (str != NULL && *str)
        {
-           t = str;
+           char_u  *t = str;
+
            if (itemisflag)
            {
                if ((t[0] && t[1])
@@ -5037,13 +5096,13 @@ build_stl_str_hl(
        }
        else if (num >= 0)
        {
-           int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
-           char_u nstr[20];
+           int     nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16));
+           char_u  nstr[20];
+           char_u  *t = nstr;
 
            if (p + 20 >= out + outlen)
                break;          // not sufficient space
            prevchar_isitem = TRUE;
-           t = nstr;
            if (opt == STL_VIRTCOL_ALT)
            {
                *t++ = '-';
@@ -5054,12 +5113,13 @@ build_stl_str_hl(
                *t++ = '0';
            *t++ = '*';
            *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd');
-           *t = 0;
+           *t = NUL;
 
            for (n = num, l = 1; n >= nbase; n /= nbase)
                l++;
            if (opt == STL_VIRTCOL_ALT)
                l++;
+
            if (l > maxwid)
            {
                l += 2;
@@ -5069,14 +5129,13 @@ build_stl_str_hl(
                *t++ = '>';
                *t++ = '%';
                *t = t[-3];
-               *++t = 0;
-               vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
-                                                                  0, num, n);
+               *++t = NUL;
+               p += vim_snprintf_safelen((char *)p, outlen - (p - out),
+                   (char *)nstr, 0, num, n);
            }
            else
-               vim_snprintf((char *)p, outlen - (p - out), (char *)nstr,
-                                                                minwid, num);
-           p += STRLEN(p);
+               p += vim_snprintf_safelen((char *)p, outlen - (p - out),
+                   (char *)nstr, minwid, num);
        }
        else
            stl_items[curitem].stl_type = Empty;
@@ -5089,6 +5148,7 @@ build_stl_str_hl(
        curitem++;
     }
     *p = NUL;
+    outputlen = (size_t)(p - out);
     itemcnt = curitem;
 
 #ifdef FEAT_EVAL
@@ -5145,10 +5205,12 @@ build_stl_str_hl(
                    break;
            itemcnt = l;
            *s++ = '>';
-           *s = 0;
+           *s = NUL;
        }
        else
        {
+           char_u  *end = out + outputlen;
+
            if (has_mbyte)
            {
                n = 0;
@@ -5161,7 +5223,8 @@ build_stl_str_hl(
            else
                n = width - maxwidth + 1;
            p = s + n;
-           STRMOVE(s + 1, p);
+           mch_memmove(s + 1, p, (size_t)(end - p) + 1);       // +1 for NUL
+           end -= (size_t)(p - (s + 1));
            *s = '<';
 
            --n;        // count the '<'
@@ -5176,14 +5239,15 @@ build_stl_str_hl(
            // Fill up for half a double-wide character.
            while (++width < maxwidth)
            {
-               s = s + STRLEN(s);
+               s = end;
                MB_CHAR2BYTES(fillchar, s);
                *s = NUL;
+               end = s;
            }
        }
        width = maxwidth;
     }
-    else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen)
+    else if (width < maxwidth && outputlen + maxwidth - width + 1 < outlen)
     {
        // Find how many separators there are, which we will use when
        // figuring out how many groups there are.
@@ -5284,7 +5348,7 @@ build_stl_str_hl(
 #endif // FEAT_STL_OPT
 
 /*
- * Get relative cursor position in window into "buf[buflen]", in the localized
+ * Get relative cursor position in window into "buf[]", in the localized
  * percentage form like %99, 99%; using "Top", "Bot" or "All" when appropriate.
  */
     int
@@ -5295,7 +5359,6 @@ get_rel_pos(
 {
     long       above; // number of lines above window
     long       below; // number of lines below window
-    int                len;
 
     if (buflen < 3) // need at least 3 chars for writing
        return 0;
@@ -5309,42 +5372,31 @@ get_rel_pos(
 #endif
     below = wp->w_buffer->b_ml.ml_line_count - wp->w_botline + 1;
     if (below <= 0)
-       len = vim_snprintf((char *)buf, buflen, "%s", (above == 0) ? _("All") : 
_("Bot"));
-    else if (above <= 0)
-       len = vim_snprintf((char *)buf, buflen, "%s", _("Top"));
-    else
-    {
-       int perc = (above > 1000000L)
-                   ?  (int)(above / ((above + below) / 100L))
-                   :  (int)(above * 100L / (above + below));
+       return (int)vim_snprintf_safelen((char *)buf, buflen,
+           "%s", (above == 0) ? _("All") : _("Bot"));
 
-       // localized percentage value
-       len = vim_snprintf((char *)buf, buflen, _("%s%d%%"), (perc < 10) ? " " 
: "", perc);
-    }
-    if (len < 0)
-    {
-       buf[0] = NUL;
-       len = 0;
-    }
-    else if (len > buflen - 1)
-       len = buflen - 1;
+    if (above <= 0)
+       return (int)vim_snprintf_safelen((char *)buf, buflen,
+           "%s", _("Top"));
 
-    return len;
+    // localized percentage value
+    return (int)vim_snprintf_safelen((char *)buf, buflen,
+       _("%2d%%"), calc_percentage(above, above + below));
 }
 
 /*
- * Append (file 2 of 8) to "buf[buflen]", if editing more than one file.
- * Return TRUE if it was appended.
+ * Append (file 2 of 8) to "buf[]", if editing more than one file.
+ * Return the number of characters appended.
  */
     static int
 append_arg_number(
     win_T      *wp,
     char_u     *buf,
-    int                buflen,
+    size_t     buflen,
     int                add_file)       // Add "file" before the arg number
 {
     if (ARGCOUNT <= 1)         // nothing to do
-       return FALSE;
+       return 0;
 
     char *msg;
     switch ((wp->w_arg_idx_invalid ? 1 : 0) + (add_file ? 2 : 0))
@@ -5355,10 +5407,8 @@ append_arg_number(
        case 3: msg = _(" (file (%d) of %d)"); break;
     }
 
-    char_u *p = buf + STRLEN(buf);     // go to the end of the buffer
-    vim_snprintf((char *)p, (size_t)(buflen - (p - buf)), msg,
+    return (int)vim_snprintf_safelen((char *)buf, buflen, msg,
                                                  wp->w_arg_idx + 1, ARGCOUNT);
-    return TRUE;
 }
 
 /*
@@ -5698,17 +5748,16 @@ chk_modeline(
     int                flags)          // Same as for do_modelines().
 {
     char_u     *s;
+    char_u     *line_end;              // point to the end of the line
     char_u     *e;
-    char_u     *linecopy;              // local copy of any modeline found
     int                prev;
-    int                vers;
-    int                end;
     int                retval = OK;
-    sctx_T     save_current_sctx;
     ESTACK_CHECK_DECLARATION;
 
     prev = -1;
-    for (s = ml_get(lnum); *s != NUL; ++s)
+    s = ml_get(lnum);
+    line_end = s + ml_get_len(lnum);
+    for (; *s != NUL; ++s)
     {
        if (prev == -1 || vim_isspace(prev))
        {
@@ -5718,6 +5767,8 @@ chk_modeline(
            // Accept both "vim" and "Vim".
            if ((s[0] == 'v' || s[0] == 'V') && s[1] == 'i' && s[2] == 'm')
            {
+               int vers;
+
                if (s[3] == '<' || s[3] == '=' || s[3] == '>')
                    e = s + 4;
                else
@@ -5739,14 +5790,23 @@ chk_modeline(
 
     if (*s)
     {
+       size_t  len;
+       char_u  *linecopy;              // local copy of any modeline found
+       int     end;
+
        do                              // skip over "ex:", "vi:" or "vim:"
            ++s;
        while (s[-1] != ':');
 
-       s = linecopy = vim_strsave(s);  // copy the line, it will change
+       len = (size_t)(line_end - s);           // remember the line length
+                                               // so we can restore 'line_end'
+                                               // after the copy
+       s = linecopy = vim_strnsave(s, len);    // copy the line, it will change
        if (linecopy == NULL)
            return FAIL;
 
+       line_end = s + len;                     // restore 'line_end'
+
        // prepare for emsg()
        estack_push(ETYPE_MODELINE, (char_u *)"modelines", lnum);
        ESTACK_CHECK_SETUP;
@@ -5764,7 +5824,10 @@ chk_modeline(
             */
            for (e = s; *e != ':' && *e != NUL; ++e)
                if (e[0] == '\' && e[1] == ':')
-                   STRMOVE(e, e + 1);
+               {
+                   mch_memmove(e, e + 1, (size_t)(line_end - (e + 1)) + 1);    
// +1 for NUL
+                   --line_end;
+               }
            if (*e == NUL)
                end = TRUE;
 
@@ -5781,15 +5844,15 @@ chk_modeline(
                if (*e != ':')          // no terminating ':'?
                    break;
                end = TRUE;
-               s = vim_strchr(s, ' ') + 1;
+               s += (*(s + 2) == ' ') ? 3 : 4;
            }
            *e = NUL;                   // truncate the set command
 
            if (*s != NUL)              // skip over an empty "::"
            {
                int secure_save = secure;
+               sctx_T  save_current_sctx = current_sctx;
 
-               save_current_sctx = current_sctx;
                current_sctx.sc_version = 1;
 #ifdef FEAT_EVAL
                current_sctx.sc_sid = SID_MODELINE;
@@ -5807,7 +5870,8 @@ chk_modeline(
                if (retval == FAIL)             // stop if error found
                    break;
            }
-           s = e + 1;                  // advance to next part
+           s = (e == line_end) ? e : e + 1;    // advance to next part
+                                               // careful not to go off the end
        }
 
        ESTACK_CHECK_NOW;
diff --git a/src/proto.h b/src/proto.h
index f04ba0525..a5ca9e4e2 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -140,6 +140,7 @@ void siemsg(const char *, ...) ATTRIBUTE_COLD 
ATTRIBUTE_FORMAT_PRINTF(1, 2);
 int vim_snprintf_add(char *, size_t, const char *, ...) 
ATTRIBUTE_FORMAT_PRINTF(3, 4);
 
 int vim_snprintf(char *, size_t, const char *, ...) ATTRIBUTE_FORMAT_PRINTF(3, 
4);
+size_t vim_snprintf_safelen(char *, size_t, const char *, ...) 
ATTRIBUTE_FORMAT_PRINTF(3, 4);
 
 int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap)
        ATTRIBUTE_FORMAT_PRINTF(3, 0);
diff --git a/src/strings.c b/src/strings.c
index d6f1b3823..e1d23e387 100644
--- a/src/strings.c
+++ b/src/strings.c
@@ -2487,6 +2487,33 @@ vim_snprintf(char *str, size_t str_m, const char *fmt, 
...)
     return str_l;
 }
 
+/*
+ * Like vim_snprintf() except the return value can be safely used to increment 
a
+ * buffer length.
+ * Normal `snprintf()` (and `vim_snprintf()`) returns the number of bytes that
+ * would have been copied if the destination buffer was large enough.
+ * This means that you cannot rely on it's return value for the destination
+ * length because the destination may be shorter than the source. This function
+ * guarantees the returned length will never be greater than the destination 
length.
+ */
+    size_t
+vim_snprintf_safelen(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);
+
+    if (str_l < 0)
+    {
+       *str = NUL;
+       return 0;
+    }
+    return ((size_t)str_l >= str_m) ? str_m - 1 : (size_t)str_l;
+}
+
     int
 vim_vsnprintf(
     char       *str,
diff --git a/src/version.c b/src/version.c
index 4609244f5..e500aa19e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1291,
 /**/
     1290,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1u2xpf-00CgLA-Ku%40256bit.org.

Raspunde prin e-mail lui