summary refs log tree commit diff
path: root/Src/Zle/computil.c
diff options
context:
space:
mode:
authorSven Wischnowsky <wischnow@users.sourceforge.net>2000-06-13 09:05:35 +0000
committerSven Wischnowsky <wischnow@users.sourceforge.net>2000-06-13 09:05:35 +0000
commitcedd1006e661b990aaa8881c2efd4116bed574a3 (patch)
tree0d38ad379e55e3b1f9388a5fc661753de65c30a6 /Src/Zle/computil.c
parent055d961f84fcfb430aceb40bdb7932d962b143e9 (diff)
downloadzsh-cedd1006e661b990aaa8881c2efd4116bed574a3.tar.gz
zsh-cedd1006e661b990aaa8881c2efd4116bed574a3.tar.xz
zsh-cedd1006e661b990aaa8881c2efd4116bed574a3.zip
fixes for calling compfiles, for completing words with special characters; make compfiles optimisations work with globcomplete and simple match (sunsite isn't responding)
Diffstat (limited to 'Src/Zle/computil.c')
-rw-r--r--Src/Zle/computil.c194
1 files changed, 169 insertions, 25 deletions
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index ecb7ca3e1..d32f77a1c 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -3059,27 +3059,164 @@ cfp_test_exact(LinkList names, char *skipped)
     return (found ? ret : NULL);
 }
 
