changeset 36518:b33ecff44972 draft v9.1.0851

patch 9.1.0851: too many strlen() calls in getchar.c Commit: https://github.com/vim/vim/commit/e7a1bbf2102ecd2083613ff18d7d46c45d1e568e Author: John Marriott <basilisk@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 <basilisk@internode.on.net> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Mon, 11 Nov 2024 20:45:03 +0100
parents c41db5462506
children a5e92f109ac3
files src/getchar.c src/structs.h src/version.c
diffstat 3 files changed, 66 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- 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
+	vim_strncpy(p->b_str, s, (size_t)slen);
+	p->b_strlen = slen;
 	buf->bh_space = (int)(len - slen);
-	vim_strncpy(p->b_str, s, (size_t)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 
 add_num_buff(buffheader_T *buf, long n)
 {
     char_u	number[32];
-
-    sprintf((char *)number, "%ld", n);
-    add_buff(buf, number, -1L);
+    int		numberlen;
+
+    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
 	    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
 	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
 
--- 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
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    851,
+/**/
     850,
 /**/
     849,