0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

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 <basilisk@internode.on.net>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
John Marriott 2025-04-10 21:34:19 +02:00 committed by Christian Brabandt
parent 06a41ad084
commit ec032de646
No known key found for this signature in database
GPG Key ID: F3F92DA383FDDE09
4 changed files with 333 additions and 239 deletions

View File

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

View File

@ -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_add(char *, size_t, const char *, ...) ATTRIBUTE_FORMAT_PRINTF(3, 4);
int vim_snprintf(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) int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap)
ATTRIBUTE_FORMAT_PRINTF(3, 0); ATTRIBUTE_FORMAT_PRINTF(3, 0);

View File

@ -2487,6 +2487,33 @@ vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
return str_l; 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 int
vim_vsnprintf( vim_vsnprintf(
char *str, char *str,

View File

@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1291,
/**/ /**/
1290, 1290,
/**/ /**/