about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/parameter.c231
-rw-r--r--Src/builtin.c72
-rw-r--r--Src/hashtable.c74
-rw-r--r--Src/init.c2
-rw-r--r--Src/lex.c40
-rw-r--r--Src/zsh.h5
6 files changed, 298 insertions, 126 deletions
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 6960dceb0..dc92aaaf8 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -1611,49 +1611,56 @@ scanpmuserdirs(HashTable ht, ScanFunc func, int flags)
 	}
 }
 
-/* Functions for the regularaliases and globalaliases special parameters. */
+/* Functions for the raliases, galiases and saliases special parameters. */
 
 /**/
 static void
-setralias(Param pm, char *value, int dis)
+setalias(HashTable ht, Param pm, char *value, int flags)
 {
-    aliastab->addnode(aliastab, ztrdup(pm->nam), createaliasnode(value, dis));
+    ht->addnode(aliastab, ztrdup(pm->nam),
+		createaliasnode(value, flags));
 }
 
 /**/
 static void
 setpmralias(Param pm, char *value)
 {
-    setralias(pm, value, 0);
+    setalias(aliastab, pm, value, 0);
 }
 
 /**/
 static void
 setpmdisralias(Param pm, char *value)
 {
-    setralias(pm, value, DISABLED);
+    setalias(aliastab, pm, value, DISABLED);
 }
 
 /**/
 static void
-setgalias(Param pm, char *value, int dis)
+setpmgalias(Param pm, char *value)
 {
-    aliastab->addnode(aliastab, ztrdup(pm->nam),
-		      createaliasnode(value, dis | ALIAS_GLOBAL));
+    setalias(aliastab, pm, value, ALIAS_GLOBAL);
 }
 
 /**/
 static void
-setpmgalias(Param pm, char *value)
+setpmdisgalias(Param pm, char *value)
 {
-    setgalias(pm, value, 0);
+    setgalias(aliastab, pm, value, ALIAS_GLOBAL|DISABLED);
 }
 
 /**/
 static void
-setpmdisgalias(Param pm, char *value)
+setpmsalias(Param pm, char *value)
 {
-    setgalias(pm, value, DISABLED);
+    setgalias(sufaliastab, pm, value, 0);
+}
+
+/**/
+static void
+setpmdissalias(Param pm, char *value)
+{
+    setgalias(sufaliastab, pm, value, DISABLED);
 }
 
 /**/
@@ -1668,7 +1675,17 @@ unsetpmalias(Param pm, int exp)
 
 /**/
 static void
-setaliases(Param pm, HashTable ht, int global, int dis)
+unsetpmsalias(Param pm, int exp)
+{
+    HashNode hd = sufaliastab->removenode(sufaliastab, pm->nam);
+
+    if (hd)
+	sufaliastab->freenode(hd);
+}
+
+/**/
+static void
+setaliases(HashTable alht, Param pm, HashTable ht, int flags)
 {
     int i;
     HashNode hn, next, hd;
@@ -1676,13 +1693,18 @@ setaliases(Param pm, HashTable ht, int global, int dis)
     if (!ht)
 	return;
 
-    for (i = 0; i < aliastab->hsize; i++)
-	for (hn = aliastab->nodes[i]; hn; hn = next) {
+    for (i = 0; i < alht->hsize; i++)
+	for (hn = alht->nodes[i]; hn; hn = next) {
 	    next = hn->next;
-	    if (((global && (((Alias) hn)->flags & ALIAS_GLOBAL)) ||
-		 (!global && !(((Alias) hn)->flags & ALIAS_GLOBAL))) &&
-		(hd = aliastab->removenode(aliastab, hn->nam)))
-		aliastab->freenode(hd);
+	    /*
+	     * The following respects the DISABLED flag, e.g.
+	     * we get a different behaviour for raliases and dis_raliases.
+	     * The predecessor to this code didn't do that; presumably
+	     * that was a bug.
+	     */
+	    if (flags == ((Alias)hn)->flags &&
+		(hd = alht->removenode(alht, hn->nam)))
+		alht->freenode(hd);
 	}
 
     for (i = 0; i < ht->hsize; i++)
@@ -1696,10 +1718,8 @@ setaliases(Param pm, HashTable ht, int global, int dis)
 	    v.pm = (Param) hn;
 
 	    if ((val = getstrvalue(&v)))
-		aliastab->addnode(aliastab, ztrdup(hn->nam),
-				  createaliasnode(ztrdup(val),
-						  (global ? ALIAS_GLOBAL : 0) |
-						  (dis ? DISABLED : 0)));
+		alht->addnode(alht, ztrdup(hn->nam),
+			      createaliasnode(ztrdup(val), flags));
 	}
     deleteparamtable(ht);
 }
