0
0
mirror of https://github.com/vim/vim.git synced 2025-07-25 10:54:51 -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);
#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('\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_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);
*p++ = '"';
if (buf_spname(curbuf) != NULL)
vim_strncpy((char_u *)p, buf_spname(curbuf), IOSIZE - (p - buffer) - 1);
buffer[bufferlen++] = '"';
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",
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) ?
" " : "");
// 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);
(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,
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,
n);
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;
#define SPACE_FOR_FNAME (IOSIZE - 100)
#define SPACE_FOR_DIR (IOSIZE - 20)
#define SPACE_FOR_ARGNR (IOSIZE - 10) // at least room for " - VIM"
// 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"
// 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);
buflen = vim_snprintf_safelen((char *)buf,
SPACE_FOR_FNAME, "%s",
((p = transstr(gettail(curbuf->b_fname))) != NULL)
? p
: (char_u *)"");
vim_free(p);
}
else
STRCPY(buf, "");
}
// 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;
{
// 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 (off < SPACE_FOR_DIR)
if (buflen < SPACE_FOR_DIR)
{
p = transstr(buf + off);
if (p != NULL)
{
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
{
vim_strncpy(buf + off, (char_u *)"...",
(size_t)(SPACE_FOR_ARGNR - off));
buflen += vim_snprintf_safelen((char *)buf + buflen,
SPACE_FOR_ARGNR - buflen, "...)");
}
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,6 +4766,7 @@ build_stl_str_hl(
else
str = gettail(NameBuff);
break;
}
case STL_VIM_EXPR: // '{'
{
@ -4715,6 +4774,9 @@ build_stl_str_hl(
char_u *block_start = s - 1;
#endif
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,7 +5018,9 @@ build_stl_str_hl(
break;
case STL_HIGHLIGHT:
t = s;
{
char_u *t = s;
while (*s != '#' && *s != NUL)
++s;
if (*s == '#')
@ -4977,12 +5034,14 @@ build_stl_str_hl(
++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])
@ -5039,11 +5098,11 @@ build_stl_str_hl(
{
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"));
if (above <= 0)
return (int)vim_snprintf_safelen((char *)buf, buflen,
"%s", _("Top"));
// 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;
return len;
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;

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(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);

View File

@ -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,

View File

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