patch 9.1.0851: too many strlen() calls in getchar.c

Commit: 
https://github.com/vim/vim/commit/e7a1bbf2102ecd2083613ff18d7d46c45d1e568e
Author: John Marriott <basil...@internode.on.net>
Date:   Mon Nov 11 20:40:33 2024 +0100

    patch 9.1.0851: too many strlen() calls in getchar.c
    
    Problem:  too many strlen() calls in getchar.c
    Solution: refactor code and reduce strlen() calls
              (John Marriott)
    
    closes: #16017
    
    Signed-off-by: John Marriott <basil...@internode.on.net>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/getchar.c b/src/getchar.c
index 96e180f4a..c1628ee5a 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -36,9 +36,9 @@
 
 #define MINIMAL_SIZE 20                        // minimal size for b_str
 
-static buffheader_T redobuff = {{NULL, {NUL}}, NULL, 0, 0};
-static buffheader_T old_redobuff = {{NULL, {NUL}}, NULL, 0, 0};
-static buffheader_T recordbuff = {{NULL, {NUL}}, NULL, 0, 0};
+static buffheader_T redobuff = {{NULL, 0, {NUL}}, NULL, 0, 0, FALSE};
+static buffheader_T old_redobuff = {{NULL, 0, {NUL}}, NULL, 0, 0, FALSE};
+static buffheader_T recordbuff = {{NULL, 0, {NUL}}, NULL, 0, 0, FALSE};
 
 static int typeahead_char = 0;         // typeahead char that's not flushed
 