@@ -1708,53 +1728,103 @@ setaliases(Param pm, HashTable ht, int global, int dis)
 static void
 setpmraliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 0, 0);
+    setaliases(aliastab, pm, ht, 0);
 }
 
 /**/
 static void
 setpmdisraliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 0, DISABLED);
+    setaliases(aliastab, pm, ht, DISABLED);
 }
 
 /**/
 static void
 setpmgaliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 1, 0);
+    setaliases(aliastab, pm, ht, ALIAS_GLOBAL);
 }
 
 /**/
 static void
 setpmdisgaliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 1, DISABLED);
+    setaliases(aliastab, pm, ht, ALIAS_GLOBAL|DISABLED);
 }
 
 /**/
-static HashNode
-getalias(HashTable ht, char *name, int global, int dis)
+static void
+setpmsaliases(Param pm, HashTable ht)
 {
-    Param pm = NULL;
-    Alias al;
+    setaliases(sufaliastab, pm, ht, ALIAS_SUFFIX);
+}
 
-    pm = (Param) zhalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
+/**/
+static void
+setpmdissaliases(Param pm, HashTable ht)
+{
+    setaliases(sufaliastab, pm, ht, ALIAS_SUFFIX|DISABLED);
+}
+
+/**/
+static void
+assignaliasdefs(Param pm, int flags)
+{
     pm->flags = PM_SCALAR;
-    pm->sets.cfn = (global ? (dis ? setpmdisgalias : setpmgalias) :
-		    (dis ? setpmdisralias : setpmralias));
+
+    /* we really need to squirrel the flags away somewhere... */
+    switch (flags) {
+    case 0:
+	    pm->sets.cfn = setpmralias;
+	    break;
+
+    case ALIAS_GLOBAL:
+	    pm->sets.cfn = setpmgalias;
+	    break;
+
+    case ALIAS_SUFFIX:
+	    pm->sets.cfn = setpmsalias;
+	    break;
+
+    case DISABLED:
+	    pm->sets.cfn = setpmdisralias;
+	    break;
+
+    case ALIAS_GLOBAL|DISABLED:
+	    pm->sets.cfn = setpmdisgalias;
+	    break;
+
+    case ALIAS_SUFFIX|DISABLED:
+	    pm->sets.cfn = setpmdissalias;
+	    break;
+   }
+
     pm->gets.cfn = strgetfn;
-    pm->unsetfn = unsetpmalias;
+    if (flags & ALIAS_SUFFIX)
+	pm->unsetfn = unsetpmsalias;
+    else
+	pm->unsetfn = unsetpmalias;
     pm->ct = 0;
     pm->env = NULL;
     pm->ename = NULL;
     pm->old = NULL;
     pm->level = 0;
-    if ((al = (Alias) aliastab->getnode2(aliastab, name)) &&
-	((global && (al->flags & ALIAS_GLOBAL)) ||
-	 (!global && !(al->flags & ALIAS_GLOBAL))) &&
-	(dis ? (al->flags & DISABLED) : !(al->flags & DISABLED)))
+}
+
+/**/
+static HashNode
+getalias(HashTable alht, HashTable ht, char *name, int flags)
+{
+    Param pm = NULL;
+    Alias al;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+
+    assignaliasdefs(pm, flags);
+
+    if ((al = (Alias) alht->getnode2(alht, name)) &&
+	flags == al->flags)
 	pm->u.str = dupstring(al->text);
     else {
 	pm->u.str = dupstring("");
@@ -1767,61 +1837,64 @@ getalias(HashTable ht, char *name, int global, int dis)
 static HashNode
 getpmralias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 0, 0);
+    return getalias(aliastab, ht, name, 0);
 }
 
 /**/
 static HashNode
 getpmdisralias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 0, 0);
