about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--Doc/Zsh/builtins.yo12
-rw-r--r--Src/builtin.c2
-rw-r--r--Src/module.c136
-rw-r--r--Src/zsh.h11
5 files changed, 120 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog
index c3321dc52..c7ec6a906 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2008-05-08  Peter Stephenson  <pws@csr.com>
 
+	* 24980: Doc/Zsh/builtins.yo, Src/builtin.c, Src/module.c,
+	Src/zsh.h: add zmodload -mF to manipulate features by pattern.
+
 	* 24972: Phil Pennock: Doc/Zsh/mod_files.yo, Src/Modules/files.c,
 	Src/Modules/files.mdd:  Add zf_* commands for zsh/files modules
 	plus a few extra options.
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 574692078..cca0a3972 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1901,7 +1901,7 @@ findex(zmodload)
 cindex(modules, loading)
 cindex(loading modules)
 xitem(tt(zmodload) [ tt(-dL) ] [ ... ])
-xitem(tt(zmodload -F) [ tt(-lLe) tt(-P) tt(param) ] var(module) [tt(PLUS()-)]var(feature...))
+xitem(tt(zmodload -F) [ tt(-lLme) tt(-P) tt(param) ] var(module) [tt(PLUS()-)]var(feature...))
 xitem(tt(zmodload -e) [ tt(-A) ] [ ... ])
 xitem(tt(zmodload) [ tt(-a) [ tt(-bcpf) [ tt(-I) ] ] ] [ tt(-iL) ] ...)
 xitem(tt(zmodload) tt(-u) [ tt(-abcdpf) [ tt(-I) ] ] [ tt(-iL) ] ...)
@@ -1952,7 +1952,7 @@ Each module has a boot and a cleanup function.  The module
 will not be loaded if its boot function fails.  Similarly a module
 can only be unloaded if its cleanup function runs successfully.
 )
