summaryrefslogtreecommitdiffstats
path: root/src/filepath.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-06-01 16:09:41 +0200
committerBram Moolenaar <Bram@vim.org>2020-06-01 16:09:41 +0200
commit6c9ba0428041d5316871245be38c13faa0107026 (patch)
tree98e9246ce0516f0eb54b6893ce8398d4db42baf3 /src/filepath.c
parentd14fd5285e491a39028c4b4722ddbe7c9dfa9bb2 (diff)
patch 8.2.0875: getting attributes for directory entries is slowv8.2.0875
Problem: Getting attributes for directory entries is slow. Solution: Add readdirex(). (Ken Takata, closes #5619)
Diffstat (limited to 'src/filepath.c')
-rw-r--r--src/filepath.c157
1 files changed, 118 insertions, 39 deletions
diff --git a/src/filepath.c b/src/filepath.c
index 27a26e5edc..ad7b8b03d4 100644
--- a/src/filepath.c
+++ b/src/filepath.c
@@ -1029,6 +1029,25 @@ f_getcwd(typval_T *argvars, typval_T *rettv)
}
/*
+ * Convert "st" to file permission string.
+ */
+ char_u *
+getfpermst(stat_T *st, char_u *perm)
+{
+ char_u flags[] = "rwx";
+ int i;
+
+ for (i = 0; i < 9; i++)
+ {
+ if (st->st_mode & (1 << (8 - i)))
+ perm[i] = flags[i % 3];
+ else
+ perm[i] = '-';
+ }
+ return perm;
+}
+
+/*
* "getfperm({fname})" function
*/
void
@@ -1037,24 +1056,13 @@ f_getfperm(typval_T *argvars, typval_T *rettv)
char_u *fname;
stat_T st;
char_u *perm = NULL;
- char_u flags[] = "rwx";
- int i;
+ char_u permbuf[] = "---------";
fname = tv_get_string(&argvars[0]);
rettv->v_type = VAR_STRING;
if (mch_stat((char *)fname, &st) >= 0)
- {
- perm = vim_strsave((char_u *)"---------");
- if (perm != NULL)
- {
- for (i = 0; i < 9; i++)
- {
- if (st.st_mode & (1 << (8 - i)))
- perm[i] = flags[i % 3];
- }
- }
- }
+ perm = vim_strsave(getfpermst(&st, permbuf));
rettv->vval.v_string = perm;
}
@@ -1106,6 +1114,33 @@ f_getftime(typval_T *argvars, typval_T *rettv)
}
/*
+ * Convert "st" to file type string.
+ */
+ char_u *
+getftypest(stat_T *st)
+{
+ char *t;
+
+ if (S_ISREG(st->st_mode))
+ t = "file";
+ else if (S_ISDIR(st->st_mode))
+ t = "dir";
+ else if (S_ISLNK(st->st_mode))
+ t = "link";
+ else if (S_ISBLK(st->st_mode))
+ t = "bdev";
+ else if (S_ISCHR(st->st_mode))
+ t = "cdev";
+ else if (S_ISFIFO(st->st_mode))
+ t = "fifo";
+ else if (S_ISSOCK(st->st_mode))
+ t = "socket";
+ else
+ t = "other";
+ return (char_u*)t;
+}
+
+/*
* "getftype({fname})" function
*/
void
@@ -1114,31 +1149,12 @@ f_getftype(typval_T *argvars, typval_T *rettv)
char_u *fname;
stat_T st;
char_u *type = NULL;
- char *t;
fname = tv_get_string(&argvars[0]);
rettv->v_type = VAR_STRING;
if (mch_lstat((char *)fname, &st) >= 0)
- {
- if (S_ISREG(st.st_mode))
- t = "file";
- else if (S_ISDIR(st.st_mode))
- t = "dir";
- else if (S_ISLNK(st.st_mode))
- t = "link";
- else if (S_ISBLK(st.st_mode))
- t = "bdev";
- else if (S_ISCHR(st.st_mode))
- t = "cdev";
- else if (S_ISFIFO(st.st_mode))
- t = "fifo";
- else if (S_ISSOCK(st.st_mode))
- t = "socket";
- else
- t = "other";
- type = vim_strsave((char_u *)t);
- }
+ type = vim_strsave(getftypest(&st));
rettv->vval.v_string = type;
}
@@ -1359,7 +1375,7 @@ f_pathshorten(typval_T *argvars, typval_T *rettv)
* Evaluate "expr" (= "context") for readdir().
*/
static int
-readdir_checkitem(void *context, char_u *name)
+readdir_checkitem(void *context, void *item)
{
typval_T *expr = (typval_T *)context;
typval_T save_val;
@@ -1367,9 +1383,7 @@ readdir_checkitem(void *context, char_u *name)
typval_T argv[2];
int retval = 0;
int error = FALSE;
-
- if (expr->v_type == VAR_UNKNOWN)
- return 1;
+ char_u *name = (char_u*)item;
prepare_vimvar(VV_VAL, &save_val);
set_vim_var_string(VV_VAL, name, -1);
@@ -1408,8 +1422,9 @@ f_readdir(typval_T *argvars, typval_T *rettv)
path = tv_get_string(&argvars[0]);
expr = &argvars[1];
- ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
- if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
+ ret = readdir_core(&ga, path, FALSE, (void *)expr,
+ (expr->v_type == VAR_UNKNOWN) ? NULL : readdir_checkitem);
+ if (ret == OK)
{
for (i = 0; i < ga.ga_len; i++)
{
@@ -1421,6 +1436,70 @@ f_readdir(typval_T *argvars, typval_T *rettv)
}
/*
+ * Evaluate "expr" (= "context") for readdirex().
+ */
+ static int
+readdirex_checkitem(void *context, void *item)
+{
+ typval_T *expr = (typval_T *)context;
+ typval_T save_val;
+ typval_T rettv;
+ typval_T argv[2];
+ int retval = 0;
+ int error = FALSE;
+ dict_T *dict = (dict_T*)item;
+
+ prepare_vimvar(VV_VAL, &save_val);
+ set_vim_var_dict(VV_VAL, dict);
+ argv[0].v_type = VAR_DICT;
+ argv[0].vval.v_dict = dict;
+
+ if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
+ goto theend;
+
+ retval = tv_get_number_chk(&rettv, &error);
+ if (error)
+ retval = -1;
+ clear_tv(&rettv);
+
+theend:
+ set_vim_var_dict(VV_VAL, NULL);
+ restore_vimvar(VV_VAL, &save_val);
+ return retval;
+}
+
+/*
+ * "readdirex()" function
+ */
+ void
+f_readdirex(typval_T *argvars, typval_T *rettv)
+{
+ typval_T *expr;
+ int ret;
+ char_u *path;
+ garray_T ga;
+ int i;
+
+ if (rettv_list_alloc(rettv) == FAIL)
+ return;
+ path = tv_get_string(&argvars[0]);
+ expr = &argvars[1];
+
+ ret = readdir_core(&ga, path, TRUE, (void *)expr,
+ (expr->v_type == VAR_UNKNOWN) ? NULL : readdirex_checkitem);
+ if (ret == OK)
+ {
+ for (i = 0; i < ga.ga_len; i++)
+ {
+ dict_T *dict = ((dict_T**)ga.ga_data)[i];
+ list_append_dict(rettv->vval.v_list, dict);
+ dict_unref(dict);
+ }
+ }
+ ga_clear(&ga);
+}
+
+/*
* "readfile()" function
*/
void