+    return getalias(aliastab, ht, name, DISABLED);
 }
 
 /**/
 static HashNode
 getpmgalias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 1, 0);
+    return getalias(aliastab, ht, name, ALIAS_GLOBAL);
 }
 
 /**/
 static HashNode
 getpmdisgalias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 1, DISABLED);
+    return getalias(aliastab, ht, name, ALIAS_GLOBAL|DISABLED);
+}
+
+/**/
+static HashNode
+getpmsalias(HashTable ht, char *name)
+{
+    return getalias(sufaliastab, ht, name, ALIAS_SUFFIX);
+}
+
+/**/
+static HashNode
+getpmdissalias(HashTable ht, char *name)
+{
+    return getalias(sufaliastab, ht, name, ALIAS_SUFFIX|DISABLED);
 }
 
 /**/
 static void
-scanaliases(HashTable ht, ScanFunc func, int flags, int global, int dis)
+scanaliases(HashTable alht, HashTable ht, ScanFunc func,
+	    int pmflags, int alflags)
 {
     struct param pm;
     int i;
-    HashNode hn;
     Alias al;
 
-    pm.flags = PM_SCALAR;
-    pm.sets.cfn = (global ? (dis ? setpmdisgalias : setpmgalias) :
-		   (dis ? setpmdisralias : setpmralias));
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = unsetpmalias;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    assignaliasdefs(&pm, alflags);
 
-    for (i = 0; i < aliastab->hsize; i++)
-	for (hn = aliastab->nodes[i]; hn; hn = hn->next) {
-	    if (((global && ((al = (Alias) hn)->flags & ALIAS_GLOBAL)) ||
-		 (!global && !((al = (Alias) hn)->flags & ALIAS_GLOBAL))) &&
-		(dis ? (al->flags & DISABLED) : !(al->flags & DISABLED))) {
-		pm.nam = hn->nam;
+    for (i = 0; i < alht->hsize; i++)
+	for (al = (Alias) alht->nodes[i]; al; al = (Alias) al->next) {
+	    if (alflags == al->flags) {
+		pm.nam = al->nam;
 		if (func != scancountparams &&
-		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
-		     !(flags & SCANPM_WANTKEYS)))
+		    ((pmflags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(pmflags & SCANPM_WANTKEYS)))
 		    pm.u.str = dupstring(al->text);
-		func((HashNode) &pm, flags);
+		func((HashNode) &pm, pmflags);
 	    }
 	}
 }
@@ -1830,28 +1903,42 @@ scanaliases(HashTable ht, ScanFunc func, int flags, int global, int dis)
 static void
 scanpmraliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 0, 0);
+    scanaliases(aliastab, ht, func, flags, 0);
 }
 
 /**/
 static void
 scanpmdisraliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 0, DISABLED);
+    scanaliases(aliastab, ht, func, flags, DISABLED);
 }
 
 /**/
 static void
 scanpmgaliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 1, 0);
+    scanaliases(aliastab, ht, func, flags, ALIAS_GLOBAL);
 }
 
 /**/
 static void
 scanpmdisgaliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 1, DISABLED);
+    scanaliases(aliastab, ht, func, flags, ALIAS_GLOBAL|DISABLED);
+}
+
+/**/
+static void
+scanpmsaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX);
+}
+
+/**/
+static void
+scanpmdissaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX|DISABLED);
 }
 
 /* Table for defined parameters. */
