Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: configurability of pattern characters, part 2



Here's the basic disable -p / enable -p and emulation behaviour to be
exposed to public view before the rest.  Still to come: restore patterns
for completion (possibly with zsh/parameter variable help); tests for
some of the leading combinations.

Up to now, this has only had finger tests of some of the simpler forms,
so there could well be bugs lurking in the disabling of certain
patterns.  These should emerge when I write some ztst code.

It's unlikely to make your shell eat your pet rabbit if you don't
actually use disable -p, however.

If somebody can spot some effect I haven't documented, please shout.

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index f3a7f6a..a9a150f 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -291,8 +291,8 @@ enditem()
 findex(disable)
 cindex(disabling commands)
 cindex(commands, disabling)
-item(tt(disable) [ tt(-afmrs) ] var(name) ...)(
-Temporarily disable the var(name)d hash table elements.  The default
+item(tt(disable) [ tt(-afmprs) ] var(name) ...)(
+Temporarily disable the var(name)d hash table elements or patterns.  The default
 is to disable builtin commands.  This allows you to use an external
 command with the same name as a builtin command.  The tt(-a) option
 causes tt(disable) to act on regular or global aliases.  The tt(-s)
@@ -305,6 +305,80 @@ quoted to prevent them from undergoing filename expansion), and all hash
 table elements from the corresponding hash table matching these patterns
 are disabled.  Disabled objects can be enabled with the tt(enable)
 command.
+
+With the option tt(-p), var(name) ... refer to elements of the
+shell's pattern syntax as described in noderef(Filename Generation).
+Certain elements can be disabled separately, as given below.
+
+Note that patterns
+not allowed by the current settings for the options tt(EXTENDED_GLOB),
+tt(KSH_GLOB) and tt(SH_GLOB) are never enabled, regardless of the
+setting here.  For example, if tt(EXTENDED_GLOB) is not active,
+the pattern tt(^) is ineffective even if `tt(disable -p "^")' has
+not been issued.  The list below indicates any option settings
+that restrict the use of the pattern.  It should be noted that
+setting tt(SH_GLOB) has a wider effect then merely disabling patterns
+as certain expressions, in particular those involving parentheses,
+are parsed differently.
+
+The following patterns may be disabled; all
+the strings need quoting on the command line to prevent them from
+being interpreted immediately as patterns and the patterns are
+shown below in single quotes as a reminder.
+startitem()
+item(tt('?'))(
+The pattern character tt(?) wherever it occurs, including when preceding
+a parenthesis with tt(KSH_GLOB).
+)
+item(tt('*'))(
+The pattern character tt(*) wherever it occurs, including recursive
+globbing and when preceding a parenthesis with tt(KSH_GLOB).
+)
+item('LSQUARE()')(
+Character classes.
+)
+item(tt('<') (tt(NO_SH_GLOB)))(
+Numeric ranges.
+)
+item(tt('|') (tt(NO_SH_GLOB)))(
+Alternation in grouped patterns, case statements, or KSH_GLOB
+parenthesised expressions.
+)
+item(tt('LPAR()') (tt(NO_SH_GLOB)))(
+Grouping using single parentheses.  Disabling this does not disable the
+use of parentheses for tt(KSH_GLOB) where they are introduced by a
+special character, nor for glob qualifiers (use `tt(setopt
+NO_BARE_GLOB_QUAL)' to disable glob qualifiers that use parentheses
+only).
+)
+item(tt('~') (tt(EXTENDED_GLOB)))(
+Exclusion in the form var(A)tt(~)var(B).
+)
+item(tt('^') (tt(EXTENDED_GLOB)))(
+Exclusion in the form var(A)tt(^)var(B).
+)
+item(tt('#') (tt(EXTENDED_GLOB)))(
+The pattern character tt(#) wherever it occurs, both for
+repetition of a previous pattern and for indicating globbing flags.
+)
+item(tt('?LPAR()') (tt(KSH_GLOB)))(
+The grouping form tt(?LPAR())var(...)tt(RPAR()).  Note this is also
+disabled if tt('?') is disabled.
+)
+item(tt('*LPAR()') (tt(KSH_GLOB)))(
+The grouping form tt(*LPAR())var(...)tt(RPAR()).  Note this is also
+disabled if tt('*') is disabled.
+)
+item(tt('PLUS()LPAR()') (tt(KSH_GLOB)))(
+The grouping form tt(PLUS()LPAR())var(...)tt(RPAR()).
+)
+item(tt('!LPAR()') (tt(KSH_GLOB)))(
+The grouping form tt(!LPAR())var(...)tt(RPAR()).
+)
+item(tt('@LPAR()') (tt(KSH_GLOB)))(
+The grouping form tt(@LPAR())var(...)tt(RPAR()).
+)
+enditem()
 )
 findex(disown)
 cindex(jobs, disowning)
