diff options
Diffstat (limited to 'src/nvim/path.c')
| -rw-r--r-- | src/nvim/path.c | 135 | 
1 files changed, 98 insertions, 37 deletions
| diff --git a/src/nvim/path.c b/src/nvim/path.c index 6bf42ed2fa..4f3f7c0661 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +  #include <assert.h>  #include <inttypes.h>  #include <stdbool.h> @@ -329,7 +332,7 @@ int path_fnamencmp(const char *const fname1, const char *const fname2,          && (p_fic ? (c1 != c2 && CH_FOLD(c1) != CH_FOLD(c2)) : c1 != c2)) {        break;      } -    len -= MB_PTR2LEN((const char_u *)p1); +    len -= (size_t)MB_PTR2LEN((const char_u *)p1);      p1 += MB_PTR2LEN((const char_u *)p1);      p2 += MB_PTR2LEN((const char_u *)p2);    } @@ -432,7 +435,7 @@ bool add_pathsep(char *p)  /// @return [allocated] Copy of absolute path to `fname` or NULL when  ///                     `fname` is NULL.  char *FullName_save(const char *fname, bool force) -  FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC +  FUNC_ATTR_MALLOC  {    if (fname == NULL) {      return NULL; @@ -449,10 +452,10 @@ char *FullName_save(const char *fname, bool force)  /// Saves the absolute path.  /// @param name An absolute or relative path.  /// @return The absolute path of `name`. -char_u *save_absolute_path(const char_u *name) -  FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL +char_u *save_abs_path(const char_u *name) +  FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL  { -  if (!path_is_absolute_path(name)) { +  if (!path_is_absolute(name)) {      return (char_u *)FullName_save((char *)name, true);    }    return vim_strsave((char_u *) name); @@ -670,11 +673,12 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,      // Find all matching entries.      char_u *name;      scandir_next_with_dots(NULL);  // initialize -    while ((name = (char_u *) scandir_next_with_dots(&dir)) && name != NULL) { +    while ((name = (char_u *)scandir_next_with_dots(&dir)) != NULL) {        if ((name[0] != '.'             || starts_with_dot             || ((flags & EW_DODOT) -               && name[1] != NUL && (name[1] != '.' || name[2] != NUL))) +               && name[1] != NUL +               && (name[1] != '.' || name[2] != NUL)))  // -V557            && ((regmatch.regprog != NULL && vim_regexec(®match, name, 0))                || ((flags & EW_NOTWILD)                    && fnamencmp(path + (s - buf), name, e - s) == 0))) { @@ -811,7 +815,7 @@ static void expand_path_option(char_u *curdir, garray_T *gap)        STRCPY(buf, curdir);  // relative to current directory      } else if (path_with_url((char *)buf)) {        continue;  // URL can't be used here -    } else if (!path_is_absolute_path(buf)) { +    } else if (!path_is_absolute(buf)) {        // Expand relative path to their full path equivalent        size_t len = STRLEN(curdir);        if (len + STRLEN(buf) + 3 > MAXPATHL) { @@ -946,19 +950,17 @@ static void uniquefy_paths(garray_T *gap, char_u *pattern)        }      } -    if (path_is_absolute_path(path)) { -      /* -       * Last resort: shorten relative to curdir if possible. -       * 'possible' means: -       * 1. It is under the current directory. -       * 2. The result is actually shorter than the original. -       * -       *	    Before		  curdir	After -       *	    /foo/bar/file.txt	  /foo/bar	./file.txt -       *	    c:\foo\bar\file.txt   c:\foo\bar	.\file.txt -       *	    /file.txt		  /		/file.txt -       *	    c:\file.txt		  c:\		.\file.txt -       */ +    if (path_is_absolute(path)) { +      // Last resort: shorten relative to curdir if possible. +      // 'possible' means: +      // 1. It is under the current directory. +      // 2. The result is actually shorter than the original. +      // +      //     Before                curdir        After +      //     /foo/bar/file.txt     /foo/bar      ./file.txt +      //     c:\foo\bar\file.txt   c:\foo\bar    .\file.txt +      //     /file.txt             /             /file.txt +      //     c:\file.txt           c:\           .\file.txt        short_name = path_shorten_fname(path, curdir);        if (short_name != NULL && short_name > path + 1            ) { @@ -1218,7 +1220,7 @@ int gen_expand_wildcards(int num_pat, char_u **pat, int *num_file,         */        if (path_has_exp_wildcard(p)) {          if ((flags & EW_PATH) -            && !path_is_absolute_path(p) +            && !path_is_absolute(p)              && !(p[0] == '.'                   && (vim_ispathsep(p[1])                       || (p[1] == '.' && vim_ispathsep(p[2])))) @@ -1664,7 +1666,7 @@ int path_with_url(const char *fname)   */  bool vim_isAbsName(char_u *name)  { -  return path_with_url((char *)name) != 0 || path_is_absolute_path(name); +  return path_with_url((char *)name) != 0 || path_is_absolute(name);  }  /// Save absolute file name to "buf[len]". @@ -1687,6 +1689,9 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)    if (strlen(fname) > (len - 1)) {      xstrlcpy(buf, fname, len);  // truncate +#ifdef WIN32 +    slash_adjust((char_u *)buf); +#endif      return FAIL;    } @@ -1695,10 +1700,13 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)      return OK;    } -  int rv = path_get_absolute_path((char_u *)fname, (char_u *)buf, len, force); +  int rv = path_to_absolute((char_u *)fname, (char_u *)buf, len, force);    if (rv == FAIL) {      xstrlcpy(buf, fname, len);  // something failed; use the filename    } +#ifdef WIN32 +  slash_adjust((char_u *)buf); +#endif    return rv;  } @@ -1712,7 +1720,7 @@ int vim_FullName(const char *fname, char *buf, size_t len, bool force)  ///  /// @param fname is the filename to expand  /// @return [allocated] Full path (NULL for failure). -char *fix_fname(char *fname) +char *fix_fname(const char *fname)  {  #ifdef UNIX    return FullName_save(fname, true); @@ -1732,7 +1740,7 @@ char *fix_fname(char *fname)    path_fix_case((char_u *)fname);  // set correct case for file name  # endif -  return fname; +  return (char *)fname;  #endif  } @@ -1853,7 +1861,7 @@ int pathcmp(const char *p, const char *q, int maxlen)        break;      } -    if ((p_fic ? vim_toupper(c1) != vim_toupper(c2) : c1 != c2) +    if ((p_fic ? mb_toupper(c1) != mb_toupper(c2) : c1 != c2)  #ifdef BACKSLASH_IN_FILENAME          /* consider '/' and '\\' to be equal */          && !((c1 == '/' && c2 == '\\') @@ -1864,8 +1872,8 @@ int pathcmp(const char *p, const char *q, int maxlen)          return -1;        if (vim_ispathsep(c2))          return 1; -      return p_fic ? vim_toupper(c1) - vim_toupper(c2) -             : c1 - c2;         /* no match */ +      return p_fic ? mb_toupper(c1) - mb_toupper(c2) +                   : c1 - c2;  // no match      }      i += MB_PTR2LEN((char_u *)p + i); @@ -1901,7 +1909,7 @@ int pathcmp(const char *p, const char *q, int maxlen)  ///   - Pointer into `full_path` if shortened.  ///   - `full_path` unchanged if no shorter name is possible.  ///   - NULL if `full_path` is NULL. -char_u *path_shorten_fname_if_possible(char_u *full_path) +char_u *path_try_shorten_fname(char_u *full_path)  {    char_u *dirname = xmalloc(MAXPATHL);    char_u *p = full_path; @@ -2182,8 +2190,8 @@ int append_path(char *path, const char *to_append, size_t max_len)  /// @param  force  also expand when "fname" is already absolute.  ///  /// @return FAIL for failure, OK for success. -static int path_get_absolute_path(const char_u *fname, char_u *buf, -                                  size_t len, int force) +static int path_to_absolute(const char_u *fname, char_u *buf, size_t len, +                            int force)  {    char_u *p;    *buf = NUL; @@ -2192,12 +2200,18 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,    char *end_of_path = (char *) fname;    // expand it if forced or not an absolute path -  if (force || !path_is_absolute_path(fname)) { -    if ((p = vim_strrchr(fname, '/')) != NULL) { +  if (force || !path_is_absolute(fname)) { +    p = vim_strrchr(fname, '/'); +#ifdef WIN32 +    if (p == NULL) { +      p = vim_strrchr(fname, '\\'); +    } +#endif +    if (p != NULL) {        // relative to root        if (p == fname) {          // only one path component -        relative_directory[0] = '/'; +        relative_directory[0] = PATHSEP;          relative_directory[1] = NUL;        } else {          assert(p >= fname); @@ -2219,10 +2233,10 @@ static int path_get_absolute_path(const char_u *fname, char_u *buf,    return append_path((char *)buf, end_of_path, len);  } -/// Check if the given file is absolute. +/// Check if file `fname` is a full (absolute) path.  ///  /// @return `TRUE` if "fname" is absolute. -int path_is_absolute_path(const char_u *fname) +int path_is_absolute(const char_u *fname)  {  #ifdef WIN32    // A name like "d:/foo" and "//server/share" is absolute @@ -2234,3 +2248,50 @@ int path_is_absolute_path(const char_u *fname)    return *fname == '/' || *fname == '~';  #endif  } + +/// Builds a full path from an invocation name `argv0`, based on heuristics. +/// +/// @param[in]  argv0     Name by which Nvim was invoked. +/// @param[out] buf       Guessed full path to `argv0`. +/// @param[in]  bufsize   Size of `buf`. +/// +/// @see os_exepath +void path_guess_exepath(const char *argv0, char *buf, size_t bufsize) +  FUNC_ATTR_NONNULL_ALL +{ +  char *path = getenv("PATH"); + +  if (path == NULL || path_is_absolute((char_u *)argv0)) { +    xstrlcpy(buf, argv0, bufsize); +  } else if (argv0[0] == '.' || strchr(argv0, PATHSEP)) { +    // Relative to CWD. +    if (os_dirname((char_u *)buf, MAXPATHL) != OK) { +      buf[0] = NUL; +    } +    xstrlcat(buf, PATHSEPSTR, bufsize); +    xstrlcat(buf, argv0, bufsize); +  } else { +    // Search $PATH for plausible location. +    const void *iter = NULL; +    do { +      const char *dir; +      size_t dir_len; +      iter = vim_env_iter(ENV_SEPCHAR, path, iter, &dir, &dir_len); +      if (dir == NULL || dir_len == 0) { +        break; +      } +      if (dir_len + 1 > sizeof(NameBuff)) { +        continue; +      } +      xstrlcpy((char *)NameBuff, dir, dir_len + 1); +      xstrlcat((char *)NameBuff, PATHSEPSTR, sizeof(NameBuff)); +      xstrlcat((char *)NameBuff, argv0, sizeof(NameBuff)); +      if (os_can_exe(NameBuff, NULL, false)) { +        xstrlcpy(buf, (char *)NameBuff, bufsize); +        return; +      } +    } while (iter != NULL); +    // Not found in $PATH, fall back to argv0. +    xstrlcpy(buf, argv0, bufsize); +  } +} | 
