patch 9.1.1122: too many strlen() calls in findfile.c

Commit: 
https://github.com/vim/vim/commit/d6e3c9048dfb7e8f08f8fadc820c7e2208c3f030
Author: John Marriott <basil...@internode.on.net>
Date:   Tue Feb 18 20:45:48 2025 +0100

    patch 9.1.1122: too many strlen() calls in findfile.c
    
    Problem:  too many strlen() calls in findfile.c
    Solution: refactor findfile.c and remove calls to strlen()
              (John Marriott)
    
    closes: #16595
    
    Signed-off-by: John Marriott <basil...@internode.on.net>
    Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/findfile.c b/src/findfile.c
index b6ee0920f..ccb3ef885 100644
--- a/src/findfile.c
+++ b/src/findfile.c
@@ -66,8 +66,8 @@ typedef struct ff_stack
 
     // the fix part (no wildcards) and the part containing the wildcards
     // of the search path
-    char_u             *ffs_fix_path;
-    char_u             *ffs_wc_path;
+    string_T           ffs_fix_path;
+    string_T           ffs_wc_path;
 
     // files/dirs found in the above directory, matched by the first wildcard
     // of wc_part
@@ -167,31 +167,31 @@ typedef struct ff_search_ctx_T
      ff_visited_list_hdr_T     *ffsc_dir_visited_list;
      ff_visited_list_hdr_T     *ffsc_visited_lists_list;
      ff_visited_list_hdr_T     *ffsc_dir_visited_lists_list;
-     char_u                    *ffsc_file_to_search;
-     char_u                    *ffsc_start_dir;
-     char_u                    *ffsc_fix_path;
-     char_u                    *ffsc_wc_path;
+     string_T                  ffsc_file_to_search;
+     string_T                  ffsc_start_dir;
+     string_T                  ffsc_fix_path;
+     string_T                  ffsc_wc_path;
      int                       ffsc_level;
-     char_u                    **ffsc_stopdirs_v;
+     string_T                  *ffsc_stopdirs_v;
      int                       ffsc_find_what;
      int                       ffsc_tagfile;
 } ff_search_ctx_T;
 
 // locally needed functions
-static int ff_check_visited(ff_visited_T **, char_u *, char_u *);
+static int ff_check_visited(ff_visited_T **, char_u *, size_t, char_u *, 
size_t);
 static void vim_findfile_free_visited(void *search_ctx_arg);
 static void vim_findfile_free_visited_list(ff_visited_list_hdr_T **list_headp);
 static void ff_free_visited_list(ff_visited_T *vl);
-static ff_visited_list_hdr_T* ff_get_visited_list(char_u *, 
ff_visited_list_hdr_T **list_headp);
+static ff_visited_list_hdr_T* ff_get_visited_list(char_u *, size_t, 
ff_visited_list_hdr_T **list_headp);
 
 static void ff_push(ff_search_ctx_T *search_ctx, ff_stack_T *stack_ptr);
 static ff_stack_T *ff_pop(ff_search_ctx_T *search_ctx);
 static void ff_clear(ff_search_ctx_T *search_ctx);
 static void ff_free_stack_element(ff_stack_T *stack_ptr);
-static ff_stack_T *ff_create_stack_element(char_u *, char_u *, int, int);
-static int ff_path_in_stoplist(char_u *, int, char_u **);
+static ff_stack_T *ff_create_stack_element(char_u *, size_t, char_u *, size_t, 
int, int);
+static int ff_path_in_stoplist(char_u *, int, string_T *);
 
-static char_u  *ff_expand_buffer = NULL; // used for expanding filenames
+static string_T ff_expand_buffer = {NULL, 0};      // used for expanding 
filenames
 
 #if 0
 /*
@@ -283,6 +283,7 @@ vim_findnext(void)
 vim_findfile_init(
     char_u     *path,
     char_u     *filename,
+    size_t     filenamelen,
     char_u     *stopdirs UNUSED,
     int                level,
     int                free_visited,
@@ -294,6 +295,7 @@ vim_findfile_init(
     char_u             *wc_part;
     ff_stack_T         *sptr;
     ff_search_ctx_T    *search_ctx;
+    int                        add_sep;
 
     // If a search context is given by the caller, reuse it, else allocate a
     // new one.
@@ -320,19 +322,20 @@ vim_findfile_init(
        // filename. If no list for the current filename exists, creates a new
        // one.
        search_ctx->ffsc_visited_list = ff_get_visited_list(filename,
-                                       &search_ctx->ffsc_visited_lists_list);
+                                       filenamelen, 
&search_ctx->ffsc_visited_lists_list);
        if (search_ctx->ffsc_visited_list == NULL)
            goto error_return;
        search_ctx->ffsc_dir_visited_list = ff_get_visited_list(filename,
-                                   &search_ctx->ffsc_dir_visited_lists_list);
+                                   filenamelen, 
&search_ctx->ffsc_dir_visited_lists_list);
        if (search_ctx->ffsc_dir_visited_list == NULL)
            goto error_return;
     }
 
-    if (ff_expand_buffer == NULL)
+    if (ff_expand_buffer.string == NULL)
     {
-       ff_expand_buffer = alloc(MAXPATHL);
-       if (ff_expand_buffer == NULL)
+       ff_expand_buffer.length = 0;
+       ff_expand_buffer.string = alloc(MAXPATHL);
+       if (ff_expand_buffer.string == NULL)
            goto error_return;
     }
 
@@ -348,13 +351,23 @@ vim_findfile_init(
        if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL)
        {
            // Make the start dir an absolute path name.
-           vim_strncpy(ff_expand_buffer, rel_fname, len);
-           search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, FALSE);
+           vim_strncpy(ff_expand_buffer.string, rel_fname, len);
+           ff_expand_buffer.length = len;
+
+           search_ctx->ffsc_start_dir.string = 
FullName_save(ff_expand_buffer.string, FALSE);
+           if (search_ctx->ffsc_start_dir.string == NULL)
+               goto error_return;
+           search_ctx->ffsc_start_dir.length = 
STRLEN(search_ctx->ffsc_start_dir.string);
        }
        else
-           search_ctx->ffsc_start_dir = vim_strnsave(rel_fname, len);
-       if (search_ctx->ffsc_start_dir == NULL)
-           goto error_return;
+       {
+           search_ctx->ffsc_start_dir.length = len;
+           search_ctx->ffsc_start_dir.string = vim_strnsave(rel_fname,
+               search_ctx->ffsc_start_dir.length);
+           if (search_ctx->ffsc_start_dir.string == NULL)
+               goto error_return;
+       }
+
        if (*++path != NUL)
            ++path;
     }
@@ -369,17 +382,21 @@ vim_findfile_init(
            drive[0] = path[0];
            drive[1] = ':';
            drive[2] = NUL;
-           if (vim_FullName(drive, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
+           if (vim_FullName(drive, ff_expand_buffer.string, MAXPATHL, TRUE) == 
FAIL)
                goto error_return;
            path += 2;
        }
        else
 #endif
-       if (mch_dirname(ff_expand_buffer, MAXPATHL) == FAIL)
+       if (mch_dirname(ff_expand_buffer.string, MAXPATHL) == FAIL)
            goto error_return;
 
-       search_ctx->ffsc_start_dir = vim_strsave(ff_expand_buffer);
-       if (search_ctx->ffsc_start_dir == NULL)
+       ff_expand_buffer.length = STRLEN(ff_expand_buffer.string);
+
+       search_ctx->ffsc_start_dir.length = ff_expand_buffer.length;
+       search_ctx->ffsc_start_dir.string = 
vim_strnsave(ff_expand_buffer.string,
+           search_ctx->ffsc_start_dir.length);
+       if (search_ctx->ffsc_start_dir.string == NULL)
            goto error_return;
 
 #ifdef BACKSLASH_IN_FILENAME
@@ -387,8 +404,11 @@ vim_findfile_init(
        // directory (but not for "//machine/dir").  Only use the drive name.
        if ((*path == '/' || *path == '\')
                && path[1] != path[0]
-               && search_ctx->ffsc_start_dir[1] == ':')
-           search_ctx->ffsc_start_dir[2] = NUL;
+               && search_ctx->ffsc_start_dir.string[1] == ':')
+       {
+           search_ctx->ffsc_start_dir.string[2] = NUL;
+           search_ctx->ffsc_start_dir.length = 2;
+       }
 #endif
     }
 
@@ -410,10 +430,12 @@ vim_findfile_init(
            walker++;
 
        dircount = 1;
-       search_ctx->ffsc_stopdirs_v = ALLOC_ONE(char_u *);
+       search_ctx->ffsc_stopdirs_v = ALLOC_ONE(string_T);
 
        if (search_ctx->ffsc_stopdirs_v != NULL)
        {
+           string_T    *tmp;                   // for convenience
+
            do
            {
                char_u  *helper;
@@ -422,7 +444,7 @@ vim_findfile_init(
 
                helper = walker;
                ptr = vim_realloc(search_ctx->ffsc_stopdirs_v,
-                                          (dircount + 1) * sizeof(char_u *));
+                                          (dircount + 1) * sizeof(string_T));
                if (ptr)
                    search_ctx->ffsc_stopdirs_v = ptr;
                else
@@ -431,23 +453,36 @@ vim_findfile_init(
                walker = vim_strchr(walker, ';');
                len = walker ? (size_t)(walker - helper) : STRLEN(helper);
                // "" means ascent till top of directory tree.
+
                if (*helper != NUL && !vim_isAbsName(helper)
                                                         && len + 1 < MAXPATHL)
                {
                    // Make the stop dir an absolute path name.
-                   vim_strncpy(ff_expand_buffer, helper, len);
-                   search_ctx->ffsc_stopdirs_v[dircount-1] =
-                                       FullName_save(ff_expand_buffer, FALSE);
+                   vim_strncpy(ff_expand_buffer.string, helper, len);
+                   ff_expand_buffer.length = len;
+
+                   tmp = &search_ctx->ffsc_stopdirs_v[dircount - 1];
+                   tmp->string = FullName_save(ff_expand_buffer.string, FALSE);
+                   if (tmp->string != NULL)
+                       tmp->length = STRLEN(tmp->string);
                }
                else
-                   search_ctx->ffsc_stopdirs_v[dircount-1] =
-                                                    vim_strnsave(helper, len);
+               {
+                   tmp = &search_ctx->ffsc_stopdirs_v[dircount - 1];
+                   tmp->length = len;
+                   tmp->string = vim_strnsave(helper, tmp->length);
+                   if (tmp->string == NULL)
+                       tmp->length = 0;
+               }
                if (walker)
                    walker++;
                dircount++;
 
            } while (walker != NULL);
-           search_ctx->ffsc_stopdirs_v[dircount-1] = NULL;
+
+           tmp = &search_ctx->ffsc_stopdirs_v[dircount - 1];
+           tmp->string = NULL;
+           tmp->length = 0;
        }
     }
 
@@ -462,11 +497,14 @@ vim_findfile_init(
     if (wc_part != NULL)
     {
        int     llevel;
-       int     len;
        char    *errpt;
 
        // save the fix part of the path
-       search_ctx->ffsc_fix_path = vim_strnsave(path, wc_part - path);
+       search_ctx->ffsc_fix_path.length = (size_t)(wc_part - path);
+       search_ctx->ffsc_fix_path.string = vim_strnsave(path,
+           search_ctx->ffsc_fix_path.length);
+       if (search_ctx->ffsc_fix_path.string == NULL)
+           goto error_return;
 
        /*
         * copy wc_path and add restricts to the '**' wildcard.
@@ -477,27 +515,27 @@ vim_findfile_init(
         * Due to this technique the path looks awful if you print it as a
         * string.
         */