@@ -376,7 +450,9 @@ the section COMPATIBILITY in zmanref(zsh)
 ifnzman(\
 noderef(Compatibility)
 )\
-.
+.  In addition to setting shell options, the command also restores
+the pristine state of pattern enables, as if all patterns had been
+enabled using tt(enable -p).
 
 If the tt(emulate) command occurs inside a function that has been
 marked for execution tracing with tt(functions -t) then the tt(xtrace)
@@ -390,9 +466,11 @@ are reset to their default value corresponding to the specified emulation
 mode, except for certain options describing the interactive
 environment; otherwise, only those options likely to cause portability
 problems in scripts and functions are altered.  If the tt(-L) switch is given,
-the options tt(LOCAL_OPTIONS) and tt(LOCAL_TRAPS) will be set as
-well, causing the effects of the tt(emulate) command and any tt(setopt) and
-tt(trap) commands to be local to the immediately surrounding shell
+the options tt(LOCAL_OPTIONS), tt(LOCAL_PATTERNS) and tt(LOCAL_TRAPS)
+will be set as
+well, causing the effects of the tt(emulate) command and any tt(setopt),
+tt(disable -p) or tt(enable -b), and tt(trap) commands to be local to
+the immediately surrounding shell
 function, if any; normally these options are turned off in all emulation
 modes except tt(ksh). The tt(-L) switch is mutually exclusive with the
 use of tt(-c) in var(flags).
@@ -414,7 +492,8 @@ Use of tt(-c) enables `sticky' emulation mode for functions defined
 within the evaluated expression:  the emulation mode is associated
 thereafter with the function so that whenever the function is executed
 the emulation (respecting the tt(-R) switch, if present) and all
-options are set before entry to the function, and restored after exit.
+options are set (and pattern disables cleared)
+before entry to the function, and the state is restored after exit.
 If the function is called when the sticky emulation is already in
 effect, either within an `tt(emulate) var(shell) tt(-c)' expression or
 within another function with the same sticky emulation, entry and exit
@@ -471,7 +550,7 @@ endsitem()
 findex(enable)
 cindex(enabling commands)
 cindex(commands, enabling)
