diff src/evalfunc.c @ 16231:0761a4c111a7 v8.1.1120

patch 8.1.1120: cannot easily get directory entry matches commit https://github.com/vim/vim/commit/543c9b1921d7605498b54afdef518e312f1b4515 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Apr 5 22:50:40 2019 +0200 patch 8.1.1120: cannot easily get directory entry matches Problem: Cannot easily get directory entry matches. Solution: Add the readdir() function. (Yasuhiro Matsumoto, closes https://github.com/vim/vim/issues/2439)
author Bram Moolenaar <Bram@vim.org>
date Fri, 05 Apr 2019 23:00:06 +0200
parents abb67309c1ca
children 219c58b3879c
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -319,6 +319,7 @@ static void f_pyeval(typval_T *argvars, 
 static void f_pyxeval(typval_T *argvars, typval_T *rettv);
 #endif
 static void f_range(typval_T *argvars, typval_T *rettv);
+static void f_readdir(typval_T *argvars, typval_T *rettv);
 static void f_readfile(typval_T *argvars, typval_T *rettv);
 static void f_reg_executing(typval_T *argvars, typval_T *rettv);
 static void f_reg_recording(typval_T *argvars, typval_T *rettv);
@@ -819,6 +820,7 @@ static struct fst
     {"pyxeval",		1, 1, f_pyxeval},
 #endif
     {"range",		1, 3, f_range},
+    {"readdir",		1, 2, f_readdir},
     {"readfile",	1, 3, f_readfile},
     {"reg_executing",	0, 0, f_reg_executing},
     {"reg_recording",	0, 0, f_reg_recording},
@@ -9118,6 +9120,189 @@ f_range(typval_T *argvars, typval_T *ret
 }
 
 /*
+ * Evaluate "expr" for readdir().
+ */
+    static int
+readdir_checkitem(typval_T *expr, char_u *name)
+{
+    typval_T	save_val;
+    typval_T	rettv;
+    typval_T	argv[2];
+    int		retval = 0;
+    int		error = FALSE;
+
+    prepare_vimvar(VV_VAL, &save_val);
+    set_vim_var_string(VV_VAL, name, -1);
+    argv[0].v_type = VAR_STRING;
+    argv[0].vval.v_string = name;
+
+    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_string(VV_VAL, NULL, 0);
+    restore_vimvar(VV_VAL, &save_val);
+    return retval;
+}
+
+/*
+ * "readdir()" function
+ */
+    static void
+f_readdir(typval_T *argvars, typval_T *rettv)
+{
+    typval_T	*expr;
+    int		failed = FALSE;
+    char_u	*path;
+    garray_T	ga;
+    int		i;
+#ifdef MSWIN
+    char_u		*buf, *p;
+    WIN32_FIND_DATA	fb;
+    int			ok;
+    HANDLE		hFind = INVALID_HANDLE_VALUE;
+    WIN32_FIND_DATAW    wfb;
+    WCHAR		*wn = NULL;	// UCS-2 name, NULL when not used.
+#endif
+
+    if (rettv_list_alloc(rettv) == FAIL)
+	return;
+    path = tv_get_string(&argvars[0]);
+    expr = &argvars[1];
+    ga_init2(&ga, (int)sizeof(char *), 20);
+
+#ifdef MSWIN
+    buf = alloc((int)MAXPATHL);
+    if (buf == NULL)
+	return;
+    STRNCPY(buf, path, MAXPATHL-5);
+    p = vim_strpbrk(path, (char_u *)"\\/");
+    if (p != NULL)
+	*p = NUL;
+    STRCAT(buf, "\\*");
+
+    wn = enc_to_utf16(buf, NULL);
+    if (wn != NULL)
+	hFind = FindFirstFileW(wn, &wfb);
+    ok = (hFind != INVALID_HANDLE_VALUE);
+    if (!ok)
+	smsg(_(e_notopen), path);
+    else
+    {
+	while (ok)
+	{
+	    int	ignore;
+
+	    p = utf16_to_enc(wfb.cFileName, NULL);   // p is allocated here
+	    if (p == NULL)
+		break;  // out of memory
+
+	    ignore = p[0] == '.' && (p[1] == NUL
+					      || (p[1] == '.' && p[2] == NUL));
+	    if (!ignore && expr->v_type != VAR_UNKNOWN)
+	    {
+		int r = readdir_checkitem(expr, p);
+
+		if (r < 0)
+		{
+		    vim_free(p);
+		    break;
+		}
+		if (r == 0)
+		    ignore = TRUE;
+	    }
+
+	    if (!ignore)
+	    {
+		if (ga_grow(&ga, 1) == OK)
+		    ((char_u**)ga.ga_data)[ga.ga_len++] = vim_strsave(p);
+		else
+		{
+		    failed = TRUE;
+		    vim_free(p);
+		    break;
+		}
+	    }
+
+	    vim_free(p);
+	    ok = FindNextFileW(hFind, &wfb);
+	}
+	FindClose(hFind);
+    }
+
+    vim_free(buf);
+    vim_free(wn);
+#else
+    DIR		*dirp;
+    struct dirent *dp;
+    char_u	*p;
+
+    dirp = opendir((char *)path);
+    if (dirp == NULL)
+	smsg(_(e_notopen), path);
+    else
+    {
+	for (;;)
+	{
+	    int	ignore;
+
+	    dp = readdir(dirp);
+	    if (dp == NULL)
+		break;
+	    p = (char_u *)dp->d_name;
+
+	    ignore = p[0] == '.' &&
+		    (p[1] == NUL ||
+		     (p[1] == '.' && p[2] == NUL));
+	    if (!ignore && expr->v_type != VAR_UNKNOWN)
+	    {
+		int r = readdir_checkitem(expr, p);
+
+		if (r < 0)
+		    break;
+		if (r == 0)
+		    ignore = TRUE;
+	    }
+
+	    if (!ignore)
+	    {
+		if (ga_grow(&ga, 1) == OK)
+		    ((char_u**)ga.ga_data)[ga.ga_len++] = vim_strsave(p);
+		else
+		{
+		    failed = TRUE;
+		    break;
+		}
+	    }
+	}
+
+	closedir(dirp);
+    }
+#endif
+
+    rettv->vval.v_list = list_alloc();
+    if (!failed && rettv->vval.v_list != NULL)
+    {
+	++rettv->vval.v_list->lv_refcount;
+	sort_strings((char_u **)ga.ga_data, ga.ga_len);
+	for (i = 0; i < ga.ga_len; i++)
+	{
+	    p = ((char_u **)ga.ga_data)[i];
+	    list_append_string(rettv->vval.v_list, p, -1);
+	}
+    }
+    for (i = 0; i < ga.ga_len; i++)
+	vim_free(((char_u **)ga.ga_data)[i]);
+
+    ga_clear(&ga);
+}
+
+/*
  * "readfile()" function
  */
     static void