]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0031: Inefficient use of ga_concat() v9.2.0031
authorJohn Marriott <basilisk@internode.on.net>
Thu, 19 Feb 2026 17:25:27 +0000 (17:25 +0000)
committerChristian Brabandt <cb@256bit.org>
Thu, 19 Feb 2026 17:27:51 +0000 (17:27 +0000)
Problem:  Inefficient use of ga_concat()
Solution: Use ga_concat_len() when the length is already known to avoid
          use of strlen() (John Marriott).

closes: #19422

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: John Marriott <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/clientserver.c
src/json.c
src/list.c
src/macros.h
src/testing.c
src/version.c

index 028da5c06388cb620efcc44a3203af36b8667988..3d801bbf0f661f6ff62ef443177d0500f20537ee 100644 (file)
@@ -674,12 +674,16 @@ build_drop_cmd(
     int                i;
     char_u     *inicmd = NULL;
     char_u     *p;
-    char_u     *cdp;
+    string_T   cdp;
     char_u     *cwd;
     // reset wildignore temporarily
-    const char *wig[] =
-    { "<CR><C-\\><C-N>:let g:_wig=&wig|set wig=",
-      "<C-\\><C-N>:let &wig=g:_wig|unlet g:_wig<CR>"};
+# define STRING_INIT(s) \
+    {(char_u *)(s), STRLEN_LITERAL(s)}
+    const string_T wig[] = {
+       STRING_INIT("<CR><C-\\><C-N>:let g:_wig=&wig|set wig="),
+       STRING_INIT("<C-\\><C-N>:let &wig=g:_wig|unlet g:_wig<CR>")
+    };
+# undef STRING_INIT
 
     if (filec > 0 && filev[0][0] == '+')
     {
@@ -700,7 +704,7 @@ build_drop_cmd(
        vim_free(cwd);
        return NULL;
     }
-    cdp = vim_strsave_escaped_ext(cwd,
+    cdp.string = vim_strsave_escaped_ext(cwd,
 # ifdef BACKSLASH_IN_FILENAME
            (char_u *)"",  // rem_backslash() will tell what chars to escape
 # else
@@ -708,20 +712,20 @@ build_drop_cmd(
 # endif
            '\\', TRUE);
     vim_free(cwd);
-    if (cdp == NULL)
+    if (cdp.string == NULL)
        return NULL;
+    cdp.length = STRLEN(cdp.string);
     ga_init2(&ga, 1, 100);
-    ga_concat(&ga, (char_u *)"<C-\\><C-N>:cd ");
-    ga_concat(&ga, cdp);
+    GA_CONCAT_LITERAL(&ga, "<C-\\><C-N>:cd ");
+    ga_concat_len(&ga, cdp.string, cdp.length);
     // reset wildignorecase temporarily
-    ga_concat(&ga, (char_u *)wig[0]);
+    ga_concat_len(&ga, wig[0].string, wig[0].length);
 
     // Call inputsave() so that a prompt for an encryption key works.
-    ga_concat(&ga, (char_u *)
-           "<CR><C-\\><C-N>:if exists('*inputsave')|call inputsave()|endif|");
+    GA_CONCAT_LITERAL(&ga, "<CR><C-\\><C-N>:if exists('*inputsave')|call inputsave()|endif|");
     if (tabs)
-       ga_concat(&ga, (char_u *)"tab ");
-    ga_concat(&ga, (char_u *)"drop");
+       GA_CONCAT_LITERAL(&ga, "tab ");
+    GA_CONCAT_LITERAL(&ga, "drop");
     for (i = 0; i < filec; i++)
     {
        // On Unix the shell has already expanded the wildcards, don't want to
@@ -739,16 +743,15 @@ build_drop_cmd(
            vim_free(ga.ga_data);
            return NULL;
        }
-       ga_concat(&ga, (char_u *)" ");
+       GA_CONCAT_LITERAL(&ga, " ");
        ga_concat(&ga, p);
        vim_free(p);
     }
-    ga_concat(&ga, (char_u *)
-                 "|if exists('*inputrestore')|call inputrestore()|endif<CR>");
+    GA_CONCAT_LITERAL(&ga, "|if exists('*inputrestore')|call inputrestore()|endif<CR>");
 
     // The :drop commands goes to Insert mode when 'insertmode' is set, use
     // CTRL-\ CTRL-N again.
-    ga_concat(&ga, (char_u *)"<C-\\><C-N>");
+    GA_CONCAT_LITERAL(&ga, "<C-\\><C-N>");
 
     // Switch back to the correct current directory (prior to temporary path
     // switch) unless 'autochdir' is set, in which case it will already be
@@ -761,34 +764,34 @@ build_drop_cmd(
     //      cd -
     //    endif
     //  endif
-    ga_concat(&ga, (char_u *)":if !exists('+acd')||!&acd|if haslocaldir()|");
+    GA_CONCAT_LITERAL(&ga, ":if !exists('+acd')||!&acd|if haslocaldir()|");
 # ifdef MSWIN
     // in case :set shellslash is set, need to normalize the directory separators
     // '/' is not valid in a filename so replacing '/' by '\\' should be safe
-    ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd()->tr('/','\\') ==# '");
+    GA_CONCAT_LITERAL(&ga, "cd -|lcd -|elseif getcwd()->tr('/','\\') ==# '");
 # else
-    ga_concat(&ga, (char_u *)"cd -|lcd -|elseif getcwd() ==# '");
+    GA_CONCAT_LITERAL(&ga, "cd -|lcd -|elseif getcwd() ==# '");
 # endif
-    ga_concat(&ga, cdp);
-    ga_concat(&ga, (char_u *)"'|cd -|endif|endif<CR>");
-    vim_free(cdp);
+    ga_concat_len(&ga, cdp.string, cdp.length);
+    GA_CONCAT_LITERAL(&ga, "'|cd -|endif|endif<CR>");
+    vim_free(cdp.string);
     // reset wildignorecase
-    ga_concat(&ga, (char_u *)wig[1]);
+    ga_concat_len(&ga, wig[1].string, wig[1].length);
 
     if (sendReply)
-       ga_concat(&ga, (char_u *)":call SetupRemoteReplies()<CR>");
-    ga_concat(&ga, (char_u *)":");
+       GA_CONCAT_LITERAL(&ga, ":call SetupRemoteReplies()<CR>");
+    GA_CONCAT_LITERAL(&ga, ":");
     if (inicmd != NULL)
     {
        // Can't use <CR> after "inicmd", because a "startinsert" would cause
        // the following commands to be inserted as text.  Use a "|",
        // hopefully "inicmd" does allow this...
        ga_concat(&ga, inicmd);
-       ga_concat(&ga, (char_u *)"|");
+       GA_CONCAT_LITERAL(&ga, "|");
     }
     // Bring the window to the foreground, goto Insert mode when 'im' set and
     // clear command line.
-    ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f<CR>");
+    GA_CONCAT_LITERAL(&ga, "cal foreground()|if &im|star|en|redr|f<CR>");
     ga_append(&ga, NUL);
     return ga.ga_data;
 }
index d70d3b6c55f51fe9fdf06ef8222ad9092f917b06..8b0b050b8ab703fbe542e7ac1a84a31c186e9b5d 100644 (file)
@@ -96,6 +96,7 @@ json_encode_lsp_msg(typval_T *val)
 {
     garray_T   ga;
     garray_T   lspga;
+    size_t     IObufflen;
 
     ga_init2(&ga, 1, 4000);
     if (json_encode_gap(&ga, val, 0) == FAIL)
@@ -104,10 +105,10 @@ json_encode_lsp_msg(typval_T *val)
 
     ga_init2(&lspga, 1, 4000);
     // Header according to LSP specification.
-    vim_snprintf((char *)IObuff, IOSIZE,
+    IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE,
            "Content-Length: %u\r\n\r\n",
            ga.ga_len - 1);
-    ga_concat(&lspga, IObuff);
+    ga_concat_len(&lspga, IObuff, IObufflen);
     ga_concat_len(&lspga, ga.ga_data, ga.ga_len);
     ga_clear(&ga);
     return lspga.ga_data;
@@ -145,7 +146,7 @@ write_string(garray_T *gap, char_u *str)
 
     if (res == NULL)
     {
-       ga_concat(gap, (char_u *)"\"\"");
+       GA_CONCAT_LITERAL(gap, "\"\"");
        return;
     }
 
@@ -199,16 +200,21 @@ write_string(garray_T *gap, char_u *str)
                    ga_append(gap, c);
                    break;
                default:
-                   vim_snprintf((char *)numbuf, NUMBUFLEN, "\\u%04lx",
-                                                                     (long)c);
-                   ga_concat(gap, numbuf);
+               {
+                   size_t  numbuflen;
+
+                   numbuflen = vim_snprintf_safelen((char *)numbuf,
+                       sizeof(numbuf), "\\u%04lx", (long)c);
+                   ga_concat_len(gap, numbuf, numbuflen);
+               }
            }
 
            res += 1;
        }
        else
        {
-           int l = utf_ptr2len(res);
+           int     l = utf_ptr2len(res);
+           size_t  numbuflen;
 
            if (l > 1)
            {
@@ -222,8 +228,9 @@ write_string(garray_T *gap, char_u *str)
                ga_concat_len(gap, from, res - from);
            from = res + 1;
 
-           numbuf[utf_char2bytes(0xFFFD, numbuf)] = NUL;
-           ga_concat(gap, numbuf);
+           numbuflen = utf_char2bytes(0xFFFD, numbuf);
+           numbuf[numbuflen] = NUL;
+           ga_concat_len(gap, numbuf, numbuflen);
 
            res += l;
        }
@@ -276,8 +283,8 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
        case VAR_BOOL:
            switch ((long)val->vval.v_number)
            {
-               case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
-               case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
+               case VVAL_FALSE: GA_CONCAT_LITERAL(gap, "false"); break;
+               case VVAL_TRUE: GA_CONCAT_LITERAL(gap, "true"); break;
            }
            break;
 
@@ -289,14 +296,18 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
                                    // empty item
                                    break;
                                // FALLTHROUGH
-               case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
+               case VVAL_NULL: GA_CONCAT_LITERAL(gap, "null"); break;
            }
            break;
 
        case VAR_NUMBER:
-           vim_snprintf((char *)numbuf, NUMBUFLEN, "%lld",
-                                             (varnumber_T)val->vval.v_number);
-           ga_concat(gap, numbuf);
+           {
+               size_t  numbuflen;
+
+               numbuflen = vim_snprintf_safelen((char *)numbuf, sizeof(numbuf),
+                   "%lld", (varnumber_T)val->vval.v_number);
+               ga_concat_len(gap, numbuf, numbuflen);
+           }
            break;
 
        case VAR_STRING:
@@ -318,17 +329,19 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
        case VAR_BLOB:
            b = val->vval.v_blob;
            if (b == NULL || b->bv_ga.ga_len == 0)
-               ga_concat(gap, (char_u *)"[]");
+               GA_CONCAT_LITERAL(gap, "[]");
            else
            {
                ga_append(gap, '[');
                for (i = 0; i < b->bv_ga.ga_len; i++)
                {
+                   size_t  numbuflen;
+
                    if (i > 0)
-                       ga_concat(gap, (char_u *)",");
-                   vim_snprintf((char *)numbuf, NUMBUFLEN, "%d",
-                           blob_get(b, i));
-                   ga_concat(gap, numbuf);
+                       GA_CONCAT_LITERAL(gap, ",");
+                   numbuflen = vim_snprintf_safelen((char *)numbuf, sizeof(numbuf),
+                       "%d", blob_get(b, i));
+                   ga_concat_len(gap, numbuf, numbuflen);
                }
                ga_append(gap, ']');
            }
@@ -337,11 +350,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
        case VAR_LIST:
            l = val->vval.v_list;
            if (l == NULL)
-               ga_concat(gap, (char_u *)"[]");
+               GA_CONCAT_LITERAL(gap, "[]");
            else
            {
                if (l->lv_copyID == copyID)
-                   ga_concat(gap, (char_u *)"[]");
+                   GA_CONCAT_LITERAL(gap, "[]");
                else
                {
                    listitem_T  *li;
@@ -373,11 +386,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
        case VAR_TUPLE:
            tuple = val->vval.v_tuple;
            if (tuple == NULL)
-               ga_concat(gap, (char_u *)"[]");
+               GA_CONCAT_LITERAL(gap, "[]");
            else
            {
                if (tuple->tv_copyID == copyID)
-                   ga_concat(gap, (char_u *)"[]");
+                   GA_CONCAT_LITERAL(gap, "[]");
                else
                {
                    int         len = TUPLE_LEN(tuple);
@@ -409,11 +422,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
        case VAR_DICT:
            d = val->vval.v_dict;
            if (d == NULL)
-               ga_concat(gap, (char_u *)"{}");
+               GA_CONCAT_LITERAL(gap, "{}");
            else
            {
                if (d->dv_copyID == copyID)
-                   ga_concat(gap, (char_u *)"{}");
+                   GA_CONCAT_LITERAL(gap, "{}");
                else
                {
                    int         first = TRUE;
@@ -451,20 +464,22 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options)
        case VAR_FLOAT:
 #if defined(HAVE_MATH_H)
            if (isnan(val->vval.v_float))
-               ga_concat(gap, (char_u *)"NaN");
+               GA_CONCAT_LITERAL(gap, "NaN");
            else if (isinf(val->vval.v_float))
            {
                if (val->vval.v_float < 0.0)
-                   ga_concat(gap, (char_u *)"-Infinity");
+                   GA_CONCAT_LITERAL(gap, "-Infinity");
                else
-                   ga_concat(gap, (char_u *)"Infinity");
+                   GA_CONCAT_LITERAL(gap, "Infinity");
            }
            else
 #endif
            {
-               vim_snprintf((char *)numbuf, NUMBUFLEN, "%g",
-                                                          val->vval.v_float);
-               ga_concat(gap, numbuf);
+               size_t  numbuflen;
+
+               numbuflen = vim_snprintf_safelen((char *)numbuf, sizeof(numbuf),
+                   "%g", val->vval.v_float);
+               ga_concat_len(gap, numbuf, numbuflen);
            }
            break;
        case VAR_UNKNOWN:
@@ -612,9 +627,11 @@ json_decode_string(js_read_T *reader, typval_T *res, int quote)
                    if (res != NULL)
                    {
                        char_u  buf[NUMBUFLEN];
+                       size_t  buflen;
 
-                       buf[utf_char2bytes((int)nr, buf)] = NUL;
-                       ga_concat(&ga, buf);
+                       buflen = utf_char2bytes((int)nr, buf);
+                       buf[buflen] = NUL;
+                       ga_concat_len(&ga, buf, buflen);
                    }
                    break;
                default:
index c3d7b5a2b87f058d9799d412dbd1cda4a903ce2b..253b1be9ffbd3ef0c476691dbd48b932a14bab0b 100644 (file)
@@ -1466,7 +1466,7 @@ list2string(typval_T *tv, int copyID, int restore_copyID)
 }
 
 typedef struct join_S {
-    char_u     *s;
+    string_T   s;
     char_u     *tofree;
 } join_T;
 
@@ -1482,37 +1482,39 @@ list_join_inner(
 {
     int                i;
     join_T     *p;
-    int                len;
     int                sumlen = 0;
     int                first = TRUE;
     char_u     *tofree;
     char_u     numbuf[NUMBUFLEN];
     listitem_T *item;
-    char_u     *s;
+    string_T   s;
+    size_t     seplen;
 
     // Stringify each item in the list.
     CHECK_LIST_MATERIALIZE(l);
     for (item = l->lv_first; item != NULL && !got_int; item = item->li_next)
     {
-       s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID,
+       s.string = echo_string_core(&item->li_tv, &tofree, numbuf, copyID,
                                      echo_style, restore_copyID, !echo_style);
-       if (s == NULL)
+       if (s.string == NULL)
            return FAIL;
 
-       len = (int)STRLEN(s);
-       sumlen += len;
+       s.length = STRLEN(s.string);
+       sumlen += (int)s.length;
 
        (void)ga_grow(join_gap, 1);
        p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++);
-       if (tofree != NULL || s != numbuf)
+       if (tofree != NULL || s.string != numbuf)
        {
-           p->s = s;
+           p->s.string = s.string;
+           p->s.length = s.length;
            p->tofree = tofree;
        }
        else
        {
-           p->s = vim_strnsave(s, len);
-           p->tofree = p->s;
+           p->s.string = vim_strnsave(s.string, s.length);
+           p->s.length = s.length;
+           p->tofree = p->s.string;
        }
 
        line_breakcheck();
@@ -1522,8 +1524,9 @@ list_join_inner(
 
     // Allocate result buffer with its total size, avoid re-allocation and
     // multiple copy operations.  Add 2 for a tailing ']' and NUL.
+    seplen = STRLEN(sep);
     if (join_gap->ga_len >= 2)
-       sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1);
+       sumlen += (int)seplen * (join_gap->ga_len - 1);
     if (ga_grow(gap, sumlen + 2) == FAIL)
        return FAIL;
 
@@ -1532,11 +1535,11 @@ list_join_inner(
        if (first)
            first = FALSE;
        else
-           ga_concat(gap, sep);
+           ga_concat_len(gap, sep, seplen);
        p = ((join_T *)join_gap->ga_data) + i;
 
-       if (p->s != NULL)
-           ga_concat(gap, p->s);
+       if (p->s.string != NULL)
+           ga_concat_len(gap, p->s.string, p->s.length);
        line_breakcheck();
     }
 
@@ -1836,8 +1839,11 @@ f_list2str(typval_T *argvars, typval_T *rettv)
 
        FOR_ALL_LIST_ITEMS(l, li)
        {
-           buf[(*char2bytes)(tv_get_number(&li->li_tv), buf)] = NUL;
-           ga_concat(&ga, buf);
+           size_t  buflen;
+
+           buflen = (size_t)(*char2bytes)(tv_get_number(&li->li_tv), buf);
+           buf[buflen] = NUL;
+           ga_concat_len(&ga, buf, buflen);
        }
        ga_append(&ga, NUL);
     }
index 3e2c1c568b408a63eb2c269f9f8f8226cb1640f7..9007b5b37a9e787ea30fb9131ba1440f20a5add1 100644 (file)
 #define GA_GROW_FAILS(gap, n) unlikely((((gap)->ga_maxlen - (gap)->ga_len < (n)) ? ga_grow_inner((gap), (n)) : OK) == FAIL)
 // Inlined version of ga_grow() with optimized condition that it succeeds.
 #define GA_GROW_OK(gap, n) likely((((gap)->ga_maxlen - (gap)->ga_len < (n)) ? ga_grow_inner((gap), (n)) : OK) == OK)
+#define GA_CONCAT_LITERAL(gap, s) ga_concat_len((gap), (char_u *)(s), STRLEN_LITERAL(s))
 
 #ifndef MIN
 # define MIN(a, b) ((a) < (b) ? (a) : (b))
index dd8dc8e51210d0d4643eef82021f6629ddf069cd..75e5edfc710157e415098e66c7e926b58151872e 100644 (file)
@@ -21,7 +21,6 @@
     static void
 prepare_assert_error(garray_T *gap)
 {
-    char    buf[NUMBUFLEN];
     char_u  *sname = estack_sfile(ESTACK_NONE);
 
     ga_init2(gap, 1, 100);
@@ -29,15 +28,18 @@ prepare_assert_error(garray_T *gap)
     {
        ga_concat(gap, sname);
        if (SOURCING_LNUM > 0)
-           ga_concat(gap, (char_u *)" ");
+           GA_CONCAT_LITERAL(gap, " ");
     }
     if (SOURCING_LNUM > 0)
     {
-       sprintf(buf, "line %ld", (long)SOURCING_LNUM);
-       ga_concat(gap, (char_u *)buf);
+       char    buf[NUMBUFLEN];
+       size_t  buflen;
+
+       buflen = vim_snprintf_safelen(buf, sizeof(buf), "line %ld", (long)SOURCING_LNUM);
+       ga_concat_len(gap, (char_u *)buf, buflen);
     }
     if (sname != NULL || SOURCING_LNUM > 0)
-       ga_concat(gap, (char_u *)": ");
+       GA_CONCAT_LITERAL(gap, ": ");
     vim_free(sname);
 }
 
@@ -54,28 +56,31 @@ ga_concat_esc(garray_T *gap, char_u *p, int clen)
     {
        mch_memmove(buf, p, clen);
        buf[clen] = NUL;
-       ga_concat(gap, buf);
+       ga_concat_len(gap, buf, clen);
        return;
     }
 
     switch (*p)
     {
-       case BS: ga_concat(gap, (char_u *)"\\b"); break;
-       case ESC: ga_concat(gap, (char_u *)"\\e"); break;
-       case FF: ga_concat(gap, (char_u *)"\\f"); break;
-       case NL: ga_concat(gap, (char_u *)"\\n"); break;
-       case TAB: ga_concat(gap, (char_u *)"\\t"); break;
-       case CAR: ga_concat(gap, (char_u *)"\\r"); break;
-       case '\\': ga_concat(gap, (char_u *)"\\\\"); break;
+       case BS: GA_CONCAT_LITERAL(gap, "\\b"); break;
+       case ESC: GA_CONCAT_LITERAL(gap, "\\e"); break;
+       case FF: GA_CONCAT_LITERAL(gap, "\\f"); break;
+       case NL: GA_CONCAT_LITERAL(gap, "\\n"); break;
+       case TAB: GA_CONCAT_LITERAL(gap, "\\t"); break;
+       case CAR: GA_CONCAT_LITERAL(gap, "\\r"); break;
+       case '\\': GA_CONCAT_LITERAL(gap, "\\\\"); break;
        default:
-                  if (*p < ' ' || *p == 0x7f)
-                  {
-                      vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
-                      ga_concat(gap, buf);
-                  }
-                  else
-                      ga_append(gap, *p);
-                  break;
+          if (*p < ' ' || *p == 0x7f)
+          {
+               size_t  buflen;
+
+               buflen = vim_snprintf_safelen((char *)buf, sizeof(buf),
+                   "\\x%02x", *p);
+               ga_concat_len(gap, buf, buflen);
+          }
+          else
+              ga_append(gap, *p);
+          break;
     }
 }
 
@@ -91,11 +96,12 @@ ga_concat_shorten_esc(garray_T *gap, char_u *str)
     int            c;
     int            clen;
     char_u  buf[NUMBUFLEN];
+    size_t  buflen;
     int            same_len;
 
     if (str == NULL)
     {
-       ga_concat(gap, (char_u *)"NULL");
+       GA_CONCAT_LITERAL(gap, "NULL");
        return;
     }
 
@@ -112,12 +118,13 @@ ga_concat_shorten_esc(garray_T *gap, char_u *str)
        }
        if (same_len > 20)
        {
-           ga_concat(gap, (char_u *)"\\[");
+           GA_CONCAT_LITERAL(gap, "\\[");
            ga_concat_esc(gap, p, clen);
-           ga_concat(gap, (char_u *)" occurs ");
-           vim_snprintf((char *)buf, NUMBUFLEN, "%d", same_len);
-           ga_concat(gap, buf);
-           ga_concat(gap, (char_u *)" times]");
+           GA_CONCAT_LITERAL(gap, " occurs ");
+           buflen = vim_snprintf_safelen((char *)buf, sizeof(buf),
+               "%d", same_len);
+           ga_concat_len(gap, buf, buflen);
+           GA_CONCAT_LITERAL(gap, " times]");
            p = s;
        }
        else
@@ -154,15 +161,15 @@ fill_assert_error(
     {
        ga_concat(gap, echo_string(opt_msg_tv, &tofree, numbuf, 0));
        vim_free(tofree);
-       ga_concat(gap, (char_u *)": ");
+       GA_CONCAT_LITERAL(gap, ": ");
     }
 
     if (atype == ASSERT_MATCH || atype == ASSERT_NOTMATCH)
-       ga_concat(gap, (char_u *)"Pattern ");
+       GA_CONCAT_LITERAL(gap, "Pattern ");
     else if (atype == ASSERT_NOTEQUAL)
-       ga_concat(gap, (char_u *)"Expected not equal to ");
+       GA_CONCAT_LITERAL(gap, "Expected not equal to ");
     else
-       ga_concat(gap, (char_u *)"Expected ");
+       GA_CONCAT_LITERAL(gap, "Expected ");
     if (exp_str == NULL)
     {
        // When comparing dictionaries, drop the items that are equal, so that
@@ -227,29 +234,30 @@ fill_assert_error(
     else
     {
        if (atype == ASSERT_FAILS)
-           ga_concat(gap, (char_u *)"'");
+           GA_CONCAT_LITERAL(gap, "'");
        ga_concat_shorten_esc(gap, exp_str);
        if (atype == ASSERT_FAILS)
-           ga_concat(gap, (char_u *)"'");
+           GA_CONCAT_LITERAL(gap, "'");
     }
     if (atype != ASSERT_NOTEQUAL)
     {
        if (atype == ASSERT_MATCH)
-           ga_concat(gap, (char_u *)" does not match ");
+           GA_CONCAT_LITERAL(gap, " does not match ");
        else if (atype == ASSERT_NOTMATCH)
-           ga_concat(gap, (char_u *)" does match ");
+           GA_CONCAT_LITERAL(gap, " does match ");
        else
-           ga_concat(gap, (char_u *)" but got ");
+           GA_CONCAT_LITERAL(gap, " but got ");
        ga_concat_shorten_esc(gap, tv2string(got_tv, &tofree, numbuf, 0));
        vim_free(tofree);
 
        if (omitted != 0)
        {
-           char buf[100];
+           char    buf[100];
+           size_t  buflen;
 
-           vim_snprintf(buf, 100, " - %d equal item%s omitted",
-                                            omitted, omitted == 1 ? "" : "s");
-           ga_concat(gap, (char_u *)buf);
+           buflen = vim_snprintf_safelen(buf, sizeof(buf),
+               " - %d equal item%s omitted", omitted, omitted == 1 ? "" : "s");
+           ga_concat_len(gap, (char_u *)buf, buflen);
        }
     }
 
@@ -368,9 +376,9 @@ assert_beeps(typval_T *argvars, int no_beep)
     {
        prepare_assert_error(&ga);
        if (no_beep)
-           ga_concat(&ga, (char_u *)"command did beep: ");
+           GA_CONCAT_LITERAL(&ga, "command did beep: ");
        else
-           ga_concat(&ga, (char_u *)"command did not beep: ");
+           GA_CONCAT_LITERAL(&ga, "command did not beep: ");
        ga_concat(&ga, cmd);
        assert_error(&ga);
        ga_clear(&ga);
@@ -427,16 +435,18 @@ assert_equalfile(typval_T *argvars)
     char       line1[200];
     char       line2[200];
     int                lineidx = 0;
+    size_t     IObufflen;
 
     if (fname1 == NULL || fname2 == NULL)
        return 0;
 
     IObuff[0] = NUL;
+    IObufflen = 0;
     fd1 = mch_fopen((char *)fname1, READBIN);
     if (fd1 == NULL)
     {
-       vim_snprintf((char *)IObuff, IOSIZE, (char *)e_cant_read_file_str,
-                                                                      fname1);
+       IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE,
+           (char *)e_cant_read_file_str, fname1);
     }
     else
     {
@@ -444,8 +454,8 @@ assert_equalfile(typval_T *argvars)
        if (fd2 == NULL)
        {
            fclose(fd1);
-           vim_snprintf((char *)IObuff, IOSIZE, (char *)e_cant_read_file_str,
-                                                                      fname2);
+           IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE,
+               (char *)e_cant_read_file_str, fname2);
        }
        else
        {
@@ -460,12 +470,16 @@ assert_equalfile(typval_T *argvars)
                if (c1 == EOF)
                {
                    if (c2 != EOF)
+                   {
                        STRCPY(IObuff, "first file is shorter");
+                       IObufflen = 21;
+                   }
                    break;
                }
                else if (c2 == EOF)
                {
                    STRCPY(IObuff, "second file is shorter");
+                   IObufflen = 22;
                    break;
                }
                else
@@ -475,9 +489,8 @@ assert_equalfile(typval_T *argvars)
                    ++lineidx;
                    if (c1 != c2)
                    {
-                       vim_snprintf((char *)IObuff, IOSIZE,
-                                           "difference at byte %ld, line %ld",
-                                                            count, linecount);
+                       IObufflen = vim_snprintf_safelen((char *)IObuff, IOSIZE,
+                           "difference at byte %ld, line %ld", count, linecount);
                        break;
                    }
                }
@@ -499,7 +512,7 @@ assert_equalfile(typval_T *argvars)
        }
     }
 
-    if (IObuff[0] != NUL)
+    if (IObufflen > 0)
     {
        garray_T        ga;
        prepare_assert_error(&ga);
@@ -510,21 +523,21 @@ assert_equalfile(typval_T *argvars)
 
            ga_concat(&ga, echo_string(&argvars[2], &tofree, numbuf, 0));
            vim_free(tofree);
-           ga_concat(&ga, (char_u *)": ");
+           GA_CONCAT_LITERAL(&ga, ": ");
        }
-       ga_concat(&ga, IObuff);
+       ga_concat_len(&ga, IObuff, IObufflen);
        if (lineidx > 0)
        {
            line1[lineidx] = NUL;
            line2[lineidx] = NUL;
-           ga_concat(&ga, (char_u *)" after \"");
-           ga_concat(&ga, (char_u *)line1);
+           GA_CONCAT_LITERAL(&ga, " after \"");
+           ga_concat_len(&ga, (char_u *)line1, lineidx);
            if (STRCMP(line1, line2) != 0)
            {
-               ga_concat(&ga, (char_u *)"\" vs \"");
-               ga_concat(&ga, (char_u *)line2);
+               GA_CONCAT_LITERAL(&ga, "\" vs \"");
+               ga_concat_len(&ga, (char_u *)line2, lineidx);
            }
-           ga_concat(&ga, (char_u *)"\"");
+           GA_CONCAT_LITERAL(&ga, "\"");
        }
        assert_error(&ga);
        ga_clear(&ga);
@@ -576,7 +589,7 @@ f_assert_exception(typval_T *argvars, typval_T *rettv)
     if (*get_vim_var_str(VV_EXCEPTION) == NUL)
     {
        prepare_assert_error(&ga);
-       ga_concat(&ga, (char_u *)"v:exception is not set");
+       GA_CONCAT_LITERAL(&ga, "v:exception is not set");
        assert_error(&ga);
        ga_clear(&ga);
        rettv->vval.v_number = 1;
@@ -630,7 +643,7 @@ f_assert_fails(typval_T *argvars, typval_T *rettv)
     if (called_emsg == called_emsg_before)
     {
        prepare_assert_error(&ga);
-       ga_concat(&ga, (char_u *)"command did not fail: ");
+       GA_CONCAT_LITERAL(&ga, "command did not fail: ");
        assert_append_cmd_or_arg(&ga, argvars, cmd);
        assert_error(&ga);
        ga_clear(&ga);
@@ -749,7 +762,7 @@ f_assert_fails(typval_T *argvars, typval_T *rettv)
            }
            fill_assert_error(&ga, &argvars[2], expected_str,
                        &argvars[error_found_index], &actual_tv, ASSERT_FAILS);
-           ga_concat(&ga, (char_u *)": ");
+           GA_CONCAT_LITERAL(&ga, ": ");
            assert_append_cmd_or_arg(&ga, argvars, cmd);
            assert_error(&ga);
            ga_clear(&ga);
index 5df5e5dcc59999be2f2c08c2ae9f55536ea5e94a..b929dea0fb0c88ddcba3090563b8efd4f21d166a 100644 (file)
@@ -734,6 +734,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    31,
 /**/
     30,
 /**/