@@ -129,17 +129,19 @@ free_buff(buffheader_T *buf)
     static char_u *
 get_buffcont(
     buffheader_T       *buffer,
-    int                        dozero)     // count == zero is not an error
+    int                        dozero,     // count == zero is not an error
+    size_t             *len)       // the length of the returned buffer
 {
     long_u         count = 0;
     char_u         *p = NULL;
     char_u         *p2;
     char_u         *str;
     buffblock_T *bp;
+    size_t         i = 0;
 
     // compute the total length of the string
     for (bp = buffer->bh_first.b_next; bp != NULL; bp = bp->b_next)
-       count += (long_u)STRLEN(bp->b_str);
+       count += (long_u)bp->b_strlen;
 
     if ((count > 0 || dozero) && (p = alloc(count + 1)) != NULL)
     {
@@ -148,7 +150,12 @@ get_buffcont(
            for (str = bp->b_str; *str; )
                *p2++ = *str++;
        *p2 = NUL;
+       i = (size_t)(p2 - p);
     }
+
+    if (len != NULL)
+       *len = i;
+
     return p;
 }
 
@@ -163,14 +170,13 @@ get_recorded(void)
     char_u     *p;
     size_t     len;
 
-    p = get_buffcont(&recordbuff, TRUE);
+    p = get_buffcont(&recordbuff, TRUE, &len);
     free_buff(&recordbuff);
 
     /*
      * Remove the characters that were added the last time, these must be the
      * (possibly mapped) characters that stopped the recording.
      */
-    len = STRLEN(p);
     if (len >= last_recorded_len)
     {
        len -= last_recorded_len;
@@ -194,7 +200,7 @@ get_recorded(void)
     char_u *
 get_inserted(void)
 {
-    return get_buffcont(&redobuff, FALSE);
+    return get_buffcont(&redobuff, FALSE, NULL);
 }
 
 /*
@@ -207,9 +213,6 @@ add_buff(
     char_u             *s,
     long               slen)   // length of "s" or -1
 {
-    buffblock_T *p;
-    long_u         len;
-
     if (slen < 0)
        slen = (long)STRLEN(s);
     if (slen == 0)                             // don't add empty strings
@@ -217,8 +220,8 @@ add_buff(
 
     if (buf->bh_first.b_next == NULL)  // first add to list
     {
-       buf->bh_space = 0;
        buf->bh_curr = &(buf->bh_first);
+       buf->bh_create_newblock = TRUE;
     }
     else if (buf->bh_curr == NULL)     // buffer has already been read
     {
@@ -226,19 +229,26 @@ add_buff(
        return;
     }
     else if (buf->bh_index != 0)
+    {
        mch_memmove(buf->bh_first.b_next->b_str,
                    buf->bh_first.b_next->b_str + buf->bh_index,
-                   STRLEN(buf->bh_first.b_next->b_str + buf->bh_index) + 1);
+                   (buf->bh_first.b_next->b_strlen - buf->bh_index) + 1);
+       buf->bh_first.b_next->b_strlen -= buf->bh_index;
+       buf->bh_space += buf->bh_index;
+    }
     buf->bh_index = 0;
 
-    if (buf->bh_space >= (int)slen)
+    if (!buf->bh_create_newblock && buf->bh_space >= (int)slen)
     {
-       len = (long_u)STRLEN(buf->bh_curr->b_str);
-       vim_strncpy(buf->bh_curr->b_str + len, s, (size_t)slen);
+       vim_strncpy(buf->bh_curr->b_str + buf->bh_curr->b_strlen, s, 
(size_t)slen);
+       buf->bh_curr->b_strlen += slen;
        buf->bh_space -= slen;
     }
     else
     {
+       long_u      len;
+       buffblock_T *p;
+
        if (slen < MINIMAL_SIZE)
            len = MINIMAL_SIZE;
        else
@@ -246,8 +256,10 @@ add_buff(
        p = alloc(offsetof(buffblock_T, b_str) + len + 1);
        if (p == NULL)
            return; // no space, just forget it
-       buf->bh_space = (int)(len - slen);
        vim_strncpy(p->b_str, s, (size_t)slen);
+       p->b_strlen = slen;
+       buf->bh_space = (int)(len - slen);
+       buf->bh_create_newblock = FALSE;
 
        p->b_next = buf->bh_curr->b_next;
        buf->bh_curr->b_next = p;
@@ -262,15 +274,13 @@ add_buff(
     static void
 delete_buff_tail(buffheader_T *buf, int slen)
 {
-    int len;
-
     if (buf->bh_curr == NULL)
        return;  // nothing to delete
-    len = (int)STRLEN(buf->bh_curr->b_str);
-    if (len < slen)
+    if (buf->bh_curr->b_strlen < (size_t)slen)
        return;
 
-    buf->bh_curr->b_str[len - slen] = NUL;
+    buf->bh_curr->b_str[buf->bh_curr->b_strlen - (size_t)slen] = NUL;
+    buf->bh_curr->b_strlen -= slen;
     buf->bh_space += slen;
 }
 
@@ -281,9 +291,10 @@ delete_buff_tail(buffheader_T *buf, int slen)
 add_num_buff(buffheader_T *buf, long n)
 {
     char_u     number[32];
+    int                numberlen;
 
-    sprintf((char *)number, "%ld", n);
-    add_buff(buf, number, -1L);
+    numberlen = vim_snprintf((char *)number, sizeof(number), "%ld", n);
+    add_buff(buf, number, (long)numberlen);
 }
 
 /*
@@ -297,6 +308,7 @@ add_char_buff(buffheader_T *buf, int c)
     int                len;
     int                i;
     char_u     temp[4];
+    long       templen;
 
     if (IS_SPECIAL(c))
        len = 1;
@@ -314,6 +326,7 @@ add_char_buff(buffheader_T *buf, int c)
            temp[1] = K_SECOND(c);
            temp[2] = K_THIRD(c);
            temp[3] = NUL;
+           templen = 3;
        }
 #ifdef FEAT_GUI
        else if (c == CSI)
@@ -323,22 +336,24 @@ add_char_buff(buffheader_T *buf, int c)
            temp[1] = KS_EXTRA;
            temp[2] = (int)KE_CSI;
            temp[3] = NUL;
+           templen = 3;
        }
 #endif
        else
        {
            temp[0] = c;
            temp[1] = NUL;
+           templen = 1;
        }
-       add_buff(buf, temp, -1L);
+       add_buff(buf, temp, templen);
     }
 }
 
 // First read ahead buffer. Used for translated commands.
-static buffheader_T readbuf1 = {{NULL, {NUL}}, NULL, 0, 0};
+static buffheader_T readbuf1 = {{NULL, 0, {NUL}}, NULL, 0, 0, FALSE};
 
 // Second read ahead buffer. Used for redo.
-static buffheader_T readbuf2 = {{NULL, {NUL}}, NULL, 0, 0};
+static buffheader_T readbuf2 = {{NULL, 0, {NUL}}, NULL, 0, 0, FALSE};
 
 /*
  * Get one byte from the read buffers.  Use readbuf1 one first, use readbuf2
@@ -390,12 +405,12 @@ start_stuff(void)
     if (readbuf1.bh_first.b_next != NULL)
     {
        readbuf1.bh_curr = &(readbuf1.bh_first);
-       readbuf1.bh_space = 0;
+       readbuf1.bh_create_newblock = TRUE;             // force a new block to 
be created (see add_buff())
     }
     if (readbuf2.bh_first.b_next != NULL)
     {
        readbuf2.bh_curr = &(readbuf2.bh_first);
-       readbuf2.bh_space = 0;
+       readbuf2.bh_create_newblock = TRUE;             // force a new block to 
be created (see add_buff())
     }
 }
 
@@ -529,6 +544,7 @@ CancelRedo(void)
 saveRedobuff(save_redo_T *save_redo)
 {
     char_u     *s;
+    size_t     slen;
 
     save_redo->sr_redobuff = redobuff;
     redobuff.bh_first.b_next = NULL;
@@ -536,11 +552,11 @@ saveRedobuff(save_redo_T *save_redo)
     old_redobuff.bh_first.b_next = NULL;
 
     // Make a copy, so that ":normal ." in a function works.
-    s = get_buffcont(&save_redo->sr_redobuff, FALSE);
+    s = get_buffcont(&save_redo->sr_redobuff, FALSE, &slen);
     if (s == NULL)
        return;
 
-    add_buff(&redobuff, s, -1L);
+    add_buff(&redobuff, s, (long)slen);
     vim_free(s);
 }
 
@@ -2219,13 +2235,15 @@ do_key_input_pre(int c)
        // character.  Only use it when changed, otherwise continue with the
        // original character.
        char_u *v_char;
+       size_t  v_charlen;
 
        v_char = get_vim_var_str(VV_CHAR);
+       v_charlen = STRLEN(v_char);
 
        // Convert special bytes when it is special string.
-       if (STRLEN(v_char) >= 3 && v_char[0] == K_SPECIAL)
+       if (v_charlen >= 3 && v_char[0] == K_SPECIAL)
            res = TERMCAP2KEY(v_char[1], v_char[2]);
-       else if (STRLEN(v_char) > 0)
+       else if (v_charlen > 0)
            res = PTR2CHAR(v_char);
     }
 
@@ -2438,9 +2456,9 @@ getchar_common(typval_T *argvars, typval_T *rettv)
            i += (*mb_char2bytes)(n, temp + i);
        else
            temp[i++] = n;
-       temp[i++] = NUL;
+       temp[i] = NUL;
        rettv->v_type = VAR_STRING;
-       rettv->vval.v_string = vim_strsave(temp);
+       rettv->vval.v_string = vim_strnsave(temp, i);
 
        if (is_mouse_key(n))
        {
@@ -2507,9 +2525,9 @@ f_getcharstr(typval_T *argvars, typval_T *rettv)
        else
            temp[i++] = n;
     }
-    temp[i++] = NUL;
+    temp[i] = NUL;
     rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = vim_strsave(temp);
+    rettv->vval.v_string = vim_strnsave(temp, i);
 }
 
 /*
@@ -3256,7 +3274,7 @@ handle_mapping(
                buf[1] = KS_EXTRA;
                buf[2] = KE_IGNORE;
                buf[3] = NUL;
-               map_str = vim_strsave(buf);
+               map_str = vim_strnsave(buf, 3);
                if (State & MODE_CMDLINE)
                {
                    // redraw the command below the error
@@ -4265,6 +4283,7 @@ getcmdkeycmd(
 may_add_last_used_map_to_redobuff(void)
 {
     char_u  buf[3 + 20];
+    int            buflen;
     int            sid = -1;
 
     if (last_used_map != NULL)
@@ -4279,8 +4298,10 @@ may_add_last_used_map_to_redobuff(void)
     buf[0] = K_SPECIAL;
     buf[1] = KS_EXTRA;
     buf[2] = KE_SID;
-    vim_snprintf((char *)buf + 3, 20, "%d;", sid);
-    add_buff(&redobuff, buf, -1L);
+    buflen = 3;
+
+    buflen += vim_snprintf((char *)buf + 3, 20, "%d;", sid);
+    add_buff(&redobuff, buf, (long)buflen);
 }
 #endif
 
diff --git a/src/structs.h b/src/structs.h
index 66d57e02d..19768e658 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -573,6 +573,7 @@ typedef struct buffheader buffheader_T;
 struct buffblock
 {
     buffblock_T        *b_next;        // pointer to next buffblock
+    size_t     b_strlen;       // length of b_str, excluding the NUL
     char_u     b_str[1];       // contents (actually longer)
 };
 
@@ -585,6 +586,7 @@ struct buffheader
     buffblock_T        *bh_curr;       // buffblock for appending
     int                bh_index;       // index for reading
     int                bh_space;       // space in bh_curr for appending
+    int                bh_create_newblock;     // create a new block?
 };
 
 typedef struct
diff --git a/src/version.c b/src/version.c
index 636dfaa12..665b30b0f 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 */
+/**/
+    851,
 /**/
     850,
 /**/

-- 
-- 
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/E1tAaLP-00EvUS-DZ%40256bit.org.

Raspunde prin e-mail lui