diff options
Diffstat (limited to 'src/nvim/file_search.c')
-rw-r--r-- | src/nvim/file_search.c | 542 |
1 files changed, 319 insertions, 223 deletions
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 1e6153bf8d..c374322d22 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -50,6 +50,8 @@ #include <stdlib.h> #include <string.h> +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" @@ -80,7 +82,7 @@ #include "nvim/strings.h" #include "nvim/vim_defs.h" -static char *ff_expand_buffer = NULL; // used for expanding filenames +static String ff_expand_buffer = STRING_INIT; // used for expanding filenames // type for the directory search stack typedef struct ff_stack { @@ -88,8 +90,8 @@ typedef struct ff_stack { // the fix part (no wildcards) and the part containing the wildcards // of the search path - char *ffs_fix_path; - char *ffs_wc_path; + String ffs_fix_path; + String ffs_wc_path; // files/dirs found in the above directory, matched by the first wildcard // of wc_part @@ -172,12 +174,12 @@ typedef struct { 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 *ffsc_file_to_search; - char *ffsc_start_dir; - char *ffsc_fix_path; - char *ffsc_wc_path; + String ffsc_file_to_search; + String ffsc_start_dir; + String ffsc_fix_path; + String ffsc_wc_path; int ffsc_level; - char **ffsc_stopdirs_v; + String *ffsc_stopdirs_v; int ffsc_find_what; int ffsc_tagfile; } ff_search_ctx_T; @@ -244,8 +246,9 @@ static const char e_path_too_long_for_completion[] /// /// @param tagfile expanding names of tags files /// @param rel_fname file name to use for "." -void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, int free_visited, - int find_what, void *search_ctx_arg, int tagfile, char *rel_fname) +void *vim_findfile_init(char *path, char *filename, size_t filenamelen, char *stopdirs, int level, + int free_visited, int find_what, void *search_ctx_arg, int tagfile, + char *rel_fname) { ff_stack_T *sptr; ff_search_ctx_T *search_ctx; @@ -270,20 +273,23 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i // Reuse old visited lists. Get the visited list for the given // 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); + search_ctx->ffsc_visited_list + = ff_get_visited_list(filename, 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); + search_ctx->ffsc_dir_visited_list + = ff_get_visited_list(filename, filenamelen, + &search_ctx->ffsc_dir_visited_lists_list); if (search_ctx->ffsc_dir_visited_list == NULL) { goto error_return; } } - if (ff_expand_buffer == NULL) { - ff_expand_buffer = xmalloc(MAXPATHL); + if (ff_expand_buffer.data == NULL) { + ff_expand_buffer.size = 0; + ff_expand_buffer.data = xmalloc(MAXPATHL); } // Store information on starting dir now if path is relative. @@ -296,10 +302,11 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL) { // Make the start dir an absolute path name. - xmemcpyz(ff_expand_buffer, rel_fname, len); - search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, false); + xmemcpyz(ff_expand_buffer.data, rel_fname, len); + ff_expand_buffer.size = len; + search_ctx->ffsc_start_dir = cstr_as_string(FullName_save(ff_expand_buffer.data, false)); } else { - search_ctx->ffsc_start_dir = xmemdupz(rel_fname, len); + search_ctx->ffsc_start_dir = cbuf_to_string(rel_fname, len); } if (*++path != NUL) { path++; @@ -313,25 +320,27 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i 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.data, MAXPATHL, true) == FAIL) { goto error_return; } path += 2; } else #endif - if (os_dirname(ff_expand_buffer, MAXPATHL) == FAIL) { + if (os_dirname(ff_expand_buffer.data, MAXPATHL) == FAIL) { goto error_return; } + ff_expand_buffer.size = strlen(ff_expand_buffer.data); - search_ctx->ffsc_start_dir = xstrdup(ff_expand_buffer); + search_ctx->ffsc_start_dir = copy_string(ff_expand_buffer, NULL); #ifdef BACKSLASH_IN_FILENAME // A path that starts with "/dir" is relative to the drive, not to the // 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.data[1] == ':') { + search_ctx->ffsc_start_dir.data[2] = NUL; + search_ctx->ffsc_start_dir.size = 2; } #endif } @@ -351,12 +360,12 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i } size_t dircount = 1; - search_ctx->ffsc_stopdirs_v = xmalloc(sizeof(char *)); + search_ctx->ffsc_stopdirs_v = xmalloc(sizeof(String)); do { char *helper = walker; void *ptr = xrealloc(search_ctx->ffsc_stopdirs_v, - (dircount + 1) * sizeof(char *)); + (dircount + 1) * sizeof(String)); search_ctx->ffsc_stopdirs_v = ptr; walker = vim_strchr(walker, ';'); assert(!walker || walker - helper >= 0); @@ -364,17 +373,19 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i // "" means ascent till top of directory tree. if (*helper != NUL && !vim_isAbsName(helper) && len + 1 < MAXPATHL) { // Make the stop dir an absolute path name. - xmemcpyz(ff_expand_buffer, helper, len); - search_ctx->ffsc_stopdirs_v[dircount - 1] = FullName_save(helper, len); + xmemcpyz(ff_expand_buffer.data, helper, len); + ff_expand_buffer.size = len; + search_ctx->ffsc_stopdirs_v[dircount - 1] = cstr_as_string(FullName_save(helper, len)); } else { - search_ctx->ffsc_stopdirs_v[dircount - 1] = xmemdupz(helper, len); + search_ctx->ffsc_stopdirs_v[dircount - 1] = cbuf_to_string(helper, len); } if (walker) { walker++; } dircount++; } while (walker != NULL); - search_ctx->ffsc_stopdirs_v[dircount - 1] = NULL; + + search_ctx->ffsc_stopdirs_v[dircount - 1] = NULL_STRING; } search_ctx->ffsc_level = level; @@ -385,12 +396,11 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i char *wc_part = vim_strchr(path, '*'); if (wc_part != NULL) { int64_t llevel; - int len; char *errpt; // save the fix part of the path assert(wc_part - path >= 0); - search_ctx->ffsc_fix_path = xstrnsave(path, (size_t)(wc_part - path)); + search_ctx->ffsc_fix_path = cbuf_to_string(path, (size_t)(wc_part - path)); // copy wc_path and add restricts to the '**' wildcard. // The octet after a '**' is used as a (binary) counter. @@ -399,24 +409,24 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i // If no restrict is given after '**' the default is used. // Due to this technique the path looks awful if you print it as a // string. - len = 0; + ff_expand_buffer.size = 0; while (*wc_part != NUL) { - if (len + 5 >= MAXPATHL) { + if (ff_expand_buffer.size + 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.data[ff_expand_buffer.size++] = *wc_part++; + ff_expand_buffer.data[ff_expand_buffer.size++] = *wc_part++; llevel = strtol(wc_part, &errpt, 10); if (errpt != wc_part && llevel > 0 && llevel < 255) { - ff_expand_buffer[len++] = (char)llevel; + ff_expand_buffer.data[ff_expand_buffer.size++] = (char)llevel; } else if (errpt != wc_part && llevel == 0) { // restrict is 0 -> remove already added '**' - len -= 2; + ff_expand_buffer.size -= 2; } else { - ff_expand_buffer[len++] = FF_MAX_STAR_STAR_EXPAND; + ff_expand_buffer.data[ff_expand_buffer.size++] = FF_MAX_STAR_STAR_EXPAND; } wc_part = errpt; if (*wc_part != NUL && !vim_ispathsep(*wc_part)) { @@ -426,78 +436,108 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i goto error_return; } } else { - ff_expand_buffer[len++] = *wc_part++; + ff_expand_buffer.data[ff_expand_buffer.size++] = *wc_part++; } } - ff_expand_buffer[len] = NUL; - search_ctx->ffsc_wc_path = xstrdup(ff_expand_buffer); + ff_expand_buffer.data[ff_expand_buffer.size] = NUL; + search_ctx->ffsc_wc_path = copy_string(ff_expand_buffer, false); } else { - search_ctx->ffsc_fix_path = xstrdup(path); + search_ctx->ffsc_fix_path = cstr_to_string(path); } - if (search_ctx->ffsc_start_dir == NULL) { + if (search_ctx->ffsc_start_dir.data == NULL) { // store the fix part as startdir. // This is needed if the parameter path is fully qualified. - search_ctx->ffsc_start_dir = xstrdup(search_ctx->ffsc_fix_path); - search_ctx->ffsc_fix_path[0] = NUL; + search_ctx->ffsc_start_dir = copy_string(search_ctx->ffsc_fix_path, false); + search_ctx->ffsc_fix_path.data[0] = NUL; + search_ctx->ffsc_fix_path.size = 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.size + + search_ctx->ffsc_fix_path.size + 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); - { - size_t eb_len = strlen(ff_expand_buffer); - char *buf = xmalloc(eb_len + strlen(search_ctx->ffsc_fix_path) + 1); - STRCPY(buf, ff_expand_buffer); - STRCPY(buf + eb_len, search_ctx->ffsc_fix_path); + bool add_sep = !after_pathsep(search_ctx->ffsc_start_dir.data, + search_ctx->ffsc_start_dir.data + search_ctx->ffsc_start_dir.size); + ff_expand_buffer.size = (size_t)vim_snprintf(ff_expand_buffer.data, + MAXPATHL, + "%s%s", + search_ctx->ffsc_start_dir.data, + add_sep ? PATHSEPSTR : ""); + assert(ff_expand_buffer.size < MAXPATHL); + + { + size_t bufsize = ff_expand_buffer.size + search_ctx->ffsc_fix_path.size + 1; + char *buf = xmalloc(bufsize); + + vim_snprintf(buf, + bufsize, + "%s%s", + ff_expand_buffer.data, + search_ctx->ffsc_fix_path.data); if (os_isdir(buf)) { - strcat(ff_expand_buffer, search_ctx->ffsc_fix_path); - add_pathsep(ff_expand_buffer); + if (search_ctx->ffsc_fix_path.size > 0) { + add_sep = !after_pathsep(search_ctx->ffsc_fix_path.data, + search_ctx->ffsc_fix_path.data + search_ctx->ffsc_fix_path.size); + ff_expand_buffer.size += (size_t)vim_snprintf(ff_expand_buffer.data + ff_expand_buffer.size, + MAXPATHL - ff_expand_buffer.size, + "%s%s", + search_ctx->ffsc_fix_path.data, + add_sep ? PATHSEPSTR : ""); + assert(ff_expand_buffer.size < MAXPATHL); + } } else { - char *p = path_tail(search_ctx->ffsc_fix_path); - char *wc_path = NULL; - char *temp = NULL; - int len = 0; + char *p = path_tail(search_ctx->ffsc_fix_path.data); + int len = (int)search_ctx->ffsc_fix_path.size; - if (p > search_ctx->ffsc_fix_path) { + if (p > search_ctx->ffsc_fix_path.data) { // do not add '..' to the path and start upwards searching - len = (int)(p - search_ctx->ffsc_fix_path) - 1; - if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path, "..", 2) == 0) - && (len == 2 || search_ctx->ffsc_fix_path[2] == PATHSEP)) { + len = (int)(p - search_ctx->ffsc_fix_path.data) - 1; + if ((len >= 2 && strncmp(search_ctx->ffsc_fix_path.data, "..", 2) == 0) + && (len == 2 || search_ctx->ffsc_fix_path.data[2] == PATHSEP)) { xfree(buf); goto error_return; } - xstrlcat(ff_expand_buffer, search_ctx->ffsc_fix_path, eb_len + (size_t)len + 1); - add_pathsep(ff_expand_buffer); - } else { - len = (int)strlen(search_ctx->ffsc_fix_path); + + add_sep = !after_pathsep(search_ctx->ffsc_fix_path.data, + search_ctx->ffsc_fix_path.data + search_ctx->ffsc_fix_path.size); + ff_expand_buffer.size += (size_t)vim_snprintf(ff_expand_buffer.data + ff_expand_buffer.size, + MAXPATHL - ff_expand_buffer.size, + "%.*s%s", + len, + search_ctx->ffsc_fix_path.data, + add_sep ? PATHSEPSTR : ""); + assert(ff_expand_buffer.size < MAXPATHL); } - if (search_ctx->ffsc_wc_path != NULL) { - wc_path = xstrdup(search_ctx->ffsc_wc_path); - temp = xmalloc(strlen(search_ctx->ffsc_wc_path) - + strlen(search_ctx->ffsc_fix_path + len) - + 1); - STRCPY(temp, search_ctx->ffsc_fix_path + len); - strcat(temp, search_ctx->ffsc_wc_path); - xfree(search_ctx->ffsc_wc_path); - xfree(wc_path); - search_ctx->ffsc_wc_path = temp; + if (search_ctx->ffsc_wc_path.data != NULL) { + size_t tempsize = (search_ctx->ffsc_fix_path.size - (size_t)len) + + search_ctx->ffsc_wc_path.size + 1; + char *temp = xmalloc(tempsize); + search_ctx->ffsc_wc_path.size = (size_t)vim_snprintf(temp, + tempsize, + "%s%s", + search_ctx->ffsc_fix_path.data + len, + search_ctx->ffsc_wc_path.data); + assert(search_ctx->ffsc_wc_path.size < tempsize); + xfree(search_ctx->ffsc_wc_path.data); + search_ctx->ffsc_wc_path.data = temp; } } xfree(buf); } - sptr = ff_create_stack_element(ff_expand_buffer, search_ctx->ffsc_wc_path, level, 0); + sptr = ff_create_stack_element(ff_expand_buffer.data, + ff_expand_buffer.size, + search_ctx->ffsc_wc_path.data, + search_ctx->ffsc_wc_path.size, + level, 0); ff_push(search_ctx, sptr); - search_ctx->ffsc_file_to_search = xstrdup(filename); + search_ctx->ffsc_file_to_search = cbuf_to_string(filename, filenamelen); return search_ctx; error_return: @@ -570,12 +610,9 @@ void vim_findfile_cleanup(void *ctx) /// NULL if nothing found. char *vim_findfile(void *search_ctx_arg) { - char *rest_of_wildcards; + String rest_of_wildcards; char *path_end = NULL; ff_stack_T *stackp = NULL; - size_t len; - char *p; - char *suf; if (search_ctx_arg == NULL) { return NULL; @@ -585,11 +622,11 @@ char *vim_findfile(void *search_ctx_arg) // filepath is used as buffer for various actions and as the storage to // return a found filename. - char *file_path = xmalloc(MAXPATHL); + String file_path = { .data = xmalloc(MAXPATHL) }; // 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.data != NULL) { + path_end = &search_ctx->ffsc_start_dir.data[search_ctx->ffsc_start_dir.size]; } // upward search loop @@ -627,12 +664,13 @@ char *vim_findfile(void *search_ctx_arg) // first time (hence stackp->ff_filearray == NULL) 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.data, stackp->ffs_fix_path.size, + stackp->ffs_wc_path.data, stackp->ffs_wc_path.size) == FAIL) { #ifdef FF_VERBOSE if (p_verbose >= 5) { verbose_enter_scroll(); smsg(0, "Already Searched: %s (%s)", - stackp->ffs_fix_path, stackp->ffs_wc_path); + stackp->ffs_fix_path.data, stackp->ffs_wc_path.data); msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); } @@ -643,7 +681,7 @@ char *vim_findfile(void *search_ctx_arg) } else if (p_verbose >= 5) { verbose_enter_scroll(); smsg(0, "Searching: %s (%s)", - stackp->ffs_fix_path, stackp->ffs_wc_path); + stackp->ffs_fix_path.data, stackp->ffs_wc_path.data); msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); #endif @@ -655,7 +693,8 @@ char *vim_findfile(void *search_ctx_arg) continue; } - file_path[0] = NUL; + file_path.data[0] = NUL; + file_path.size = 0; // If no filearray till now expand wildcards // The function expand_wildcards() can handle an array of paths @@ -665,62 +704,79 @@ char *vim_findfile(void *search_ctx_arg) char *dirptrs[2]; // we use filepath to build the path expand_wildcards() should expand. - dirptrs[0] = file_path; + dirptrs[0] = file_path.data; 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 (strlen(search_ctx->ffsc_start_dir) + 1 >= MAXPATHL) { + if (!vim_isAbsName(stackp->ffs_fix_path.data) + && search_ctx->ffsc_start_dir.data) { + if (search_ctx->ffsc_start_dir.size + 1 >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } - STRCPY(file_path, search_ctx->ffsc_start_dir); - if (!add_pathsep(file_path)) { + bool add_sep = !after_pathsep(search_ctx->ffsc_start_dir.data, + search_ctx->ffsc_start_dir.data + + search_ctx->ffsc_start_dir.size); + file_path.size = (size_t)vim_snprintf(file_path.data, + MAXPATHL, + "%s%s", + search_ctx->ffsc_start_dir.data, + add_sep ? PATHSEPSTR : ""); + if (file_path.size >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } } // append the fix part of the search path - if (strlen(file_path) + strlen(stackp->ffs_fix_path) + 1 >= MAXPATHL) { + if (file_path.size + stackp->ffs_fix_path.size + 1 >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } - strcat(file_path, stackp->ffs_fix_path); - if (!add_pathsep(file_path)) { + bool add_sep = !after_pathsep(stackp->ffs_fix_path.data, + stackp->ffs_fix_path.data + stackp->ffs_fix_path.size); + file_path.size += (size_t)vim_snprintf(file_path.data + file_path.size, + MAXPATHL - file_path.size, + "%s%s", + stackp->ffs_fix_path.data, + add_sep ? PATHSEPSTR : ""); + if (file_path.size >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } rest_of_wildcards = stackp->ffs_wc_path; - if (*rest_of_wildcards != NUL) { - len = strlen(file_path); - if (strncmp(rest_of_wildcards, "**", 2) == 0) { + if (*rest_of_wildcards.data != NUL) { + if (strncmp(rest_of_wildcards.data, "**", 2) == 0) { // pointer to the restrict byte // The restrict byte is not a character! - p = rest_of_wildcards + 2; + char *p = rest_of_wildcards.data + 2; if (*p > 0) { (*p)--; - if (len + 1 >= MAXPATHL) { + if (file_path.size + 1 >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } - file_path[len++] = '*'; + file_path.data[file_path.size++] = '*'; } if (*p == 0) { // remove '**<numb> from wildcards - STRMOVE(rest_of_wildcards, rest_of_wildcards + 3); + memmove(rest_of_wildcards.data, + rest_of_wildcards.data + 3, + (rest_of_wildcards.size - 3) + 1); // +1 for NUL + rest_of_wildcards.size -= 3; + stackp->ffs_wc_path.size = rest_of_wildcards.size; } else { - rest_of_wildcards += 3; + rest_of_wildcards.data += 3; + rest_of_wildcards.size -= 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.data; } } @@ -729,18 +785,20 @@ char *vim_findfile(void *search_ctx_arg) // still something else left. This is handled below by // 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) { + while (*rest_of_wildcards.data + && !vim_ispathsep(*rest_of_wildcards.data)) { + if (file_path.size + 1 >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } - file_path[len++] = *rest_of_wildcards++; + file_path.data[file_path.size++] = *rest_of_wildcards.data++; + rest_of_wildcards.size--; } - file_path[len] = NUL; - if (vim_ispathsep(*rest_of_wildcards)) { - rest_of_wildcards++; + file_path.data[file_path.size] = NUL; + if (vim_ispathsep(*rest_of_wildcards.data)) { + rest_of_wildcards.data++; + rest_of_wildcards.size--; } } @@ -748,7 +806,7 @@ char *vim_findfile(void *search_ctx_arg) // If the path is a URL don't try this. if (path_with_url(dirptrs[0])) { stackp->ffs_filearray = xmalloc(sizeof(char *)); - stackp->ffs_filearray[0] = xstrdup(dirptrs[0]); + stackp->ffs_filearray[0] = xmemdupz(dirptrs[0], file_path.size); stackp->ffs_filearray_size = 1; } else { // Add EW_NOTWILD because the expanded path may contain @@ -763,12 +821,13 @@ char *vim_findfile(void *search_ctx_arg) stackp->ffs_filearray_cur = 0; stackp->ffs_stage = 0; } else { - rest_of_wildcards = &stackp->ffs_wc_path[strlen(stackp->ffs_wc_path)]; + rest_of_wildcards.data = &stackp->ffs_wc_path.data[stackp->ffs_wc_path.size]; + rest_of_wildcards.size = 0; } if (stackp->ffs_stage == 0) { // this is the first time we work on this directory - if (*rest_of_wildcards == NUL) { + if (*rest_of_wildcards.data == NUL) { // We don't have further wildcards to expand, so we have to // check for the final file now. for (int i = stackp->ffs_filearray_cur; i < stackp->ffs_filearray_size; i++) { @@ -777,44 +836,45 @@ char *vim_findfile(void *search_ctx_arg) continue; // not a directory } // prepare the filename to be checked for existence below - if (strlen(stackp->ffs_filearray[i]) + 1 - + strlen(search_ctx->ffsc_file_to_search) >= MAXPATHL) { + size_t len = strlen(stackp->ffs_filearray[i]); + if (len + 1 + search_ctx->ffsc_file_to_search.size >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } - STRCPY(file_path, stackp->ffs_filearray[i]); - if (!add_pathsep(file_path)) { + bool add_sep = !after_pathsep(stackp->ffs_filearray[i], + stackp->ffs_filearray[i] + len); + file_path.size = (size_t)vim_snprintf(file_path.data, + MAXPATHL, + "%s%s%s", + stackp->ffs_filearray[i], + add_sep ? PATHSEPSTR : "", + search_ctx->ffsc_file_to_search.data); + if (file_path.size >= MAXPATHL) { ff_free_stack_element(stackp); goto fail; } - strcat(file_path, search_ctx->ffsc_file_to_search); // Try without extra suffix and then with suffixes // from 'suffixesadd'. - len = strlen(file_path); - if (search_ctx->ffsc_tagfile) { - suf = ""; - } else { - suf = curbuf->b_p_sua; - } + char *suf = search_ctx->ffsc_tagfile ? "" : curbuf->b_p_sua; while (true) { // if file exists and we didn't already find it - if ((path_with_url(file_path) - || (os_path_exists(file_path) + if ((path_with_url(file_path.data) + || (os_path_exists(file_path.data) && (search_ctx->ffsc_find_what == FINDFILE_BOTH || ((search_ctx->ffsc_find_what == FINDFILE_DIR) - == os_isdir(file_path))))) + == os_isdir(file_path.data))))) #ifndef FF_VERBOSE && (ff_check_visited(&search_ctx->ffsc_visited_list->ffvl_visited_list, - file_path, "") == OK) + file_path.data, file_path.size, "", 0) == OK) #endif ) { #ifdef FF_VERBOSE if (ff_check_visited(&search_ctx->ffsc_visited_list->ffvl_visited_list, - file_path, "") == FAIL) { + file_path.data, file_path.size, "", 0) == FAIL) { if (p_verbose >= 5) { verbose_enter_scroll(); - smsg(0, "Already: %s", file_path); + smsg(0, "Already: %s", file_path.data); msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); } @@ -827,32 +887,37 @@ char *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 (!path_with_url(file_path.data)) { + file_path.size = simplify_filename(file_path.data); } - if (os_dirname(ff_expand_buffer, MAXPATHL) == OK) { - p = path_shorten_fname(file_path, ff_expand_buffer); + + if (os_dirname(ff_expand_buffer.data, MAXPATHL) == OK) { + ff_expand_buffer.size = strlen(ff_expand_buffer.data); + char *p = path_shorten_fname(file_path.data, ff_expand_buffer.data); if (p != NULL) { - STRMOVE(file_path, p); + memmove(file_path.data, p, + (size_t)((file_path.data + file_path.size) - p) + 1); // +1 for NUL + file_path.size -= (size_t)(p - file_path.data); } } #ifdef FF_VERBOSE if (p_verbose >= 5) { verbose_enter_scroll(); - smsg(0, "HIT: %s", file_path); + smsg(0, "HIT: %s", file_path.data); msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); } #endif - return file_path; + return file_path.data; } // Not found or found already, try next suffix. if (*suf == NUL) { break; } - assert(MAXPATHL >= len); - copy_option_part(&suf, file_path + len, MAXPATHL - len, ","); + assert(MAXPATHL >= file_path.size); + file_path.size += copy_option_part(&suf, file_path.data + file_path.size, + MAXPATHL - file_path.size, ","); } } } else { @@ -863,7 +928,9 @@ char *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.data, + rest_of_wildcards.size, stackp->ffs_level - 1, 0)); } } @@ -873,11 +940,11 @@ char *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.data, "**", 2) == 0) { for (int i = stackp->ffs_filearray_cur; i < stackp->ffs_filearray_size; i++) { if (path_fnamecmp(stackp->ffs_filearray[i], - stackp->ffs_fix_path) == 0) { + stackp->ffs_fix_path.data) == 0) { continue; // don't repush same directory } if (!os_isdir(stackp->ffs_filearray[i])) { @@ -885,7 +952,10 @@ char *vim_findfile(void *search_ctx_arg) } ff_push(search_ctx, ff_create_stack_element(stackp->ffs_filearray[i], - stackp->ffs_wc_path, stackp->ffs_level - 1, 1)); + strlen(stackp->ffs_filearray[i]), + stackp->ffs_wc_path.data, + stackp->ffs_wc_path.size, + stackp->ffs_level - 1, 1)); } } @@ -895,45 +965,58 @@ char *vim_findfile(void *search_ctx_arg) // 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.data && search_ctx->ffsc_stopdirs_v != NULL && !got_int) { ff_stack_T *sptr; // path_end may point to the NUL or the previous path separator - ptrdiff_t plen = (path_end - search_ctx->ffsc_start_dir) + (*path_end != NUL); + ptrdiff_t plen = (path_end - search_ctx->ffsc_start_dir.data) + (*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.data, (size_t)plen, search_ctx->ffsc_stopdirs_v)) { break; } // cut of last dir - while (path_end > search_ctx->ffsc_start_dir && vim_ispathsep(*path_end)) { + while (path_end > search_ctx->ffsc_start_dir.data && vim_ispathsep(*path_end)) { path_end--; } - while (path_end > search_ctx->ffsc_start_dir && !vim_ispathsep(path_end[-1])) { + while (path_end > search_ctx->ffsc_start_dir.data && !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.size = (size_t)(path_end - search_ctx->ffsc_start_dir.data); path_end--; - if (*search_ctx->ffsc_start_dir == 0) { + if (*search_ctx->ffsc_start_dir.data == NUL) { break; } - if (strlen(search_ctx->ffsc_start_dir) + 1 - + strlen(search_ctx->ffsc_fix_path) >= MAXPATHL) { + if (search_ctx->ffsc_start_dir.size + 1 + + search_ctx->ffsc_fix_path.size >= MAXPATHL) { goto fail; } - STRCPY(file_path, search_ctx->ffsc_start_dir); - if (!add_pathsep(file_path)) { + bool add_sep = !after_pathsep(search_ctx->ffsc_start_dir.data, + search_ctx->ffsc_start_dir.data + + search_ctx->ffsc_start_dir.size); + file_path.size = (size_t)vim_snprintf(file_path.data, + MAXPATHL, + "%s%s%s", + search_ctx->ffsc_start_dir.data, + add_sep ? PATHSEPSTR : "", + search_ctx->ffsc_fix_path.data); + if (file_path.size >= MAXPATHL) { goto fail; } - strcat(file_path, search_ctx->ffsc_fix_path); // 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.data, + file_path.size, + search_ctx->ffsc_wc_path.data, + search_ctx->ffsc_wc_path.size, + search_ctx->ffsc_level, 0); ff_push(search_ctx, sptr); } else { break; @@ -941,7 +1024,7 @@ char *vim_findfile(void *search_ctx_arg) } fail: - xfree(file_path); + xfree(file_path.data); return NULL; } @@ -988,7 +1071,7 @@ static void ff_free_visited_list(ff_visited_T *vl) /// @return the already visited list for the given filename. If none is found it /// allocates a new one. -static ff_visited_list_hdr_T *ff_get_visited_list(char *filename, +static ff_visited_list_hdr_T *ff_get_visited_list(char *filename, size_t filenamelen, ff_visited_list_hdr_T **list_headp) { ff_visited_list_hdr_T *retptr = NULL; @@ -1025,7 +1108,7 @@ static ff_visited_list_hdr_T *ff_get_visited_list(char *filename, retptr = xmalloc(sizeof(*retptr)); retptr->ffvl_visited_list = NULL; - retptr->ffvl_filename = xstrdup(filename); + retptr->ffvl_filename = xmemdupz(filename, filenamelen); retptr->ffvl_next = *list_headp; *list_headp = retptr; @@ -1074,7 +1157,8 @@ static bool ff_wc_equal(char *s1, char *s2) /// /// @return FAIL if the given file/dir is already in the list or, /// OK if it is newly added -static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_path) +static int ff_check_visited(ff_visited_T **visited_list, char *fname, size_t fnamelen, + char *wc_path, size_t wc_pathlen) { ff_visited_T *vp; bool url = false; @@ -1083,10 +1167,12 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p // For a URL we only compare the name, otherwise we compare the // device/inode. if (path_with_url(fname)) { - xstrlcpy(ff_expand_buffer, fname, MAXPATHL); + xmemcpyz(ff_expand_buffer.data, fname, fnamelen); + ff_expand_buffer.size = fnamelen; url = true; } else { - ff_expand_buffer[0] = NUL; + ff_expand_buffer.data[0] = NUL; + ff_expand_buffer.size = 0; if (!os_fileid(fname, &file_id)) { return FAIL; } @@ -1094,7 +1180,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p // check against list of already visited files for (vp = *visited_list; vp != NULL; vp = vp->ffv_next) { - if ((url && path_fnamecmp(vp->ffv_fname, ff_expand_buffer) == 0) + if ((url && path_fnamecmp(vp->ffv_fname, ff_expand_buffer.data) == 0) || (!url && vp->file_id_valid && os_fileid_equal(&(vp->file_id), &file_id))) { // are the wildcard parts equal @@ -1106,7 +1192,7 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p } // New file/dir. Add it to the list of visited files/dirs. - vp = xmalloc(offsetof(ff_visited_T, ffv_fname) + strlen(ff_expand_buffer) + 1); + vp = xmalloc(offsetof(ff_visited_T, ffv_fname) + ff_expand_buffer.size + 1); if (!url) { vp->file_id_valid = true; @@ -1114,11 +1200,11 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p vp->ffv_fname[0] = NUL; } else { vp->file_id_valid = false; - STRCPY(vp->ffv_fname, ff_expand_buffer); + STRCPY(vp->ffv_fname, ff_expand_buffer.data); } if (wc_path != NULL) { - vp->ffv_wc_path = xstrdup(wc_path); + vp->ffv_wc_path = xmemdupz(wc_path, wc_pathlen); } else { vp->ffv_wc_path = NULL; } @@ -1130,8 +1216,8 @@ static int ff_check_visited(ff_visited_T **visited_list, char *fname, char *wc_p } /// create stack element from given path pieces -static ff_stack_T *ff_create_stack_element(char *fix_part, char *wc_part, int level, - int star_star_empty) +static ff_stack_T *ff_create_stack_element(char *fix_part, size_t fix_partlen, char *wc_part, + size_t wc_partlen, int level, int star_star_empty) { ff_stack_T *stack = xmalloc(sizeof(ff_stack_T)); @@ -1146,13 +1232,15 @@ static ff_stack_T *ff_create_stack_element(char *fix_part, char *wc_part, int le // the following saves NULL pointer checks in vim_findfile if (fix_part == NULL) { fix_part = ""; + fix_partlen = 0; } - stack->ffs_fix_path = xstrdup(fix_part); + stack->ffs_fix_path = cbuf_to_string(fix_part, fix_partlen); if (wc_part == NULL) { wc_part = ""; + wc_partlen = 0; } - stack->ffs_wc_path = xstrdup(wc_part); + stack->ffs_wc_path = cbuf_to_string(wc_part, wc_partlen); return stack; } @@ -1190,9 +1278,9 @@ static void ff_free_stack_element(ff_stack_T *const stack_ptr) return; } - // free handles possible NULL pointers - xfree(stack_ptr->ffs_fix_path); - xfree(stack_ptr->ffs_wc_path); + // API_CLEAR_STRING handles possible NULL pointers + API_CLEAR_STRING(stack_ptr->ffs_fix_path); + API_CLEAR_STRING(stack_ptr->ffs_wc_path); if (stack_ptr->ffs_filearray != NULL) { FreeWild(stack_ptr->ffs_filearray_size, stack_ptr->ffs_filearray); @@ -1211,34 +1299,28 @@ static void ff_clear(ff_search_ctx_T *search_ctx) ff_free_stack_element(sptr); } - xfree(search_ctx->ffsc_file_to_search); - xfree(search_ctx->ffsc_start_dir); - xfree(search_ctx->ffsc_fix_path); - xfree(search_ctx->ffsc_wc_path); - if (search_ctx->ffsc_stopdirs_v != NULL) { int i = 0; - while (search_ctx->ffsc_stopdirs_v[i] != NULL) { - xfree(search_ctx->ffsc_stopdirs_v[i]); + while (search_ctx->ffsc_stopdirs_v[i].data != NULL) { + xfree(search_ctx->ffsc_stopdirs_v[i].data); i++; } - xfree(search_ctx->ffsc_stopdirs_v); + XFREE_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; + API_CLEAR_STRING(search_ctx->ffsc_file_to_search); + API_CLEAR_STRING(search_ctx->ffsc_start_dir); + API_CLEAR_STRING(search_ctx->ffsc_fix_path); + API_CLEAR_STRING(search_ctx->ffsc_wc_path); search_ctx->ffsc_level = 0; } /// check if the given path is in the stopdirs /// /// @return true if yes else false -static bool ff_path_in_stoplist(char *path, size_t path_len, char **stopdirs_v) +static bool ff_path_in_stoplist(char *path, size_t path_len, String *stopdirs_v) { // eat up trailing path separators, except the first while (path_len > 1 && vim_ispathsep(path[path_len - 1])) { @@ -1250,13 +1332,13 @@ static bool ff_path_in_stoplist(char *path, size_t path_len, char **stopdirs_v) return true; } - for (int i = 0; stopdirs_v[i] != NULL; i++) { + for (int i = 0; stopdirs_v[i].data != 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 (path_fnamencmp(stopdirs_v[i], path, path_len) == 0 - && (strlen(stopdirs_v[i]) <= path_len - || vim_ispathsep(stopdirs_v[i][path_len]))) { + if (path_fnamencmp(stopdirs_v[i].data, path, path_len) == 0 + && (stopdirs_v[i].size <= path_len + || vim_ispathsep(stopdirs_v[i].data[path_len]))) { return true; } } @@ -1307,7 +1389,7 @@ char *find_file_in_path(char *ptr, size_t len, int options, int first, char *rel #if defined(EXITFREE) void free_findfile(void) { - XFREE_CLEAR(ff_expand_buffer); + API_CLEAR_STRING(ff_expand_buffer); } #endif @@ -1351,7 +1433,7 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch static char *dir; static bool did_findfile_init = false; char *file_name = NULL; - char *buf = NULL; + static size_t file_to_findlen = 0; if (rel_fname != NULL && path_with_url(rel_fname)) { // Do not attempt to search "relative" to a URL. #6009 @@ -1370,12 +1452,15 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch ptr[len] = save_char; xfree(*file_to_find); - *file_to_find = xstrdup(NameBuff); + file_to_findlen = strlen(NameBuff); + *file_to_find = xmemdupz(NameBuff, file_to_findlen); if (options & FNAME_UNESC) { // Change all "\ " to " ". for (ptr = *file_to_find; *ptr != NUL; ptr++) { if (ptr[0] == '\\' && ptr[1] == ' ') { - memmove(ptr, ptr + 1, strlen(ptr)); + memmove(ptr, ptr + 1, + (size_t)((*file_to_find + file_to_findlen) - (ptr + 1)) + 1); + file_to_findlen--; } } } @@ -1402,42 +1487,48 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch // filename on the first call. if (first == true) { if (path_with_url(*file_to_find)) { - file_name = xstrdup(*file_to_find); + file_name = xmemdupz(*file_to_find, file_to_findlen); goto theend; } + size_t rel_fnamelen = rel_fname != NULL ? strlen(rel_fname) : 0; + // When FNAME_REL flag given first use the directory of the file. // Otherwise or when this fails use the current directory. for (int run = 1; run <= 2; run++) { - size_t l = strlen(*file_to_find); + size_t l = file_to_findlen; if (run == 1 && rel_to_curdir && (options & FNAME_REL) && rel_fname != NULL - && strlen(rel_fname) + l < MAXPATHL) { - STRCPY(NameBuff, rel_fname); - STRCPY(path_tail(NameBuff), *file_to_find); - l = strlen(NameBuff); + && rel_fnamelen + l < MAXPATHL) { + l = (size_t)vim_snprintf(NameBuff, + MAXPATHL, + "%.*s%s", + (int)(path_tail(rel_fname) - rel_fname), + rel_fname, + *file_to_find); + assert(l < MAXPATHL); } else { STRCPY(NameBuff, *file_to_find); run = 2; } // When the file doesn't exist, try adding parts of 'suffixesadd'. - buf = suffixes; + char *suffix = suffixes; while (true) { if ((os_path_exists(NameBuff) && (find_what == FINDFILE_BOTH || ((find_what == FINDFILE_DIR) == os_isdir(NameBuff))))) { - file_name = xstrdup(NameBuff); + file_name = xmemdupz(NameBuff, l); goto theend; } - if (*buf == NUL) { + if (*suffix == NUL) { break; } assert(MAXPATHL >= l); - copy_option_part(&buf, NameBuff + l, MAXPATHL - l, ","); + l += copy_option_part(&suffix, NameBuff + l, MAXPATHL - l, ","); } } } @@ -1470,15 +1561,15 @@ char *find_file_in_path_option(char *ptr, size_t len, int options, int first, ch break; } - buf = xmalloc(MAXPATHL); + char *buf = xmalloc(MAXPATHL); // 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) { @@ -1618,19 +1709,24 @@ char *file_name_in_line(char *line, int col, int options, int count, char *rel_f } if (file_lnum != NULL) { - const char *line_english = " line "; - const char *line_transl = _(line_msg); + const 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(). char *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 (!isdigit((uint8_t)(*p))) { |