-       len = 0;
+       ff_expand_buffer.length = 0;
        while (*wc_part != NUL)
        {
-           if (len + 5 >= MAXPATHL)
+           if (ff_expand_buffer.length + 5 >= MAXPATHL)
            {
                emsg(_(e_path_too_long_for_completion));
                break;
            }
            if (STRNCMP(wc_part, "**", 2) == 0)
            {
-               ff_expand_buffer[len++] = *wc_part++;
-               ff_expand_buffer[len++] = *wc_part++;
+               ff_expand_buffer.string[ff_expand_buffer.length++] = *wc_part++;
+               ff_expand_buffer.string[ff_expand_buffer.length++] = *wc_part++;
 
                llevel = strtol((char *)wc_part, &errpt, 10);
                if ((char_u *)errpt != wc_part && llevel > 0 && llevel < 255)
-                   ff_expand_buffer[len++] = llevel;
+                   ff_expand_buffer.string[ff_expand_buffer.length++] = llevel;
                else if ((char_u *)errpt != wc_part && llevel == 0)
                    // restrict is 0 -> remove already added '**'
-                   len -= 2;
+                   ff_expand_buffer.length -= 2;
                else
-                   ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND;
+                   ff_expand_buffer.string[ff_expand_buffer.length++] = 
FF_MAX_STAR_STAR_EXPAND;
                wc_part = (char_u *)errpt;
                if (*wc_part != NUL && !vim_ispathsep(*wc_part))
                {
@@ -506,107 +544,153 @@ vim_findfile_init(
                }
            }
            else
-               ff_expand_buffer[len++] = *wc_part++;
+               ff_expand_buffer.string[ff_expand_buffer.length++] = *wc_part++;
        }
-       ff_expand_buffer[len] = NUL;
-       search_ctx->ffsc_wc_path = vim_strsave(ff_expand_buffer);
+       ff_expand_buffer.string[ff_expand_buffer.length] = NUL;
 
-       if (search_ctx->ffsc_wc_path == NULL)
+       search_ctx->ffsc_wc_path.length = ff_expand_buffer.length;
+       search_ctx->ffsc_wc_path.string = vim_strnsave(ff_expand_buffer.string,
+           search_ctx->ffsc_wc_path.length);
+       if (search_ctx->ffsc_wc_path.string == NULL)
            goto error_return;
     }
     else
-       search_ctx->ffsc_fix_path = vim_strsave(path);
+    {
+       search_ctx->ffsc_fix_path.length = STRLEN(path);
+       search_ctx->ffsc_fix_path.string = vim_strnsave(path,
+           search_ctx->ffsc_fix_path.length);
+       if (search_ctx->ffsc_fix_path.string == NULL)
+           goto error_return;
+    }
 
-    if (search_ctx->ffsc_start_dir == NULL)
+    if (search_ctx->ffsc_start_dir.string == NULL)
     {
        // store the fix part as startdir.
        // This is needed if the parameter path is fully qualified.
-       search_ctx->ffsc_start_dir = vim_strsave(search_ctx->ffsc_fix_path);
-       if (search_ctx->ffsc_start_dir == NULL)
+       search_ctx->ffsc_start_dir.length = search_ctx->ffsc_fix_path.length;
+       search_ctx->ffsc_start_dir.string = 
vim_strnsave(search_ctx->ffsc_fix_path.string,
+           search_ctx->ffsc_start_dir.length);
+       if (search_ctx->ffsc_start_dir.string == NULL)
            goto error_return;
-       search_ctx->ffsc_fix_path[0] = NUL;
+       search_ctx->ffsc_fix_path.string[0] = NUL;
+       search_ctx->ffsc_fix_path.length = 0;
     }
 
     // create an absolute path
-    if (STRLEN(search_ctx->ffsc_start_dir)
-                         + STRLEN(search_ctx->ffsc_fix_path) + 3 >= MAXPATHL)
+    if (search_ctx->ffsc_start_dir.length
+           + search_ctx->ffsc_fix_path.length + 3 >= MAXPATHL)
     {
        emsg(_(e_path_too_long_for_completion));
        goto error_return;
     }
-    STRCPY(ff_expand_buffer, search_ctx->ffsc_start_dir);
-    add_pathsep(ff_expand_buffer);
+
+    add_sep = !after_pathsep(search_ctx->ffsc_start_dir.string,
+       search_ctx->ffsc_start_dir.string + search_ctx->ffsc_start_dir.length);
+    ff_expand_buffer.length = vim_snprintf(
+           (char *)ff_expand_buffer.string,
+           MAXPATHL,
+           "%s%s",
+           search_ctx->ffsc_start_dir.string,
+           add_sep ? PATHSEPSTR : "");
+
     {
-       int    eb_len = (int)STRLEN(ff_expand_buffer);
-       char_u *buf = alloc(eb_len
-                               + (int)STRLEN(search_ctx->ffsc_fix_path) + 1);
+       size_t  bufsize = ff_expand_buffer.length + 
search_ctx->ffsc_fix_path.length + 1;
+       char_u  *buf = alloc(bufsize);
 
-       STRCPY(buf, ff_expand_buffer);
-       STRCPY(buf + eb_len, search_ctx->ffsc_fix_path);
+       if (buf == NULL)
+           goto error_return;
+
+       vim_snprintf(
+               (char *)buf,
+               bufsize,
+               "%s%s",
+               ff_expand_buffer.string,
+               search_ctx->ffsc_fix_path.string);
        if (mch_isdir(buf))
        {
-           STRCAT(ff_expand_buffer, search_ctx->ffsc_fix_path);
-           add_pathsep(ff_expand_buffer);
+           if (search_ctx->ffsc_fix_path.length > 0)
+           {
+               add_sep = !after_pathsep(search_ctx->ffsc_fix_path.string,
+                   search_ctx->ffsc_fix_path.string + 
search_ctx->ffsc_fix_path.length);
+               ff_expand_buffer.length += vim_snprintf(
+                       (char *)ff_expand_buffer.string + 
ff_expand_buffer.length,
+                       MAXPATHL - ff_expand_buffer.length,
+                       "%s%s",
+                       search_ctx->ffsc_fix_path.string,
+                       add_sep ? PATHSEPSTR : "");
+           }
        }
        else
        {
-           char_u *p =  gettail(search_ctx->ffsc_fix_path);
-           char_u *wc_path = NULL;
-           char_u *temp = NULL;
-           int    len = 0;
+           char_u *p = gettail(search_ctx->ffsc_fix_path.string);
+           int    len = (int)search_ctx->ffsc_fix_path.length;
 
-           if (p > search_ctx->ffsc_fix_path)
+           if (p > search_ctx->ffsc_fix_path.string)
            {
                // do not add '..' to the path and start upwards searching
-               len = (int)(p - search_ctx->ffsc_fix_path) - 1;
+               len = (int)(p - search_ctx->ffsc_fix_path.string) - 1;
                if ((len >= 2
-                       && STRNCMP(search_ctx->ffsc_fix_path, "..", 2) == 0)
-                       && (len == 2
-                                  || search_ctx->ffsc_fix_path[2] == PATHSEP))
+                       && STRNCMP(search_ctx->ffsc_fix_path.string, "..", 2) 
== 0)
+                       && (len == 2 || search_ctx->ffsc_fix_path.string[2] == 
PATHSEP))
                {
                    vim_free(buf);
                    goto error_return;
                }
-               STRNCAT(ff_expand_buffer, search_ctx->ffsc_fix_path, len);
-               add_pathsep(ff_expand_buffer);
+
+               add_sep = !after_pathsep(search_ctx->ffsc_fix_path.string,
+                   search_ctx->ffsc_fix_path.string + 
search_ctx->ffsc_fix_path.length);
+               ff_expand_buffer.length += vim_snprintf(
+                       (char *)ff_expand_buffer.string + 
ff_expand_buffer.length,
+                       MAXPATHL - ff_expand_buffer.length,
+                       "%.*s%s",
+                       len,
+                       search_ctx->ffsc_fix_path.string,
+                       add_sep ? PATHSEPSTR : "");
            }