-item(tt(zmodload -F) [ tt(-alLe) tt(-P) tt(param) ] var(module) [tt(PLUS()-)]var(feature...))(
+item(tt(zmodload -F) [ tt(-almLe) tt(-P) tt(param) ] var(module) [tt(PLUS()-)]var(feature...))(
 tt(zmodload -F) allows more selective control over the features provided
 by modules.  With no options apart from tt(-F), the module named
 var(module) is loaded, if it was not already loaded, and the list of
@@ -2006,6 +2006,12 @@ any feature given with a prefix tt(PLUS()) or tt(-) is tested to
 see if is provided and in the given state.  If the tests on all features
 in the list succeed, status 0 is returned, else status 1.
 
+With tt(-m), each entry in the given list of features is taken
+as a pattern to be matched against the list of features provided
+by the module.  An initial tt(PLUS()) or tt(-) must be given explicitly.
+This may not be combined with the tt(-a) option as autoloads must
+be specified explicitly.
+
 With tt(-a), the given list of features is marked for autoload from
 the specified module, which may not yet be loaded.  An optional tt(PLUS())
 may appear before the feature name.  If the feature is prefixed with
@@ -2015,7 +2021,7 @@ features; when the module is loaded only the requested feature is
 enabled.  Autoload requests are preserved if the module is
 subsequently unloaded until an explicit `tt(zmodload -Fa) var(module)
 tt(-)var(feature)' is issued.  It is not an error to request an autoload
-for a feature of a module that is already loaded.  
+for a feature of a module that is already loaded.
 
 When the module is loaded each autoload is checked against the features
 actually provided by the module; if the feature is not provided the
diff --git a/Src/builtin.c b/Src/builtin.c
index a9f181419..d28d9fffd 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -131,7 +131,7 @@ static struct builtin builtins[] =
     BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL),
     BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"),
     BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
-    BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilpue", NULL),
+    BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpue", NULL),
     BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL),
 };
 
diff --git a/Src/module.c b/Src/module.c
index a89010d74..c4fb95c78 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -1967,7 +1967,7 @@ finish_module(Module m)
 
 /**/
 static int
-do_module_features(Module m, char **enablesstr, int flags)
+do_module_features(Module m, Feature_enables enablesarr, int flags)
 {
     char **features;
     int ret = 0;
@@ -2019,19 +2019,26 @@ do_module_features(Module m, char **enablesstr, int flags)
 		    (void)autofeatures(NULL, m->node.nam, arg, 0,
 				       FEAT_IGNORE|FEAT_REMOVE);
 		    /*
-		     * don't want to try to enable *that*... 
+		     * don't want to try to enable *that*...
 		     * expunge it from the enable string.
 		     */
-		    if (enablesstr) {
-			for (ptr = enablesstr; *ptr; ptr++) {
-			    if (!strcmp(al, *ptr)) {
+		    if (enablesarr) {
+			Feature_enables fep;
+			for (fep = enablesarr; fep->str; fep++) {
+			    char *str = fep->str;
+			    if (*str == '+' || *str == '-')
+				str++;
+			    if (fep->pat ? pattry(fep->pat, al) :
+				!strcmp(al, str)) {
 				/* can't enable it after all, so return 1 */
 				ret = 1;
-				while (*ptr) {
-				    *ptr = ptr[1];
-				    ptr++;
+				while (fep->str) {
+				    fep->str = fep[1].str;
+				    fep->pat = fep[1].pat;
+				    fep++;
 				}
-				break;
+				if (!fep->pat)
+				    break;
 			    }
 			}
 		    }
@@ -2039,11 +2046,11 @@ do_module_features(Module m, char **enablesstr, int flags)
 	    }
 	}
 
-	if (enablesstr) {
-	    char **ep;
-	    for (ep = enablesstr; *ep; ep++) {
-		char **fp, *esp = *ep;
-		int on = 1;
+	if (enablesarr) {
+	    Feature_enables fep;
+	    for (fep = enablesarr; fep->str; fep++) {
+		char **fp, *esp = fep->str;
+		int on = 1, found = 0;
 		if (*esp == '+')
 		    esp++;
 		else if (*esp == '-') {
@@ -2051,13 +2058,17 @@ do_module_features(Module m, char **enablesstr, int flags)
 		    esp++;
 		}
 		for (fp = features; *fp; fp++)
-		    if (!strcmp(*fp, esp)) {
+		    if (fep->pat ? pattry(fep->pat, *fp) : !strcmp(*fp, esp)) {
 			enables[fp - features] = on;
-			break;
+			found++;
+			if (!fep->pat)
+			    break;
 		    }
-		if (!*fp) {
+		if (!found) {
 		    if (!(flags & FEAT_IGNORE))
-			zwarn("module `%s' has no such feature: `%s'",
+			zwarn(fep->pat ?
+			      "module `%s' has no feature matching: `%s'" :
+			      "module `%s' has no such feature: `%s'",
 			      m->node.nam, esp);
 		    return 1;
 		}
@@ -2075,7 +2086,7 @@ do_module_features(Module m, char **enablesstr, int flags)
 
 	if (enables_module(m, &enables))
 	    return 2;
-    } else if (enablesstr) {
+    } else if (enablesarr) {
 	if (!(flags & FEAT_IGNORE))
 	    zwarn("module `%s' does not support features", m->node.nam);
 	return 1;
@@ -2097,9 +2108,9 @@ do_module_features(Module m, char **enablesstr, int flags)
 
 /**/
 static int
-do_boot_module(Module m, char **enablesstr, int silent)
+do_boot_module(Module m, Feature_enables enablesarr, int silent)
 {
-    int ret = do_module_features(m, enablesstr,
+    int ret = do_module_features(m, enablesarr,
 				 silent ? FEAT_IGNORE|FEAT_CHECKAUTO :
 				 FEAT_CHECKAUTO);
 
@@ -2159,7 +2170,7 @@ modname_ok(char const *p)
 
 /**/
 mod_export int
-load_module(char const *name, char **enablesstr, int silent)
+load_module(char const *name, Feature_enables enablesarr, int silent)
 {
     Module m;
     void *handle = NULL;
@@ -2194,7 +2205,7 @@ load_module(char const *name, char **enablesstr, int silent)
 	modulestab->addnode(modulestab, ztrdup(name), m);
 
 	if ((set = setup_module(m)) ||
-	    (bootret = do_boot_module(m, enablesstr, silent)) == 1) {
+	    (bootret = do_boot_module(m, enablesarr, silent)) == 1) {
 	    if (!set)
 		do_cleanup_module(m);
 	    finish_module(m);
@@ -2263,7 +2274,7 @@ load_module(char const *name, char **enablesstr, int silent)
 	m->node.flags |= MOD_INIT_S;
     }
     m->node.flags |= MOD_SETUP;
-    if ((bootret = do_boot_module(m, enablesstr, silent)) == 1) {
+    if ((bootret = do_boot_module(m, enablesarr, silent)) == 1) {
 	do_cleanup_module(m);
 	finish_module(m);
 	if (m->node.flags & MOD_LINKED)
@@ -2301,7 +2312,7 @@ load_module(char const *name, char **enablesstr, int silent)
 
 /**/
 mod_export int
-require_module(const char *module, char **features)
+require_module(const char *module, Feature_enables features)
 {
     Module m = NULL;
     int ret = 0;
@@ -2962,7 +2973,10 @@ bin_zmodload_load(char *nam, char **args, Options ops)
 static int
 bin_zmodload_features(const char *nam, char **args, Options ops)
 {
+    int iarg;
     char *modname = *args;
+    Patprog *patprogs;
+    Feature_enables features, fep;
 
     if (modname)
 	args++;
@@ -2986,6 +3000,23 @@ bin_zmodload_features(const char *nam, char **args, Options ops)
 	return 1;
     }
 
+    if (OPT_ISSET(ops,'m')) {
+	char **argp;
+	Patprog *patprogp;
+
+	/* not NULL terminated */
+	patprogp = patprogs =
+	    (Patprog *)zhalloc(arrlen(args)*sizeof(Patprog));
+	for (argp = args; *argp; argp++, patprogp++) {
+	    char *arg = *argp;
+	    if (*arg == '+' || *arg == '-')
+		arg++;
+	    tokenize(arg);
+	    *patprogp = patcompile(arg, 0, 0);
+	}
+    } else
+	patprogs = NULL;
+
     if (OPT_ISSET(ops,'l') || OPT_ISSET(ops,'L') || OPT_ISSET(ops,'e')) {
 	/*
 	 * With option 'l', list all features one per line with + or -.
@@ -3063,9 +3094,9 @@ bin_zmodload_features(const char *nam, char **args, Options ops)
 		     m->node.nam);
 	    return 1;
 	}
-	for (arrp = args; *arrp; arrp++) {
+	for (arrp = args, iarg = 0; *arrp; arrp++, iarg++) {
 	    char *arg = *arrp;
-	    int on;
+	    int on, found = 0;
 	    if (*arg == '-') {
 		on = 0;
 		arg++;
@@ -3075,17 +3106,22 @@ bin_zmodload_features(const char *nam, char **args, Options ops)
 	    } else
 		on = -1;
 	    for (fp = features, ep = enables; *fp; fp++, ep++) {
-		if (!strcmp(arg, *fp)) {
+		if (patprogs ? pattry(patprogs[iarg], *fp) :
+		    !strcmp(arg, *fp)) {
 		    /* for -e, check given state, if any */
 		    if (OPT_ISSET(ops,'e') && on != -1 &&
 			on != (*ep & 1))
 			return 1;
-		    break;
+		    found++;
+		    if (!patprogs)
+			break;
 		}
 	    }
-	    if (!*fp) {
+	    if (!found) {
 		if (!OPT_ISSET(ops,'e'))
-		    zwarnnam(nam, "module `%s' has no such feature: `%s'",
+		    zwarnnam(nam, patprogs ?
+			     "module `%s' has no feature matching: `%s'" :
+			     "module `%s' has no such feature: `%s'",
 			     *arrp);
 		return 1;
 	    }
@@ -3100,12 +3136,13 @@ bin_zmodload_features(const char *nam, char **args, Options ops)
 		    continue;
 		if (*args) {
 		    char **argp;
-		    for (argp = args; *argp; argp++) {
+		    for (argp = args, iarg = 0; *argp; argp++, iarg++) {
 			char *arg = *argp;
 			/* ignore +/- for consistency */
 			if (*arg == '+' || *arg == '-')
 			    arg++;
-			if (!strcmp(*fp, arg))
+			if (patprogs ? pattry(patprogs[iarg], *fp) :
+			    !strcmp(*fp, arg))
 			    break;
 		    }
 		    if (!*argp)
@@ -3121,11 +3158,12 @@ bin_zmodload_features(const char *nam, char **args, Options ops)
 	    int term;
 	    if (*args) {
 		char **argp;
-		for (argp = args; *argp; argp++) {
+		for (argp = args, iarg = 0; *argp; argp++, iarg++) {
 		    char *arg = *argp;
 		    if (*arg == '+' || *arg == '-')
 			arg++;
-		    if (!strcmp(*fp, *argp))
+		    if (patprogs ? pattry(patprogs[iarg], *fp) :
+			!strcmp(*fp, *argp))
 			break;
 		}
 		if (!*argp)
@@ -3161,6 +3199,10 @@ bin_zmodload_features(const char *nam, char **args, Options ops)
 	zwarnnam(nam, "-P can only be used with -l or -L");
 	return 1;
     } else if (OPT_ISSET(ops,'a')) {
+	if (OPT_ISSET(ops,'m')) {
+	    zwarnnam(nam, "-m cannot be used with -a");
+	    return 1;
+	}
 	/*
 	 * With zmodload -aF, we always use the effect of -i.
 	 * The thinking is that marking a feature for
@@ -3175,7 +3217,18 @@ bin_zmodload_features(const char *nam, char **args, Options ops)
 	return autofeatures(nam, modname, args, 0, FEAT_IGNORE);
     }
 
-    return require_module(modname, args);
+    fep = features =
+	(Feature_enables)zhalloc((arrlen(args)+1)*sizeof(*fep));
+
+    while (*args) {
+	fep->str = *args++;
+	fep->pat = patprogs ? *patprogs++ : NULL;
+	fep++;
+    }
+    fep->str = NULL;
+    fep->pat = NULL;
+
+    return require_module(modname, features);
 }
 
 
@@ -3330,14 +3383,17 @@ handlefeatures(Module m, Features f, int **enables)
 mod_export int
 ensurefeature(const char *modname, const char *prefix, const char *feature)
 {
-    char *f, *features[2];
+    char *f;
+    struct feature_enables features[2];
 
     if (!feature)
 	return require_module(modname, NULL);
     f = dyncat(prefix, feature);
 
-    features[0] = f;
-    features[1] = NULL;
+    features[0].str = f;
+    features[0].pat = NULL;
+    features[1].str = NULL;
+    features[1].pat = NULL;
     return require_module(modname, features);
 }
 
@@ -3435,7 +3491,7 @@ autofeatures(const char *cmdnam, const char *module, char **features,
 	    zwarnnam(cmdnam, "%s: `/' is illegal in a %s", fnam, typnam);
 	    ret = 1;
 	    continue;
-	} 
+	}
 
 	if (!module) {
 	    /*
diff --git a/Src/zsh.h b/Src/zsh.h
index f3ccd636b..2f7c4fefe 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -382,6 +382,7 @@ typedef struct cmdnam    *Cmdnam;
 typedef struct complist  *Complist;
 typedef struct conddef   *Conddef;
 typedef struct features  *Features;
+typedef struct feature_enables  *Feature_enables;
 typedef struct funcstack *Funcstack;
 typedef struct funcwrap  *FuncWrap;
 typedef struct hashnode  *HashNode;
@@ -1247,6 +1248,16 @@ struct features {
     int n_abstract;
 };
 
+/*
+ * Structure describing enables for one feature.
+ */
+struct feature_enables {
+    /* String feature to enable (N.B. no leading +/- allowed) */
+    char *str;
+    /* Optional compiled pattern for str sans +/-, NULL for string match */
+    Patprog pat;
+};
+
 /* C-function hooks */
 
 typedef int (*Hookfn) _((Hookdef, void *));