summary refs log tree commit diff
path: root/Src/Zle/computil.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle/computil.c')
-rw-r--r--Src/Zle/computil.c203
1 files changed, 183 insertions, 20 deletions
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 51a1f61aa..3955ed69d 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -3058,17 +3058,37 @@ bin_compfmt(char *nam, char **args, char *ops, int func)
 #define PATH_MAX2 (PATH_MAX * 2)
 
 static LinkList
-cfp_test_exact(LinkList names, char *skipped)
+cfp_test_exact(LinkList names, char **accept, char *skipped)
 {
     char buf[PATH_MAX2 + 1], *suf, *p;
     int l, sl, found = 0;
     struct stat st;
     LinkNode node;
-    LinkList ret = newlinklist();
+    LinkList ret = newlinklist(), alist = NULL;
 
-    if (!(compprefix && *compprefix) && !(compsuffix && *compsuffix))
+    if ((!(compprefix && *compprefix) && !(compsuffix && *compsuffix)) ||
+	(!accept || !*accept ||
+	 ((!strcmp(*accept, "false") || !strcmp(*accept, "no") ||
+	   !strcmp(*accept, "off") || !strcmp(*accept, "0")) && !accept[1])))
 	return NULL;
 
+    if (accept[1] ||
+	(strcmp(*accept, "true") && strcmp(*accept, "yes") &&
+	 strcmp(*accept, "on") && strcmp(*accept, "1"))) {
+	Patprog prog;
+
+	alist = newlinklist();
+
+	for (; (p = *accept); accept++) {
+	    if (*p == '*' && !p[1]) {
+		alist = NULL;
+		break;
+	    }
+	    tokenize(p = dupstring(p));
+	    if ((prog = patcompile(p, 0, NULL)))
+		addlinknode(alist, prog);
+	}
+    }
     sl = strlen(skipped) + (compprefix ? strlen(compprefix) : 0) +
 	(compsuffix ? strlen(compsuffix) : 0);
 
@@ -3078,11 +3098,22 @@ cfp_test_exact(LinkList names, char *skipped)
     suf = dyncat(skipped, rembslash(dyncat(compprefix, compsuffix)));
 
     for (node = firstnode(names); node; incnode(node)) {
-	if ((l = strlen(p = (char *) getdata(node))) && l + sl < PATH_MAX2) {
+	l = strlen(p = (char *) getdata(node));
+	if (l + sl < PATH_MAX2) {
 	    strcpy(buf, p);
 	    strcpy(buf + l, suf);
 
-	    if (!ztat(buf, &st, 0) && S_ISDIR(st.st_mode)) {
+	    if (!ztat(buf, &st, 0)) {
+		if (alist) {
+		    LinkNode anode;
+
+		    for (anode = firstnode(alist); anode; incnode(anode))
+			if (pattry((Patprog) getdata(anode), buf))
+			    break;
+
+		    if (!anode)
+			continue;
+		}
 		found = 1;
 		addlinknode(ret, dupstring(buf));
 	    }
@@ -3334,12 +3365,14 @@ cfp_bld_pats(int dirs, LinkList names, char *skipped, char **pats)
 }
 
 static LinkList
-cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
+cfp_add_sdirs(LinkList final, LinkList orig, char *skipped,
+	      char *sdirs, char **fake)
 {
     int add = 0;
 
-    if (*sdirs) {
-	if (!strcmp(sdirs, "yes"))
+    if (*sdirs && (isset(GLOBDOTS) || (compprefix && *compprefix == '.'))) {
+	if (!strcmp(sdirs, "yes") || !strcmp(sdirs, "true") ||
+	    !strcmp(sdirs, "on") || !strcmp(sdirs, "1"))
 	    add = 2;
 	else if (!strcmp(sdirs, ".."))
 	    add = 1;
@@ -3350,10 +3383,62 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
 	char *s2 = (add == 2 ? dyncat(skipped, ".") : NULL), *m;
 
 	for (node = firstnode(orig); node; incnode(node)) {
-	    if (*(m = (char *) getdata(node))) {
-		addlinknode(final, dyncat((char *) getdata(node), s1));
+	    if ((m = (char *) getdata(node))) {
+		addlinknode(final, dyncat(m, s1));
 		if (s2)
-		    addlinknode(final, dyncat((char *) getdata(node), s2));
+		    addlinknode(final, dyncat(m, s2));
+	    }
+	}
+    }
+    if (fake && *fake) {
+	LinkNode node;
+	char *m, *f, *p, *t, *a, c;
+	int sl = strlen(skipped) + 1;
+	struct stat st1, st2;
+
+	for (; (f = *fake); fake++) {
+	    f = dupstring(f);
+	    for (p = t = f; *p; p++) {
+		if (*p == ':')
+		    break;
+		else if (*p == '\\' && p[1])
+		    p++;
+		*t++ = *p;
+	    }
+	    if (*p) {
+		*t = *p++ = '\0';
+		if (!*p)
+		    continue;
+
+		for (node = firstnode(orig); node; incnode(node)) {
+		    if ((m = (char *) getdata(node)) &&
+			(!strcmp(f, m) ||
+			 (!stat(f, &st1) && !stat((*m ? m : "."), &st2) &&
+			  st1.st_dev == st2.st_dev &&
+			  st1.st_ino == st2.st_ino))) {
+			while (*p) {
+			    while (*p && inblank(*p))
+				p++;
+			    if (!*p)
+				break;
+			    for (f = t = p; *p; p++) {
+				if (inblank(*p))
+				    break;
+				else if (*p == '\\' && p[1])
+				    p++;
+				*t++ = *p;
+			    }
+			    c = *t;
+			    *t = '\0';
+			    a = (char *) zhalloc(strlen(m) + sl + strlen(f));
+			    strcpy(a, m);
+			    strcat(a, skipped);
+			    strcat(a, f);
+			    addlinknode(final, a);
+			    *t = c;
+			}
+		    }
+		}
 	    }
 	}
     }
@@ -3361,14 +3446,14 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
 }
 
 static LinkList
-cf_pats(int dirs, int noopt, LinkList names, char *skipped, char *matcher,
-	char *sdirs, char **pats)
+cf_pats(int dirs, int noopt, LinkList names, char **accept, char *skipped,
+	char *matcher, char *sdirs, char **fake, char **pats)
 {
     LinkList ret;
     char *dpats[2];
 
-    if (dirs && (ret = cfp_test_exact(names, skipped)))
-	return cfp_add_sdirs(ret, names, skipped, sdirs);
+    if ((ret = cfp_test_exact(names, accept, skipped)))
+	return cfp_add_sdirs(ret, names, skipped, sdirs, fake);
 
     if (dirs) {
 	dpats[0] = "*(-/)";
@@ -3379,7 +3464,7 @@ cf_pats(int dirs, int noopt, LinkList names, char *skipped, char *matcher,
 	cfp_opt_pats(pats, matcher);
 
     return cfp_add_sdirs(cfp_bld_pats(dirs, names, skipped, pats),
-			 names, skipped, sdirs);
+			 names, skipped, sdirs, fake);
 }
 
 static void
@@ -3421,6 +3506,61 @@ cf_ignore(char **names, LinkList ign, char *style, char *path)
     }
 }
 
+static LinkList
+cf_remove_other(char **names, char *pre, int *amb)
+{
+    char *p;
+
+    if ((p = strchr(pre, '/'))) {
+	char **n;
+
+	*p = '\0';
+	pre = dyncat(pre, "/");
+	*p = '/';
+
+	for (n = names; *n; n++)
+	    if (strpfx(pre, *n))
+		break;
+
+	if (*n) {
+	    LinkList ret = newlinklist();
+
+	    for (; *names; names++)
+		if (strpfx(pre, *names))
+		    addlinknode(ret, dupstring(*names));
+
+	    *amb = 0;
+
+	    return ret;
+	} else {
+	    if (!(p = *names++))
+		*amb = 0;
+	    else {
+		char *q;
+
+		if ((q = strchr((p = dupstring(p)), '/')))
+		    *q = '\0';
+
+		for (; *names; names++)
+		    if (!strpfx(p, *names)) {
+			*amb = 1;
+			return NULL;
+		    }
+	    }
+	}
+    } else {
+	if (!(p = *names++))
+	    *amb = 0;
+	else
+	    for (; *names; names++)
+		if (strcmp(p, *names)) {
+		    *amb = 1;
+		    return NULL;
+		}
+    }
+    return NULL;
+}
+
 static int
 bin_compfiles(char *nam, char **args, char *ops, int func)
 {
@@ -3438,8 +3578,8 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
 	    char **tmp;
 	    LinkList l;
 
-	    if (!args[1] || !args[2] || !args[3] || !args[4] ||
-		(args[0][1] == 'p' && !args[5])) {
+	    if (!args[1] || !args[2] || !args[3] || !args[4] || !args[5] ||
+		!args[6] || (args[0][1] == 'p' && !args[7])) {
 		zwarnnam(nam, "too few arguments", NULL, 0);
 		return 1;
 	    }
@@ -3450,8 +3590,9 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
 	    for (l = newlinklist(); *tmp; tmp++)
 		addlinknode(l, *tmp);
 	    set_list_array(args[1], cf_pats((args[0][1] == 'P'), !!args[0][2],
-					    l, args[2], args[3], args[4],
-					    args + 5));
+					    l, getaparam(args[2]), args[3],
+					    args[4], args[5],
+					    getaparam(args[6]), args + 7));
 	    return 0;
 	}
     case 'i':
@@ -3483,6 +3624,28 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
 	    set_list_array(args[2], l);
 	    return 0;
 	}
+    case 'r':
+	{
+	    char **tmp;
+	    LinkList l;
+	    int ret = 0;
+
+	    if (!args[1] || !args[2]) {
+		zwarnnam(nam, "too few arguments", NULL, 0);
+		return 1;
+	    }
+	    if (args[3]) {
+		zwarnnam(nam, "too many arguments", NULL, 0);
+		return 1;
+	    }
+	    if (!(tmp = getaparam(args[1]))) {
+		zwarnnam(nam, "unknown parameter: %s", args[1], 0);
+		return 0;
+	    }
+	    if ((l = cf_remove_other(tmp, args[2], &ret)))
+		set_list_array(args[1], l);
+	    return ret;
+	}
     }
     zwarnnam(nam, "invalid option: %s", *args, 0);
     return 1;