-           else
-               len = (int)STRLEN(search_ctx->ffsc_fix_path);
 
-           if (search_ctx->ffsc_wc_path != NULL)
+           if (search_ctx->ffsc_wc_path.string != NULL)
            {
-               wc_path = vim_strsave(search_ctx->ffsc_wc_path);
-               temp = alloc(STRLEN(search_ctx->ffsc_wc_path)
-                                + STRLEN(search_ctx->ffsc_fix_path + len)
-                                + 1);
-               if (temp == NULL || wc_path == NULL)
+               size_t  tempsize = (search_ctx->ffsc_fix_path.length - len)
+                               + search_ctx->ffsc_wc_path.length
+                               + 1;
+               char_u  *temp = alloc(tempsize);
+
+               if (temp == NULL)
                {
                    vim_free(buf);
                    vim_free(temp);
-                   vim_free(wc_path);
                    goto error_return;
                }
 
-               STRCPY(temp, search_ctx->ffsc_fix_path + len);
-               STRCAT(temp, search_ctx->ffsc_wc_path);
-               vim_free(search_ctx->ffsc_wc_path);
-               vim_free(wc_path);
-               search_ctx->ffsc_wc_path = temp;
+               search_ctx->ffsc_wc_path.length = vim_snprintf(
+                           (char *)temp,
+                           tempsize,
+                           "%s%s",
+                           search_ctx->ffsc_fix_path.string + len,
+                           search_ctx->ffsc_wc_path.string);
+               vim_free(search_ctx->ffsc_wc_path.string);
+               search_ctx->ffsc_wc_path.string = temp;
            }
        }
        vim_free(buf);
     }
 
-    sptr = ff_create_stack_element(ff_expand_buffer,
-                                          search_ctx->ffsc_wc_path, level, 0);
+    sptr = ff_create_stack_element(ff_expand_buffer.string,
+                       ff_expand_buffer.length,
+                       search_ctx->ffsc_wc_path.string,
+                       search_ctx->ffsc_wc_path.length,
+                       level,
+                       0);
 
     if (sptr == NULL)
        goto error_return;
 
     ff_push(search_ctx, sptr);
 
-    search_ctx->ffsc_file_to_search = vim_strsave(filename);
-    if (search_ctx->ffsc_file_to_search == NULL)
+    search_ctx->ffsc_file_to_search.length = filenamelen;
+    search_ctx->ffsc_file_to_search.string = vim_strnsave(filename,
+       search_ctx->ffsc_file_to_search.length);
+    if (search_ctx->ffsc_file_to_search.string == NULL)
        goto error_return;
 
     return search_ctx;
