about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/builtin.c20
-rw-r--r--Src/exec.c5
-rw-r--r--Src/options.c1
-rw-r--r--Src/pattern.c167
-rw-r--r--Src/zsh.h16
5 files changed, 205 insertions, 4 deletions
diff --git a/Src/builtin.c b/Src/builtin.c
index bc91578b3..8516acd81 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 14c2ba003..75805d3f5 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 480fccd57..ad869b253 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 54d6e7cb3..a90d3cddc 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 639c2b746..299357de8 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,