-item(tt(enable) [ tt(-afmrs) ] var(name) ...)(
+item(tt(enable) [ tt(-afmprs) ] var(name) ...)(
 Enable the var(name)d hash table elements, presumably disabled
 earlier with tt(disable).  The default is to enable builtin commands.
 The tt(-a) option causes tt(enable) to act on regular or global aliases.
@@ -483,6 +562,13 @@ printed.  With the tt(-m) flag the arguments are taken as patterns
 (should be quoted) and all hash table elements from the corresponding
 hash table matching these patterns are enabled.  Enabled objects can be
 disabled with the tt(disable) builtin command.
+
+tt(enable -p) reenables patterns disabled with tt(disable -p).  Note
+that it does not override globbing options; for example, `tt(enable -p
+"~")' does not cause the pattern character tt(~) to be active unless
+the tt(EXTENDED_GLOB) option is also set.  To enable all possible
+patterns (so that they may be invidually disabled with tt(disable -p)),
+use `tt(setopt EXTENDED_GLOB KSH_GLOB NO_SH_GLOB)'.
 )
 findex(eval)
 cindex(evaluating arguments as commands)
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 60892dd..ec86232 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1618,6 +1618,19 @@ A shell function can also guarantee itself a known shell configuration
 with a formulation like `tt(emulate -L zsh)'; the tt(-L) activates
 tt(LOCAL_OPTIONS).
 )
+pindex(LOCAL_PATTERNS)
+pindex(NO_LOCAL_PATTERNS)
+pindex(LOCALPATTERNS)
+pindex(NOLOCALPATTERNS)
+item(tt(LOCAL_PATTERNS))(
+If this option is set at the point of return from a shell function,
+the state of pattern disables, as set with the builtin command
+`tt(disable -p)', is restored to what it was when the function was
+entered.  The behaviour of this option is similar to the effect
+of tt(LOCAL_OPTIONS) on options; hence `tt(emulate -L sh)' (or
+indeed any other emulation with the tt(-L) option) activates
+tt(LOCAL_PATTERNS).
+)
 pindex(LOCAL_TRAPS)
 pindex(NO_LOCAL_TRAPS)
 pindex(LOCALTRAPS)
diff --git a/Doc/zmacros.yo b/Doc/zmacros.yo
index 19506d2..aed5bd8 100644
--- a/Doc/zmacros.yo
+++ b/Doc/zmacros.yo
@@ -33,6 +33,7 @@ DEFINEMACRO(RQUOTE)(0)(CHAR(39))
 DEFINEMACRO(LPAR)(0)(CHAR(40))
 DEFINEMACRO(RPAR)(0)(CHAR(41))
 DEFINEMACRO(PLUS)(0)(CHAR(43))
+DEFINEMACRO(LSQUARE)(0)(CHAR(91))
 
 DEFINEMACRO(DASH)(0)(ifztexi(--)ifnztexi(-))
 
diff --git a/Src/builtin.c b/Src/builtin.c
index bc91578..8516acd 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -55,11 +55,11 @@ static struct builtin builtins[] =
     BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL),
     BUILTIN("declare", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klmprtuxz", NULL),
     BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "clpv", NULL),
-    BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmrs", NULL),
+    BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmprs", NULL),
     BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
     BUILTIN("echo", BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"),
     BUILTIN("emulate", 0, bin_emulate, 0, -1, 0, "LR", NULL),
-    BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmrs", NULL),
+    BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", NULL),
     BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
     BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
     BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"),
@@ -467,7 +467,9 @@ bin_enable(char *name, char **argv, Options ops, int func)
     int match = 0, returnval = 0;
 
     /* Find out which hash table we are working with. */
-    if (OPT_ISSET(ops,'f'))
+    if (OPT_ISSET(ops,'p')) {
+	return pat_enables(name, argv, func == BIN_ENABLE);
+    } else if (OPT_ISSET(ops,'f'))
 	ht = shfunctab;
     else if (OPT_ISSET(ops,'r'))
 	ht = reswdtab;
@@ -5020,6 +5022,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
     int opt_R = OPT_ISSET(ops, 'R');
     int saveemulation, savehackchar;
     int ret = 1, new_emulation;
+    unsigned int savepatterns;
     char saveopts[OPT_SIZE], new_opts[OPT_SIZE];
     char *cmd = 0;
     const char *shname = *argv;
@@ -5061,7 +5064,8 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
     if (!argv[1]) {
 	emulate(shname, OPT_ISSET(ops,'R'), &emulation, opts);
 	if (OPT_ISSET(ops,'L'))
-	    opts[LOCALOPTIONS] = opts[LOCALTRAPS] = 1;
+	    opts[LOCALOPTIONS] = opts[LOCALTRAPS] = opts[LOCALPATTERNS] = 1;
+	clearpatterndisables();
 	return 0;
     }
 
@@ -5082,6 +5086,13 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
 	goto restore;
     }
 
+    savepatterns = savepatterndisables();
+    /*
+     * All emulations start with an empty set of pattern disables,
+     * hence no special "sticky" behaviour is required.
+     */
+    clearpatterndisables();
+
     saveemulation = emulation;
     emulation = new_emulation;
     memcpy(opts, new_opts, sizeof(opts));
@@ -5131,6 +5142,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func))
     sticky = save_sticky;
     emulation = saveemulation;
     memcpy(opts, saveopts, sizeof(opts));
+    restorepatterndisables(savepatterns);
 restore:
     keyboardhackchar = savehackchar;
     inittyptab();	/* restore banghist */
diff --git a/Src/exec.c b/Src/exec.c
index 14c2ba0..75805d3 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -4627,6 +4627,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
     }
 
     starttrapscope();
+    startpatternscope();
 
     pptab = pparams;
     if (!(flags & PM_UNDEFINED))
@@ -4674,6 +4675,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 		 offptr++)
 		opts[*offptr] = 0;
 	}
+	/* All emulations start with pattern disables clear */
+	clearpatterndisables();
     } else
 	restore_sticky = 0;
 
@@ -4774,6 +4777,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
     scriptname = oldscriptname;
     oflags = ooflags;
 
+    endpatternscope();		/* before restoring old LOCALPATTERNS */
+
     if (restore_sticky) {
 	/*
 	 * If we switched to an emulation environment just for
diff --git a/Src/options.c b/Src/options.c
index 480fccd..ad869b2 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -179,6 +179,7 @@ static struct optname optns[] = {
 {{NULL, "listrowsfirst",      0},			 LISTROWSFIRST},
 {{NULL, "listtypes",	      OPT_ALL},			 LISTTYPES},
 {{NULL, "localoptions",	      OPT_EMULATE|OPT_KSH},	 LOCALOPTIONS},
+{{NULL, "localpatterns",      OPT_EMULATE},		 LOCALPATTERNS},
 {{NULL, "localtraps",	      OPT_EMULATE|OPT_KSH},	 LOCALTRAPS},
 {{NULL, "login",	      OPT_SPECIAL},		 LOGINSHELL},
 {{NULL, "longlistjobs",	      0},			 LONGLISTJOBS},
diff --git a/Src/pattern.c b/Src/pattern.c
index 54d6e7c..a90d3cd 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -233,6 +233,27 @@ static const char zpc_chars[ZPC_COUNT] = {
 };
 
 /*
+ * Corresponding strings used in enable/disable -p.
+ * NULL means no way of turning this on or off.
+ */
+static const char *zpc_strings[ZPC_COUNT] = {
+   NULL, NULL, "|", NULL, "~", "(", "?", "*", "[", "<",
+   "^", "#", NULL, "?(", "*(", "+(", "!(", "@("
+};
+
+/*
+ * Corresponding array of pattern disables as set by the user
+ * using "disable -p".
+ */
+static char zpc_disables[ZPC_COUNT];
+
+/*
+ * Stack of saved (compressed) zpc_disables for function scope.
+ */
+
+static struct zpc_disables_save *zpc_disables_stack;
+
+/*
  * Characters which terminate a simple string (ZPC_COUNT) or
  * an entire pattern segment (the first ZPC_SEG_COUNT).
  * Each entry is either the corresponding character in zpc_chars
@@ -414,7 +435,19 @@ static long rn_offs;
 static void
 patcompcharsset(void)
 {
+    char *spp, *disp;
+    int i;
+
+    /* Initialise enabled special characters */
     memcpy(zpc_special, zpc_chars, ZPC_COUNT);
+    /* Apply user disables from disable -p */
+    for (i = 0, spp = zpc_special, disp = zpc_disables;
+	 i < ZPC_COUNT;
+	 i++, spp++, disp++) {
+	if (*disp)
+	    *spp = Marker;
+    }
+
     if (!isset(EXTENDEDGLOB)) {
 	/* Extended glob characters are not active */
 	zpc_special[ZPC_TILDE] = zpc_special[ZPC_HAT] =
@@ -3799,3 +3832,137 @@ freepatprog(Patprog prog)
     if (prog && prog != dummy_patprog1 && prog != dummy_patprog2)
 	zfree(prog, prog->size);
 }
+
+/* Disable or reenable a pattern character */
+
+/**/
+int
+pat_enables(const char *cmd, char **patp, int enable)
+{
+    int ret = 0;
+    const char **stringp;
+    char *disp;
+
+    if (!*patp) {
+	int done = 0;
+	for (stringp = zpc_strings, disp = zpc_disables;
+	     stringp < zpc_strings + ZPC_COUNT;
+	     stringp++, disp++) {
+	    if (!*stringp)
+		continue;
+	    if (enable ? *disp : !*disp)
+		continue;
+	    if (done)
+		putc(' ', stdout);
+	    printf("'%s'", *stringp);
+	    done = 1;
+	}
+	if (done)
+	    putc('\n', stdout);
+	return 0;
+    }
+
+    for (; *patp; patp++) {
+	for (stringp = zpc_strings, disp = zpc_disables;
+	     stringp < zpc_strings + ZPC_COUNT;
+	     stringp++, disp++) {
+	    if (*stringp && !strcmp(*stringp, *patp)) {
+		*disp = (char)!enable;
+		break;
+	    }
+	}
+	if (stringp == zpc_strings + ZPC_COUNT) {
+	    zerrnam(cmd, "invalid pattern: %s", *patp);
+	    ret = 1;
+	}
+    }
+
+    return ret;
+}
+
+/*
+ * Save the current state of pattern disables, returning the saved value.
+ */
+
+/**/
+unsigned int
+savepatterndisables(void)
+{
+    unsigned int disables, bit;
+    char *disp;
+
+    disables = 0;
+    for (bit = 1, disp = zpc_disables;
+	 disp < zpc_disables + ZPC_COUNT;
+	 bit <<= 1, disp++) {
+	if (*disp)
+	    disables |= bit;
+    }
+    return disables;
+}
+
+/*
+ * Function scope saving pattern enables.
+ */
+
+/**/
+void
+startpatternscope(void)
+{
+    Zpc_disables_save newdis;
+
+    newdis = (Zpc_disables_save)zalloc(sizeof(*newdis));
+    newdis->next = zpc_disables_stack;
+    newdis->disables = savepatterndisables();
+
+    zpc_disables_stack = newdis;
+}
+
+/*
+ * Restore completely the state of pattern disables.
+ */
+
+/**/
+void
+restorepatterndisables(unsigned int disables)
+{
+    char *disp;
+    unsigned int bit;
+
+    for (bit = 1, disp = zpc_disables;
+	 disp < zpc_disables + ZPC_COUNT;
+	 bit <<= 1, disp++) {
+	if (disables & bit)
+	    *disp = 1;
+	else
+	    *disp = 0;
+    }
+}
+
+/*
+ * Function scope to restore pattern enables if localpatterns is turned on.
+ */
+
+/**/
+void
+endpatternscope(void)
+{
+    Zpc_disables_save olddis;
+
+    olddis = zpc_disables_stack;
+    zpc_disables_stack = olddis->next;
+
+    if (isset(LOCALPATTERNS))
+	restorepatterndisables(olddis->disables);
+
+    zfree(olddis, sizeof(*olddis));
+}
+
+/* Reinitialise pattern disables */
+
+/**/
+void
+clearpatterndisables(void)
+{
+    memset(zpc_disables, 0, ZPC_COUNT);
+}
diff --git a/Src/zsh.h b/Src/zsh.h
index 639c2b7..299357d 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1414,6 +1414,21 @@ enum zpc_chars {
 };
 
 /*
+ * Structure to save disables special characters for function scope.
+ */
+struct zpc_disables_save {
+    struct zpc_disables_save *next;
+    /*
+     * Bit vector of ZPC_COUNT disabled characters.
+     * We'll live dangerously and assumed ZPC_COUNT is no greater
+     * than the number of bits an an unsigned int.
+     */
+    unsigned int disables;
+};
+
+typedef struct zpc_disables_save *Zpc_disables_save;
+
+/*
  * Special match types used in character classes.  These
  * are represented as tokens, with Meta added.  The character
  * class is represented as a metafied string, with only these
@@ -2074,6 +2089,7 @@ enum {
     LISTROWSFIRST,
     LISTTYPES,
     LOCALOPTIONS,
+    LOCALPATTERNS,
     LOCALTRAPS,
     LOGINSHELL,
     LONGLISTJOBS,

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author