@@ -628,6 +712,7 @@ error_return:
 vim_findfile_stopdir(char_u *buf)
 {
     char_u     *r_ptr = buf;
+    char_u     *r_ptr_end = NULL;          // points to NUL at end of string 
"r_ptr"
 
     while (*r_ptr != NUL && *r_ptr != ';')
     {
@@ -635,14 +720,18 @@ vim_findfile_stopdir(char_u *buf)
        {
            // Overwrite the escape char,
            // use STRLEN(r_ptr) to move the trailing '
-           STRMOVE(r_ptr, r_ptr + 1);
+           if (r_ptr_end == NULL)
+               r_ptr_end = r_ptr + STRLEN(r_ptr);
+           mch_memmove(r_ptr, r_ptr + 1,
+               (size_t)(r_ptr_end - (r_ptr + 1)) + 1); // +1 for NUL
            r_ptr++;
+           --r_ptr_end;
        }
        r_ptr++;
     }
     if (*r_ptr == ';')
     {
-       *r_ptr = 0;
+       *r_ptr = NUL;
        r_ptr++;
     }
     else if (*r_ptr == NUL)
@@ -679,14 +768,10 @@ vim_findfile_cleanup(void *ctx)
     char_u *
 vim_findfile(void *search_ctx_arg)
 {
-    char_u     *file_path;
-    char_u     *rest_of_wildcards;
+    string_T   file_path;
+    string_T   rest_of_wildcards;
     char_u     *path_end = NULL;
     ff_stack_T *stackp;
-    int                len;
-    int                i;
-    char_u     *p;
-    char_u     *suf;
     ff_search_ctx_T *search_ctx;
 
     if (search_ctx_arg == NULL)
@@ -698,13 +783,13 @@ vim_findfile(void *search_ctx_arg)
      * filepath is used as buffer for various actions and as the storage to
      * return a found filename.
      */
-    if ((file_path = alloc(MAXPATHL)) == NULL)
+    if ((file_path.string = alloc(MAXPATHL)) == NULL)
        return NULL;
 
     // store the end of the start dir -- needed for upward search
-    if (search_ctx->ffsc_start_dir != NULL)
-       path_end = &search_ctx->ffsc_start_dir[
-                                         STRLEN(search_ctx->ffsc_start_dir)];
+    if (search_ctx->ffsc_start_dir.string != NULL)
+       path_end = &search_ctx->ffsc_start_dir.string[
+                                           search_ctx->ffsc_start_dir.length];
 
     // upward search loop
     for (;;)
@@ -744,14 +829,17 @@ vim_findfile(void *search_ctx_arg)
            if (stackp->ffs_filearray == NULL
                    && ff_check_visited(&search_ctx->ffsc_dir_visited_list
                                                          ->ffvl_visited_list,
-                           stackp->ffs_fix_path, stackp->ffs_wc_path) == FAIL)
+                           stackp->ffs_fix_path.string,
+                           stackp->ffs_fix_path.length,
+                           stackp->ffs_wc_path.string,
+                           stackp->ffs_wc_path.length) == FAIL)
            {
 #ifdef FF_VERBOSE
                if (p_verbose >= 5)
                {
                    verbose_enter_scroll();
                    smsg("Already Searched: %s (%s)",
-                                  stackp->ffs_fix_path, stackp->ffs_wc_path);
+                                  stackp->ffs_fix_path.string, 
stackp->ffs_wc_path.string);
                    // don't overwrite this either
                    msg_puts("
");
                    verbose_leave_scroll();
@@ -765,7 +853,7 @@ vim_findfile(void *search_ctx_arg)
            {
                verbose_enter_scroll();
                smsg("Searching: %s (%s)",
-                                  stackp->ffs_fix_path, stackp->ffs_wc_path);
+                                  stackp->ffs_fix_path.string, 
stackp->ffs_wc_path.string);
                // don't overwrite this either
                msg_puts("
");
                verbose_leave_scroll();
@@ -779,7 +867,8 @@ vim_findfile(void *search_ctx_arg)
                continue;
            }
 
-           file_path[0] = NUL;
+           file_path.string[0] = NUL;
+           file_path.length = 0;
 
            /*
             * If no filearray till now expand wildcards
@@ -793,17 +882,23 @@ vim_findfile(void *search_ctx_arg)
 
                // we use filepath to build the path expand_wildcards() should
                // expand.
-               dirptrs[0] = file_path;
+               dirptrs[0] = file_path.string;
                dirptrs[1] = NULL;
 
                // if we have a start dir copy it in
-               if (!vim_isAbsName(stackp->ffs_fix_path)
-                                               && search_ctx->ffsc_start_dir)
+               if (!vim_isAbsName(stackp->ffs_fix_path.string)
+                                               && 
search_ctx->ffsc_start_dir.string)
                {
-                   if (STRLEN(search_ctx->ffsc_start_dir) + 1 < MAXPATHL)
+                   if (search_ctx->ffsc_start_dir.length + 1 < MAXPATHL)
                    {
-                       STRCPY(file_path, search_ctx->ffsc_start_dir);
-                       add_pathsep(file_path);
+                       int add_sep = 
!after_pathsep(search_ctx->ffsc_start_dir.string,
+                           search_ctx->ffsc_start_dir.string + 
search_ctx->ffsc_start_dir.length);
+                       file_path.length = vim_snprintf(
+                           (char *)file_path.string,
+                           MAXPATHL,
+                           "%s%s",
+                           search_ctx->ffsc_start_dir.string,
+                           add_sep ? PATHSEPSTR : "");
                    }
                    else
                    {
@@ -813,11 +908,16 @@ vim_findfile(void *search_ctx_arg)
                }
 
                // append the fix part of the search path
-               if (STRLEN(file_path) + STRLEN(stackp->ffs_fix_path) + 1
-                                                                   < MAXPATHL)
+               if (file_path.length + stackp->ffs_fix_path.length + 1 < 
MAXPATHL)
                {
-                   STRCAT(file_path, stackp->ffs_fix_path);
-                   add_pathsep(file_path);
+                   int add_sep = !after_pathsep(stackp->ffs_fix_path.string,
+                       stackp->ffs_fix_path.string + 
stackp->ffs_fix_path.length);
+                   file_path.length += vim_snprintf(
+                       (char *)file_path.string + file_path.length,
+                       MAXPATHL - file_path.length,
+                       "%s%s",
+                       stackp->ffs_fix_path.string,
+                       add_sep ? PATHSEPSTR : "");
                }
                else
                {
@@ -825,21 +925,23 @@ vim_findfile(void *search_ctx_arg)
                    goto fail;
                }
 
-               rest_of_wildcards = stackp->ffs_wc_path;
-               if (*rest_of_wildcards != NUL)
+               rest_of_wildcards.string = stackp->ffs_wc_path.string;
+               rest_of_wildcards.length = stackp->ffs_wc_path.length;
+               if (*rest_of_wildcards.string != NUL)
                {
-                   len = (int)STRLEN(file_path);
-                   if (STRNCMP(rest_of_wildcards, "**", 2) == 0)
+                   if (STRNCMP(rest_of_wildcards.string, "**", 2) == 0)
                    {
+                       char_u  *p;
+
                        // pointer to the restrict byte
                        // The restrict byte is not a character!
-                       p = rest_of_wildcards + 2;
+                       p = rest_of_wildcards.string + 2;
 
                        if (*p > 0)
                        {
                            (*p)--;
-                           if (len + 1 < MAXPATHL)
-                               file_path[len++] = '*';
+                           if (file_path.length + 1 < MAXPATHL)
+                               file_path.string[file_path.length++] = '*';
                            else
                            {
                                ff_free_stack_element(stackp);
@@ -850,16 +952,23 @@ vim_findfile(void *search_ctx_arg)
                        if (*p == 0)
                        {
                            // remove '**<numb> from wildcards
-                           STRMOVE(rest_of_wildcards, rest_of_wildcards + 3);
+                           mch_memmove(rest_of_wildcards.string,
+                                       rest_of_wildcards.string + 3,
+                                       (size_t)(rest_of_wildcards.length - 3) 
+ 1);    // +1 for NUL
+                           rest_of_wildcards.length -= 3;
+                           stackp->ffs_wc_path.length = 
rest_of_wildcards.length;
                        }
                        else
-                           rest_of_wildcards += 3;
+                       {
+                           rest_of_wildcards.string += 3;
+                           rest_of_wildcards.length -= 3;
+                       }
 
                        if (stackp->ffs_star_star_empty == 0)
                        {
                            // if not done before, expand '**' to empty
                            stackp->ffs_star_star_empty = 1;
-                           dirptrs[1] = stackp->ffs_fix_path;
+                           dirptrs[1] = stackp->ffs_fix_path.string;
                        }
                    }
 
@@ -870,19 +979,27 @@ vim_findfile(void *search_ctx_arg)
                     * pushing every directory returned from expand_wildcards()
                     * on the stack again for further search.
                     */
-                   while (*rest_of_wildcards
-                           && !vim_ispathsep(*rest_of_wildcards))
-                       if (len + 1 < MAXPATHL)
-                           file_path[len++] = *rest_of_wildcards++;
+                   while (*rest_of_wildcards.string
+                           && !vim_ispathsep(*rest_of_wildcards.string))
+                   {
+                       if (file_path.length + 1 < MAXPATHL)
+                       {
+                           file_path.string[file_path.length++] = 
*rest_of_wildcards.string++;
+                           --rest_of_wildcards.length;
+                       }
                        else
                        {
                            ff_free_stack_element(stackp);
                            goto fail;
                        }
+                   }
 
-                   file_path[len] = NUL;
-                   if (vim_ispathsep(*rest_of_wildcards))
-                       rest_of_wildcards++;
+                   file_path.string[file_path.length] = NUL;
+                   if (vim_ispathsep(*rest_of_wildcards.string))
+                   {
+                       rest_of_wildcards.string++;
+                       rest_of_wildcards.length--;
+                   }
                }
 
                /*
@@ -894,7 +1011,7 @@ vim_findfile(void *search_ctx_arg)
                    stackp->ffs_filearray = ALLOC_ONE(char_u *);
                    if (stackp->ffs_filearray != NULL
                            && (stackp->ffs_filearray[0]
-                               = vim_strsave(dirptrs[0])) != NULL)
+                               = vim_strnsave(dirptrs[0], file_path.length)) 
!= NULL)
                        stackp->ffs_filearray_size = 1;
                    else
                        stackp->ffs_filearray_size = 0;
@@ -912,14 +1029,22 @@ vim_findfile(void *search_ctx_arg)
                stackp->ffs_stage = 0;
            }
            else
-               rest_of_wildcards = &stackp->ffs_wc_path[
-                                                STRLEN(stackp->ffs_wc_path)];
+           {
+               rest_of_wildcards.string = &stackp->ffs_wc_path.string[
+                                                       
stackp->ffs_wc_path.length];
+               rest_of_wildcards.length = 0;
+           }
 
            if (stackp->ffs_stage == 0)
            {
+               int i;
+
                // this is the first time we work on this directory
-               if (*rest_of_wildcards == NUL)
+               if (*rest_of_wildcards.string == NUL)
                {
+                   size_t  len;
+                   char_u  *suf;
+
                    /*
                     * We don't have further wildcards to expand, so we have to
                     * check for the final file now.
@@ -933,13 +1058,19 @@ vim_findfile(void *search_ctx_arg)
 
                        // prepare the filename to be checked for existence
                        // below
-                       if (STRLEN(stackp->ffs_filearray[i]) + 1
-                               + STRLEN(search_ctx->ffsc_file_to_search)
-                                                                   < MAXPATHL)
+                       len = STRLEN(stackp->ffs_filearray[i]);
+                       if (len + 1 + search_ctx->ffsc_file_to_search.length
+                                                                       < 
MAXPATHL)
                        {
-                           STRCPY(file_path, stackp->ffs_filearray[i]);
-                           add_pathsep(file_path);
-                           STRCAT(file_path, search_ctx->ffsc_file_to_search);
+                           int add_sep = 
!after_pathsep(stackp->ffs_filearray[i],
+                                   stackp->ffs_filearray[i] + len);
+                           file_path.length = vim_snprintf(
+                                   (char *)file_path.string,
+                                   MAXPATHL,
+                                   "%s%s%s",
+                                   stackp->ffs_filearray[i],
+                                   add_sep ? PATHSEPSTR : "",
+                                   search_ctx->ffsc_file_to_search.string);
                        }
                        else
                        {
@@ -951,7 +1082,6 @@ vim_findfile(void *search_ctx_arg)
                         * Try without extra suffix and then with suffixes
                         * from 'suffixesadd'.
                         */
-                       len = (int)STRLEN(file_path);
                        if (search_ctx->ffsc_tagfile)
                            suf = (char_u *)"";
                        else
@@ -959,18 +1089,20 @@ vim_findfile(void *search_ctx_arg)
                        for (;;)
                        {
                            // if file exists and we didn't already find it
-                           if ((path_with_url(file_path)
-                                 || (mch_getperm(file_path) >= 0
+                           if ((path_with_url(file_path.string)
+                                 || (mch_getperm(file_path.string) >= 0
                                      && (search_ctx->ffsc_find_what
                                                              == FINDFILE_BOTH
                                          || ((search_ctx->ffsc_find_what
                                                              == FINDFILE_DIR)
-                                                  == mch_isdir(file_path)))))
+                                                  == 
mch_isdir(file_path.string)))))
 #ifndef FF_VERBOSE
                                    && (ff_check_visited(
                                            &search_ctx->ffsc_visited_list
                                                           ->ffvl_visited_list,
-                                           file_path, (char_u *)"") == OK)
+                                           file_path.string,
+                                           file_path.length,
+                                           (char_u *)"", 0) == OK)
 #endif
                               )
                            {
@@ -978,13 +1110,14 @@ vim_findfile(void *search_ctx_arg)
                                if (ff_check_visited(
                                            &search_ctx->ffsc_visited_list
                                                           ->ffvl_visited_list,
-                                             file_path, (char_u *)"") == FAIL)
+                                             file_path.string,
+                                             file_path.length,
+                                             (char_u *)"", 0) == FAIL)
                                {
                                    if (p_verbose >= 5)
                                    {
                                        verbose_enter_scroll();
-                                       smsg("Already: %s",
-                                                                  file_path);
+                                       smsg("Already: %s", file_path.string);
                                        // don't overwrite this either
                                        msg_puts("
");
                                        verbose_leave_scroll();
@@ -997,34 +1130,42 @@ vim_findfile(void *search_ctx_arg)
                                stackp->ffs_filearray_cur = i + 1;
                                ff_push(search_ctx, stackp);
 
-                               if (!path_with_url(file_path))
-                                   simplify_filename(file_path);
-                               if (mch_dirname(ff_expand_buffer, MAXPATHL)
+                               if (!path_with_url(file_path.string))
+                                   file_path.length = 
simplify_filename(file_path.string);
+
+                               if (mch_dirname(ff_expand_buffer.string, 
MAXPATHL)
                                                                        == OK)
                                {
-                                   p = shorten_fname(file_path,
-                                                           ff_expand_buffer);
+                                   char_u  *p;
+
+                                   ff_expand_buffer.length = 
STRLEN(ff_expand_buffer.string);
+                                   p = shorten_fname(file_path.string,
+                                                           
ff_expand_buffer.string);
                                    if (p != NULL)
-                                       STRMOVE(file_path, p);
+                                   {
+                                       mch_memmove(file_path.string, p,
+                                           (size_t)((file_path.string + 
file_path.length) - p) + 1);  // +1 for NUL
+                                       file_path.length -= (p - 
file_path.string);
+                                   }
                                }
 #ifdef FF_VERBOSE
                                if (p_verbose >= 5)
                                {
                                    verbose_enter_scroll();
-                                   smsg("HIT: %s", file_path);
+                                   smsg("HIT: %s", file_path.string);
                                    // don't overwrite this either
                                    msg_puts("
");
                                    verbose_leave_scroll();
                                }
 #endif
-                               return file_path;
+                               return file_path.string;
                            }
 
                            // Not found or found already, try next suffix.
                            if (*suf == NUL)
                                break;
-                           copy_option_part(&suf, file_path + len,
-                                                        MAXPATHL - len, ",");
+                           file_path.length += copy_option_part(&suf, 
file_path.string + file_path.length,
+                                                        MAXPATHL - 
file_path.length, ",");
                        }
                    }
                }
@@ -1043,7 +1184,9 @@ vim_findfile(void *search_ctx_arg)
                        ff_push(search_ctx,
                                ff_create_stack_element(
                                                     stackp->ffs_filearray[i],
-                                                    rest_of_wildcards,
+                                                    
STRLEN(stackp->ffs_filearray[i]),
+                                                    rest_of_wildcards.string,
+                                                    rest_of_wildcards.length,
                                                     stackp->ffs_level - 1, 0));
                    }
                }
