zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: zsh/files adjustments
@ 2008-05-08  6:08 Phil Pennock
  2008-05-08  9:05 ` Peter Stephenson
  0 siblings, 1 reply; 3+ messages in thread
From: Phil Pennock @ 2008-05-08  6:08 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1448 bytes --]

This patch for zsh/files:
 * Updates the documentation to be more cautionary
 * Adds new binary names for the commands
 * Implements ln -h/-n to inhibit chasing symlinks

On this last point: the BSD systems all have a fairly consistent set of
options for dealing with how symlinks are chased, documented in
symlink(7), which is why they have "ln -h" where GNU went with "ln -n";
the BSDs nowadays implement -n as a compatibility option.  I decided to
add both.

To rip an example from one I contributed to the OpenBSD man-page for
ln(1):

----------------------------8< cut here >8------------------------------
    In the next example, the second call to ln removes the original foo and
     creates a replacement pointing to baz:

           $ mkdir bar baz
           $ ln -s bar foo
           $ ln -shf baz foo

     Without the -h option, this would instead leave foo pointing to bar and
     inside foo create a new symlink baz pointing to itself.  This results
     from directory-walking.
----------------------------8< cut here >8------------------------------

Is there any thought to being able to name groups of features, perhaps
with a g: prefix, so that it becomes possible to do:
  zmodload -F zsh/files +g:zf_commands
  zmodload -F zsh/files -g:bare_commands
?  Is this desirable?  I'd view the semantics as batch-enable/disable,
so that later items on the command-line override, even if more general.

Feedback appreciated,
-Phil

[-- Attachment #2: files-ln.patch --]
[-- Type: text/x-diff, Size: 8421 bytes --]

Index: Doc/Zsh/mod_files.yo
===================================================================
RCS file: /home/cvsroot/zsh/Doc/Zsh/mod_files.yo,v
retrieving revision 1.3
diff -p -u -r1.3 mod_files.yo
--- Doc/Zsh/mod_files.yo	21 Aug 2007 22:59:49 -0000	1.3
+++ Doc/Zsh/mod_files.yo	8 May 2008 05:54:02 -0000
@@ -2,7 +2,17 @@ COMMENT(!MOD!zsh/files
 Some basic file manipulation commands as builtins.
 !MOD!)
 cindex(files, manipulating)
-The tt(zsh/files) module makes some standard commands available as builtins:
+The tt(zsh/files) module makes available some common commands for file
+manipulation as builtins; these commands are probably not needed for
+many normal situations but can be useful in emergency recovery
+situations with constrained resources.  The commands do not implement
+all features now required by relevant standards committees.
+
+For all commands, a variant beginning tt(zf_) is also available and loaded
+automatically.  Using the features capability of zmodload will let you load
+only those names you want.
+
+The commands loaded by default are:
 
 startitem()
 findex(chgrp)
@@ -51,8 +61,8 @@ a deep directory tree can't end up recur
 a result of directories being moved up the tree.
 )
 findex(ln)
-xitem(tt(ln) [ tt(-dfis) ] var(filename) var(dest))
-item(tt(ln) [ tt(-dfis) ] var(filename) ... var(dir))(
+xitem(tt(ln) [ tt(-dfhins) ] var(filename) var(dest))
+item(tt(ln) [ tt(-dfhins) ] var(filename) ... var(dir))(
 Creates hard (or, with tt(-s), symbolic) links.  In the first form, the
 specified var(dest)ination is created, as a link to the specified
 var(filename).  In the second form, each of the var(filename)s is
@@ -69,6 +79,16 @@ By default, existing files cannot be rep
 The tt(-i) option causes the user to be queried about replacing
 existing files.  The tt(-f) option causes existing files to be
 silently deleted, without querying.  tt(-f) takes precedence.
+
+The tt(-h) and tt(-n) options are identical and both exist for
+compatibility; either one indicates that if the target is a symlink
+then it should not be dereferenced.
+Typically this is used in combination with tt(-sf) so that if an
+existing link points to a directory then it will be removed,
+instead of followed.
+If this option is used with multiple filenames and the target
+is a symbolic link pointing to a directory then the result is
+an error.
 )
 findex(mkdir)
 item(tt(mkdir) [ tt(-p) ] [ tt(-m) var(mode) ] var(dir) ...)(
Index: Src/Modules/files.c
===================================================================
RCS file: /home/cvsroot/zsh/Src/Modules/files.c,v
retrieving revision 1.18
diff -p -u -r1.18 files.c
--- Src/Modules/files.c	21 Aug 2007 22:59:49 -0000	1.18
+++ Src/Modules/files.c	8 May 2008 05:56:18 -0000
@@ -166,23 +166,37 @@ bin_rmdir(char *nam, char **args, UNUSED
 #define BIN_LN 0
 #define BIN_MV 1
 
-#define MV_NODIRS (1<<0)
-#define MV_FORCE  (1<<1)
-#define MV_INTER  (1<<2)
-#define MV_ASKNW  (1<<3)
-#define MV_ATOMIC (1<<4)
-
-/* bin_ln actually does three related jobs: hard linking, symbolic *
- * linking, and renaming.  If called as mv it renames, otherwise   *
- * it looks at the -s option.  If hard linking, it will refuse to  *
- * attempt linking to a directory unless the -d option is given.   */
+#define MV_NODIRS		(1<<0)
+#define MV_FORCE		(1<<1)
+#define MV_INTERACTIVE		(1<<2)
+#define MV_ASKNW		(1<<3)
+#define MV_ATOMIC		(1<<4)
+#define MV_NOCHASETARGET	(1<<5)
+
+/*
+ * bin_ln actually does three related jobs: hard linking, symbolic
+ * linking, and renaming.  If called as mv it renames, otherwise
+ * it looks at the -s option.  If hard linking, it will refuse to
+ * attempt linking to a directory unless the -d option is given.
+ */
+
+/*
+ * Option compatibility: BSD systems settled on using mostly-standardised
+ * options across multiple commands to deal with symlinks; see, eg,
+ * symlink(7) on a *BSD system for details.  Per this, to work on a link
+ * directly we use "-h" and "ln -hsf" will not follow the target if it
+ * points to a directory.  GNU settled on using -n for ln(1), so we
+ * have "ln -nsf".  We handle them both.
+ *
+ * Logic compared against that of FreeBSD's ln.c, compatible license.
+ */
 
 /**/
 static int
 bin_ln(char *nam, char **args, Options ops, int func)
 {
     MoveFunc move;
-    int flags, err = 0;
+    int flags, have_dir, err = 0;
     char **a, *ptr, *rp, *buf;
     struct stat st;
     size_t blen;
@@ -195,6 +209,8 @@ bin_ln(char *nam, char **args, Options o
     } else {
 	flags = OPT_ISSET(ops,'f') ? MV_FORCE : 0;
 #ifdef HAVE_LSTAT
+	if(OPT_ISSET(ops,'h') || OPT_ISSET(ops,'n'))
+	    flags |= MV_NOCHASETARGET;
 	if(OPT_ISSET(ops,'s'))
 	    move = (MoveFunc) symlink;
 	else
@@ -206,12 +222,39 @@ bin_ln(char *nam, char **args, Options o
 	}
     }
     if(OPT_ISSET(ops,'i') && !OPT_ISSET(ops,'f'))
-	flags |= MV_INTER;
+	flags |= MV_INTERACTIVE;
     for(a = args; a[1]; a++) ;
     if(a != args) {
 	rp = unmeta(*a);
-	if(rp && !stat(rp, &st) && S_ISDIR(st.st_mode))
-	    goto havedir;
+	if(rp && !stat(rp, &st) && S_ISDIR(st.st_mode)) {
+	    have_dir = 1;
+	    if((flags & MV_NOCHASETARGET)
+	      && !lstat(rp, &st) && S_ISLNK(st.st_mode)) {
+		/*
+		 * So we have "ln -h" with the target being a symlink pointing
+		 * to a directory; if there are multiple sources but the target
+		 * is a symlink, then it's an error as we're not following
+		 * symlinks; if OTOH there's just one source, then we need to
+		 * either fail EEXIST or if "-f" given then remove the target.
+		 */
+		if(a > args+1) {
+		    errno = ENOTDIR;
+		    zwarnnam(nam, "%s: %e", *a, errno);
+		    return 1;
+		}
+		if(flags & MV_FORCE) {
+		    unlink(rp);
+		    have_dir = 0;
+		} else {
+		    errno = EEXIST;
+		    zwarnnam(nam, "%s: %e", *a, errno);
+		    return 1;
+		}
+	    }
+	    /* Normal case, target is a directory, chase into it */
+	    if (have_dir)
+		goto havedir;
+	}
     }
     if(a > args+1) {
 	zwarnnam(nam, "last of many arguments must be a directory");
@@ -269,7 +312,7 @@ domove(char *nam, MoveFunc move, char *p
 	    zwarnnam(nam, "%s: cannot overwrite directory", q);
 	    zsfree(pbuf);
 	    return 1;
-	} else if(flags & MV_INTER) {
+	} else if(flags & MV_INTERACTIVE) {
 	    nicezputs(nam, stderr);
 	    fputs(": replace `", stderr);
 	    nicezputs(q, stderr);