+static char *
+cfp_matcher_pats(char *matcher, char *add)
+{
+    Cmatcher m = parse_cmatcher(NULL, matcher);
+
+    if (m && m != pcm_err) {
+	char *tmp;
+	int al = strlen(add), tl;
+	VARARR(Cmatcher, ms, al);
+	Cmatcher *mp;
+	Cpattern stopp;
+	int stopl = 0;
+
+	memset(ms, 0, al * sizeof(Cmatcher));
+
+	for (; m && *add; m = m->next) {
+	    stopp = NULL;
+	    if (!(m->flags & (CMF_LEFT|CMF_RIGHT))) {
+		if (m->llen == 1 && m->wlen == 1) {
+		    for (tmp = add, tl = al, mp = ms; tl; tl--, tmp++, mp++) {
+			if (pattern_match(m->line, tmp, NULL, NULL)) {
+			    if (*mp) {
+				*tmp = '\0';
+				al = tmp - add;
+				break;
+			    } else
+				*mp = m;
+			}
+		    }
+		} else {
+		    stopp = m->line;
+		    stopl = m->llen;
+		}
+	    } else if (m->flags & CMF_RIGHT) {
+		if (m->wlen < 0 && !m->llen && m->ralen == 1) {
+		    for (tmp = add, tl = al, mp = ms; tl; tl--, tmp++, mp++) {
+			if (pattern_match(m->right, tmp, NULL, NULL)) {
+			    if (*mp) {
+				*tmp = '\0';
+				al = tmp - add;
+				break;
+			    } else
+				*mp = m;
+			}
+		    }
+		} else if (m->llen) {
+		    stopp = m->line;
+		    stopl = m->llen;
+		} else {
+		    stopp = m->right;
+		    stopl = m->ralen;
+		}
+	    } else {
+		if (!m->lalen)
+		    return "";
+
+		stopp = m->left;
+		stopl = m->lalen;
+	    }
+	    if (stopp)
+		for (tmp = add, tl = al; tl >= stopl; tl--, tmp++)
+		    if (pattern_match(stopp, tmp, NULL, NULL)) {
+			*tmp = '\0';
+			al = tmp - add;
+			break;
+		    }
+	}
+	if (*add) {
+	    char *ret = "", buf[259];
+
+	    for (mp = ms; *add; add++, mp++) {
+		if (!(m = *mp)) {
+		    buf[0] = *add;
+		    buf[1] = '\0';
+		} else if (m->flags & CMF_RIGHT) {
+		    buf[0] = '*';
+		    buf[1] = *add;
+		    buf[2] = '\0';
+		} else {
+		    unsigned char *t, c;
+		    char *p = buf;
+		    int i;
+
+		    for (i = 256, t = m->word->tab; i--; t++)
+			if (*t)
+			    break;
+		    if (i) {
+			t = m->word->tab;
+			*p++ = '[';
+			if (m->line->equiv && m->word->equiv) {
+			    *p++ = *add;
+			    c = m->line->tab[STOUC(*add)];
+			    for (i = 0; i < 256; i++)
+				if (m->word->tab[i] == c) {
+				    *p++ = (char) i;
+				    break;
+				}
+			} else {
+			    if (*add == ']' || t[STOUC(']')])
+				*p++ = ']';
+			    for (i = 0; i < 256; i++, t++)
+				if (*t && ((char) i) != *add &&
+				    i != ']' && i != '-' &&
+				    i != '^' && i != '!')
+				    *p++ = (char) i;
+			    *p++ = *add;
+			    t = m->word->tab;
+			    if (*add != '^' && t[STOUC('^')])
+				*p++ = '^';
+			    if (*add != '!' && t[STOUC('!')])
+				*p++ = '!';
+			    if (*add != '-' && t[STOUC('-')])
+				*p++ = '-';
+			}
+			*p++ = ']';
+			*p = '\0';
+		    } else {
+			*p = '?';
+			p[1] = '\0';
+		    }
+		}
+		ret = dyncat(ret, buf);
+	    }
+	    return ret;
+	}
+    }
+    return add;
+}
+
 static void
 cfp_opt_pats(char **pats, char *matcher)
 {
     char *add, **p, *q, *t, *s;
 
-    /**** For now we don't try to improve the patterns if there are match
-     *    specs. We should work on this some more...
-     *
-     *    And another one: we can do this with comppatmatch if the word
-     *    doesn't contain wildcards, unless the approximate matcher is
-     *    active. Better: unless there is a compadd function. I.e., we
-     *    need one more piece of information from the shell code, at least
-     *    I'd prefer to get it from _path_files in case we find other
-     *    conditions for not trying to improve patterns. */
-
-    if ((comppatmatch && *comppatmatch) || *matcher ||
-	!compprefix || !*compprefix)
+    if (!compprefix || !*compprefix)
 	return;
 
-    add = rembslash(compprefix);
-
+    if (comppatmatch && *comppatmatch) {
+	tokenize(t = rembslash(dyncat(compprefix, compsuffix)));
+	remnulargs(t);
+	if (haswilds(t))
+	    return;
+    }
+    add = (char *) zhalloc(sizeof(compprefix) * 2 + 1);
+    for (s = compprefix, t = add; *s; s++) {
+	if (*s != '\\' || !s[1] || s[1] == '*' || s[1] == '?' ||
+	    s[1] == '<' || s[1] == '>' || s[1] == '(' || s[1] == ')' ||
+	    s[1] == '[' || s[1] == ']' || s[1] == '|' || s[1] == '#' ||
+	    s[1] == '^' || s[1] == '~') {
+	    if ((s == compprefix || s[-1] != '\\') &&
+		(*s == '*' || *s == '?' || *s == '<' || *s == '>' ||
+		 *s == '(' || *s == ')' || *s == '[' || *s == ']' ||
+		 *s == '|' || *s == '#' || *s == '^' || *s == '~'))
+		*t++ = '\\';
+	    *t++ = *s;
+	}
+    }
+    *t = '\0';
     for (p = pats; *add && (q = *p); p++) {
 	if (*q) {
 	    q = dupstring(q);
@@ -3124,6 +3261,9 @@ cfp_opt_pats(char **pats, char *matcher)
 	}
     }
     if (*add) {
+	if (*matcher && !(add = cfp_matcher_pats(matcher, add)))
+	    return;
+
 	for (p = pats; *p; p++)
 	    if (**p == '*')
 		*p = dyncat(add, *p);
@@ -3189,8 +3329,8 @@ cfp_add_sdirs(LinkList final, LinkList orig, char *skipped, char *sdirs)
 }
 
 static LinkList
-cf_pats(int dirs, LinkList names, char *skipped, char *matcher, char *sdirs,
-	char **pats)
+cf_pats(int dirs, int noopt, LinkList names, char *skipped, char *matcher,
+	char *sdirs, char **pats)
 {
     LinkList ret;
     char *dpats[2];
@@ -3203,7 +3343,8 @@ cf_pats(int dirs, LinkList names, char *skipped, char *matcher, char *sdirs,
 	dpats[1] = NULL;
 	pats = dpats;
     }
-    cfp_opt_pats(pats, matcher);
+    if (!noopt)
+	cfp_opt_pats(pats, matcher);
 
     return cfp_add_sdirs(cfp_bld_pats(dirs, names, skipped, pats),
 			 names, skipped, sdirs);
@@ -3255,14 +3396,13 @@ bin_compfiles(char *nam, char **args, char *ops, int func)
 	zwarnnam(nam, "missing option: %s", *args, 0);
 	return 1;
     }
-    if (args[0][2]) {
-	zwarnnam(nam, "invalid option: %s", *args, 0);
-	return 1;
-    }
     switch (args[0][1]) {
     case 'p':
     case 'P':
-	{
+	if (args[0][2] && (args[0][2] != '-' || args[0][3])) {
+	    zwarnnam(nam, "invalid option: %s", *args, 0);
+	    return 1;
+	} else {
 	    char **tmp;
 	    LinkList l;
 
@@ -3277,12 +3417,16 @@ 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'), l, args[2],
-					    args[3], args[4], args + 5));
+	    set_list_array(args[1], cf_pats((args[0][1] == 'P'), !!args[0][2],
+					    l, args[2], args[3], args[4],
+					    args + 5));
 	    return 0;
 	}
     case 'i':
-	{
+	if (args[0][2]) {
+	    zwarnnam(nam, "invalid option: %s", *args, 0);
+	    return 1;
+	} else {
 	    char **tmp;
 	    LinkList l;