@@ -1055,68 +1198,83 @@ vim_findfile(void *search_ctx_arg)
             * if wildcards contains '**' we have to descent till we reach the
             * leaves of the directory tree.
             */
-           if (STRNCMP(stackp->ffs_wc_path, "**", 2) == 0)
+           if (STRNCMP(stackp->ffs_wc_path.string, "**", 2) == 0)
            {
+               int i;
+
                for (i = stackp->ffs_filearray_cur;
                                          i < stackp->ffs_filearray_size; ++i)
                {
                    if (fnamecmp(stackp->ffs_filearray[i],
-                                                  stackp->ffs_fix_path) == 0)
+                                                  stackp->ffs_fix_path.string) 
== 0)
                        continue; // don't repush same directory
                    if (!mch_isdir(stackp->ffs_filearray[i]))
                        continue;   // not a directory
                    ff_push(search_ctx,
-                           ff_create_stack_element(stackp->ffs_filearray[i],
-                               stackp->ffs_wc_path, stackp->ffs_level - 1, 1));
+                           ff_create_stack_element(
+                               stackp->ffs_filearray[i],
+                               STRLEN(stackp->ffs_filearray[i]),
+                               stackp->ffs_wc_path.string,
+                               stackp->ffs_wc_path.length,
+                               stackp->ffs_level - 1, 1));
                }
            }
 
            // we are done with the current directory
            ff_free_stack_element(stackp);
-
        }
 
        // If we reached this, we didn't find anything downwards.
        // Let's check if we should do an upward search.