@@ -1932,12 +2019,18 @@ static struct pardef partab[] = {
     { "galiases", 0,
       getpmgalias, scanpmgaliases, setpmgaliases,
       NULL, NULL, stdunsetfn, NULL },
+    { "saliases", 0,
+      getpmsalias, scanpmsaliases, setpmsaliases,
+      NULL, NULL, stdunsetfn, NULL },
     { "dis_aliases", 0,
       getpmdisralias, scanpmdisraliases, setpmdisraliases,
       NULL, NULL, stdunsetfn, NULL },
     { "dis_galiases", 0,
       getpmdisgalias, scanpmdisgaliases, setpmdisgaliases,
       NULL, NULL, stdunsetfn, NULL },
+    { "dis_saliases", 0,
+      getpmdissalias, scanpmdissaliases, setpmdissaliases,
+      NULL, NULL, stdunsetfn, NULL },
     { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
diff --git a/Src/builtin.c b/Src/builtin.c
index bdb7c72d8..057800df6 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -45,7 +45,7 @@ static struct builtin builtins[] =
     BUILTIN("[", 0, bin_test, 0, -1, BIN_BRACKET, NULL, NULL),
     BUILTIN(".", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
     BUILTIN(":", BINF_PSPECIAL, bin_true, 0, -1, 0, NULL, NULL),
-    BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmr", NULL),
+    BUILTIN("alias", BINF_MAGICEQUALS | BINF_PLUSOPTS, bin_alias, 0, -1, 0, "Lgmrs", NULL),
     BUILTIN("autoload", BINF_PLUSOPTS, bin_functions, 0, -1, 0, "tUXwkz", "u"),
     BUILTIN("bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL),
     BUILTIN("break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL),
@@ -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:%lprtux", NULL),
     BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "clpv", NULL),
-    BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL),
+    BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmrs", NULL),
     BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
     BUILTIN("echo", BINF_PRINTOPTS | BINF_SKIPINVALID, bin_print, 0, -1, BIN_ECHO, "neE", "-"),
     BUILTIN("emulate", 0, bin_emulate, 1, 1, 0, "LR", NULL),
-    BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL),
+    BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmrs", 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"),
@@ -123,9 +123,9 @@ static struct builtin builtins[] =
     BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"),
     BUILTIN("typeset", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%lprtuxm", NULL),
     BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
-    BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"),
+    BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "ms", "a"),
     BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"),
-    BUILTIN("unhash", 0, bin_unhash, 1, -1, 0, "adfm", NULL),
+    BUILTIN("unhash", 0, bin_unhash, 1, -1, 0, "adfms", NULL),
     BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmv", NULL),
     BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL),
     BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL),
@@ -461,6 +461,8 @@ bin_enable(char *name, char **argv, Options ops, int func)
 	ht = shfunctab;
     else if (OPT_ISSET(ops,'r'))
 	ht = reswdtab;
+    else if (OPT_ISSET(ops,'s'))
+	ht = sufaliastab;
     else if (OPT_ISSET(ops,'a'))
 	ht = aliastab;
     else