@@ -705,12 +748,14 @@ bin_chown(char *nam, char **args, Option
 /* module paraphernalia */
 
 #ifdef HAVE_LSTAT
-# define LN_OPTS "dfis"
+# define LN_OPTS "dfhins"
 #else
 # define LN_OPTS "dfi"
 #endif
 
 static struct builtin bintab[] = {
+    /* The names which overlap commands without necessarily being
+     * fully compatible. */
     BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs",    NULL),
     BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs",    NULL),
     BUILTIN("ln",    0, bin_ln,    1, -1, BIN_LN,    LN_OPTS, NULL),
@@ -719,6 +764,16 @@ static struct builtin bintab[] = {
     BUILTIN("rm",    0, bin_rm,    1, -1, 0,         "dfirs", NULL),
     BUILTIN("rmdir", 0, bin_rmdir, 1, -1, 0,         NULL,    NULL),
     BUILTIN("sync",  0, bin_sync,  0,  0, 0,         NULL,    NULL),
+    /* The "safe" zsh-only names */
+    BUILTIN("zf_chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "hRs",    NULL),
+    BUILTIN("zf_chown", 0, bin_chown, 2, -1, BIN_CHOWN, "hRs",    NULL),
+    BUILTIN("zf_ln",    0, bin_ln,    1, -1, BIN_LN,    LN_OPTS, NULL),
+    BUILTIN("zf_mkdir", 0, bin_mkdir, 1, -1, 0,         "pm:",   NULL),
+    BUILTIN("zf_mv",    0, bin_ln,    2, -1, BIN_MV,    "fi",    NULL),
+    BUILTIN("zf_rm",    0, bin_rm,    1, -1, 0,         "dfirs", NULL),
+    BUILTIN("zf_rmdir", 0, bin_rmdir, 1, -1, 0,         NULL,    NULL),
+    BUILTIN("zf_sync",  0, bin_sync,  0,  0, 0,         NULL,    NULL),
+
 };
 
 static struct features module_features = {
Index: Src/Modules/files.mdd
===================================================================
RCS file: /home/cvsroot/zsh/Src/Modules/files.mdd,v
retrieving revision 1.3
diff -p -u -r1.3 files.mdd
--- Src/Modules/files.mdd	20 Jun 2007 20:59:17 -0000	1.3
+++ Src/Modules/files.mdd	8 May 2008 04:18:56 -0000
@@ -2,6 +2,6 @@ name=zsh/files
 link=dynamic
 load=no
 
-autofeatures="b:chgrp b:chown b:ln b:mkdir b:mv b:rm b:rmdir b:sync"
+autofeatures="b:chgrp b:chown b:ln b:mkdir b:mv b:rm b:rmdir b:sync b:zf_chgrp b:zf_chown b:zf_ln b:zf_mkdir b:zf_mv b:zf_rm b:zf_rmdir b:zf_sync"
 
 objects="files.o"

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: PATCH: zsh/files adjustments
  2008-05-08  6:08 PATCH: zsh/files adjustments Phil Pennock
@ 2008-05-08  9:05 ` Peter Stephenson
  2008-05-08 12:03   ` Peter Stephenson
  0 siblings, 1 reply; 3+ messages in thread
From: Peter Stephenson @ 2008-05-08  9:05 UTC (permalink / raw)
  To: Zsh hackers list

On Wed, 7 May 2008 23:08:13 -0700
Phil Pennock <zsh-workers+phil.pennock@spodhuis.org> wrote:
> This patch for zsh/files:
>  * Updates the documentation to be more cautionary
>  * Adds new binary names for the commands
>  * Implements ln -h/-n to inhibit chasing symlinks

Looks OK and I've committed it.

> Is there any thought to being able to name groups of features, perhaps
> with a g: prefix, so that it becomes possible to do:
>   zmodload -F zsh/files +g:zf_commands
>   zmodload -F zsh/files -g:bare_commands
> ?  Is this desirable?  I'd view the semantics as batch-enable/disable,
> so that later items on the command-line override, even if more general.

Something like this is probably desirable, but we might get away with an
option to handle features based on pattern.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: PATCH: zsh/files adjustments
  2008-05-08  9:05 ` Peter Stephenson
@ 2008-05-08 12:03   ` Peter Stephenson
  0 siblings, 0 replies; 3+ messages in thread
From: Peter Stephenson @ 2008-05-08 12:03 UTC (permalink / raw)
  To: Zsh hackers list

On Thu, 8 May 2008 10:05:35 +0100
Peter Stephenson <pws@csr.com> wrote:
> On Wed, 7 May 2008 23:08:13 -0700
> Phil Pennock <zsh-workers+phil.pennock@spodhuis.org> wrote:
> > Is there any thought to being able to name groups of features, perhaps
> > with a g: prefix, so that it becomes possible to do:
> >   zmodload -F zsh/files +g:zf_commands
> >   zmodload -F zsh/files -g:bare_commands
> > ?  Is this desirable?  I'd view the semantics as batch-enable/disable,
> > so that later items on the command-line override, even if more general.
> 
> Something like this is probably desirable, but we might get away with an
> option to handle features based on pattern.

...which is relatively straightforward to add and fully consistent with
lots of other builtins, so is probably worth doing anyway.  Adding struct
feature_enables meant the majority of cases that just pass a NULL
into the module system to specify feature lists can continue to do so.

zmodload -mF zsh/files 'b:zf_*'
setopt extendedglob
zmodload -mf zsh/files 'b:^zf_*'

Index: Doc/Zsh/builtins.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/builtins.yo,v
retrieving revision 1.104
diff -u -r1.104 builtins.yo
--- Doc/Zsh/builtins.yo	28 Mar 2008 09:59:08 -0000	1.104
+++ Doc/Zsh/builtins.yo	8 May 2008 11:58:03 -0000
@@ -1901,7 +1901,7 @@
 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 @@
 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 @@
 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 @@
 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
Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.191
diff -u -r1.191 builtin.c
--- Src/builtin.c	22 Apr 2008 15:08:12 -0000	1.191
+++ Src/builtin.c	8 May 2008 11:58:09 -0000
@@ -131,7 +131,7 @@
     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),
 };
 
Index: Src/module.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/module.c,v
retrieving revision 1.36
diff -u -r1.36 module.c
--- Src/module.c	31 Jul 2007 14:35:52 -0000	1.36
+++ Src/module.c	8 May 2008 11:58:10 -0000
@@ -1967,7 +1967,7 @@
 
 /**/
 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 @@
 		    (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 @@
 	    }
 	}
 
-	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 @@
 		    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 @@
 
 	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 @@
 
 /**/
 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 @@
 
 /**/
 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 @@
 	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 @@
 	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 @@
 
 /**/
 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 @@
 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 @@
 	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 @@
 		     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 @@
 	    } 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 @@
 		    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 @@
 	    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 @@
 	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 @@
 	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 @@
 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 @@
 	    zwarnnam(cmdnam, "%s: `/' is illegal in a %s", fnam, typnam);
 	    ret = 1;
 	    continue;
-	} 
+	}
 
 	if (!module) {
 	    /*
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.130
diff -u -r1.130 zsh.h
--- Src/zsh.h	6 May 2008 09:23:08 -0000	1.130
+++ Src/zsh.h	8 May 2008 11:58:12 -0000
@@ -382,6 +382,7 @@
 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 @@
     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 *));


-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2008-05-08 12:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-05-08  6:08 PATCH: zsh/files adjustments Phil Pennock
2008-05-08  9:05 ` Peter Stephenson
2008-05-08 12:03   ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).