-       if (search_ctx->ffsc_start_dir
+       if (search_ctx->ffsc_start_dir.string
                && search_ctx->ffsc_stopdirs_v != NULL && !got_int)
        {
            ff_stack_T  *sptr;
            // path_end may point to the NUL or the previous path separator
-           int plen = (path_end - search_ctx->ffsc_start_dir)
+           int plen = (path_end - search_ctx->ffsc_start_dir.string)
                                                          + (*path_end != NUL);
 
            // is the last starting directory in the stop list?
-           if (ff_path_in_stoplist(search_ctx->ffsc_start_dir,
+           if (ff_path_in_stoplist(search_ctx->ffsc_start_dir.string,
                                    plen, search_ctx->ffsc_stopdirs_v) == TRUE)
                break;
 
            // cut of last dir
-           while (path_end > search_ctx->ffsc_start_dir
+           while (path_end > search_ctx->ffsc_start_dir.string
                                                  && vim_ispathsep(*path_end))
                path_end--;
-           while (path_end > search_ctx->ffsc_start_dir
+           while (path_end > search_ctx->ffsc_start_dir.string
                                              && !vim_ispathsep(path_end[-1]))
                path_end--;
-           *path_end = 0;
+           *path_end = NUL;
+
+           // we may have shortened search_ctx->ffsc_start_dir, so update it's 
length
+           search_ctx->ffsc_start_dir.length = (size_t)(path_end - 
search_ctx->ffsc_start_dir.string);
            path_end--;
 
-           if (*search_ctx->ffsc_start_dir == 0)
+           if (*search_ctx->ffsc_start_dir.string == NUL)
                break;
 
-           if (STRLEN(search_ctx->ffsc_start_dir) + 1
-                   + STRLEN(search_ctx->ffsc_fix_path) < MAXPATHL)
+           if (search_ctx->ffsc_start_dir.length + 1
+                   + search_ctx->ffsc_fix_path.length < MAXPATHL)
            {
-               STRCPY(file_path, search_ctx->ffsc_start_dir);
-               add_pathsep(file_path);
-               STRCAT(file_path, search_ctx->ffsc_fix_path);
+               int add_sep = !after_pathsep(search_ctx->ffsc_start_dir.string,
+                           search_ctx->ffsc_start_dir.string + 
search_ctx->ffsc_start_dir.length);
+               file_path.length = vim_snprintf(
+                       (char *)file_path.string,
+                       MAXPATHL,
+                       "%s%s%s",
+                       search_ctx->ffsc_start_dir.string,
+                       add_sep ? PATHSEPSTR : "",
+                       search_ctx->ffsc_fix_path.string);
            }
            else
                goto fail;
 
            // create a new stack entry
-           sptr = ff_create_stack_element(file_path,
-                   search_ctx->ffsc_wc_path, search_ctx->ffsc_level, 0);
+           sptr = ff_create_stack_element(file_path.string, file_path.length,
+                   search_ctx->ffsc_wc_path.string, 
search_ctx->ffsc_wc_path.length,
+                   search_ctx->ffsc_level, 0);
            if (sptr == NULL)
                break;
            ff_push(search_ctx, sptr);
@@ -1126,7 +1284,7 @@ vim_findfile(void *search_ctx_arg)
     }
 
 fail:
-    vim_free(file_path);
+    vim_free(file_path.string);
     return NULL;
 }
 
@@ -1186,6 +1344,7 @@ ff_free_visited_list(ff_visited_T *vl)
     static ff_visited_list_hdr_T*
 ff_get_visited_list(
     char_u                     *filename,
+    size_t                     filenamelen,
     ff_visited_list_hdr_T      **list_headp)
 {
     ff_visited_list_hdr_T  *retptr = NULL;
@@ -1234,7 +1393,7 @@ ff_get_visited_list(
        return NULL;
 
     retptr->ffvl_visited_list = NULL;
-    retptr->ffvl_filename = vim_strsave(filename);
+    retptr->ffvl_filename = vim_strnsave(filename, filenamelen);
     if (retptr->ffvl_filename == NULL)
     {
        vim_free(retptr);
@@ -1300,7 +1459,9 @@ ff_wc_equal(char_u *s1, char_u *s2)
 ff_check_visited(
     ff_visited_T       **visited_list,
     char_u             *fname,
-    char_u             *wc_path)
+    size_t             fnamelen,
+    char_u             *wc_path,
+    size_t             wc_pathlen)
 {
     ff_visited_T       *vp;
 #ifdef UNIX
@@ -1312,20 +1473,24 @@ ff_check_visited(
     // device/inode (unix) or the full path name (not Unix).
     if (path_with_url(fname))
     {
-       vim_strncpy(ff_expand_buffer, fname, MAXPATHL - 1);
+       vim_strncpy(ff_expand_buffer.string, fname, fnamelen);
+       ff_expand_buffer.length = fnamelen;
 #ifdef UNIX
        url = TRUE;
 #endif
     }
     else
     {
-       ff_expand_buffer[0] = NUL;
+       ff_expand_buffer.string[0] = NUL;
+       ff_expand_buffer.length = 0;
 #ifdef UNIX
        if (mch_stat((char *)fname, &st) < 0)
+           return FAIL;
 #else
-       if (vim_FullName(fname, ff_expand_buffer, MAXPATHL, TRUE) == FAIL)
-#endif
+       if (vim_FullName(fname, ff_expand_buffer.string, MAXPATHL, TRUE) == 
FAIL)
            return FAIL;
+       ff_expand_buffer.length = STRLEN(ff_expand_buffer.string);
+#endif
     }
 
     // check against list of already visited files
@@ -1337,7 +1502,7 @@ ff_check_visited(
                                                  && vp->ffv_ino == st.st_ino)
                     :
 #endif
-               fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0
+               fnamecmp(vp->ffv_fname, ff_expand_buffer.string) == 0
           )
        {
            // are the wildcard parts equal
@@ -1351,7 +1516,7 @@ ff_check_visited(
      * New file/dir.  Add it to the list of visited files/dirs.
      */
     vp = alloc(
-            offsetof(ff_visited_T, ffv_fname) + STRLEN(ff_expand_buffer) + 1);
+            offsetof(ff_visited_T, ffv_fname) + ff_expand_buffer.length + 1);
     if (vp == NULL)
        return OK;
 
@@ -1359,20 +1524,20 @@ ff_check_visited(
     if (!url)
     {
        vp->ffv_dev_valid = TRUE;
-       vp->ffv_ino = st.st_ino;
        vp->ffv_dev = st.st_dev;
+       vp->ffv_ino = st.st_ino;
        vp->ffv_fname[0] = NUL;
     }
     else
     {
        vp->ffv_dev_valid = FALSE;
 #endif
-       STRCPY(vp->ffv_fname, ff_expand_buffer);
+       STRCPY(vp->ffv_fname, ff_expand_buffer.string);
 #ifdef UNIX
     }
 #endif
     if (wc_path != NULL)
-       vp->ffv_wc_path = vim_strsave(wc_path);
+       vp->ffv_wc_path = vim_strnsave(wc_path, wc_pathlen);
     else
        vp->ffv_wc_path = NULL;
 
@@ -1388,7 +1553,9 @@ ff_check_visited(
     static ff_stack_T *
 ff_create_stack_element(
     char_u     *fix_part,
+    size_t     fix_partlen,
     char_u     *wc_part,
+    size_t     wc_partlen,
     int                level,
     int                star_star_empty)
 {
@@ -1408,14 +1575,22 @@ ff_create_stack_element(
 
     // the following saves NULL pointer checks in vim_findfile
     if (fix_part == NULL)
+    {
        fix_part = (char_u *)"";
-    new->ffs_fix_path = vim_strsave(fix_part);
+       fix_partlen = 0;
+    }
+    new->ffs_fix_path.string = vim_strnsave(fix_part, fix_partlen);
+    new->ffs_fix_path.length = fix_partlen;
 
     if (wc_part == NULL)
-       wc_part  = (char_u *)"";
-    new->ffs_wc_path = vim_strsave(wc_part);
+    {
+       wc_part = (char_u *)"";
+       wc_partlen = 0;
+    }
+    new->ffs_wc_path.string = vim_strnsave(wc_part, wc_partlen);
+    new->ffs_wc_path.length = wc_partlen;
 
-    if (new->ffs_fix_path == NULL || new->ffs_wc_path == NULL)
+    if (new->ffs_fix_path.string == NULL || new->ffs_wc_path.string == NULL)
     {
        ff_free_stack_element(new);
        new = NULL;
@@ -1461,9 +1636,9 @@ ff_pop(ff_search_ctx_T *search_ctx)
     static void
 ff_free_stack_element(ff_stack_T *stack_ptr)
 {
-    // vim_free handles possible NULL pointers
-    vim_free(stack_ptr->ffs_fix_path);
-    vim_free(stack_ptr->ffs_wc_path);
+    // VIM_CLEAR_STRING handles possible NULL pointers
+    VIM_CLEAR_STRING(stack_ptr->ffs_fix_path);
+    VIM_CLEAR_STRING(stack_ptr->ffs_wc_path);
 
     if (stack_ptr->ffs_filearray != NULL)
        FreeWild(stack_ptr->ffs_filearray_size, stack_ptr->ffs_filearray);
@@ -1483,29 +1658,23 @@ ff_clear(ff_search_ctx_T *search_ctx)
     while ((sptr = ff_pop(search_ctx)) != NULL)
        ff_free_stack_element(sptr);
 
-    vim_free(search_ctx->ffsc_file_to_search);
-    vim_free(search_ctx->ffsc_start_dir);
-    vim_free(search_ctx->ffsc_fix_path);
-    vim_free(search_ctx->ffsc_wc_path);
-
     if (search_ctx->ffsc_stopdirs_v != NULL)
     {
        int  i = 0;
 
-       while (search_ctx->ffsc_stopdirs_v[i] != NULL)
+       while (search_ctx->ffsc_stopdirs_v[i].string != NULL)
        {
-           vim_free(search_ctx->ffsc_stopdirs_v[i]);
+           vim_free(search_ctx->ffsc_stopdirs_v[i].string);
            i++;
        }
-       vim_free(search_ctx->ffsc_stopdirs_v);
+       VIM_CLEAR(search_ctx->ffsc_stopdirs_v);
     }
-    search_ctx->ffsc_stopdirs_v = NULL;
 
     // reset everything
-    search_ctx->ffsc_file_to_search = NULL;
-    search_ctx->ffsc_start_dir = NULL;
-    search_ctx->ffsc_fix_path = NULL;
-    search_ctx->ffsc_wc_path = NULL;
+    VIM_CLEAR_STRING(search_ctx->ffsc_file_to_search);
+    VIM_CLEAR_STRING(search_ctx->ffsc_start_dir);
+    VIM_CLEAR_STRING(search_ctx->ffsc_fix_path);
+    VIM_CLEAR_STRING(search_ctx->ffsc_wc_path);
     search_ctx->ffsc_level = 0;
 }
 
@@ -1514,7 +1683,7 @@ ff_clear(ff_search_ctx_T *search_ctx)
  * returns TRUE if yes else FALSE
  */
     static int
-ff_path_in_stoplist(char_u *path, int path_len, char_u **stopdirs_v)
+ff_path_in_stoplist(char_u *path, int path_len, string_T *stopdirs_v)
 {
     int                i = 0;
 
@@ -1526,13 +1695,13 @@ ff_path_in_stoplist(char_u *path, int path_len, char_u 
**stopdirs_v)
     if (path_len == 0)
        return TRUE;
 
-    for (i = 0; stopdirs_v[i] != NULL; i++)
+    for (i = 0; stopdirs_v[i].string != NULL; i++)
        // match for parent directory. So '/home' also matches
        // '/home/rks'. Check for PATHSEP in stopdirs_v[i], else
        // '/home/r' would also match '/home/rks'
-       if (fnamencmp(stopdirs_v[i], path, path_len) == 0
-               && ((int)STRLEN(stopdirs_v[i]) <= path_len
-                   || vim_ispathsep(stopdirs_v[i][path_len])))
+       if (fnamencmp(stopdirs_v[i].string, path, path_len) == 0
+               && ((int)stopdirs_v[i].length <= path_len
+                   || vim_ispathsep(stopdirs_v[i].string[path_len])))
            return TRUE;
 
     return FALSE;
@@ -1583,7 +1752,7 @@ find_file_in_path(
     void
 free_findfile(void)
 {
-    VIM_CLEAR(ff_expand_buffer);
+    VIM_CLEAR_STRING(ff_expand_buffer);
 }
 # endif
 
@@ -1628,9 +1797,7 @@ find_file_in_path_option(
     ff_search_ctx_T    **search_ctx = (ff_search_ctx_T **)search_ctx_arg;
     static char_u      *dir;
     static int         did_findfile_init = FALSE;
-    char_u             save_char;
     char_u             *file_name = NULL;
-    char_u             *buf = NULL;
     int                        rel_to_curdir;
 # ifdef AMIGA
     struct Process     *proc = (struct Process *)FindTask(0L);
@@ -1639,9 +1806,12 @@ find_file_in_path_option(
     // Avoid a requester here for a volume that doesn't exist.
     proc->pr_WindowPtr = (APTR)-1L;
 # endif
+    static size_t      file_to_findlen = 0;
 
     if (first == TRUE)
     {
+       char_u  save_char;
+
        if (len == 0)
            return NULL;
 
@@ -1652,10 +1822,12 @@ find_file_in_path_option(
        ptr[len] = save_char;
 
        vim_free(*file_to_find);
-       *file_to_find = vim_strsave(NameBuff);
+       file_to_findlen = STRLEN(NameBuff);
+       *file_to_find = vim_strnsave(NameBuff, file_to_findlen);
        if (*file_to_find == NULL)      // out of memory
        {
            file_name = NULL;
+           file_to_findlen = 0;
            goto theend;
        }
        if (options & FNAME_UNESC)
@@ -1663,7 +1835,11 @@ find_file_in_path_option(
            // Change all "\ " to " ".
            for (ptr = *file_to_find; *ptr != NUL; ++ptr)
                if (ptr[0] == '\' && ptr[1] == ' ')
-                   mch_memmove(ptr, ptr + 1, STRLEN(ptr));
+               {
+                   mch_memmove(ptr, ptr + 1,
+                       (size_t)((*file_to_find + file_to_findlen) - (ptr + 1)) 
+ 1);
+                   --file_to_findlen;
+               }
        }
     }
 
@@ -1697,27 +1873,36 @@ find_file_in_path_option(
        {
            int         l;
            int         run;
+           size_t      rel_fnamelen = 0;
+           char_u      *suffix;
 
            if (path_with_url(*file_to_find))
            {
-               file_name = vim_strsave(*file_to_find);
+               file_name = vim_strnsave(*file_to_find, file_to_findlen);
                goto theend;
            }
 
+           if (rel_fname != NULL)
+               rel_fnamelen = STRLEN(rel_fname);
+
            // When FNAME_REL flag given first use the directory of the file.
            // Otherwise or when this fails use the current directory.
            for (run = 1; run <= 2; ++run)
            {
-               l = (int)STRLEN(*file_to_find);
+               l = (int)file_to_findlen;
                if (run == 1
                        && rel_to_curdir
                        && (options & FNAME_REL)
                        && rel_fname != NULL
-                       && STRLEN(rel_fname) + l < MAXPATHL)
+                       && rel_fnamelen + l < MAXPATHL)
                {
-                   STRCPY(NameBuff, rel_fname);
-                   STRCPY(gettail(NameBuff), *file_to_find);
-                   l = (int)STRLEN(NameBuff);
+                   l = vim_snprintf(
+                       (char *)NameBuff,
+                       MAXPATHL,
+                       "%.*s%s",
+                       (int)(gettail(rel_fname) - rel_fname),
+                       rel_fname,
+                       *file_to_find);
                }
                else
                {
@@ -1727,7 +1912,7 @@ find_file_in_path_option(
 
                // When the file doesn't exist, try adding parts of
                // 'suffixesadd'.
-               buf = suffixes;
+               suffix = suffixes;
                for (;;)
                {
                    if (mch_getperm(NameBuff) >= 0
@@ -1735,12 +1920,12 @@ find_file_in_path_option(
                                 || ((find_what == FINDFILE_DIR)
                                                    == mch_isdir(NameBuff))))
                    {
-                       file_name = vim_strsave(NameBuff);
+                       file_name = vim_strnsave(NameBuff, l);
                        goto theend;
                    }
-                   if (*buf == NUL)
+                   if (*suffix == NUL)
                        break;
-                   copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ",");
+                   l += copy_option_part(&suffix, NameBuff + l, MAXPATHL - l, 
",");
                }
            }
        }
@@ -1772,6 +1957,7 @@ find_file_in_path_option(
            }
            else
            {
+               char_u  *buf;
                char_u  *r_ptr;
 
                if (dir == NULL || *dir == NUL)
@@ -1787,12 +1973,12 @@ find_file_in_path_option(
                    break;
 
                // copy next path
-               buf[0] = 0;
+               buf[0] = NUL;
                copy_option_part(&dir, buf, MAXPATHL, " ,");
 
                // get the stopdir string
                r_ptr = vim_findfile_stopdir(buf);
-               *search_ctx = vim_findfile_init(buf, *file_to_find,
+               *search_ctx = vim_findfile_init(buf, *file_to_find, 
file_to_findlen,
                                            r_ptr, 100, FALSE, find_what,
                                           *search_ctx, FALSE, rel_fname);
                if (*search_ctx != NULL)
@@ -1963,20 +2149,27 @@ file_name_in_line(
 
     if (file_lnum != NULL)
     {
-       char_u *p;
-       char    *line_english = " line ";
-       char    *line_transl = _(line_msg);
+       char_u  *p;
+       char    *match_text = " line ";         // english
+       size_t  match_textlen = 6;
 
        // Get the number after the file name and a separator character.
        // Also accept " line 999" with and without the same translation as
        // used in last_set_msg().
        p = ptr + len;
-       if (STRNCMP(p, line_english, STRLEN(line_english)) == 0)
-           p += STRLEN(line_english);
-       else if (STRNCMP(p, line_transl, STRLEN(line_transl)) == 0)
-           p += STRLEN(line_transl);
+       if (STRNCMP(p, match_text, match_textlen) == 0)
+           p += match_textlen;
        else
-           p = skipwhite(p);
+       {
+           // no match with english, try localized
+           match_text = _(line_msg);
+           match_textlen = STRLEN(match_text);
+
+           if (STRNCMP(p, match_text, match_textlen) == 0)
+               p += match_textlen;
+           else
+               p = skipwhite(p);
+       }
        if (*p != NUL)
        {
            if (!SAFE_isdigit(*p))
@@ -2177,7 +2370,7 @@ find_previous_pathsep(char_u *path, char_u **psep)
 is_unique(char_u *maybe_unique, garray_T *gap, int i)
 {
     int            j;
-    int            candidate_len;
+    int            candidate_len = (int)STRLEN(maybe_unique);
     int            other_path_len;
     char_u  **other_paths = (char_u **)gap->ga_data;
     char_u  *rival;
@@ -2187,7 +2380,6 @@ is_unique(char_u *maybe_unique, garray_T *gap, int i)
        if (j == i)
            continue;  // don't compare it with itself
 
-       candidate_len = (int)STRLEN(maybe_unique);
        other_path_len = (int)STRLEN(other_paths[j]);
        if (other_path_len < candidate_len)
            continue;  // it's different when it's shorter
@@ -2217,50 +2409,60 @@ expand_path_option(
        garray_T        *gap)
 {
     char_u     *buf;
+    size_t     buflen;
     char_u     *p;
-    int                len;
+    size_t     curdirlen = 0;
 
     if ((buf = alloc(MAXPATHL)) == NULL)
        return;
 
     while (*path_option != NUL)
     {
-       copy_option_part(&path_option, buf, MAXPATHL, " ,");
+       buflen = copy_option_part(&path_option, buf, MAXPATHL, " ,");
 
        if (buf[0] == '.' && (buf[1] == NUL || vim_ispathsep(buf[1])))
        {
+           size_t  plen;
+
            // Relative to current buffer:
            // "/path/file" + "." -> "/path/"
            // "/path/file"  + "./subdir" -> "/path/subdir"
            if (curbuf->b_ffname == NULL)
                continue;
            p = gettail(curbuf->b_ffname);
-           len = (int)(p - curbuf->b_ffname);
-           if (len + (int)STRLEN(buf) >= MAXPATHL)
+           plen = (size_t)(p - curbuf->b_ffname);
+           if (plen + buflen >= MAXPATHL)
                continue;
            if (buf[1] == NUL)
-               buf[len] = NUL;
+               buf[plen] = NUL;
            else
-               STRMOVE(buf + len, buf + 2);
-           mch_memmove(buf, curbuf->b_ffname, len);
-           simplify_filename(buf);
+               mch_memmove(buf + plen, buf + 2, (buflen - 2) + 1); // +1 for 
NUL
+           mch_memmove(buf, curbuf->b_ffname, plen);
+           buflen = simplify_filename(buf);
        }
        else if (buf[0] == NUL)
+       {
            // relative to current directory
            STRCPY(buf, curdir);
+           if (curdirlen == 0)
+               curdirlen = STRLEN(curdir);
+           buflen = curdirlen;
+       }
        else if (path_with_url(buf))
            // URL can't be used here
            continue;
        else if (!mch_isFullName(buf))
        {
            // Expand relative path to their full path equivalent
-           len = (int)STRLEN(curdir);
-           if (len + (int)STRLEN(buf) + 3 > MAXPATHL)
+           if (curdirlen == 0)
+               curdirlen = STRLEN(curdir);
+           if (curdirlen + buflen + 3 > MAXPATHL)
                continue;
-           STRMOVE(buf + len + 1, buf);
+
+           mch_memmove(buf + curdirlen + 1, buf, buflen + 1);      // +1 for 
NUL
            STRCPY(buf, curdir);
-           buf[len] = PATHSEP;
-           simplify_filename(buf);
+           buf[curdirlen] = PATHSEP;
+           buflen = simplify_filename(buf);
        }
 
        if (ga_grow(gap, 1) == FAIL)
@@ -2269,12 +2471,11 @@ expand_path_option(
 # if defined(MSWIN)
        // Avoid the path ending in a backslash, it fails when a comma is
        // appended.
-       len = (int)STRLEN(buf);
-       if (buf[len - 1] == '\')
-           buf[len - 1] = '/';
+       if (buf[buflen - 1] == '\')
+           buf[buflen - 1] = '/';
 # endif
 
-       p = vim_strsave(buf);
+       p = vim_strnsave(buf, buflen);
        if (p == NULL)
            break;
        ((char_u **)gap->ga_data)[gap->ga_len++] = p;
@@ -2360,8 +2561,7 @@ uniquefy_paths(
     if (file_pattern == NULL)
        return;
     file_pattern[0] = '*';
-    file_pattern[1] = NUL;
-    STRCAT(file_pattern, pattern);
+    STRCPY(file_pattern + 1, pattern);
     pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, FALSE);
     vim_free(file_pattern);
     if (pat == NULL)
@@ -2387,14 +2587,13 @@ uniquefy_paths(
        char_u      *path = fnames[i];
        int         is_in_curdir;
        char_u      *dir_end = gettail_dir(path);
-       char_u      *pathsep_p;
        char_u      *path_cutoff;
 
        len = (int)STRLEN(path);
        is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
                                             && curdir[dir_end - path] == NUL;
        if (is_in_curdir)
-           in_curdir[i] = vim_strsave(path);
+           in_curdir[i] = vim_strnsave(path, len);
 
        // Shorten the filename while maintaining its uniqueness
        path_cutoff = get_path_cutoff(path, &path_ga);
@@ -2415,17 +2614,20 @@ uniquefy_paths(
        {
            // Here all files can be reached without path, so get shortest
            // unique path.  We start at the end of the path.
-           pathsep_p = path + len - 1;
+           char_u  *pathsep_p = path + len - 1;
 
            while (find_previous_pathsep(path, &pathsep_p))
+           {
                if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
                        && is_unique(pathsep_p + 1, gap, i)
                        && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
                {
                    sort_again = TRUE;
-                   mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
+                   mch_memmove(path, pathsep_p + 1,
+                           (size_t)((path + len) - (pathsep_p + 1)) + 1);  // 
+1 for NUL
                    break;
                }
+           }
        }
 
        if (mch_isFullName(path))
@@ -2453,9 +2655,7 @@ uniquefy_paths(
 # endif
                )
            {
-               STRCPY(path, ".");
-               add_pathsep(path);
-               STRMOVE(path + STRLEN(path), short_name);
+               vim_snprintf((char *)path, MAXPATHL, ".%s%s", PATHSEPSTR, 
short_name);
            }
        }
        ui_breakcheck();
@@ -2464,8 +2664,9 @@ uniquefy_paths(
     // Shorten filenames in /in/current/directory/{filename}
     for (i = 0; i < gap->ga_len && !got_int; i++)
     {
-       char_u *rel_path;
-       char_u *path = in_curdir[i];
+       size_t  rel_pathsize;
+       char_u  *rel_path;
+       char_u  *path = in_curdir[i];
 
        if (path == NULL)
            continue;
@@ -2481,12 +2682,12 @@ uniquefy_paths(
            continue;
        }
 
-       rel_path = alloc(STRLEN(short_name) + STRLEN(PATHSEPSTR) + 2);
+       rel_pathsize = 1 + STRLEN_LITERAL(PATHSEPSTR) + STRLEN(short_name) + 1;
+       rel_path = alloc(rel_pathsize);
        if (rel_path == NULL)
            goto theend;
-       STRCPY(rel_path, ".");
-       add_pathsep(rel_path);
-       STRCAT(rel_path, short_name);
+
+       vim_snprintf((char *)rel_path, rel_pathsize, ".%s%s", PATHSEPSTR, 
short_name);
 
        vim_free(fnames[i]);
        fnames[i] = rel_path;
@@ -2561,12 +2762,13 @@ expand_in_path(
  * resulting file name is simplified in place and will either be the same
  * length as that supplied, or shorter.
  */
-    void
+    size_t
 simplify_filename(char_u *filename)
 {
 #ifndef AMIGA      // Amiga doesn't have "..", it uses "/"
     int                components = 0;
     char_u     *p, *tail, *start;
+    char_u     *p_end;                     // point to NUL at end of string "p"
     int                stripping_disabled = FALSE;
     int                relative = TRUE;
 
@@ -2584,11 +2786,13 @@ simplify_filename(char_u *filename)
        while (vim_ispathsep(*p));
     }
     start = p;     // remember start after "c:/" or "/" or "///"
+    p_end = p + STRLEN(p);
 #ifdef UNIX
     // Posix says that "//path" is unchanged but "///path" is "/path".
     if (start > filename + 2)
     {
-       STRMOVE(filename + 1, p);
+       mch_memmove(filename + 1, p, (size_t)(p_end - p) + 1);      // +1 for 
NUL
+       p_end -= (size_t)(p - (filename + 1));
        start = p = filename + 1;
     }
 #endif
@@ -2614,8 +2818,11 @@ simplify_filename(char_u *filename)
        }
        else
 # endif
-         if (vim_ispathsep(*p))
-           STRMOVE(p, p + 1);          // remove duplicate "/"
+       if (vim_ispathsep(*p))
+       {
+           mch_memmove(p, p + 1, (size_t)(p_end - (p + 1)) + 1); // remove 
duplicate "/"
+           --p_end;
+       }
        else if (p[0] == '.' && (vim_ispathsep(p[1]) || p[1] == NUL))
        {
            if (p == start && relative)
@@ -2632,7 +2839,9 @@ simplify_filename(char_u *filename)
                        MB_PTR_ADV(tail);
                else if (p > start)
                    --p;                // strip preceding path separator
-               STRMOVE(p, tail);
+
+               mch_memmove(p, tail, (size_t)(p_end - tail) + 1);
+               p_end -= (size_t)(tail - p);
            }
        }
        else if (p[0] == '.' && p[1] == '.' &&
@@ -2748,19 +2957,25 @@ simplify_filename(char_u *filename)
                    {
                        if (p > start && tail[-1] == '.')
                            --p;
-                       STRMOVE(p, tail);       // strip previous component
+
+                       mch_memmove(p, tail, (size_t)(p_end - tail) + 1);       
// strip previous component
+                       p_end -= (size_t)(tail - p);
                    }
 
                    --components;
                }
            }
            else if (p == start && !relative)   // leading "/.." or "/../"
-               STRMOVE(p, tail);               // strip ".." or "../"
+           {
+               mch_memmove(p, tail, (size_t)(p_end - tail) + 1);               
// strip ".." or "../"
+               p_end -= (size_t)(tail - p);
+           }
            else
            {
                if (p == start + 2 && p[-2] == '.')     // leading "./../"
                {
-                   STRMOVE(p - 2, p);                  // strip leading "./"
+                   mch_memmove(p - 2, p, (size_t)(p_end - p) + 1); // strip 
leading "./"
+                   p_end -= 2;
                    tail -= 2;
                }
                p = tail;               // skip to char after ".." or "../"
@@ -2773,6 +2988,8 @@ simplify_filename(char_u *filename)
        }
     } while (*p != NUL);
 #endif // !AMIGA
+
+    return (size_t)(p_end - filename);
 }
 
 #if defined(FEAT_EVAL) || defined(PROTO)
diff --git a/src/proto/findfile.pro b/src/proto/findfile.pro
index 1c2822157..628042c13 100644
--- a/src/proto/findfile.pro
+++ b/src/proto/findfile.pro
@@ -1,5 +1,5 @@
 /* findfile.c */
-void *vim_findfile_init(char_u *path, char_u *filename, char_u *stopdirs, int 
level, int free_visited, int find_what, void *search_ctx_arg, int tagfile, 
char_u *rel_fname);
+void *vim_findfile_init(char_u *path, char_u *filename, size_t filenamelen, 
char_u *stopdirs, int level, int free_visited, int find_what, void 
*search_ctx_arg, int tagfile, char_u *rel_fname);
 char_u *vim_findfile_stopdir(char_u *buf);
 void vim_findfile_cleanup(void *ctx);
 char_u *vim_findfile(void *search_ctx_arg);
@@ -14,6 +14,6 @@ char_u *find_file_name_in_path(char_u *ptr, int len, int 
options, long count, ch
 int vim_ispathlistsep(int c);
 void uniquefy_paths(garray_T *gap, char_u *pattern, char_u *path_option);
 int expand_in_path(garray_T *gap, char_u *pattern, int flags);
-void simplify_filename(char_u *filename);
+size_t simplify_filename(char_u *filename);
 void f_simplify(typval_T *argvars, typval_T *rettv);
 /* vim: set ft=c : */
diff --git a/src/tag.c b/src/tag.c
index f94d3eb9d..21ff5636a 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -3421,6 +3421,7 @@ get_tagfname(
            *filename++ = NUL;
 
            tnp->tn_search_ctx = vim_findfile_init(buf, filename,
+                   STRLEN(filename),
                    r_ptr, 100,
                    FALSE,         // don't free visited list
                    FINDFILE_FILE, // we search for a file
diff --git a/src/version.c b/src/version.c
index ba99dde61..f400ca9e6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1122,
 /**/
     1121,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion visit 
https://groups.google.com/d/msgid/vim_dev/E1tkTlD-00GiXW-Gg%40256bit.org.

Raspunde prin e-mail lui