diff options
| author | Thiago de Arruda <tpadilha84@gmail.com> | 2015-03-31 11:50:22 -0300 | 
|---|---|---|
| committer | Thiago de Arruda <tpadilha84@gmail.com> | 2015-03-31 11:50:39 -0300 | 
| commit | ad7a317c42b7eb4d27a888f217750a4f4bb67bc8 (patch) | |
| tree | 6a2e7808d6064a556dfc81320775fddb79257b7c /src | |
| parent | 27ead64da044f841515d52e273dc3f963e6c678c (diff) | |
| parent | feca9624b8bec45ecd112aab8495143e8ed3e3a4 (diff) | |
| download | rneovim-ad7a317c42b7eb4d27a888f217750a4f4bb67bc8.tar.gz rneovim-ad7a317c42b7eb4d27a888f217750a4f4bb67bc8.tar.bz2 rneovim-ad7a317c42b7eb4d27a888f217750a4f4bb67bc8.zip | |
Merge PR #1212 'os_scandir/scandir_next/closedir()'
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/buffer.c | 2 | ||||
| -rw-r--r-- | src/nvim/charset.c | 5 | ||||
| -rw-r--r-- | src/nvim/eval.c | 2 | ||||
| -rw-r--r-- | src/nvim/ex_cmds.c | 2 | ||||
| -rw-r--r-- | src/nvim/ex_docmd.c | 4 | ||||
| -rw-r--r-- | src/nvim/main.c | 4 | ||||
| -rw-r--r-- | src/nvim/os/fs.c | 33 | ||||
| -rw-r--r-- | src/nvim/os/fs_defs.h | 5 | ||||
| -rw-r--r-- | src/nvim/os_unix.c | 93 | ||||
| -rw-r--r-- | src/nvim/os_unix_defs.h | 19 | ||||
| -rw-r--r-- | src/nvim/path.c | 221 | ||||
| -rw-r--r-- | src/nvim/tag.c | 2 | 
12 files changed, 206 insertions, 186 deletions
| diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index dd20d61f75..11cb7bdeac 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -2253,7 +2253,7 @@ setfname (      }      sfname = vim_strsave(sfname);  #ifdef USE_FNAME_CASE -    fname_case(sfname, 0);            /* set correct case for short file name */ +    path_fix_case(sfname);            /* set correct case for short file name */  #endif      free(buf->b_ffname);      free(buf->b_sfname); diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 5e11e202a3..4633bacb78 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -24,6 +24,7 @@  #include "nvim/move.h"  #include "nvim/os_unix.h"  #include "nvim/strings.h" +#include "nvim/path.h"  #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -871,7 +872,7 @@ int vim_isfilec(int c)  /// return TRUE if 'c' is a valid file-name character or a wildcard character  /// Assume characters above 0x100 are valid (multi-byte). -/// Explicitly interpret ']' as a wildcard character as mch_has_wildcard("]") +/// Explicitly interpret ']' as a wildcard character as path_has_wildcard("]")  /// returns false.  ///  /// @param c @@ -882,7 +883,7 @@ int vim_isfilec_or_wc(int c)    char_u buf[2];    buf[0] = (char_u)c;    buf[1] = NUL; -  return vim_isfilec(c) || c == ']' || mch_has_wildcard(buf); +  return vim_isfilec(c) || c == ']' || path_has_wildcard(buf);  }  /// return TRUE if 'c' is a printable character diff --git a/src/nvim/eval.c b/src/nvim/eval.c index deeca10310..9d8421ef04 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -9895,9 +9895,7 @@ static void f_has(typval_T *argvars, typval_T *rettv)  #if defined(WIN64) || defined(_WIN64)      "win64",  #endif -#ifndef CASE_INSENSITIVE_FILENAME      "fname_case", -#endif  #ifdef HAVE_ACL      "acl",  #endif diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 81c7ecab5f..e687eab3c4 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -2563,7 +2563,7 @@ do_ecmd (        sfname = ffname;  #ifdef USE_FNAME_CASE      if (sfname != NULL) -      fname_case(sfname, 0);             /* set correct case for sfname */ +      path_fix_case(sfname);             // set correct case for sfname  #endif      if ((flags & ECMD_ADDBUF) && (ffname == NULL || *ffname == NUL)) diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 776ed844e9..db4f3a54f1 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3432,7 +3432,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)     * the file name contains a wildcard it should not cause expanding.     * (it will be expanded anyway if there is a wildcard before replacing).     */ -  has_wildcards = mch_has_wildcard(p); +  has_wildcards = path_has_wildcard(p);    while (*p != NUL) {      /* Skip over `=expr`, wildcards in it are not expanded. */      if (p[0] == '`' && p[1] == '=') { @@ -3543,7 +3543,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp)            || vim_strchr(eap->arg, '~') != NULL) {          expand_env_esc(eap->arg, NameBuff, MAXPATHL,              TRUE, TRUE, NULL); -        has_wildcards = mch_has_wildcard(NameBuff); +        has_wildcards = path_has_wildcard(NameBuff);          p = NameBuff;        } else          p = NULL; diff --git a/src/nvim/main.c b/src/nvim/main.c index 55935564b8..a03fd2e8a9 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1290,8 +1290,8 @@ scripterror:        }  #ifdef USE_FNAME_CASE -      /* Make the case of the file name match the actual file. */ -      fname_case(p, 0); +      // Make the case of the file name match the actual file. +      path_fix_case(p);  #endif        alist_add(&global_alist, p, diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 6200685076..d583323b1f 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -348,6 +348,39 @@ int os_rmdir(const char *path)    return result;  } +/// Opens a directory. +/// @param[out] dir   The Directory object. +/// @param      path  Path to the directory. +/// @returns true if dir contains one or more items, false if not or an error +///          occurred. +bool os_scandir(Directory *dir, const char *path) +  FUNC_ATTR_NONNULL_ALL +{ +  int r = uv_fs_scandir(uv_default_loop(), &dir->request, path, 0, NULL); +  if (r <= 0) { +    os_closedir(dir); +  } +  return r > 0; +} + +/// Increments the directory pointer. +/// @param dir  The Directory object. +/// @returns a pointer to the next path in `dir` or `NULL`. +const char *os_scandir_next(Directory *dir) +  FUNC_ATTR_NONNULL_ALL +{ +  int err = uv_fs_scandir_next(&dir->request, &dir->ent); +  return err != UV_EOF ? dir->ent.name : NULL; +} + +/// Frees memory associated with `os_scandir()`. +/// @param dir  The directory. +void os_closedir(Directory *dir) +  FUNC_ATTR_NONNULL_ALL +{ +  uv_fs_req_cleanup(&dir->request); +} +  /// Remove a file.  ///  /// @return `0` for success, non-zero for failure. diff --git a/src/nvim/os/fs_defs.h b/src/nvim/os/fs_defs.h index e4d79aab66..ddd382a3cb 100644 --- a/src/nvim/os/fs_defs.h +++ b/src/nvim/os/fs_defs.h @@ -16,4 +16,9 @@ typedef struct {  #define FILE_ID_EMPTY (FileID) {.inode = 0, .device_id = 0} +typedef struct { +  uv_fs_t request;  ///< @private The request to uv for the directory. +  uv_dirent_t ent;  ///< @private The entry information. +} Directory; +  #endif  // NVIM_OS_FS_DEFS_H diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index 8e4569033a..70cafc62ca 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -69,62 +69,6 @@ static int selinux_enabled = -1;  # include "os_unix.c.generated.h"  #endif -#if defined(USE_FNAME_CASE) -/* - * Set the case of the file name, if it already exists.  This will cause the - * file name to remain exactly the same. - * Only required for file systems where case is ignored and preserved. - */ -void fname_case( -char_u      *name, -int len               /* buffer size, only used when name gets longer */ -) -{ -  char_u      *slash, *tail; -  DIR         *dirp; -  struct dirent *dp; - -  FileInfo file_info; -  if (os_fileinfo_link((char *)name, &file_info)) { -    /* Open the directory where the file is located. */ -    slash = vim_strrchr(name, '/'); -    if (slash == NULL) { -      dirp = opendir("."); -      tail = name; -    } else { -      *slash = NUL; -      dirp = opendir((char *)name); -      *slash = '/'; -      tail = slash + 1; -    } - -    if (dirp != NULL) { -      while ((dp = readdir(dirp)) != NULL) { -        /* Only accept names that differ in case and are the same byte -         * length. TODO: accept different length name. */ -        if (STRICMP(tail, dp->d_name) == 0 -            && STRLEN(tail) == STRLEN(dp->d_name)) { -          char_u newname[MAXPATHL + 1]; - -          /* Verify the inode is equal. */ -          STRLCPY(newname, name, MAXPATHL + 1); -          STRLCPY(newname + (tail - name), dp->d_name, -              MAXPATHL - (tail - name) + 1); -          FileInfo file_info_new; -          if (os_fileinfo_link((char *)newname, &file_info_new) -              && os_fileinfo_id_equal(&file_info, &file_info_new)) { -            STRCPY(tail, dp->d_name); -            break; -          } -        } -      } - -      closedir(dirp); -    } -  } -} -#endif -  #if defined(HAVE_ACL)  # ifdef HAVE_SYS_ACL_H  #  include <sys/acl.h> @@ -719,47 +663,12 @@ static void save_patterns(int num_pat, char_u **pat, int *num_file,    *num_file = num_pat;  } -/* - * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can - * expand. - */ -int mch_has_exp_wildcard(char_u *p) -{ -  for (; *p; mb_ptr_adv(p)) { -    if (*p == '\\' && p[1] != NUL) -      ++p; -    else if (vim_strchr((char_u *) -                 "*?[{'" -                 , *p) != NULL) -      return TRUE; -  } -  return FALSE; -} - -/* - * Return TRUE if the string "p" contains a wildcard. - * Don't recognize '~' at the end as a wildcard. - */ -int mch_has_wildcard(char_u *p) -{ -  for (; *p; mb_ptr_adv(p)) { -    if (*p == '\\' && p[1] != NUL) -      ++p; -    else if (vim_strchr((char_u *) -                 "*?[{`'$" -                 , *p) != NULL -             || (*p == '~' && p[1] != NUL)) -      return TRUE; -  } -  return FALSE; -} -  static int have_wildcard(int num, char_u **file)  {    int i;    for (i = 0; i < num; i++) -    if (mch_has_wildcard(file[i])) +    if (path_has_wildcard(file[i]))        return 1;    return 0;  } diff --git a/src/nvim/os_unix_defs.h b/src/nvim/os_unix_defs.h index 4ffd23aa25..24b069b090 100644 --- a/src/nvim/os_unix_defs.h +++ b/src/nvim/os_unix_defs.h @@ -44,25 +44,6 @@  # define SIGDUMMYARG  #endif -#ifdef HAVE_DIRENT_H -# include <dirent.h> -# ifndef NAMLEN -#  define NAMLEN(dirent) strlen((dirent)->d_name) -# endif -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# if HAVE_SYS_NDIR_H -#  include <sys/ndir.h> -# endif -# if HAVE_SYS_DIR_H -#  include <sys/dir.h> -# endif -# if HAVE_NDIR_H -#  include <ndir.h> -# endif -#endif -  #if !defined(HAVE_SYS_TIME_H) || defined(TIME_WITH_SYS_TIME)  # include <time.h>          /* on some systems time.h should not be                                 included together with sys/time.h */ diff --git a/src/nvim/path.c b/src/nvim/path.c index 346be9108d..e83b4e44ed 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -400,6 +400,32 @@ char_u *save_absolute_path(const char_u *name)    return vim_strsave((char_u *) name);  } +/// Checks if a path has a wildcard character including '~', unless at the end. +/// @param p  The path to expand. +/// @returns Unix: True if it contains one of "?[{`'$". +/// @returns Windows: True if it contains one of "*?$[". +bool path_has_wildcard(const char_u *p) +  FUNC_ATTR_NONNULL_ALL +{ +  for (; *p; mb_ptr_adv(p)) { +#if defined(UNIX) +    if (p[0] == '\\' && p[1] != NUL) { +      p++; +      continue; +    } + +    const char *wildcards = "*?[{`'$"; +#else +    // Windows: +    const char *wildcards = "?*$[`"; +#endif +    if (vim_strchr((char_u *)wildcards, *p) != NULL +        || (p[0] == '~' && p[1] != NUL)) { +      return true; +    } +  } +  return false; +}  #if defined(UNIX)  /* @@ -410,39 +436,67 @@ static int pstrcmp(const void *a, const void *b)  {    return pathcmp(*(char **)a, *(char **)b, -1);  } +#endif -/* - * Recursively expand one path component into all matching files and/or - * directories.  Adds matches to "gap".  Handles "*", "?", "[a-z]", "**", etc. - * "path" has backslashes before chars that are not to be expanded, starting - * at "path + wildoff". - * Return the number of matches found. - * NOTE: much of this is identical to dos_expandpath(), keep in sync! - */ -int  -unix_expandpath ( -    garray_T *gap, -    char_u *path, -    int wildoff, -    int flags,                      /* EW_* flags */ -    int didstar                    /* expanded "**" once already */ -) +/// Checks if a path has a character path_expand can expand. +/// @param p  The path to expand. +/// @returns Unix: True if it contains one of *?[{. +/// @returns Windows: True if it contains one of *?[. +bool path_has_exp_wildcard(const char_u *p) +  FUNC_ATTR_NONNULL_ALL +{ +  for (; *p != NUL; mb_ptr_adv(p)) { +#if defined(UNIX) +    if (p[0] == '\\' && p[1] != NUL) { +      p++; +      continue; +    } + +    const char *wildcards = "*?[{"; +#else +    const char *wildcards = "*?[";  // Windows. +#endif +    if (vim_strchr((char_u *) wildcards, *p) != NULL) { +      return true; +    } +  } +  return false; +} + +/// Recursively expands one path component into all matching files and/or +/// directories. Handles "*", "?", "[a-z]", "**", etc. +/// @remark "**" in `path` requests recursive expansion. +/// +/// @param[out] gap  The matches found. +/// @param path     The path to search. +/// @param flags    Flags for regexp expansion. +///   - EW_ICASE: Ignore case. +///   - EW_NOERROR: Silence error messeges. +///   - EW_NOTWILD: Add matches literally. +/// @returns the number of matches found. +static size_t path_expand(garray_T *gap, const char_u *path, int flags) +  FUNC_ATTR_NONNULL_ALL +{ +  return do_path_expand(gap, path, 0, flags, false); +} + +/// Implementation of path_expand(). +/// +/// Chars before `path + wildoff` do not get expanded. +static size_t do_path_expand(garray_T *gap, const char_u *path, +                             size_t wildoff, int flags, bool didstar) +  FUNC_ATTR_NONNULL_ALL  {    char_u      *buf; -  char_u      *path_end;    char_u      *p, *s, *e;    int start_len = gap->ga_len;    char_u      *pat; -  regmatch_T regmatch;    int starts_with_dot;    int matches;    int len;    int starstar = FALSE;    static int stardepth = 0;         /* depth for "**" expansion */ -  DIR         *dirp; -  struct dirent *dp; -    /* Expanding "**" may take a long time, check for CTRL-C. */    if (stardepth > 0) {      os_breakcheck(); @@ -461,7 +515,7 @@ unix_expandpath (    p = buf;    s = buf;    e = NULL; -  path_end = path; +  const char_u *path_end = path;    while (*path_end != NUL) {      /* May ignore a wildcard that has a backslash before it; it will       * be removed by rem_backslash() or file_pat_to_reg_pat() below. */ @@ -510,11 +564,14 @@ unix_expandpath (      return 0;    } -  /* compile the regexp into a program */ -  if (flags & EW_ICASE) -    regmatch.rm_ic = TRUE;              /* 'wildignorecase' set */ -  else -    regmatch.rm_ic = p_fic;     /* ignore case when 'fileignorecase' is set */ +  // compile the regexp into a program +  regmatch_T regmatch; +#if defined(UNIX) +  // Ignore case if given 'wildignorecase', else respect 'fileignorecase'. +  regmatch.rm_ic = (flags & EW_ICASE) || p_fic; +#else +  regmatch.rm_ic = true;  // Always ignore case on Windows. +#endif    if (flags & (EW_NOERROR | EW_NOTWILD))      ++emsg_silent;    regmatch.regprog = vim_regcomp(pat, RE_MAGIC); @@ -533,26 +590,22 @@ unix_expandpath (        && *path_end == '/') {      STRCPY(s, path_end + 1);      ++stardepth; -    (void)unix_expandpath(gap, buf, (int)(s - buf), flags, TRUE); +    (void)do_path_expand(gap, buf, (int)(s - buf), flags, TRUE);      --stardepth;    } - -  /* open the directory for scanning */    *s = NUL; -  dirp = opendir(*buf == NUL ? "." : (char *)buf); -  /* Find all matching entries */ -  if (dirp != NULL) { -    for (;; ) { -      dp = readdir(dirp); -      if (dp == NULL) -        break; -      if ((dp->d_name[0] != '.' || starts_with_dot) -          && ((regmatch.regprog != NULL && vim_regexec(®match, -                   (char_u *)dp->d_name, (colnr_T)0)) +  Directory dir; +  // open the directory for scanning +  if (os_scandir(&dir, *buf == NUL ? "." : (char *)buf)) { +    // Find all matching entries. +    char_u *name; +    while((name = (char_u *) os_scandir_next(&dir))) { +      if ((name[0] != '.' || starts_with_dot) +          && ((regmatch.regprog != NULL && vim_regexec(®match, name, 0))                || ((flags & EW_NOTWILD) -                  && fnamencmp(path + (s - buf), dp->d_name, e - s) == 0))) { -        STRCPY(s, dp->d_name); +                  && fnamencmp(path + (s - buf), name, e - s) == 0))) { +        STRCPY(s, name);          len = STRLEN(buf);          if (starstar && stardepth < 100) { @@ -561,15 +614,15 @@ unix_expandpath (            STRCPY(buf + len, "/**");            STRCPY(buf + len + 3, path_end);            ++stardepth; -          (void)unix_expandpath(gap, buf, len + 1, flags, TRUE); +          (void)do_path_expand(gap, buf, len + 1, flags, true);            --stardepth;          }          STRCPY(buf + len, path_end); -        if (mch_has_exp_wildcard(path_end)) {       /* handle more wildcards */ +        if (path_has_exp_wildcard(path_end)) {      /* handle more wildcards */            /* need to expand another component of the path */            /* remove backslashes for the remaining components only */ -          (void)unix_expandpath(gap, buf, len + 1, flags, FALSE); +          (void)do_path_expand(gap, buf, len + 1, flags, false);          } else {            /* no more wildcards, check if there is a match */            /* remove backslashes for the remaining components only */ @@ -581,8 +634,7 @@ unix_expandpath (          }        }      } - -    closedir(dirp); +    os_closedir(&dir);    }    free(buf); @@ -594,7 +646,6 @@ unix_expandpath (          sizeof(char_u *), pstrcmp);    return matches;  } -#endif  /*   * Moves "*psep" back to the previous path separator in "path". @@ -1078,7 +1129,7 @@ gen_expand_wildcards (         * If there are no wildcards: Add the file name if it exists or         * when EW_NOTFOUND is given.         */ -      if (mch_has_exp_wildcard(p)) { +      if (path_has_exp_wildcard(p)) {          if ((flags & EW_PATH)              && !path_is_absolute_path(p)              && !(p[0] == '.' @@ -1092,7 +1143,7 @@ gen_expand_wildcards (            recursive = TRUE;            did_expand_in_path = TRUE;          } else -          add_pat = mch_expandpath(&ga, p, flags); +          add_pat = path_expand(&ga, p, flags);        }      } @@ -1566,13 +1617,68 @@ char_u *fix_fname(char_u *fname)    fname = vim_strsave(fname);  # ifdef USE_FNAME_CASE -  fname_case(fname, 0);  // set correct case for file name +  path_fix_case(fname);  // set correct case for file name  # endif    return fname;  #endif  } +/// Set the case of the file name, if it already exists.  This will cause the +/// file name to remain exactly the same. +/// Only required for file systems where case is ignored and preserved. +// TODO(SplinterOfChaos): Could also be used when mounting case-insensitive +// file systems. +void path_fix_case(char_u *name) +  FUNC_ATTR_NONNULL_ALL +{ +  FileInfo file_info; +  if (!os_fileinfo_link((char *)name, &file_info)) { +    return; +  } + +  // Open the directory where the file is located. +  char_u *slash = vim_strrchr(name, '/'); +  char_u *tail; +  Directory dir; +  bool ok; +  if (slash == NULL) { +    ok = os_scandir(&dir, "."); +    tail = name; +  } else { +    *slash = NUL; +    ok = os_scandir(&dir, (char *) name); +    *slash = '/'; +    tail = slash + 1; +  } + +  if (!ok) { +    return; +  } + +  char_u *entry; +  while ((entry = (char_u *) os_scandir_next(&dir))) { +    // Only accept names that differ in case and are the same byte +    // length. TODO: accept different length name. +    if (STRICMP(tail, entry) == 0 && STRLEN(tail) == STRLEN(entry)) { +      char_u newname[MAXPATHL + 1]; + +      // Verify the inode is equal. +      STRLCPY(newname, name, MAXPATHL + 1); +      STRLCPY(newname + (tail - name), entry, +              MAXPATHL - (tail - name) + 1); +      FileInfo file_info_new; +      if (os_fileinfo_link((char *)newname, &file_info_new) +          && os_fileinfo_id_equal(&file_info, &file_info_new)) { +        STRCPY(tail, entry); +        break; +      } +    } +  } + +  os_closedir(&dir); +} +  /*   * Return TRUE if "p" points to just after a path separator.   * Takes care of multi-byte characters. @@ -1670,19 +1776,6 @@ int pathcmp(const char *p, const char *q, int maxlen)    return 1;  } -/* - * Expand a path into all matching files and/or directories.  Handles "*", - * "?", "[a-z]", "**", etc. - * "path" has backslashes before chars that are not to be expanded. - * Returns the number of matches found. - * - * Uses EW_* flags - */ -int mch_expandpath(garray_T *gap, char_u *path, int flags) -{ -  return unix_expandpath(gap, path, 0, flags, FALSE); -} -  /// Try to find a shortname by comparing the fullname with the current  /// directory.  /// diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 361afb7e07..1f6b42d9cf 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -2587,7 +2587,7 @@ static char_u *expand_tag_fname(char_u *fname, char_u *tag_fname, int expand)    /*     * Expand file name (for environment variables) when needed.     */ -  if (expand && mch_has_wildcard(fname)) { +  if (expand && path_has_wildcard(fname)) {      ExpandInit(&xpc);      xpc.xp_context = EXPAND_FILES;      expanded_fname = ExpandOne(&xpc, fname, NULL, | 
