From: John Marriott Date: Fri, 3 Apr 2026 15:08:48 +0000 (+0000) Subject: patch 9.2.0291: too many strlen() calls X-Git-Tag: v9.2.0291^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cb51add7ae400a47407fb7fb7b7a54e238d4fdf4;p=thirdparty%2Fvim.git patch 9.2.0291: too many strlen() calls Problem: too many strlen() calls Solution: refactor concat_fname() and remove calls to strlen() (John Marriott) Function `concat_fnames()` can make up to 5 calls to `STRLEN()` (either directly or indirectly via `STRCAT()`). In many cases the lengths of arguments `fname1` and/or `fname2` are either known or can simply be calculated. This Commit refactors this function to accept the lengths of arguments `fname1` and `fname2` as arguments. It also adds new argument `ret` to return the resulting string as a `string_T`. Additionally: - function `add_pack_dir_to_rtp()` in `scriptfile.c`: Use a `string_T` to store local variables `new_rtp` and `afterdir`. Replace calls to `STRCAT()` with calls to `STRCPY()`. Change type of variable `keep` to `size_t` for consistency with other lengths. - function `qf_get_fnum()` in `quickfix.c`: Use a `string_T` to store local variables `ptr` and `bufname` - function `qf_push_dir()` in `quickfix.c`: Use a `string_T` to store local variable `dirname`. Replace call to `vim_strsave()` with `vim_strnsave()`. - function `qf_guess_filepath()` in `quickfix.c`: Use a `string_T` to store local variable `fullname`. - function `make_percent_swname()` in `memline.c`: Rename some variables to better reflect their use. Use a `string_T` to store local variables `d` and `fixed_name`. Slightly refactor to remove need to create an extra string. - function `get_file_in_dir()` in `memline.c`: Use a `string_T` to store local variables `tail` and `retval`. Move some variables closer to where they are used. - function `cs_resolve_file()` in `if_cscope.c`: Use a `string_T` to store local variable `csdir`. Remove one call to `STRLEN()`. - function `add_pathsep()` in `filepath.c`: Refactor and remove 1 call to `STRLEN()` - function `set_init_xdg_rtp()` in `option.c`: Use a `string_T` to store local variable `vimrc_xdg`. closes: #19854 Co-authored-by: Christian Brabandt Signed-off-by: John Marriott Signed-off-by: Christian Brabandt --- diff --git a/src/filepath.c b/src/filepath.c index 91423d9dcc..721dbc05d7 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -3178,19 +3178,25 @@ vim_fnamencmp(char_u *x, char_u *y, size_t len) * Only add a '/' or '\\' when 'sep' is TRUE and it is necessary. */ char_u * -concat_fnames(char_u *fname1, char_u *fname2, int sep) +concat_fnames(char_u *fname1, size_t fname1len, char_u *fname2, size_t fname2len, int sep, string_T *ret) { - char_u *dest; - - dest = alloc(STRLEN(fname1) + STRLEN(fname2) + 3); - if (dest == NULL) - return NULL; + ret->string = alloc(fname1len + (sep ? STRLEN_LITERAL(PATHSEPSTR) : 0) + fname2len + 1); + if (ret->string == NULL) + ret->length = 0; + else + { + STRCPY(ret->string, fname1); + ret->length = fname1len; + if (sep && *ret->string != NUL && !after_pathsep(ret->string, ret->string + ret->length)) + { + STRCPY(ret->string + ret->length, PATHSEPSTR); + ret->length += STRLEN_LITERAL(PATHSEPSTR); + } + STRCPY(ret->string + ret->length, fname2); + ret->length += fname2len; + } - STRCPY(dest, fname1); - if (sep) - add_pathsep(dest); - STRCAT(dest, fname2); - return dest; + return ret->string; } /* @@ -3200,8 +3206,14 @@ concat_fnames(char_u *fname1, char_u *fname2, int sep) void add_pathsep(char_u *p) { - if (*p != NUL && !after_pathsep(p, p + STRLEN(p))) - STRCAT(p, PATHSEPSTR); + size_t plen; + + if (*p == NUL) + return; + + plen = STRLEN(p); + if (!after_pathsep(p, p + plen)) + STRCPY(p + plen, PATHSEPSTR); } /* diff --git a/src/if_cscope.c b/src/if_cscope.c index 10437a532b..7962000777 100644 --- a/src/if_cscope.c +++ b/src/if_cscope.c @@ -2413,28 +2413,35 @@ cs_reset(exarg_T *eap UNUSED) cs_resolve_file(int i, char *name) { char *fullname; + string_T csdir = {NULL, 0}; + size_t namelen; + size_t ppathlen = 0; int len; - char_u *csdir = NULL; /* * Ppath is freed when we destroy the cscope connection. * Fullname is freed after cs_make_vim_style_matches, after it's been * copied into the tag buffer used by Vim. */ - len = (int)(strlen(name) + 2); + namelen = STRLEN(name); + len = (int)namelen + 2; if (csinfo[i].ppath != NULL) - len += (int)strlen(csinfo[i].ppath); + { + ppathlen = STRLEN(csinfo[i].ppath); + len += (int)ppathlen; + } else if (p_csre && csinfo[i].fname != NULL) { // If 'cscoperelative' is set and ppath is not set, use cscope.out // path in path resolution. - csdir = alloc(MAXPATHL); - if (csdir != NULL) + csdir.string = alloc(MAXPATHL); + if (csdir.string != NULL) { - vim_strncpy(csdir, (char_u *)csinfo[i].fname, + vim_strncpy(csdir.string, (char_u *)csinfo[i].fname, gettail((char_u *)csinfo[i].fname) - (char_u *)csinfo[i].fname); - len += (int)STRLEN(csdir); + csdir.length = STRLEN(csdir.string); + len += (int)csdir.length; } } @@ -2442,7 +2449,7 @@ cs_resolve_file(int i, char *name) // "../.." and the prefix path is also "../..". if something like this // happens, you are screwed up and need to fix how you're using cscope. if (csinfo[i].ppath != NULL - && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0) + && (strncmp(name, csinfo[i].ppath, ppathlen) != 0) && (name[0] != '/') # ifdef MSWIN && name[0] != '\\' && name[1] != ':' @@ -2452,18 +2459,20 @@ cs_resolve_file(int i, char *name) if ((fullname = alloc(len)) != NULL) (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name); } - else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL) + else if (csdir.string != NULL && csinfo[i].fname != NULL && *csdir.string != NUL) { + string_T ret; + // Check for csdir to be non empty to avoid empty path concatenated to // cscope output. - fullname = (char *)concat_fnames(csdir, (char_u *)name, TRUE); + fullname = (char *)concat_fnames(csdir.string, csdir.length, (char_u *)name, namelen, TRUE, &ret); } else { - fullname = (char *)vim_strsave((char_u *)name); + fullname = (char *)vim_strnsave((char_u *)name, namelen); } - vim_free(csdir); + vim_free(csdir.string); return fullname; } diff --git a/src/main.c b/src/main.c index b5f542a496..d4019ff51e 100644 --- a/src/main.c +++ b/src/main.c @@ -2771,13 +2771,15 @@ scripterror: if (parmp->diff_mode && mch_isdir(p) && GARGCOUNT > 0 && !mch_isdir(alist_name(&GARGLIST[0]))) { - char_u *r; + char_u *tail; + string_T ret; - r = concat_fnames(p, gettail(alist_name(&GARGLIST[0])), TRUE); - if (r != NULL) + tail = gettail(alist_name(&GARGLIST[0])); + concat_fnames(p, STRLEN(p), tail, STRLEN(tail), TRUE, &ret); + if (ret.string != NULL) { vim_free(p); - p = r; + p = ret.string; } } # endif diff --git a/src/memline.c b/src/memline.c index 97396b0b19..35b1fae230 100644 --- a/src/memline.c +++ b/src/memline.c @@ -1892,7 +1892,6 @@ recover_names( { int num_names; char_u *(names[6]); - char_u *tail; char_u *p; int num_files; int file_count = 0; @@ -1969,20 +1968,27 @@ recover_names( { if (fname == NULL) { + string_T ret; + #ifdef VMS - names[0] = concat_fnames(dir_name.string, (char_u *)"*_sw%", TRUE); + names[0] = concat_fnames(dir_name.string, dir_name.length, + (char_u *)"*_sw%", STRLEN_LITERAL("*_sw%"), TRUE, &ret); #else - names[0] = concat_fnames(dir_name.string, (char_u *)"*.sw?", TRUE); + names[0] = concat_fnames(dir_name.string, dir_name.length, + (char_u *)"*.sw?", STRLEN_LITERAL("*.sw?"), TRUE, &ret); #endif #if defined(UNIX) || defined(MSWIN) // For Unix names starting with a dot are special. MS-Windows // supports this too, on some file systems. - names[1] = concat_fnames(dir_name.string, (char_u *)".*.sw?", TRUE); - names[2] = concat_fnames(dir_name.string, (char_u *)".sw?", TRUE); + names[1] = concat_fnames(dir_name.string, dir_name.length, + (char_u *)".*.sw?", STRLEN_LITERAL(".*.sw?"), TRUE, &ret); + names[2] = concat_fnames(dir_name.string, dir_name.length, + (char_u *)".sw?", STRLEN_LITERAL(".sw?"), TRUE, &ret); num_names = 3; #else # ifdef VMS - names[1] = concat_fnames(dir_name.string, (char_u *)".*_sw%", TRUE); + names[1] = concat_fnames(dir_name.string, dir_name.length, + (char_u *)".*_sw%", STRLEN_LITERAL(".*_sw%"), TRUE, &ret); num_names = 2; # else num_names = 1; @@ -1991,6 +1997,8 @@ recover_names( } else { + char_u *tail; + #if defined(UNIX) || defined(MSWIN) p = dir_name.string + dir_name.length; if (after_pathsep(dir_name.string, p) && dir_name.length > 1 && p[-1] == p[-2]) @@ -2001,8 +2009,11 @@ recover_names( else #endif { + string_T ret; + tail = gettail(fname_res); - tail = concat_fnames(dir_name.string, tail, TRUE); + tail = concat_fnames(dir_name.string, dir_name.length, + tail, STRLEN(tail), TRUE, &ret); } if (tail == NULL) num_names = 0; @@ -2132,13 +2143,16 @@ recover_names( #ifdef FEAT_EVAL else if (ret_list != NULL) { + string_T name; + for (int i = 0; i < num_files; ++i) { - char_u *name = concat_fnames(dir_name.string, files[i], TRUE); - if (name != NULL) + concat_fnames(dir_name.string, dir_name.length, + files[i], STRLEN(files[i]), TRUE, &name); + if (name.string != NULL) { - list_append_string(ret_list, name, -1); - vim_free(name); + list_append_string(ret_list, name.string, (int)name.length); + vim_free(name.string); } } } @@ -2166,26 +2180,26 @@ recover_names( char_u * make_percent_swname(char_u *dir, char_u *dir_end, char_u *name) { - char_u *d = NULL, *s, *f; + string_T d = {NULL, 0}; + string_T fixed_fname; + char_u *p; - f = fix_fname(name != NULL ? name : (char_u *)""); - if (f == NULL) + fixed_fname.string = fix_fname(name != NULL ? name : (char_u *)""); + if (fixed_fname.string == NULL) return NULL; - s = alloc(STRLEN(f) + 1); - if (s != NULL) - { - STRCPY(s, f); - for (d = s; *d != NUL; MB_PTR_ADV(d)) - if (vim_ispathsep(*d)) - *d = '%'; - - dir_end[-1] = NUL; // remove one trailing slash - d = concat_fnames(dir, s, TRUE); - vim_free(s); - } - vim_free(f); - return d; + for (p = fixed_fname.string; *p != NUL; MB_PTR_ADV(p)) + if (vim_ispathsep(*p)) + *p = '%'; + fixed_fname.length = (size_t)(p - fixed_fname.string); + + // remove one trailing slash + p = &dir_end[-1]; + *p = NUL; + concat_fnames(dir, (size_t)(p - dir), fixed_fname.string, fixed_fname.length, TRUE, &d); + vim_free(fixed_fname.string); + + return d.string; } #endif @@ -2432,6 +2446,7 @@ recov_file_names(char_u **names, char_u *path, int prepend_dot) curbuf->b_shortname = FALSE; #endif + string_T ret; num_names = 0; @@ -2451,9 +2466,11 @@ recov_file_names(char_u **names, char_u *path, int prepend_dot) * Form the normal swap file name pattern by appending ".sw?". */ #ifdef VMS - names[num_names] = concat_fnames(path, (char_u *)"_sw%", FALSE); + names[num_names] = concat_fnames(path, STRLEN(path), + (char_u *)"_sw%", STRLEN_LITERAL("_sw%"), FALSE, &ret); #else - names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE); + names[num_names] = concat_fnames(path, STRLEN(path), + (char_u *)".sw?", STRLEN_LITERAL(".sw?"), FALSE, &ret); #endif if (names[num_names] == NULL) goto end; @@ -4746,45 +4763,61 @@ get_file_in_dir( char_u *fname, char_u *dname) // don't use "dirname", it is a global for Alpha { - char_u *t; - char_u *tail; - char_u *retval; - int save_char; + string_T tail; + string_T retval; - tail = gettail(fname); + tail.string = gettail(fname); + tail.length = STRLEN(tail.string); if (dname[0] == '.' && dname[1] == NUL) - retval = vim_strsave(fname); - else if (dname[0] == '.' && vim_ispathsep(dname[1])) + retval.string = + vim_strnsave(fname, (size_t)(tail.string - fname) + tail.length); + else { - if (tail == fname) // no path before file name - retval = concat_fnames(dname + 2, tail, TRUE); - else + size_t dname_len = STRLEN(dname); + + if (dname[0] == '.' && vim_ispathsep(dname[1])) { - save_char = *tail; - *tail = NUL; - t = concat_fnames(fname, dname + 2, TRUE); - *tail = save_char; - if (t == NULL) // out of memory - retval = NULL; + if (tail.string == fname) // no path before file name + concat_fnames(dname + 2, dname_len - 2, + tail.string, tail.length, TRUE, &retval); else { - retval = concat_fnames(t, tail, TRUE); - vim_free(t); + int save_char; + string_T tmp; + + save_char = *tail.string; + *tail.string = NUL; + concat_fnames(fname, (size_t)(tail.string - fname), + dname + 2, dname_len - 2, TRUE, &tmp); + *tail.string = save_char; + if (tmp.string == NULL) // out of memory + retval.string = NULL; + else + { + concat_fnames(tmp.string, tmp.length, + tail.string, tail.length, TRUE, &retval); + vim_free(tmp.string); + } } } + else + concat_fnames(dname, dname_len, tail.string, tail.length, + TRUE, &retval); } - else - retval = concat_fnames(dname, tail, TRUE); #ifdef MSWIN - if (retval != NULL) - for (t = gettail(retval); *t != NUL; MB_PTR_ADV(t)) + if (retval.string != NULL) + { + char_u *t; + + for (t = gettail(retval.string); *t != NUL; MB_PTR_ADV(t)) if (*t == ':') *t = '%'; + } #endif - return retval; + return retval.string; } /* diff --git a/src/misc1.c b/src/misc1.c index 3fa34c35e7..1cf73a004d 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -1752,32 +1752,39 @@ remove_tail(char_u *p, char_u *pend, char_u *name) static char_u * vim_version_dir(char_u *vimdir) { - char_u *p; + string_T p; + size_t vimdir_len; if (vimdir == NULL || *vimdir == NUL) return NULL; - p = concat_fnames(vimdir, (char_u *)VIM_VERSION_NODOT, TRUE); - if (p != NULL && mch_isdir(p)) - return p; - vim_free(p); - p = concat_fnames(vimdir, (char_u *)RUNTIME_DIRNAME, TRUE); - if (p != NULL && mch_isdir(p)) + vimdir_len = STRLEN(vimdir); + concat_fnames(vimdir, vimdir_len, + (char_u *)VIM_VERSION_NODOT, STRLEN_LITERAL(VIM_VERSION_NODOT), TRUE, &p); + if (p.string != NULL && mch_isdir(p.string)) + return p.string; + vim_free(p.string); + concat_fnames(vimdir, vimdir_len, + (char_u *)RUNTIME_DIRNAME, STRLEN_LITERAL(RUNTIME_DIRNAME), TRUE, &p); + if (p.string != NULL && mch_isdir(p.string)) { - char_u *fname = concat_fnames(p, (char_u *)"defaults.vim", TRUE); + string_T fname; + + concat_fnames(p.string, p.length, + (char_u *)"defaults.vim", STRLEN_LITERAL("defaults.vim"), TRUE, &fname); // Check that "defaults.vim" exists in this directory, to avoid picking // up a stray "runtime" directory, it would make many tests fail in // mysterious ways. - if (fname != NULL) + if (fname.string != NULL) { - int exists = file_is_readable(fname); + int exists = file_is_readable(fname.string); - vim_free(fname); + vim_free(fname.string); if (exists) - return p; + return p.string; } } - vim_free(p); + vim_free(p.string); return NULL; } diff --git a/src/option.c b/src/option.c index c369fdbf0e..ab1166098c 100644 --- a/src/option.c +++ b/src/option.c @@ -404,7 +404,7 @@ set_init_xdg_rtp(void) char_u *vimrc2 = NULL; char_u *xdg_dir = NULL; char_u *xdg_rtp = NULL; - char_u *vimrc_xdg = NULL; + string_T vimrc_xdg = {NULL, 0}; // initialize chartab, so we can expand $HOME (void)init_chartab(); @@ -418,10 +418,11 @@ set_init_xdg_rtp(void) should_free_xdg_dir = TRUE; has_xdg_env = FALSE; } - vimrc_xdg = concat_fnames(xdg_dir, (char_u *)"vim/vimrc", TRUE); + concat_fnames(xdg_dir, STRLEN(xdg_dir), + (char_u *)"vim/vimrc", STRLEN_LITERAL("vim/vimrc"), TRUE, &vimrc_xdg); if (file_is_readable(vimrc1) || file_is_readable(vimrc2) || - !file_is_readable(vimrc_xdg)) + !file_is_readable(vimrc_xdg.string)) goto theend; xdg_rtp = has_xdg_env ? (char_u *)XDG_RUNTIMEPATH @@ -450,7 +451,7 @@ set_init_xdg_rtp(void) theend: vim_free(vimrc1); vim_free(vimrc2); - vim_free(vimrc_xdg); + vim_free(vimrc_xdg.string); if (should_free_xdg_dir) vim_free(xdg_dir); } diff --git a/src/os_win32.c b/src/os_win32.c index edbe895ecd..e7216c1220 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -8614,13 +8614,15 @@ fix_arg_enc(void) if (used_file_diff_mode && mch_isdir(str) && GARGCOUNT > 0 && !mch_isdir(alist_name(&GARGLIST[0]))) { - char_u *r; + char_u *tail; + string_T ret; - r = concat_fnames(str, gettail(alist_name(&GARGLIST[0])), TRUE); - if (r != NULL) + tail = gettail(alist_name(&GARGLIST[0])); + concat_fnames(str, STRLEN(str), tail, STRLEN(tail), TRUE, &ret); + if (ret.string != NULL) { vim_free(str); - str = r; + str = ret.string; } } #endif diff --git a/src/proto/filepath.pro b/src/proto/filepath.pro index d82652ce71..d00a66775f 100644 --- a/src/proto/filepath.pro +++ b/src/proto/filepath.pro @@ -48,7 +48,7 @@ int vim_ispathsep_nocolon(int c); int dir_of_file_exists(char_u *fname); int vim_fnamecmp(char_u *x, char_u *y); int vim_fnamencmp(char_u *x, char_u *y, size_t len); -char_u *concat_fnames(char_u *fname1, char_u *fname2, int sep); +char_u *concat_fnames(char_u *fname1, size_t fname1len, char_u *fname2, size_t fname2len, int sep, string_T *ret); void add_pathsep(char_u *p); char_u *FullName_save(char_u *fname, int force); int vim_fexists(char_u *fname); diff --git a/src/quickfix.c b/src/quickfix.c index 59579171c3..527760d669 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -2728,9 +2728,10 @@ copy_loclist_stack(win_T *from, win_T *to) static int qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname) { - char_u *ptr = NULL; + string_T ptr = {NULL, 0}; buf_T *buf; - char_u *bufname; + string_T bufname; + size_t fname_len; if (fname == NULL || *fname == NUL) // no file name return 0; @@ -2743,44 +2744,52 @@ qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname) slash_adjust(directory); slash_adjust(fname); # endif + fname_len = STRLEN(fname); if (directory != NULL && !vim_isAbsName(fname) - && (ptr = concat_fnames(directory, fname, TRUE)) != NULL) + && concat_fnames(directory, STRLEN(directory), fname, fname_len, TRUE, &ptr) != NULL) { // Here we check if the file really exists. // This should normally be true, but if make works without // "leaving directory"-messages we might have missed a // directory change. - if (mch_getperm(ptr) < 0) + if (mch_getperm(ptr.string) < 0) { - vim_free(ptr); + vim_free(ptr.string); directory = qf_guess_filepath(qfl, fname); if (directory) - ptr = concat_fnames(directory, fname, TRUE); + concat_fnames(directory, STRLEN(directory), fname, fname_len, TRUE, &ptr); else - ptr = vim_strsave(fname); - if (ptr == NULL) + { + ptr.length = fname_len; + ptr.string = vim_strnsave(fname, fname_len); + } + if (ptr.string == NULL) return 0; } // Use concatenated directory name and file name - bufname = ptr; + bufname.string = ptr.string; + bufname.length = ptr.length; } else - bufname = fname; + { + bufname.string = fname; + bufname.length = fname_len; + } - if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0 + if (qf_last_bufname != NULL && STRCMP(bufname.string, qf_last_bufname) == 0 && bufref_valid(&qf_last_bufref)) { buf = qf_last_bufref.br_buf; - vim_free(ptr); + vim_free(ptr.string); } else { vim_free(qf_last_bufname); - buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT); - if (bufname == ptr) - qf_last_bufname = bufname; + buf = buflist_new(bufname.string, NULL, (linenr_T)0, BLN_NOOPT); + if (bufname.string == ptr.string) + qf_last_bufname = bufname.string; else - qf_last_bufname = vim_strsave(bufname); + qf_last_bufname = vim_strnsave(bufname.string, bufname.length); set_bufref(&qf_last_bufref, buf); } if (buf == NULL) @@ -2817,17 +2826,21 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack) (*stackptr)->dirname = vim_strsave(dirbuf); else { + size_t dirbuf_len; + // Okay we don't have an absolute path. // dirbuf must be a subdir of one of the directories on the stack. // Let's search... + dirbuf_len = STRLEN(dirbuf); ds_new = (*stackptr)->next; (*stackptr)->dirname = NULL; while (ds_new) { - char_u *dirname; + string_T dirname; - dirname = concat_fnames(ds_new->dirname, dirbuf, TRUE); - if (dirname == NULL) + concat_fnames(ds_new->dirname, STRLEN(ds_new->dirname), + dirbuf, dirbuf_len, TRUE, &dirname); + if (dirname.string == NULL) { // pop the new element from the stack and free it ds_ptr = *stackptr; @@ -2836,13 +2849,13 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack) return NULL; } - if (mch_isdir(dirname) == TRUE) + if (mch_isdir(dirname.string) == TRUE) { vim_free((*stackptr)->dirname); - (*stackptr)->dirname = dirname; + (*stackptr)->dirname = dirname.string; break; } - vim_free(dirname); + vim_free(dirname.string); ds_new = ds_new->next; } @@ -2859,7 +2872,7 @@ qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack) if (ds_new == NULL) { vim_free((*stackptr)->dirname); - (*stackptr)->dirname = vim_strsave(dirbuf); + (*stackptr)->dirname = vim_strnsave(dirbuf, dirbuf_len); } } @@ -2940,28 +2953,32 @@ qf_guess_filepath(qf_list_T *qfl, char_u *filename) { struct dir_stack_T *ds_ptr; struct dir_stack_T *ds_tmp; - char_u *fullname; + string_T fullname; + size_t filename_len; // no dirs on the stack - there's nothing we can do if (qfl->qf_dir_stack == NULL) return NULL; ds_ptr = qfl->qf_dir_stack->next; - fullname = NULL; + fullname.string = NULL; + fullname.length = 0; + filename_len = STRLEN(filename); while (ds_ptr) { - vim_free(fullname); - fullname = concat_fnames(ds_ptr->dirname, filename, TRUE); + vim_free(fullname.string); + concat_fnames(ds_ptr->dirname, STRLEN(ds_ptr->dirname), + filename, filename_len, TRUE, &fullname); // If concat_fnames failed, just go on. The worst thing that can happen // is that we delete the entire stack. - if ((fullname != NULL) && (mch_getperm(fullname) >= 0)) + if ((fullname.string != NULL) && (mch_getperm(fullname.string) >= 0)) break; ds_ptr = ds_ptr->next; } - vim_free(fullname); + vim_free(fullname.string); // clean up all dirs we already left while (qfl->qf_dir_stack->next != ds_ptr) diff --git a/src/scriptfile.c b/src/scriptfile.c index c6d2b73709..6df5781a73 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -841,19 +841,14 @@ add_pack_dir_to_rtp(char_u *fname) char_u *entry; char_u *insp = NULL; int c; - char_u *new_rtp; - int keep; - size_t oldlen; - size_t addlen; - size_t new_rtp_len; - char_u *afterdir = NULL; - size_t afterlen = 0; + string_T new_rtp; + size_t keep; + size_t p_rtp_len; + string_T afterdir = {NULL, 0}; char_u *after_insp = NULL; char_u *ffname = NULL; size_t fname_len; string_T buf = {NULL, 0}; - char_u *rtp_ffname; - int match; int retval = FAIL; p4 = p3 = p2 = p1 = get_past_head(fname); @@ -881,12 +876,17 @@ add_pack_dir_to_rtp(char_u *fname) buf.string = alloc(MAXPATHL); if (buf.string == NULL) goto theend; + + p_rtp_len = 0; for (entry = p_rtp; *entry != NUL; ) { char_u *cur_entry = entry; buf.length = (size_t)copy_option_part(&entry, buf.string, MAXPATHL, ","); + // keep track of p_rtp length as we go to make the STRLEN() below have less work to do + p_rtp_len += (*(p_rtp + buf.length) == ',') ? buf.length + 1 : buf.length; + if ((p = (char_u *)strstr((char *)buf.string, "after")) != NULL && p > buf.string && vim_ispathsep(p[-1]) @@ -902,6 +902,9 @@ add_pack_dir_to_rtp(char_u *fname) if (insp == NULL) { + char_u *rtp_ffname; + int match; + if (*buf.string != NUL && !after_pathsep(buf.string, buf.string + buf.length)) STRCPY(buf.string + buf.length, PATHSEPSTR); rtp_ffname = fix_fname(buf.string); @@ -915,69 +918,76 @@ add_pack_dir_to_rtp(char_u *fname) } } + // finish measuring the length of p_rtp + p_rtp_len += STRLEN(p_rtp + p_rtp_len); if (insp == NULL) // Both "fname" and "after" not found, append at the end. - insp = p_rtp + STRLEN(p_rtp); + insp = p_rtp + p_rtp_len; // check if rtp/pack/name/start/name/after exists - afterdir = concat_fnames(fname, (char_u *)"after", TRUE); - if (afterdir != NULL && mch_isdir(afterdir)) - afterlen = STRLEN(afterdir) + 1; // add one for comma - - oldlen = STRLEN(p_rtp); - addlen = STRLEN(fname) + 1; // add one for comma - new_rtp = alloc(oldlen + addlen + afterlen + 1); // add one for NUL - if (new_rtp == NULL) + fname_len = STRLEN(fname); + concat_fnames(fname, fname_len, (char_u *)"after", STRLEN_LITERAL("after"), TRUE, &afterdir); + if (afterdir.string == NULL || !mch_isdir(afterdir.string)) + afterdir.length = 0; + + new_rtp.string = alloc(p_rtp_len + fname_len + afterdir.length + 3); // add two for commas and one for NUL + if (new_rtp.string == NULL) goto theend; // We now have 'rtp' parts: {keep}{keep_after}{rest}. // Create new_rtp, first: {keep},{fname} - keep = (int)(insp - p_rtp); - mch_memmove(new_rtp, p_rtp, keep); - new_rtp_len = keep; + keep = (size_t)(insp - p_rtp); + mch_memmove(new_rtp.string, p_rtp, keep); + new_rtp.length = keep; if (*insp == NUL) - new_rtp[new_rtp_len++] = ','; // add comma before - mch_memmove(new_rtp + new_rtp_len, fname, addlen - 1); - new_rtp_len += addlen - 1; + new_rtp.string[new_rtp.length++] = ','; // add comma before + mch_memmove(new_rtp.string + new_rtp.length, fname, fname_len); + new_rtp.length += fname_len; if (*insp != NUL) - new_rtp[new_rtp_len++] = ','; // add comma after + new_rtp.string[new_rtp.length++] = ','; // add comma after - if (afterlen > 0 && after_insp != NULL) + if (afterdir.length > 0 && after_insp != NULL) { - int keep_after = (int)(after_insp - p_rtp); + size_t keep_after = (size_t)(after_insp - p_rtp); + size_t append_len = keep_after - keep; // Add to new_rtp: {keep},{fname}{keep_after},{afterdir} - mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, - keep_after - keep); - new_rtp_len += keep_after - keep; - mch_memmove(new_rtp + new_rtp_len, afterdir, afterlen - 1); - new_rtp_len += afterlen - 1; - new_rtp[new_rtp_len++] = ','; + mch_memmove(new_rtp.string + new_rtp.length, p_rtp + keep, + append_len); + new_rtp.length += append_len; + mch_memmove(new_rtp.string + new_rtp.length, afterdir.string, afterdir.length); + new_rtp.length += afterdir.length; + new_rtp.string[new_rtp.length++] = ','; keep = keep_after; } if (p_rtp[keep] != NUL) + { + size_t append_len = p_rtp_len - keep; + // Append rest: {keep},{fname}{keep_after},{afterdir}{rest} - mch_memmove(new_rtp + new_rtp_len, p_rtp + keep, oldlen - keep + 1); + mch_memmove(new_rtp.string + new_rtp.length, p_rtp + keep, append_len + 1); // add one for NUL + new_rtp.length += append_len; + } else - new_rtp[new_rtp_len] = NUL; + new_rtp.string[new_rtp.length] = NUL; - if (afterlen > 0 && after_insp == NULL) + if (afterdir.length > 0 && after_insp == NULL) { // Append afterdir when "after" was not found: // {keep},{fname}{rest},{afterdir} - STRCAT(new_rtp, ","); - STRCAT(new_rtp, afterdir); + new_rtp.string[new_rtp.length++] = ','; + STRCPY(new_rtp.string + new_rtp.length, afterdir.string); } - set_option_value_give_err((char_u *)"rtp", 0L, new_rtp, 0); - vim_free(new_rtp); + set_option_value_give_err((char_u *)"rtp", 0L, new_rtp.string, 0); + vim_free(new_rtp.string); retval = OK; theend: vim_free(buf.string); vim_free(ffname); - vim_free(afterdir); + vim_free(afterdir.string); return retval; } diff --git a/src/undo.c b/src/undo.c index 3b0a1524e5..4bfdc659f9 100644 --- a/src/undo.c +++ b/src/undo.c @@ -804,7 +804,7 @@ u_get_undo_file_name(char_u *buf_ffname, int reading) { char_u *dirp; char_u dir_name[IOSIZE + 1]; - char_u *munged_name = NULL; + string_T munged_name = {NULL, 0}; char_u *undo_file_name = NULL; int dir_len; char_u *p; @@ -862,16 +862,20 @@ u_get_undo_file_name(char_u *buf_ffname, int reading) dir_name[dir_len] = NUL; if (mch_isdir(dir_name)) { - if (munged_name == NULL) + string_T ret; + + if (munged_name.string == NULL) { - munged_name = vim_strnsave(ffname, ffnamelen); - if (munged_name == NULL) + munged_name.string = vim_strnsave(ffname, ffnamelen); + if (munged_name.string == NULL) return NULL; - for (p = munged_name; *p != NUL; MB_PTR_ADV(p)) + munged_name.length = ffnamelen; + for (p = munged_name.string; *p != NUL; MB_PTR_ADV(p)) if (vim_ispathsep(*p)) *p = '%'; } - undo_file_name = concat_fnames(dir_name, munged_name, TRUE); + undo_file_name = concat_fnames(dir_name, (size_t)dir_len, + munged_name.string, munged_name.length, TRUE, &ret); } } @@ -882,7 +886,7 @@ u_get_undo_file_name(char_u *buf_ffname, int reading) VIM_CLEAR(undo_file_name); } - vim_free(munged_name); + vim_free(munged_name.string); return undo_file_name; } diff --git a/src/version.c b/src/version.c index caa45fe38e..25442abc61 100644 --- a/src/version.c +++ b/src/version.c @@ -734,6 +734,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 291, /**/ 290, /**/