@@ -2671,6 +2673,8 @@ bin_whence(char *nam, char **argv, Options ops, int func)
 	informed = 0;
 
 	if (!OPT_ISSET(ops,'p')) {
+	    char *suf;
+
 	    /* Look for alias */
 	    if ((hn = aliastab->getnode(aliastab, *argv))) {
 		aliastab->printnode(hn, printflags);
@@ -2678,6 +2682,15 @@ bin_whence(char *nam, char **argv, Options ops, int func)
 		    continue;
 		informed = 1;
 	    }
+	    /* Look for suffix alias */
+	    if ((suf = strrchr(*argv, '.')) && suf[1] &&
+		suf > *argv && suf[-1] != Meta &&
+		(hn = sufaliastab->getnode(sufaliastab, suf+1))) {
+		sufaliastab->printnode(hn, printflags);
+		if (!all)
+		    continue;
+		informed = 1;
+	    }
 	    /* Look for reserved word */
 	    if ((hn = reswdtab->getnode(reswdtab, *argv))) {
 		reswdtab->printnode(hn, printflags);
@@ -2901,6 +2914,8 @@ bin_unhash(char *name, char **argv, Options ops, int func)
 	ht = nameddirtab;	/* named directories */
     else if (OPT_ISSET(ops,'f'))
 	ht = shfunctab;		/* shell functions   */
+    else if (OPT_ISSET(ops,'s'))
+	ht = sufaliastab;	/* suffix aliases, must precede aliases */
     else if (OPT_ISSET(ops,'a'))
 	ht = aliastab;		/* aliases           */
     else
@@ -2963,34 +2978,48 @@ bin_alias(char *name, char **argv, Options ops, int func)
     Alias a;
     Patprog pprog;
     Asgment asg;
-    int haveflags = 0, returnval = 0;
+    int returnval = 0;
     int flags1 = 0, flags2 = DISABLED;
     int printflags = 0;
+    int type_opts;
+    HashTable ht = aliastab;
 
     /* Did we specify the type of alias? */
-    if (OPT_ISSET(ops,'r') || OPT_ISSET(ops,'g')) {
-	if (OPT_ISSET(ops,'r') && OPT_ISSET(ops,'g')) {
+    type_opts = OPT_ISSET(ops, 'r') + OPT_ISSET(ops, 'g') +
+	OPT_ISSET(ops, 's');
+    if (type_opts) {
+	if (type_opts > 1) {
 	    zwarnnam(name, "illegal combination of options", NULL, 0);
 	    return 1;
 	}
-	haveflags = 1;
 	if (OPT_ISSET(ops,'g'))
 	    flags1 |= ALIAS_GLOBAL;
 	else
 	    flags2 |= ALIAS_GLOBAL;
+	if (OPT_ISSET(ops, 's')) {
+	    /*
+	     * Although we keep suffix aliases in a different table,
+	     * it is useful to be able to distinguish Alias structures
+	     * without reference to the table, so we have a separate
+	     * flag, too.
+	     */
+	    flags1 |= ALIAS_SUFFIX;
+	    ht = sufaliastab;
+	} else
+	    flags2 |= ALIAS_SUFFIX;
     }
 
     if (OPT_ISSET(ops,'L'))
 	printflags |= PRINT_LIST;
-    else if (OPT_PLUS(ops,'r') || OPT_PLUS(ops,'g')|| OPT_PLUS(ops,'m') ||
-	     OPT_ISSET(ops,'+'))
+    else if (OPT_PLUS(ops,'g') || OPT_PLUS(ops,'r') || OPT_PLUS(ops,'s') ||
+	     OPT_PLUS(ops,'m') || OPT_ISSET(ops,'+'))
 	printflags |= PRINT_NAMEONLY;
 
     /* In the absence of arguments, list all aliases.  If a command *
      * line flag is specified, list only those of that type.        */
     if (!*argv) {
 	queue_signals();
-	scanhashtable(aliastab, 1, flags1, flags2, aliastab->printnode, printflags);
+	scanhashtable(ht, 1, flags1, flags2, ht->printnode, printflags);
 	unqueue_signals();
 	return 0;
     }
@@ -3003,8 +3032,8 @@ bin_alias(char *name, char **argv, Options ops, int func)
 	    if ((pprog = patcompile(*argv, PAT_STATIC, NULL))) {
 		/* display the matching aliases */
 		queue_signals();
-		scanmatchtable(aliastab, pprog, flags1, flags2,
-			       aliastab->printnode, printflags);
+		scanmatchtable(ht, pprog, flags1, flags2,
+			       ht->printnode, printflags);
 		unqueue_signals();
 	    } else {
 		untokenize(*argv);
@@ -3021,14 +3050,15 @@ bin_alias(char *name, char **argv, Options ops, int func)
 	if (asg->value && !OPT_ISSET(ops,'L')) {
 	    /* The argument is of the form foo=bar and we are not *
 	     * forcing a listing with -L, so define an alias      */
-	    aliastab->addnode(aliastab, ztrdup(asg->name),
-			      createaliasnode(ztrdup(asg->value), flags1));
-	} else if ((a = (Alias) aliastab->getnode(aliastab, asg->name))) {
+	    ht->addnode(ht, ztrdup(asg->name),
+			createaliasnode(ztrdup(asg->value), flags1));
+	} else if ((a = (Alias) ht->getnode(ht, asg->name))) {
 	    /* display alias if appropriate */
-	    if (!haveflags ||
-		(OPT_ISSET(ops,'r') && !(a->flags & ALIAS_GLOBAL)) ||
-		(OPT_ISSET(ops,'g') &&  (a->flags & ALIAS_GLOBAL)))
-		aliastab->printnode((HashNode) a, printflags);
+	    if (!type_opts || ht == sufaliastab ||
+		(OPT_ISSET(ops,'r') && 
+		 !(a->flags & (ALIAS_GLOBAL|ALIAS_SUFFIX))) ||
+		(OPT_ISSET(ops,'g') && (a->flags & ALIAS_GLOBAL)))
+		ht->printnode((HashNode) a, printflags);
 	} else
 	    returnval = 1;
     }
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 9fc7a3232..faa858532 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -1014,30 +1014,51 @@ printreswdnode(HashNode hn, int printflags)
 /**/
 mod_export HashTable aliastab;
  
-/* Create new hash table for aliases */
+/* has table containing suffix aliases */
+
+/**/
+mod_export HashTable sufaliastab;
+ 
+/* Create new hash tables for aliases */
+
+/**/
+void
+createaliastable(HashTable ht)
+{
+    ht->hash        = hasher;
+    ht->emptytable  = NULL;
+    ht->filltable   = NULL;
+    ht->cmpnodes    = strcmp;
+    ht->addnode     = addhashnode;
+    ht->getnode     = gethashnode;
+    ht->getnode2    = gethashnode2;
+    ht->removenode  = removehashnode;
+    ht->disablenode = disablehashnode;
+    ht->enablenode  = enablehashnode;
+    ht->freenode    = freealiasnode;
+    ht->printnode   = printaliasnode;
+}
 
 /**/
 void
-createaliastable(void)
+createaliastables(void)
 {
+    /* Table for regular and global aliases */
+
     aliastab = newhashtable(23, "aliastab", NULL);
 
-    aliastab->hash        = hasher;
-    aliastab->emptytable  = NULL;
-    aliastab->filltable   = NULL;
-    aliastab->cmpnodes    = strcmp;
-    aliastab->addnode     = addhashnode;
-    aliastab->getnode     = gethashnode;
-    aliastab->getnode2    = gethashnode2;
-    aliastab->removenode  = removehashnode;
-    aliastab->disablenode = disablehashnode;
-    aliastab->enablenode  = enablehashnode;
-    aliastab->freenode    = freealiasnode;
-    aliastab->printnode   = printaliasnode;
+    createaliastable(aliastab);
 
     /* add the default aliases */
     aliastab->addnode(aliastab, ztrdup("run-help"), createaliasnode(ztrdup("man"), 0));
     aliastab->addnode(aliastab, ztrdup("which-command"), createaliasnode(ztrdup("whence"), 0));
+
+
+    /* Table for suffix aliases --- make this smaller */
+
+    sufaliastab = newhashtable(11, "sufaliastab", NULL);
+
+    createaliastable(sufaliastab);
 }
 
 /* Create a new alias node */
@@ -1093,10 +1114,12 @@ printaliasnode(HashNode hn, int printflags)
 
     if (printflags & PRINT_WHENCE_CSH) {
 	nicezputs(a->nam, stdout);
-	if (a->flags & ALIAS_GLOBAL)
-	    printf(": globally aliased to ");
-	else
-	    printf(": aliased to ");
+	printf(": ");
+	if (a->flags & ALIAS_SUFFIX)
+	    printf("suffix ");
+	else if (a->flags & ALIAS_GLOBAL)
+	    printf("globally ");
+	printf (" aliased to ");
 	nicezputs(a->text, stdout);
 	putchar('\n');
 	return;
@@ -1104,10 +1127,14 @@ printaliasnode(HashNode hn, int printflags)
 
     if (printflags & PRINT_WHENCE_VERBOSE) {
 	nicezputs(a->nam, stdout);
-	if (a->flags & ALIAS_GLOBAL)
-	    printf(" is a global alias for ");
+	printf(" is a");
+	if (a->flags & ALIAS_SUFFIX)
+	    printf(" suffix");
+	else if (a->flags & ALIAS_GLOBAL)
+	    printf(" global");
 	else
-	    printf(" is an alias for ");
+	    printf("n");
+	printf(" alias for");
 	nicezputs(a->text, stdout);
 	putchar('\n');
 	return;
@@ -1115,7 +1142,9 @@ printaliasnode(HashNode hn, int printflags)
 
     if (printflags & PRINT_LIST) {
 	printf("alias ");
-	if (a->flags & ALIAS_GLOBAL)
+	if (a->flags & ALIAS_SUFFIX)
+	    printf("-s ");
+	else if (a->flags & ALIAS_GLOBAL)
 	    printf("-g ");
 
 	/* If an alias begins with `-', then we must output `-- ' *
@@ -1127,6 +1156,7 @@ printaliasnode(HashNode hn, int printflags)
     quotedzputs(a->nam, stdout);
     putchar('=');
     quotedzputs(a->text, stdout);
+
     putchar('\n');
 }
 
diff --git a/Src/init.c b/Src/init.c
index 96558f84b..5c395afe2 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -792,7 +792,7 @@ setupvals(void)
     initlextabs();    /* initialize lexing tables    */
 
     createreswdtable();     /* create hash table for reserved words    */
-    createaliastable();     /* create hash table for aliases           */
+    createaliastables();    /* create hash tables for aliases           */
     createcmdnamtable();    /* create hash table for external commands */
     createshfunctable();    /* create hash table for shell functions   */
     createbuiltintable();   /* create hash table for builtin commands  */
diff --git a/Src/lex.c b/Src/lex.c
index 40e42e857..a852de369 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1510,7 +1510,7 @@ parse_subscript(char *s, int sub)
 mod_export int
 parse_subst_string(char *s)
 {
-    int c, l = strlen(s), err, olen;
+    int c, l = strlen(s), err, olen, lexstop_ret;
 
     if (!*s || !strcmp(s, nulstring))
 	return 0;
@@ -1522,6 +1522,7 @@ parse_subst_string(char *s)
     bptr = tokstr = s;
     bsiz = l + 1;
     c = hgetc();
+    lexstop_ret = lexstop;
     c = gettokstr(c, 1);
     err = errflag;
     strinend();
@@ -1603,17 +1604,32 @@ exalias(void)
 
 	if (tok == STRING) {
 	    /* Check for an alias */
-	    an = (noaliases || unset(ALIASESOPT)) ? NULL :
-		(Alias) aliastab->getnode(aliastab, yytext);
-	    if (an && !an->inuse && ((an->flags & ALIAS_GLOBAL) || incmdpos ||
-				     inalmore)) {
-		inpush(an->text, INP_ALIAS, an);
-		if (an->text[0] == ' ')
-		    aliasspaceflag = 1;
-		lexstop = 0;
-		if (yytext == copy)
-		    yytext = tokstr;
-		return 1;
+	    if (!noaliases && isset(ALIASESOPT)) {
+		char *suf;
+		
+		an = (Alias) aliastab->getnode(aliastab, yytext);
+		if (an && !an->inuse &&
+		    ((an->flags & ALIAS_GLOBAL) || incmdpos || inalmore)) {
+		    inpush(an->text, INP_ALIAS, an);
+		    if (an->text[0] == ' ')
+			aliasspaceflag = 1;
+		    lexstop = 0;
+		    if (yytext == copy)
+			yytext = tokstr;
+		    return 1;
+		}
+		if ((suf = strrchr(yytext, '.')) && suf[1] &&
+		    suf > yytext && suf[-1] != Meta &&
+		    (an = (Alias)sufaliastab->getnode(sufaliastab, suf+1)) &&
+		    !an->inuse && incmdpos) {
+		    inpush(dupstring(yytext), INP_ALIAS, NULL);
+		    inpush(" ", INP_ALIAS, NULL);
+		    inpush(an->text, INP_ALIAS, an);
+		    lexstop = 0;
+		    if (yytext == copy)
+			yytext = tokstr;
+		    return 1;
+		}
 	    }
 
 	    /* Then check for a reserved word */
diff --git a/Src/zsh.h b/Src/zsh.h
index 16558c3d3..2dca01722 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -872,8 +872,11 @@ struct alias {
     int inuse;			/* alias is being expanded  */
 };
 
-/* is this alias global */
+/* bit 0 of flags is the DISABLED flag */
+/* is this alias global? */
 #define ALIAS_GLOBAL	(1<<1)
+/* is this an alias for suffix handling? */
+#define ALIAS_SUFFIX	(1<<2)
 
 /* node in command path hash table (cmdnamtab) */