about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2007-07-06 21:52:38 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2007-07-06 21:52:38 +0000
commit1b52f47cf285d5f3835bce7ad73f360bd327d4e8 (patch)
treeaf5f6637517084bc7914dacfc7fda0a5799f3220
parent018c9a2708808b83d5962786f759a931ab27511d (diff)
downloadzsh-1b52f47cf285d5f3835bce7ad73f360bd327d4e8.tar.gz
zsh-1b52f47cf285d5f3835bce7ad73f360bd327d4e8.tar.xz
zsh-1b52f47cf285d5f3835bce7ad73f360bd327d4e8.zip
23665: autoloading of module features and related tweaks
-rw-r--r--ChangeLog25
-rw-r--r--Doc/Zsh/builtins.yo68
-rw-r--r--Etc/zsh-development-guide38
-rw-r--r--Src/Builtins/rlimits.c6
-rw-r--r--Src/Builtins/sched.c8
-rw-r--r--Src/Modules/cap.c6
-rw-r--r--Src/Modules/clone.c6
-rw-r--r--Src/Modules/datetime.c8
-rw-r--r--Src/Modules/example.c14
-rw-r--r--Src/Modules/files.c6
-rw-r--r--Src/Modules/langinfo.c19
-rw-r--r--Src/Modules/mapfile.c10
-rw-r--r--Src/Modules/mathfunc.c17
-rw-r--r--Src/Modules/parameter.c201
-rw-r--r--Src/Modules/pcre.c10
-rw-r--r--Src/Modules/regex.c6
-rw-r--r--Src/Modules/socket.c6
-rw-r--r--Src/Modules/stat.c6
-rw-r--r--Src/Modules/system.c12
-rw-r--r--Src/Modules/tcp.c6
-rw-r--r--Src/Modules/termcap.c24
-rw-r--r--Src/Modules/terminfo.c23
-rw-r--r--Src/Modules/zftp.c6
-rw-r--r--Src/Modules/zprof.c10
-rw-r--r--Src/Modules/zpty.c6
-rw-r--r--Src/Modules/zselect.c6
-rw-r--r--Src/Modules/zutil.c10
-rw-r--r--Src/Zle/compctl.c8
-rw-r--r--Src/Zle/complete.c14
-rw-r--r--Src/Zle/complist.c9
-rw-r--r--Src/Zle/computil.c14
-rw-r--r--Src/Zle/deltochar.c8
-rw-r--r--Src/Zle/zle_main.c13
-rw-r--r--Src/Zle/zleparameter.c14
-rw-r--r--Src/builtin.c2
-rw-r--r--Src/cond.c22
-rw-r--r--Src/exec.c53
-rw-r--r--Src/hashtable.c14
-rw-r--r--Src/init.c4
-rw-r--r--Src/jobs.c4
-rw-r--r--Src/mkbltnmlst.sh3
-rw-r--r--Src/module.c1239
-rw-r--r--Src/params.c16
-rw-r--r--Src/string.c2
-rw-r--r--Src/zsh.h47
-rw-r--r--Test/V01zmodload.ztst85
46 files changed, 1354 insertions, 780 deletions
diff --git a/ChangeLog b/ChangeLog
index 7c0d9afe2..8b31cf24f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2007-07-06  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 23665: Doc/Zsh/builtins.yo,
+	Etc/zsh-development-guide,Src/builtin.c, Src/cond.c, Src/exec.c,
+	Src/hashtable.c, Src/init.c, Src/jobs.c, Src/mkbltnmlst.sh,
+	Src/module.c, Src/params.c, Src/string.c, Src/zsh.h,
+	Src/Builtins/rlimits.c, Src/Builtins/sched.c, Src/Modules/cap.c,
+	Src/Modules/clone.c, Src/Modules/datetime.c,
+	Src/Modules/example.c, Src/Modules/files.c,
+	Src/Modules/langinfo.c, Src/Modules/mapfile.c,
+	Src/Modules/mathfunc.c, Src/Modules/parameter.c,
+	Src/Modules/pcre.c, Src/Modules/regex.c, Src/Modules/socket.c,
+	Src/Modules/stat.c, Src/Modules/system.c, Src/Modules/tcp.c,
+	Src/Modules/termcap.c, Src/Modules/terminfo.c,
+	Src/Modules/zftp.c, Src/Modules/zprof.c, Src/Modules/zpty.c,
+	Src/Modules/zselect.c, Src/Modules/zutil.c, Src/Zle/compctl.c,
+	Src/Zle/complete.c, Src/Zle/complist.c, Src/Zle/computil.c,
+	Src/Zle/deltochar.c, Src/Zle/zle_main.c, Src/Zle/zleparameter.c,
+	Test/V01zmodload.ztst:  Finish autoloading of modules;
+	make autoloads persistent.  Put modules in hash table.
+	Rationalise error handling and error messages.  Improve
+	module listing.  Abort at top level of list execution when
+	errflag is set 	instead of relying on called functions returning
+	early.
+
 2007-07-06  Clint Adams  <clint@zsh.org>
 
 	* 23664: Completion/Debian/Command/_bts: handle bts cache
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 2b61bb9b7..5eb71adb1 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1932,11 +1932,16 @@ the option tt(-P) var(param) then the parameter tt(param) is set to an
 array of features, either features together with their state or (if
 tt(-L) alone is given) enabled features.
 
-A set of features may be provided together with tt(-l) or tt(-L); in
-that case only the state of features provided is considered.  Each
-feature may be preceded by tt(PLUS()) or tt(-) but the character
-has no effect.  If no set of features is provided, all features
-are considered.
+With the option tt(-L) the module name may be omitted; then a list
+of all enabled features for all modules providing features is printed
+in the form of tt(zmodload -F) commands.  If tt(-l) is also given,
+the state of both enabled and disabled features is output in that form.
+
+A set of features may be provided together with tt(-l) or tt(-L) and a
+module name; in that case only the state of those features is
+considered.  Each feature may be preceded by tt(PLUS()) or tt(-) but the
+character has no effect.  If no set of features is provided, all
+features are considered.
 
 With tt(-e), the command first tests that the module is loaded;
 if it is not, status 1 is returned.  If the module is loaded,
@@ -1947,11 +1952,31 @@ 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(-a), the given list of features is marked for autoload from
-the specified module, which may not be loaded.  An optional tt(PLUS())
+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
-tt(-), the existing autoload is deleted.  Note that only standard
-features as described above can be autoloaded; other features require
-the module to be loaded.
+tt(-), any existing autoload is removed.  The options tt(-l) and tt(-L)
+may be used to list autoloads.  Autoloading is specific to individual
+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.  
+
+When the module is loaded each autoload is checked against the features
+actually provided by the module; if the feature is not provided the
+autoload request is deleted.  A warning message is output; if the
+module is being loaded to provide a different feature, and that autoload
+is successful, there is no effect on the status of the current command.
+If the module is already loaded at the time when tt(zmodload -Fa) is
+run, an error message is printed and status 1 returned.
+
+tt(zmodload -Fa) can be used with the tt(-l), tt(-L), tt(-e) and
+tt(-P) options for listing and testing the existence of autoloadable
+features.  In this case tt(-l) is ignored if tt(-L) is specified.
+tt(zmodload -FaL) with no module name lists autoloads for all modules.
+
+Note that only standard features as described above can be autoloaded;
+other features require the module to be loaded before enabling.
 )
 xitem(tt(zmodload) tt(-d) [ tt(-L) ] [ var(name) ])
 xitem(tt(zmodload) tt(-d) var(name) var(dep) ...)
@@ -1973,10 +1998,12 @@ xitem(tt(zmodload) tt(-ab) [ tt(-i) ] var(name) [ var(builtin) ... ])
 item(tt(zmodload) tt(-ub) [ tt(-i) ] var(builtin) ...)(
 The tt(-ab) option defines autoloaded builtins.  It defines the specified
 var(builtin)s.  When any of those builtins is called, the module specified
-in the first argument is loaded.  If only the var(name) is given, one
-builtin is defined, with the same name as the module.  tt(-i) suppresses
-the error if the builtin is already defined or autoloaded, regardless of
-which module it came from.
+in the first argument is loaded and all its features are enabled (for
+selective control of features use `tt(zmodload -F -a)' as described
+above).  If only the var(name) is given, one builtin is defined, with
+the same name as the module.  tt(-i) suppresses the error if the builtin
+is already defined or autoloaded, but not if another builtin of the
+same name is already defined.
 
 With tt(-ab) and no arguments, all autoloaded builtins are listed, with the
 module name (if different) shown in parentheses after the builtin name.
@@ -1987,6 +2014,9 @@ If tt(-b) is used together with the tt(-u) option, it removes builtins
 previously defined with tt(-ab).  This is only possible if the builtin is
 not yet loaded.  tt(-i) suppresses the error if the builtin is already
 removed (or never existed).
+
+Autoload requests are retained if the module is subsequently unloaded
+until an explicit `tt(zmodload -ub) var(builtin)' is issued.
 )
 xitem(tt(zmodload) tt(-ac) [ tt(-IL) ])
 xitem(tt(zmodload) tt(-ac) [ tt(-iI) ] var(name) [ var(cond) ... ])
@@ -2021,12 +2051,12 @@ Equivalent to tt(-ab) and tt(-ub).
 item(tt(zmodload -e) [ tt(-A) ] [ var(string) ... ])(
 The tt(-e) option without arguments lists all loaded modules; if the tt(-A)
 option is also given, module aliases corresponding to loaded modules are
-also shown.  With arguments only the return status is set to zero
-if all var(string)s given as arguments are names of loaded modules
-and to one if at least on var(string) is not the name of a
-loaded module.  This can be used to test for the availability 
-of things implemented by modules.  In this case, any aliases are
-automatically resolved and the tt(-A) flag is not used.
+also shown.  If arguments are provided, nothing is printed;
+the return status is set to zero if all var(string)s given as arguments
+are names of loaded modules and to one if at least on var(string) is not
+the name of a loaded module.  This can be used to test for the
+availability of things implemented by modules.  In this case, any
+aliases are automatically resolved and the tt(-A) flag is not used.
 )
 item(tt(zmodload) tt(-A) [ tt(-L) ] [ var(modalias)[tt(=)var(module)] ... ])(
 For each argument, if both var(modalias) and var(module) are given,
diff --git a/Etc/zsh-development-guide b/Etc/zsh-development-guide
index cb645d416..299fd0a18 100644
--- a/Etc/zsh-development-guide
+++ b/Etc/zsh-development-guide
@@ -218,7 +218,7 @@ by the zsh core. The first one, named `setup_', should set up any data
 needed in the module, at least any data other modules may be interested
 in.
 
-The next pair are features_ and enables_ and deal with enabling module
+The next pair are `features_' and `enables_' and deal with enabling module
 features.  Ensure you are familiar with the description of features under
 `zmodload -F'.  The function features_ takes an argument `char
 ***featuresp'; *featuresp is to be set to a NULL-terminated array
@@ -235,8 +235,7 @@ initialised so setting them is mandatory any time there are any present.
 A structure "struct features" should
 be used to contain all standard features as well as the number of
 abstract features (those only understood by the module itself).
-It contains pointers to all builtins, conditions, parameters and
-conditions controlled by the module.
+See below.
 
 enables_ takes an argument `int **enablesp'.  If *enablesp is NULL, it
 should be set to an array of the same length as *featuresp without the
@@ -248,31 +247,44 @@ function handlefeatures() conveniently handles all standard features
 present in the module's features structure; abstract features must be
 handled by the module (as with the features array, the area of the enables
 array for abstract features is not even initialised by the main shell).  As
-with features_, any handling of the array by the module itself should take
+with `features_', any handling of the array by the module itself should take
 into account that the array will not be freed and any allocation should
 therefore be from heap memory.
 
-The functions features_ and enables_ can be called at any point
-after setup_ has been called and before cleanup_ is called.  In
-particular they can be called before or after boot_.
+The functions `features_' and `enables_' can be called at any point
+after `setup_' has been called and before `cleanup_' is called.  In
+particular they can be called before or after `boot_'.
 
 The function named `boot_' should register function wrappers, hooks and
 anything that will be visible to the user that is not handled by features_
 and enables_ (so features should not be turned on here).  It will be called
 after the `setup_'-function, and also after the intial set of features
-have been set by calls to features_ and enables_.
+have been set by calls to `features_' and `enables_'.
 
 The function named `cleanup_', is called when the user tries to unload
 a module and should de-register all features and hooks.  A call
 to setfeatures with the final argument NULL will remove all standard
-features present in the module's features structure.
+features present in the module's features structure.  Note that
+`cleanup_' is called whenever `setup_' succeeded, so that `cleanup_'
+must be prepared to handle any state resulting from a failed `boot_'
+or initial call to `features_'.  Note also that a return code of 1
+from `cleanup_' will result in the module not being unloaded, so
+usually `cleanup_' will return 0 even if it has to handle an unclean
+state; if it does return 1, it must be prepared to be called again
+in a future attempt to unload.
 
 The last function, `finish_' is called when the module is actually unloaded
 and should finalize all the data initialized in the `setup_'-function.
+However, `finish_' is called even if `setup_' failed, so it should
+not rely on the module successfully being set up.
+The state from `finish_' module is currently ignored; it is called
+too late to prevent the module from being unloaded.
 
 In short, the `cleanup_'-function should undo what the `boot_'-function did
-(together with handling any residual effects of enables_), and the
-`finish_'-function should undo what the `setup_'-function did.
+(together with handling any residual effects of `enables_'), but should
+not rely on `boot_' having been successful, and the
+`finish_'-function should undo what the `setup_'-function did, but
+should not rely on `setup_' having been successful.
 
 All of these functions should return zero if they succeeded and
 non-zero otherwise.
@@ -302,6 +314,10 @@ as discussed below:
     0, /* number of abstract features */
   }
 
+Within each individual table ("bintab", etc.), features should be listed
+in ASCII order as no further sorting is performed by the shell when
+features are listed.
+
 Abstract features are handled by the module; the number present
 in `struct features' is there to ensure the main shell allocated
 space in the features and enables array in the standard
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 8d55d022d..16ef276f2 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -908,7 +908,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -916,7 +916,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -930,7 +930,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
     return 0;
 }
 
diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c
index 21a2aad32..df4b9ecf9 100644
--- a/Src/Builtins/sched.c
+++ b/Src/Builtins/sched.c
@@ -381,8 +381,8 @@ static struct paramdef partab[] = {
 static struct features module_features = {
     bintab, sizeof(bintab)/sizeof(*bintab),
     NULL, 0,
-    partab, sizeof(partab)/sizeof(*partab),
     NULL, 0,
+    partab, sizeof(partab)/sizeof(*partab),
     0
 };
 
@@ -397,7 +397,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -405,7 +405,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -430,7 +430,7 @@ cleanup_(Module m)
 	zfree(sch, sizeof(*sch));
     }
     delprepromptfn(&checksched);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/cap.c b/Src/Modules/cap.c
index 2886c42b4..9d41a4e90 100644
--- a/Src/Modules/cap.c
+++ b/Src/Modules/cap.c
@@ -141,7 +141,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -149,7 +149,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -163,7 +163,7 @@ boot_(UNUSED(Module m))
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index adab4cb59..6fdf534c0 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -128,7 +128,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -136,7 +136,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -150,7 +150,7 @@ boot_(UNUSED(Module m))
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index 06bf52046..169369d5f 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -161,8 +161,8 @@ static struct paramdef patab[] = {
 static struct features module_features = {
     bintab, sizeof(bintab)/sizeof(*bintab),
     NULL, 0,
-    patab, sizeof(patab)/sizeof(*patab),
     NULL, 0,
+    patab, sizeof(patab)/sizeof(*patab),
     0
 };
 
@@ -177,7 +177,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -185,7 +185,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -199,7 +199,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
index 88e910814..fa86f260c 100644
--- a/Src/Modules/example.c
+++ b/Src/Modules/example.c
@@ -165,19 +165,19 @@ static struct builtin bintab[] = {
 };
 
 static struct conddef cotab[] = {
-    CONDDEF("len", 0, cond_p_len, 1, 2, 0),
     CONDDEF("ex", CONDF_INFIX, cond_i_ex, 0, 0, 0),
+    CONDDEF("len", 0, cond_p_len, 1, 2, 0),
 };
 
 static struct paramdef patab[] = {
+    ARRPARAMDEF("exarr", &arrparam),
     INTPARAMDEF("exint", &intparam),
     STRPARAMDEF("exstr", &strparam),
-    ARRPARAMDEF("exarr", &arrparam),
 };
 
 static struct mathfunc mftab[] = {
-    NUMMATHFUNC("sum", math_sum, 1, -1, 0),
     STRMATHFUNC("length", math_length, 0),
+    NUMMATHFUNC("sum", math_sum, 1, -1, 0),
 };
 
 static struct funcwrap wrapper[] = {
@@ -187,8 +187,8 @@ static struct funcwrap wrapper[] = {
 static struct features module_features = {
     bintab, sizeof(bintab)/sizeof(*bintab),
     cotab, sizeof(cotab)/sizeof(*cotab),
-    patab, sizeof(patab)/sizeof(*patab),
     mftab, sizeof(mftab)/sizeof(*mftab),
+    patab, sizeof(patab)/sizeof(*patab),
     0
 };
 
@@ -205,7 +205,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -213,7 +213,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -234,7 +234,7 @@ int
 cleanup_(Module m)
 {
     deletewrapper(m, wrapper);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index ba742cc50..0ce6d78d0 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -725,7 +725,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -733,7 +733,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -747,7 +747,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/langinfo.c b/Src/Modules/langinfo.c
index cfbdeed44..f10fdfef5 100644
--- a/Src/Modules/langinfo.c
+++ b/Src/Modules/langinfo.c
@@ -376,7 +376,7 @@ static nl_item nl_vals[] = {
 };
 
 static nl_item *
-liitem(char *name)
+liitem(const char *name)
 {
     char **element;
     nl_item *nlcode;
@@ -393,16 +393,17 @@ liitem(char *name)
 
 /**/
 static HashNode
-getlanginfo(UNUSED(HashTable ht), char *name)
+getlanginfo(UNUSED(HashTable ht), const char *name)
 {
     int len, *elem;
-    char *listr;
+    char *listr, *nameu;
     Param pm = NULL;
 
-    unmetafy(name, &len);
+    nameu = dupstring(name);
+    unmetafy(nameu, &len);
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->node.nam = dupstring(name);
+    pm->node.nam = nameu;
     pm->node.flags = PM_READONLY | PM_SCALAR;
     pm->gsu.s = &nullsetscalar_gsu;
 
@@ -456,12 +457,12 @@ static struct paramdef partab[] = {
 static struct features module_features = {
     NULL, 0,
     NULL, 0,
+    NULL, 0,
 #ifdef HAVE_NL_LANGINFO
     partab, sizeof(partab)/sizeof(*partab),
 #else
     NULL, 0,
 #endif
-    NULL, 0,
     0
 };
 
@@ -476,7 +477,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -484,7 +485,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -498,7 +499,7 @@ boot_(UNUSED(Module m))
 int
 cleanup_(UNUSED(Module m))
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/mapfile.c b/Src/Modules/mapfile.c
index fb46df885..d825c7faa 100644
--- a/Src/Modules/mapfile.c
+++ b/Src/Modules/mapfile.c
@@ -213,7 +213,7 @@ static struct paramdef partab[] = {
 
 /**/
 static HashNode
-getpmmapfile(UNUSED(HashTable ht), char *name)
+getpmmapfile(UNUSED(HashTable ht), const char *name)
 {
     char *contents;
     Param pm = NULL;
@@ -268,8 +268,8 @@ scanpmmapfile(UNUSED(HashTable ht), ScanFunc func, int flags)
 static struct features module_features = {
     NULL, 0,
     NULL, 0,
-    partab, sizeof(partab)/sizeof(*partab),
     NULL, 0,
+    partab, sizeof(partab)/sizeof(*partab),
     0
 };
 
@@ -284,7 +284,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -292,7 +292,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -306,7 +306,7 @@ boot_(UNUSED(Module m))
 int
 cleanup_(UNUSED(Module m))
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c
index a473476e3..04483b555 100644
--- a/Src/Modules/mathfunc.c
+++ b/Src/Modules/mathfunc.c
@@ -125,12 +125,6 @@ enum {
 
 
 static struct mathfunc mftab[] = {
-  /* Functions taking string arguments */
-#ifdef HAVE_ERAND48
-  /* here to avoid comma hassle */
-  STRMATHFUNC("rand48", math_string, MS_RAND48),
-#endif
-
   NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) |
 	      TFLAG(TF_NOCONV|TF_NOASS)),
   NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)),
@@ -167,6 +161,9 @@ static struct mathfunc mftab[] = {
   NUMMATHFUNC("log1p", math_func, 1, 1, MF_LOG1P | BFLAG(BF_GTRM1)),
   NUMMATHFUNC("logb", math_func, 1, 1, MF_LOGB | BFLAG(BF_NONZ)),
   NUMMATHFUNC("nextafter", math_func, 2, 2, MF_NEXTAFTER),
+#ifdef HAVE_ERAND48
+  STRMATHFUNC("rand48", math_string, MS_RAND48),
+#endif
   NUMMATHFUNC("rint", math_func, 1, 1, MF_RINT),
   NUMMATHFUNC("scalb", math_func, 2, 2, MF_SCALB | TFLAG(TF_INT2)),
 #ifdef HAVE_SIGNGAM
@@ -564,8 +561,8 @@ math_string(UNUSED(char *name), char *arg, int id)
 static struct features module_features = {
     NULL, 0,
     NULL, 0,
-    NULL, 0,
     mftab, sizeof(mftab)/sizeof(*mftab),
+    NULL, 0,
     0
 };
 
@@ -580,7 +577,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -588,7 +585,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -602,7 +599,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 9112e64f1..3c7264a09 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -93,7 +93,7 @@ paramtypestr(Param pm)
 
 /**/
 static HashNode
-getpmparameter(UNUSED(HashTable ht), char *name)
+getpmparameter(UNUSED(HashTable ht), const char *name)
 {
     Param rpm, pm = NULL;
 
@@ -199,7 +199,7 @@ static const struct gsu_scalar pmcommand_gsu =
 
 /**/
 static HashNode
-getpmcommand(UNUSED(HashTable ht), char *name)
+getpmcommand(UNUSED(HashTable ht), const char *name)
 {
     Cmdnam cmd;
     Param pm = NULL;
@@ -372,7 +372,7 @@ static const struct gsu_scalar pmdisfunction_gsu =
 
 /**/
 static HashNode
-getfunction(UNUSED(HashTable ht), char *name, int dis)
+getfunction(UNUSED(HashTable ht), const char *name, int dis)
 {
     Shfunc shf;
     Param pm = NULL;
@@ -416,14 +416,14 @@ getfunction(UNUSED(HashTable ht), char *name, int dis)
 
 /**/
 static HashNode
-getpmfunction(HashTable ht, char *name)
+getpmfunction(HashTable ht, const char *name)
 {
     return getfunction(ht, name, 0);
 }
 
 /**/
 static HashNode
-getpmdisfunction(HashTable ht, char *name)
+getpmdisfunction(HashTable ht, const char *name)
 {
     return getfunction(ht, name, DISABLED);
 }
@@ -542,7 +542,7 @@ functracegetfn(UNUSED(Param pm))
 
 /**/
 static HashNode
-getbuiltin(UNUSED(HashTable ht), char *name, int dis)
+getbuiltin(UNUSED(HashTable ht), const char *name, int dis)
 {
     Param pm = NULL;
     Builtin bn;
@@ -566,14 +566,14 @@ getbuiltin(UNUSED(HashTable ht), char *name, int dis)
 
 /**/
 static HashNode
-getpmbuiltin(HashTable ht, char *name)
+getpmbuiltin(HashTable ht, const char *name)
 {
     return getbuiltin(ht, name, 0);
 }
 
 /**/
 static HashNode
-getpmdisbuiltin(HashTable ht, char *name)
+getpmdisbuiltin(HashTable ht, const char *name)
 {
     return getbuiltin(ht, name, DISABLED);
 }
@@ -721,7 +721,7 @@ static const struct gsu_scalar pmoption_gsu =
 
 /**/
 static HashNode
-getpmoption(UNUSED(HashTable ht), char *name)
+getpmoption(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     int n;
@@ -771,69 +771,29 @@ scanpmoptions(UNUSED(HashTable ht), ScanFunc func, int flags)
 
 /* Functions for the modules special parameter. */
 
-static char *modpmname;
-static int modpmfound;
-
-/**/
-static void
-modpmbuiltinscan(HashNode hn, UNUSED(int dummy))
-{
-    if (!(((Builtin) hn)->node.flags & BINF_ADDED) &&
-	!strcmp(((Builtin) hn)->optstr, modpmname))
-	modpmfound = 1;
-}
-
-/**/
-static void
-modpmparamscan(HashNode hn, UNUSED(int dummy))
-{
-    if ((((Param) hn)->node.flags & PM_AUTOLOAD) &&
-	!strcmp(((Param) hn)->u.str, modpmname))
-	modpmfound = 1;
-}
-
 /**/
 static HashNode
-getpmmodule(UNUSED(HashTable ht), char *name)
+getpmmodule(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     char *type = NULL;
-    LinkNode node;
+    Module m;
 
     pm = (Param) hcalloc(sizeof(struct param));
     pm->node.nam = dupstring(name);
     pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
 
-    if (!type) {
-	Module m;
-
-	for (node = firstnode(modules); node; incnode(node)) {
-	    m = (Module) getdata(node);
-	    if (m->u.handle && !(m->flags & MOD_UNLOAD) &&
-		!strcmp(name, m->nam)) {
-		type = ((m->flags & MOD_ALIAS) ?
-			dyncat("alias:", m->u.alias) : "loaded");
-		break;
-	    }
-	}
+    m = (Module)modulestab->getnode2(modulestab, name);
+
+    if (!m)
+	return NULL;
+    if (m->u.handle && !(m->node.flags & MOD_UNLOAD)) {
+	type = ((m->node.flags & MOD_ALIAS) ?
+		dyncat("alias:", m->u.alias) : "loaded");
     }
-    modpmname = name;
-    modpmfound = 0;
     if (!type) {
-	scanhashtable(builtintab, 0, 0, 0, modpmbuiltinscan, 0);
-	if (!modpmfound) {
-	    Conddef p;
-
-	    for (p = condtab; p; p = p->next)
-		if (p->module && !strcmp(name, p->module)) {
-		    modpmfound = 1;
-		    break;
-		}
-	    if (!modpmfound)
-		scanhashtable(realparamtab, 0, 0, 0, modpmparamscan, 0);
-	}
-	if (modpmfound)
+	if (m->autoloads && firstnode(m->autoloads))
 	    type = "autoloaded";
     }
     if (type)
@@ -853,7 +813,6 @@ scanpmmodules(UNUSED(HashTable ht), ScanFunc func, int flags)
     int i;
     HashNode hn;
     LinkList done = newlinklist();
-    LinkNode node;
     Module m;
     Conddef p;
     char *loaded = dupstring("loaded");
@@ -862,14 +821,16 @@ scanpmmodules(UNUSED(HashTable ht), ScanFunc func, int flags)
     pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
-    for (node = firstnode(modules); node; incnode(node)) {
-	m = (Module) getdata(node);
-	if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
-	    pm.node.nam = m->nam;
-	    pm.u.str = ((m->flags & MOD_ALIAS) ?
-			dyncat("alias:", m->u.alias) : loaded);
-	    addlinknode(done, pm.node.nam);
-	    func(&pm.node, flags);
+    for (i = 0; i < modulestab->hsize; i++) {
+	for (hn = modulestab->nodes[i]; hn; hn = hn->next) {
+	    m = (Module) hn;
+	    if (m->u.handle && !(m->node.flags & MOD_UNLOAD)) {
+		pm.node.nam = m->node.nam;
+		pm.u.str = ((m->node.flags & MOD_ALIAS) ?
+			    dyncat("alias:", m->u.alias) : loaded);
+		addlinknode(done, pm.node.nam);
+		func(&pm.node, flags);
+	    }
 	}
     }
     pm.u.str = dupstring("autoloaded");
@@ -928,11 +889,11 @@ dirsgetfn(UNUSED(Param pm))
 
 /**/
 static HashNode
-getpmhistory(UNUSED(HashTable ht), char *name)
+getpmhistory(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     Histent he;
-    char *p;
+    const char *p;
     int ok = 1;
 
     pm = (Param) hcalloc(sizeof(struct param));
@@ -1042,7 +1003,7 @@ pmjobtext(int job)
 
 /**/
 static HashNode
-getpmjobtext(UNUSED(HashTable ht), char *name)
+getpmjobtext(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     int job;
@@ -1139,7 +1100,7 @@ pmjobstate(int job)
 
 /**/
 static HashNode
-getpmjobstate(UNUSED(HashTable ht), char *name)
+getpmjobstate(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     int job;
@@ -1201,7 +1162,7 @@ pmjobdir(int job)
 
 /**/
 static HashNode
-getpmjobdir(UNUSED(HashTable ht), char *name)
+getpmjobdir(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     int job;
@@ -1329,7 +1290,7 @@ static const struct gsu_scalar pmnamedir_gsu =
 
 /**/
 static HashNode
-getpmnameddir(UNUSED(HashTable ht), char *name)
+getpmnameddir(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     Nameddir nd;
@@ -1378,7 +1339,7 @@ scanpmnameddirs(UNUSED(HashTable ht), ScanFunc func, int flags)
 
 /**/
 static HashNode
-getpmuserdir(UNUSED(HashTable ht), char *name)
+getpmuserdir(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     Nameddir nd;
@@ -1631,7 +1592,7 @@ assignaliasdefs(Param pm, int flags)
 
 /**/
 static HashNode
-getalias(HashTable alht, UNUSED(HashTable ht), char *name, int flags)
+getalias(HashTable alht, UNUSED(HashTable ht), const char *name, int flags)
 {
     Param pm = NULL;
     Alias al;
@@ -1653,45 +1614,45 @@ getalias(HashTable alht, UNUSED(HashTable ht), char *name, int flags)
 
 /**/
 static HashNode
-getpmralias(HashTable ht, char *name)
+getpmralias(HashTable ht, const char *name)
 {
     return getalias(aliastab, ht, name, 0);
 }
 
 /**/
 static HashNode
-getpmdisralias(HashTable ht, char *name)
+getpmdisralias(HashTable ht, const char *name)
 {
     return getalias(aliastab, ht, name, DISABLED);
 }
 
 /**/
 static HashNode
-getpmgalias(HashTable ht, char *name)
+getpmgalias(HashTable ht, const char *name)
 {
     return getalias(aliastab, ht, name, ALIAS_GLOBAL);
 }
 
 /**/
 static HashNode
-getpmdisgalias(HashTable ht, char *name)
+getpmdisgalias(HashTable ht, const char *name)
 {
     return getalias(aliastab, ht, name, ALIAS_GLOBAL|DISABLED);
 }
 
 /**/
 static HashNode
-getpmsalias(HashTable ht, char *name)
+getpmsalias(HashTable ht, const char *name)
 {
     return getalias(sufaliastab, ht, name, ALIAS_SUFFIX);
 }
 
 /**/
 static HashNode
-getpmdissalias(HashTable ht, char *name)
+getpmdissalias(HashTable ht, const char *name)
 {
     return getalias(sufaliastab, ht, name, ALIAS_SUFFIX|DISABLED);
-}
+} 
 
 /**/
 static void
@@ -1809,63 +1770,63 @@ static const struct gsu_array historywords_gsu =
 { histwgetfn, arrsetfn, stdunsetfn };
 
 static struct paramdef partab[] = {
-    SPECIALPMDEF("parameters", PM_READONLY,
-	    NULL, getpmparameter, scanpmparameters),
+    SPECIALPMDEF("aliases", 0,
+	    &pmraliases_gsu, getpmralias, scanpmraliases),
+    SPECIALPMDEF("builtins", PM_READONLY, NULL, getpmbuiltin, scanpmbuiltins),
     SPECIALPMDEF("commands", 0, &pmcommands_gsu, getpmcommand, scanpmcommands),
-    SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,
-		 scanpmfunctions),
+    SPECIALPMDEF("dirstack", PM_ARRAY,
+	    &dirs_gsu, NULL, NULL),
+    SPECIALPMDEF("dis_aliases", 0,
+	    &pmdisraliases_gsu, getpmdisralias, scanpmdisraliases),
+    SPECIALPMDEF("dis_builtins", PM_READONLY,
+	    NULL, getpmdisbuiltin, scanpmdisbuiltins),
     SPECIALPMDEF("dis_functions", 0, 
 	    &pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions),
+    SPECIALPMDEF("dis_galiases", 0,
+	    &pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
+    SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY,
+	    &disreswords_gsu, NULL, NULL),
+    SPECIALPMDEF("dis_saliases", 0,
+	    &pmdissaliases_gsu, getpmdissalias, scanpmdissaliases),
     SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY,
 	    &funcstack_gsu, NULL, NULL),
+    SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,
+		 scanpmfunctions),
     SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
 	    &functrace_gsu, NULL, NULL),
-    SPECIALPMDEF("builtins", PM_READONLY, NULL, getpmbuiltin, scanpmbuiltins),
-    SPECIALPMDEF("dis_builtins", PM_READONLY,
-	    NULL, getpmdisbuiltin, scanpmdisbuiltins),
-    SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY,
-	    &reswords_gsu, NULL, NULL),
-    SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY,
-	    &disreswords_gsu, NULL, NULL),
-    SPECIALPMDEF("options", 0,
-	    &pmoptions_gsu, getpmoption, scanpmoptions),
-    SPECIALPMDEF("modules", PM_READONLY,
-	    NULL, getpmmodule, scanpmmodules),
-    SPECIALPMDEF("dirstack", PM_ARRAY,
-	    &dirs_gsu, NULL, NULL),
+    SPECIALPMDEF("galiases", 0,
+	    &pmgaliases_gsu, getpmgalias, scanpmgaliases),
     SPECIALPMDEF("history", PM_READONLY,
 	    NULL, getpmhistory, scanpmhistory),
     SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY,
 	    &historywords_gsu, NULL, NULL),
-    SPECIALPMDEF("jobtexts", PM_READONLY,
-	    NULL, getpmjobtext, scanpmjobtexts),
-    SPECIALPMDEF("jobstates", PM_READONLY,
-	    NULL, getpmjobstate, scanpmjobstates),
     SPECIALPMDEF("jobdirs", PM_READONLY,
 	    NULL, getpmjobdir, scanpmjobdirs),
+    SPECIALPMDEF("jobstates", PM_READONLY,
+	    NULL, getpmjobstate, scanpmjobstates),
+    SPECIALPMDEF("jobtexts", PM_READONLY,
+	    NULL, getpmjobtext, scanpmjobtexts),
+    SPECIALPMDEF("modules", PM_READONLY,
+	    NULL, getpmmodule, scanpmmodules),
     SPECIALPMDEF("nameddirs", 0,
 	    &pmnameddirs_gsu, getpmnameddir, scanpmnameddirs),
-    SPECIALPMDEF("userdirs", PM_READONLY,
-	    NULL, getpmuserdir, scanpmuserdirs),
-    SPECIALPMDEF("aliases", 0,
-	    &pmraliases_gsu, getpmralias, scanpmraliases),
-    SPECIALPMDEF("galiases", 0,
-	    &pmgaliases_gsu, getpmgalias, scanpmgaliases),
+    SPECIALPMDEF("options", 0,
+	    &pmoptions_gsu, getpmoption, scanpmoptions),
+    SPECIALPMDEF("parameters", PM_READONLY,
+	    NULL, getpmparameter, scanpmparameters),
+    SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY,
+	    &reswords_gsu, NULL, NULL),
     SPECIALPMDEF("saliases", 0,
 	    &pmsaliases_gsu, getpmsalias, scanpmsaliases),
-    SPECIALPMDEF("dis_aliases", 0,
-	    &pmdisraliases_gsu, getpmdisralias, scanpmdisraliases),
-    SPECIALPMDEF("dis_galiases", 0,
-	    &pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
-    SPECIALPMDEF("dis_saliases", 0,
-	    &pmdissaliases_gsu, getpmdissalias, scanpmdissaliases)
+    SPECIALPMDEF("userdirs", PM_READONLY,
+	    NULL, getpmuserdir, scanpmuserdirs)
 };
 
 static struct features module_features = {
     NULL, 0,
     NULL, 0,
-    partab, sizeof(partab)/sizeof(*partab),
     NULL, 0,
+    partab, sizeof(partab)/sizeof(*partab),
     0
 };
 
@@ -1880,7 +1841,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -1894,7 +1855,7 @@ enables_(Module m, int **enables)
      * on the main shell, so set the flag to indicate.
      */
     incleanup = 1;
-    ret = handlefeatures(m->nam, &module_features, enables);
+    ret = handlefeatures(m, &module_features, enables);
     incleanup = 0;
     return ret;
 }
@@ -1912,7 +1873,7 @@ cleanup_(Module m)
 {
     int ret;
     incleanup = 1;
-    ret = setfeatureenables(m->nam, &module_features, NULL);
+    ret = setfeatureenables(m, &module_features, NULL);
     incleanup = 0;
     return ret;
 }
diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c
index 45c38eba0..4f8daff80 100644
--- a/Src/Modules/pcre.c
+++ b/Src/Modules/pcre.c
@@ -290,8 +290,8 @@ static struct conddef cotab[] = {
 
 static struct builtin bintab[] = {
     BUILTIN("pcre_compile", 0, bin_pcre_compile, 1, 1, 0, "aimx",  NULL),
-    BUILTIN("pcre_study",   0, bin_pcre_study,   0, 0, 0, NULL,    NULL),
-    BUILTIN("pcre_match",   0, bin_pcre_match,   1, 1, 0, "a:v:",    NULL)
+    BUILTIN("pcre_match",   0, bin_pcre_match,   1, 1, 0, "a:v:",    NULL),
+    BUILTIN("pcre_study",   0, bin_pcre_study,   0, 0, 0, NULL,    NULL)
 };
 
 
@@ -319,7 +319,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -327,7 +327,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -341,7 +341,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/regex.c b/Src/Modules/regex.c
index a3d956055..00ed46b3b 100644
--- a/Src/Modules/regex.c
+++ b/Src/Modules/regex.c
@@ -152,7 +152,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -160,7 +160,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -174,7 +174,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/socket.c b/Src/Modules/socket.c
index 413625dcf..469568a11 100644
--- a/Src/Modules/socket.c
+++ b/Src/Modules/socket.c
@@ -276,7 +276,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -284,7 +284,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -298,7 +298,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 1d55317ea..a3e95bb59 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -643,7 +643,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -651,7 +651,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -665,7 +665,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/system.c b/Src/Modules/system.c
index f8a188d42..4af464db0 100644
--- a/Src/Modules/system.c
+++ b/Src/Modules/system.c
@@ -365,7 +365,7 @@ static const struct gsu_array errnos_gsu =
 
 /**/
 static void
-fillpmsysparams(Param pm, char *name)
+fillpmsysparams(Param pm, const char *name)
 {
     char buf[DIGBUFSIZE];
     int num;
@@ -390,7 +390,7 @@ fillpmsysparams(Param pm, char *name)
 
 /**/
 static HashNode
-getpmsysparams(UNUSED(HashTable ht), char *name)
+getpmsysparams(UNUSED(HashTable ht), const char *name)
 {
     Param pm;
 
@@ -423,8 +423,8 @@ static struct paramdef partab[] = {
 static struct features module_features = {
     bintab, sizeof(bintab)/sizeof(*bintab),
     NULL, 0,
-    partab, sizeof(partab)/sizeof(*partab),
     NULL, 0,
+    partab, sizeof(partab)/sizeof(*partab),
     0
 };
 
@@ -441,7 +441,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -449,7 +449,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -464,7 +464,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/tcp.c b/Src/Modules/tcp.c
index 1bf9b3776..d1d4e5002 100644
--- a/Src/Modules/tcp.c
+++ b/Src/Modules/tcp.c
@@ -696,7 +696,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -704,7 +704,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -722,7 +722,7 @@ cleanup_(Module m)
 {
     tcp_cleanup();
     freelinklist(ztcp_sessions, (FreeFunc) ztcp_free_session);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/termcap.c b/Src/Modules/termcap.c
index c19db4892..351324a68 100644
--- a/Src/Modules/termcap.c
+++ b/Src/Modules/termcap.c
@@ -164,10 +164,10 @@ static struct builtin bintab[] = {
 
 /**/
 static HashNode
-gettermcap(UNUSED(HashTable ht), char *name)
+gettermcap(UNUSED(HashTable ht), const char *name)
 {
     int len, num;
-    char *tcstr, buf[2048], *u;
+    char *tcstr, buf[2048], *u, *nameu;
     Param pm = NULL;
 
     /* This depends on the termcap stuff in init.c */
@@ -176,16 +176,18 @@ gettermcap(UNUSED(HashTable ht), char *name)
     if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
 	return NULL;
 
-    unmetafy(name, &len);
+    
+    nameu = dupstring(name);
+    unmetafy(nameu, &len);
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->node.nam = dupstring(name);
+    pm->node.nam = nameu;
     pm->node.flags = PM_READONLY;
     u = buf;
 
     /* logic in the following cascade copied from echotc, above */
 
-    if ((num = tgetnum(name)) != -1) {
+    if ((num = tgetnum(nameu)) != -1) {
 	pm->gsu.i = &nullsetinteger_gsu;
 	pm->u.val = num;
 	pm->node.flags |= PM_INTEGER;
@@ -193,7 +195,7 @@ gettermcap(UNUSED(HashTable ht), char *name)
     }
 
     pm->gsu.s = &nullsetscalar_gsu;
-    switch (ztgetflag(name)) {
+    switch (ztgetflag(nameu)) {
     case -1:
 	break;
     case 0:
@@ -205,7 +207,7 @@ gettermcap(UNUSED(HashTable ht), char *name)
 	pm->node.flags |= PM_SCALAR;
 	return &pm->node;
     }
-    if ((tcstr = tgetstr(name, &u)) != NULL && tcstr != (char *)-1) {
+    if ((tcstr = tgetstr(nameu, &u)) != NULL && tcstr != (char *)-1) {
 	pm->u.str = dupstring(tcstr);
 	pm->node.flags |= PM_SCALAR;
     } else {
@@ -324,12 +326,12 @@ static struct features module_features = {
     NULL, 0,
 #endif
     NULL, 0,
+    NULL, 0,
 #ifdef HAVE_TGETENT
     partab, sizeof(partab)/sizeof(*partab),
 #else
     NULL, 0,
 #endif
-    NULL, 0,
     0
 };
 
@@ -344,7 +346,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -352,7 +354,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -371,7 +373,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/terminfo.c b/Src/Modules/terminfo.c
index d324c3a6c..63cbd2abc 100644
--- a/Src/Modules/terminfo.c
+++ b/Src/Modules/terminfo.c
@@ -129,10 +129,10 @@ static struct builtin bintab[] = {
 
 /**/
 static HashNode
-getterminfo(UNUSED(HashTable ht), char *name)
+getterminfo(UNUSED(HashTable ht), const char *name)
 {
     int len, num;
-    char *tistr;
+    char *tistr, *nameu;
     Param pm = NULL;
 
     /* This depends on the termcap stuff in init.c */
@@ -141,21 +141,22 @@ getterminfo(UNUSED(HashTable ht), char *name)
     if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
 	return NULL;
 
-    unmetafy(name, &len);
+    nameu = dupstring(name);
+    unmetafy(nameu, &len);
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->node.nam = dupstring(name);
+    pm->node.nam = nameu;
     pm->node.flags = PM_READONLY;
 
-    if (((num = tigetnum(name)) != -1) && (num != -2)) {
+    if (((num = tigetnum(nameu)) != -1) && (num != -2)) {
 	pm->u.val = num;
 	pm->node.flags |= PM_INTEGER;
 	pm->gsu.i = &nullsetinteger_gsu;
-    } else if ((num = tigetflag(name)) != -1) {
+    } else if ((num = tigetflag(nameu)) != -1) {
 	pm->u.str = num ? dupstring("yes") : dupstring("no");
 	pm->node.flags |= PM_SCALAR;
 	pm->gsu.s = &nullsetscalar_gsu;
-    } else if ((tistr = (char *)tigetstr(name)) != NULL && tistr != (char *)-1) {
+    } else if ((tistr = (char *)tigetstr(nameu)) != NULL && tistr != (char *)-1) {
 	pm->u.str = dupstring(tistr);
 	pm->node.flags |= PM_SCALAR;
 	pm->gsu.s = &nullsetscalar_gsu;
@@ -298,12 +299,12 @@ static struct features module_features = {
     NULL, 0,
 #endif
     NULL, 0,
+    NULL, 0,
 #ifdef USE_TERMINFO_MODULE
     partab, sizeof(partab)/sizeof(*partab),
 #else
     NULL, 0,
 #endif
-    NULL, 0,
     0
 };
 
@@ -318,7 +319,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -326,7 +327,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -349,7 +350,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 5c8822cc5..af48e80aa 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -3181,7 +3181,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -3189,7 +3189,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -3221,7 +3221,7 @@ cleanup_(Module m)
 {
     deletehookfunc("exit", zftpexithook);
     zftp_cleanup();
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/zprof.c b/Src/Modules/zprof.c
index b30e44432..bc97771c0 100644
--- a/Src/Modules/zprof.c
+++ b/Src/Modules/zprof.c
@@ -225,7 +225,7 @@ zprof_wrapper(Eprog prog, FuncWrap w, char *name)
     struct timezone dummy;
     double prev = 0, now;
 
-    if (zprof_module && !(zprof_module->flags & MOD_UNLOAD)) {
+    if (zprof_module && !(zprof_module->node.flags & MOD_UNLOAD)) {
         active = 1;
         if (!(f = findpfunc(name))) {
             f = (Pfunc) zalloc(sizeof(*f));
@@ -260,7 +260,7 @@ zprof_wrapper(Eprog prog, FuncWrap w, char *name)
     }
     runshfunc(prog, w, name);
     if (active) {
-        if (zprof_module && !(zprof_module->flags & MOD_UNLOAD)) {
+        if (zprof_module && !(zprof_module->node.flags & MOD_UNLOAD)) {
             tv.tv_sec = tv.tv_usec = 0;
             gettimeofday(&tv, &dummy);
 
@@ -315,7 +315,7 @@ setup_(Module m)
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -323,7 +323,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -345,7 +345,7 @@ cleanup_(Module m)
     freepfuncs(calls);
     freeparcs(arcs);
     deletewrapper(m, wrapper);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 3280b8175..7e140102e 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -750,7 +750,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -758,7 +758,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -777,7 +777,7 @@ cleanup_(Module m)
 {
     deletehookfunc("exit", ptyhook);
     deleteallptycmds();
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/zselect.c b/Src/Modules/zselect.c
index 3e71fa3bd..c02074646 100644
--- a/Src/Modules/zselect.c
+++ b/Src/Modules/zselect.c
@@ -294,7 +294,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -302,7 +302,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -317,7 +317,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 127509b01..76056308f 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -1801,10 +1801,10 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 }
 
 static struct builtin bintab[] = {
-    BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
     BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL),
-    BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
     BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL),
+    BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
+    BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
 };
 
 static struct features module_features = {
@@ -1828,7 +1828,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -1836,7 +1836,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -1850,7 +1850,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index bafbb2f68..143c93682 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -3938,8 +3938,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
 
 static struct builtin bintab[] = {
-    BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL),
     BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL),
+    BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL),
 };
 
 static struct features module_features = {
@@ -3974,7 +3974,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -3982,7 +3982,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -4000,7 +4000,7 @@ cleanup_(Module m)
 {
     deletehookfunc("compctl_make", (Hookfn) ccmakehookfn);
     deletehookfunc("compctl_cleanup", (Hookfn) cccleanuphookfn);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index a2af30c65..36c4c8a3d 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -1445,10 +1445,10 @@ static struct builtin bintab[] = {
 };
 
 static struct conddef cotab[] = {
+    CONDDEF("after", 0, cond_range, 1, 1, 0),
+    CONDDEF("between", 0, cond_range, 2, 2, 1),
     CONDDEF("prefix", 0, cond_psfix, 1, 2, CVT_PREPAT),
     CONDDEF("suffix", 0, cond_psfix, 1, 2, CVT_SUFPAT),
-    CONDDEF("between", 0, cond_range, 2, 2, 1),
-    CONDDEF("after", 0, cond_range, 1, 1, 0),
 };
 
 static struct funcwrap wrapper[] = {
@@ -1502,7 +1502,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -1510,7 +1510,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -1524,7 +1524,7 @@ boot_(Module m)
     addhookfunc("reverse_menu", (Hookfn) reverse_menu);
     addhookfunc("list_matches", (Hookfn) list_matches);
     addhookfunc("invalidate_list", (Hookfn) invalidate_list);
-    (void)addhookdefs(m->nam, comphooks, sizeof(comphooks)/sizeof(*comphooks));
+    (void)addhookdefs(m, comphooks, sizeof(comphooks)/sizeof(*comphooks));
     return addwrapper(m, wrapper);
 }
 
@@ -1539,10 +1539,10 @@ cleanup_(Module m)
     deletehookfunc("reverse_menu", (Hookfn) reverse_menu);
     deletehookfunc("list_matches", (Hookfn) list_matches);
     deletehookfunc("invalidate_list", (Hookfn) invalidate_list);
-    (void)deletehookdefs(m->nam, comphooks,
+    (void)deletehookdefs(m, comphooks,
 			 sizeof(comphooks)/sizeof(*comphooks));
     deletewrapper(m, wrapper);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 787b7b25c..64d7e50ce 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -3238,7 +3238,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -3246,7 +3246,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -3261,7 +3261,8 @@ boot_(Module m)
     w_menuselect = addzlefunction("menu-select", menuselect,
                                     ZLE_MENUCMP|ZLE_KEEPSUFFIX|ZLE_ISCOMP);
     if (!w_menuselect) {
-	zwarnnam(m->nam, "name clash when adding ZLE function `menu-select'");
+	zwarnnam(m->node.nam,
+		 "name clash when adding ZLE function `menu-select'");
 	return -1;
     }
     addhookfunc("comp_list_matches", (Hookfn) complistmatches);
@@ -3302,7 +3303,7 @@ cleanup_(Module m)
     deletehookfunc("menu_start", (Hookfn) domenuselect);
     unlinkkeymap("menuselect", 1);
     unlinkkeymap("listscroll", 1);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index b9df1e418..9ba38101a 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -4544,14 +4544,14 @@ bin_compgroups(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 }
 
 static struct builtin bintab[] = {
-    BUILTIN("compdescribe", 0, bin_compdescribe, 3, -1, 0, NULL, NULL),
     BUILTIN("comparguments", 0, bin_comparguments, 1, -1, 0, NULL, NULL),
-    BUILTIN("compvalues", 0, bin_compvalues, 1, -1, 0, NULL, NULL),
+    BUILTIN("compdescribe", 0, bin_compdescribe, 3, -1, 0, NULL, NULL),
+    BUILTIN("compfiles", 0, bin_compfiles, 1, -1, 0, NULL, NULL),
+    BUILTIN("compgroups", 0, bin_compgroups, 1, -1, 0, NULL, NULL),
     BUILTIN("compquote", 0, bin_compquote, 1, -1, 0, "p", NULL),
     BUILTIN("comptags", 0, bin_comptags, 1, -1, 0, NULL, NULL),
     BUILTIN("comptry", 0, bin_comptry, 0, -1, 0, NULL, NULL),
-    BUILTIN("compfiles", 0, bin_compfiles, 1, -1, 0, NULL, NULL),
-    BUILTIN("compgroups", 0, bin_compgroups, 1, -1, 0, NULL, NULL),
+    BUILTIN("compvalues", 0, bin_compvalues, 1, -1, 0, NULL, NULL)
 };
 
 static struct features module_features = {
@@ -4581,7 +4581,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -4589,7 +4589,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -4603,7 +4603,7 @@ boot_(Module m)
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Zle/deltochar.c b/Src/Zle/deltochar.c
index 0c64cf18d..d56798687 100644
--- a/Src/Zle/deltochar.c
+++ b/Src/Zle/deltochar.c
@@ -95,7 +95,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -103,7 +103,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -119,7 +119,7 @@ boot_(Module m)
 	    return 0;
 	deletezlefunction(w_deletetochar);
     }
-    zwarnnam(m->nam, "deltochar: name clash when adding ZLE functions");
+    zwarnnam(m->node.nam, "deltochar: name clash when adding ZLE functions");
     return -1;
 }
 
@@ -129,7 +129,7 @@ cleanup_(Module m)
 {
     deletezlefunction(w_deletetochar);
     deletezlefunction(w_zaptochar);
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index d2a665188..463ff157f 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1827,7 +1827,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -1835,7 +1835,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -1844,7 +1844,7 @@ boot_(Module m)
 {
     addhookfunc("before_trap", (Hookfn) zlebeforetrap);
     addhookfunc("after_trap", (Hookfn) zleaftertrap);
-    (void)addhookdefs(m->nam, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks));
+    (void)addhookdefs(m, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks));
     return 0;
 }
 
@@ -1853,13 +1853,14 @@ int
 cleanup_(Module m)
 {
     if(zleactive) {
-	zerrnam(m->nam, "can't unload the zle module while zle is active");
+	zerrnam(m->node.nam,
+		"can't unload the zle module while zle is active");
 	return 1;
     }
     deletehookfunc("before_trap", (Hookfn) zlebeforetrap);
     deletehookfunc("after_trap", (Hookfn) zleaftertrap);
-    (void)deletehookdefs(m->nam, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks));
-    return setfeatureenables(m->nam, &module_features, NULL);
+    (void)deletehookdefs(m, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks));
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/Zle/zleparameter.c b/Src/Zle/zleparameter.c
index 1b84fdff7..ab988d6df 100644
--- a/Src/Zle/zleparameter.c
+++ b/Src/Zle/zleparameter.c
@@ -56,7 +56,7 @@ widgetstr(Widget w)
 
 /**/
 static HashNode
-getpmwidgets(UNUSED(HashTable ht), char *name)
+getpmwidgets(UNUSED(HashTable ht), const char *name)
 {
     Param pm = NULL;
     Thingy th;
@@ -129,16 +129,16 @@ static const struct gsu_array keymaps_gsu =
 { keymapsgetfn, arrsetfn, stdunsetfn };
 
 static struct paramdef partab[] = {
-    SPECIALPMDEF("widgets", PM_READONLY,
-		 &zlestdhash_gsu, getpmwidgets, scanpmwidgets),
     SPECIALPMDEF("keymaps", PM_ARRAY|PM_READONLY, &keymaps_gsu, NULL, NULL),
+    SPECIALPMDEF("widgets", PM_READONLY,
+		 &zlestdhash_gsu, getpmwidgets, scanpmwidgets)
 };
 
 static struct features module_features = {
     NULL, 0,
     NULL, 0,
-    partab, sizeof(partab)/sizeof(*partab),
     NULL, 0,
+    partab, sizeof(partab)/sizeof(*partab),
     0
 };
 
@@ -153,7 +153,7 @@ setup_(UNUSED(Module m))
 int
 features_(Module m, char ***features)
 {
-    *features = featuresarray(m->nam, &module_features);
+    *features = featuresarray(m, &module_features);
     return 0;
 }
 
@@ -161,7 +161,7 @@ features_(Module m, char ***features)
 int
 enables_(Module m, int **enables)
 {
-    return handlefeatures(m->nam, &module_features, enables);
+    return handlefeatures(m, &module_features, enables);
 }
 
 /**/
@@ -175,7 +175,7 @@ boot_(UNUSED(Module m))
 int
 cleanup_(Module m)
 {
-    return setfeatureenables(m->nam, &module_features, NULL);
+    return setfeatureenables(m, &module_features, NULL);
 }
 
 /**/
diff --git a/Src/builtin.c b/Src/builtin.c
index 20bc37c21..7420ed887 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -250,7 +250,7 @@ execbuiltin(LinkList args, Builtin bn)
     name = (char *) ugetnode(args);
 
     if (!bn->handlerfunc) {
-	zwarnnam(name, "autoload failed");
+	DPUTS(1, "Missing builtin detected too late");
 	deletebuiltin(bn->node.nam);
 	return 1;
     }
diff --git a/Src/cond.c b/Src/cond.c
index 4356e5d66..e455882bb 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -96,11 +96,7 @@ evalcond(Estate state, char *fromtest)
 	{
 	    char *modname = isset(REMATCHPCRE) ? "zsh/pcre" : "zsh/regex";
 	    sprintf(overridename = overridebuf, "-%s-match", modname+4);
-	    if (ensurefeature(modname, "c:", overridename+1)) {
-		zwarnnam(fromtest, "%s not available for regex",
-			 modname);
-		return 2;
-	    }
+	    (void)ensurefeature(modname, "c:", overridename+1);
 	    ctype = COND_MODI;
 	}
 	/*FALLTHROUGH*/
@@ -129,7 +125,7 @@ evalcond(Estate state, char *fromtest)
 	    if ((cd = getconddef((ctype == COND_MODI), name + 1, 1))) {
 		if (ctype == COND_MOD &&
 		    (l < cd->min || (cd->max >= 0 && l > cd->max))) {
-		    zwarnnam(fromtest, "unrecognized condition: `%s'", name);
+		    zwarnnam(fromtest, "unknown condition: -%s", name);
 		    return 2;
 		}
 		if (tracingcond)
@@ -139,13 +135,23 @@ evalcond(Estate state, char *fromtest)
 	    else {
 		char *s = strs[0];
 
+		if (overridename) {
+		    /*
+		     * Standard regex function not available: this
+		     * is a hard error.
+		     */
+		    zerrnam(fromtest, "%s not available for regex",
+			     overridename);
+		    return 2;
+		}
+
 		strs[0] = dupstring(name);
 		name = s;
 
 		if (name && name[0] == '-' &&
 		    (cd = getconddef(0, name + 1, 1))) {
 		    if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
-			zwarnnam(fromtest, "unrecognized condition: `%s'",
+			zwarnnam(fromtest, "unknown condition: -%s",
 				 name);
 			return 2;
 		    }
@@ -154,7 +160,7 @@ evalcond(Estate state, char *fromtest)
 		    return !cd->handler(strs, cd->condid);
 		} else {
 		    zwarnnam(fromtest,
-			     "unrecognized condition: `%s'",
+			     "unknown condition: -%s",
 			     name ? name : "<null>");
 		}
 	    }
diff --git a/Src/exec.c b/Src/exec.c
index 0aee2d6a9..015753a83 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -871,7 +871,7 @@ execlist(Estate state, int dont_change_job, int exiting)
     /* Loop over all sets of comands separated by newline, *
      * semi-colon or ampersand (`sublists').               */
     code = *state->pc++;
-    while (wc_code(code) == WC_LIST && !breaks && !retflag) {
+    while (wc_code(code) == WC_LIST && !breaks && !retflag && !errflag) {
 	int donedebug;
 
 	ltype = WC_LIST_TYPE(code);
@@ -1915,6 +1915,34 @@ execsubst(LinkList strs)
     }
 }
 
+/*
+ * Check if a builtin requires an autoload and if so
+ * deal with it.  This may return NULL.
+ */
+
+/**/
+static HashNode
+resolvebuiltin(const char *cmdarg, HashNode hn)
+{
+    if (!((Builtin) hn)->handlerfunc) {
+	/*
+	 * Ensure the module is loaded and the
+	 * feature corresponding to the builtin
+	 * is enabled.
+	 */
+	(void)ensurefeature(((Builtin) hn)->optstr, "b:",
+			    (hn->flags & BINF_AUTOALL) ? NULL :
+			    hn->nam);
+	hn = builtintab->getnode(builtintab, cmdarg);
+	if (!hn) {
+	    lastval = 1;
+	    zerr("unknown builtin: %s");
+	    return NULL;
+	}
+    }
+    return hn;
+}
+
 /**/
 static void
 execcmd(Estate state, int input, int output, int how, int last1)
@@ -2011,16 +2039,9 @@ execcmd(Estate state, int input, int output, int how, int last1)
 		is_builtin = 1;
 
 		/* autoload the builtin if necessary */
-		if (!((Builtin) hn)->handlerfunc) {
-		    /*
-		     * Ensure the module is loaded and the
-		     * feature corresponding to the builtin
-		     * is enabled.
-		     */
-		    (void)ensurefeature(((Builtin) hn)->optstr, "b:", hn->nam);
-		    hn = builtintab->getnode(builtintab, cmdarg);
-		}
-		assign = (hn && (hn->flags & BINF_MAGICEQUALS));
+		if (!(hn = resolvebuiltin(cmdarg, hn)))
+		    return;
+		assign = (hn->flags & BINF_MAGICEQUALS);
 		break;
 	    }
 	    cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
@@ -2233,10 +2254,8 @@ execcmd(Estate state, int input, int output, int how, int last1)
 		is_builtin = 1;
 
 		/* autoload the builtin if necessary */
-		if (!((Builtin) hn)->handlerfunc) {
-		    (void)ensurefeature(((Builtin) hn)->optstr, "b:", cmdarg);
-		    hn = builtintab->getnode(builtintab, cmdarg);
-		}
+		if (!(hn = resolvebuiltin(cmdarg, hn)))
+		    return;
 		break;
 	    }
 	    cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
@@ -4104,8 +4123,8 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
 	wrap->module->wrapper--;
 
 	if (!wrap->module->wrapper &&
-	    (wrap->module->flags & MOD_UNLOAD))
-	    unload_module(wrap->module, NULL);
+	    (wrap->module->node.flags & MOD_UNLOAD))
+	    unload_module(wrap->module);
 
 	if (!cont)
 	    return;
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 669990566..d820c4fd4 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -78,7 +78,7 @@ static HashTable firstht, lastht;
 
 /**/
 mod_export unsigned
-hasher(char *str)
+hasher(const char *str)
 {
     unsigned hashval = 0, c;
 
@@ -223,7 +223,7 @@ addhashnode2(HashTable ht, char *nam, void *nodeptr)
 
 /**/
 mod_export HashNode
-gethashnode(HashTable ht, char *nam)
+gethashnode(HashTable ht, const char *nam)
 {
     unsigned hashval;
     HashNode hp;
@@ -247,7 +247,7 @@ gethashnode(HashTable ht, char *nam)
 
 /**/
 mod_export HashNode
-gethashnode2(HashTable ht, char *nam)
+gethashnode2(HashTable ht, const char *nam)
 {
     unsigned hashval;
     HashNode hp;
@@ -267,7 +267,7 @@ gethashnode2(HashTable ht, char *nam)
 
 /**/
 mod_export HashNode
-removehashnode(HashTable ht, char *nam)
+removehashnode(HashTable ht, const char *nam)
 {
     unsigned hashval;
     HashNode hp, hq;
@@ -795,7 +795,7 @@ createshfunctable(void)
 
 /**/
 static HashNode
-removeshfuncnode(UNUSED(HashTable ht), char *nam)
+removeshfuncnode(UNUSED(HashTable ht), const char *nam)
 {
     HashNode hn;
     int signum;
@@ -1378,7 +1378,7 @@ addnameddirnode(HashTable ht, char *nam, void *nodeptr)
 
 /**/
 static HashNode
-removenameddirnode(HashTable ht, char *nam)
+removenameddirnode(HashTable ht, const char *nam)
 {
     HashNode hn = removehashnode(ht, nam);
 
@@ -1453,7 +1453,7 @@ createhisttable(void)
 
 /**/
 unsigned
-histhasher(char *str)
+histhasher(const char *str)
 {
     unsigned hashval = 0;
 
diff --git a/Src/init.c b/Src/init.c
index 13078ea2e..e885c79b6 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -701,7 +701,7 @@ setupvals(void)
 	    close(tmppipe[1]);
     }
 
-    (void)addhookdefs(argzero, zshhooks, sizeof(zshhooks)/sizeof(*zshhooks));
+    (void)addhookdefs(NULL, zshhooks, sizeof(zshhooks)/sizeof(*zshhooks));
 
     init_eprog();
 
@@ -769,7 +769,7 @@ setupvals(void)
     watch    = mkarray(NULL);
     psvar    = mkarray(NULL);
     module_path = mkarray(ztrdup(MODULE_DIR));
-    modules = znewlinklist();
+    modulestab = newmoduletable(17, "modules");
     linkedmodules = znewlinklist();
 
     /* Set default prompts */
diff --git a/Src/jobs.c b/Src/jobs.c
index b02922a03..129da7d57 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -2147,7 +2147,7 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 
 /**/
 mod_export int
-getsignum(char *s)
+getsignum(const char *s)
 {
     int x, i;
 
@@ -2205,7 +2205,7 @@ gettrapnode(int sig, int ignoredisable)
 {
     char fname[20];
     HashNode hn;
-    HashNode (*getptr)(HashTable ht, char *name);
+    HashNode (*getptr)(HashTable ht, const char *name);
     int i;
     if (ignoredisable)
 	getptr = shfunctab->getnode2;
diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh
index d636550ac..005e2ef81 100644
--- a/Src/mkbltnmlst.sh
+++ b/Src/mkbltnmlst.sh
@@ -37,8 +37,7 @@ for x_mod in $x_mods; do
         echo "/* non-linked-in known module \`$x_mod' */"
 	linked=no
     esac
-    unset moddeps autobins autoinfixconds autoprefixconds autoparams
-    unset automathfuncs
+    unset moddeps autofeatures
     . $srcdir/../$modfile
     if test "x$autofeatures" != x; then
 	echo "  if (emulation == EMULATE_ZSH) {"
diff --git a/Src/module.c b/Src/module.c
index c82d77373..765f7c941 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -24,13 +24,16 @@
  * provided hereunder is on an "as is" basis, and Zoltán Hidvégi and the
  * Zsh Development Group have no obligation to provide maintenance,
  * support, updates, enhancements, or modifications.
- *
  */
 
 #include "zsh.mdh"
 #include "module.pro"
 
-/* List of linked-in modules. */
+/*
+ * List of linked-in modules.
+ * This is set up at boot and remains for the life of the shell;
+ * entries do not appear in "zmodload" listings.
+ */
 
 /**/
 LinkList linkedmodules;
@@ -40,19 +43,42 @@ LinkList linkedmodules;
 /**/
 char **module_path;
 
-/* List of modules */
+/* Hash of modules */
 
 /**/
-mod_export LinkList modules;
+mod_export HashTable modulestab;
 
 /*
  * Bit flags passed as the "flags" argument of a autofeaturefn_t.
+ * Used in other places, such as the final argument to
+ * do_module_features().
  */
 enum {
-    /* `-i' option: ignore errors pertaining to redefinitions */
-    AUTOFEAT_IGNORE = 0x0001,
+    /*
+     * `-i' option: ignore errors pertaining to redefinitions,
+     * or indicate to do_module_features() that it should be
+     * silent.
+     */
+    FEAT_IGNORE = 0x0001,
     /* If a condition, condition is infix rather than prefix */
-    AUTOFEAT_INFIX = 0x0002
+    FEAT_INFIX = 0x0002,
+    /*
+     * Enable all features in the module when autoloading.
+     * This is the traditional zmodload -a behaviour;
+     * zmodload -Fa only enables features explicitly marked for
+     * autoloading.
+     */
+    FEAT_AUTOALL = 0x0004,
+    /*
+     * Remove feature:  alternative to "-X:NAME" used if
+     * X is passed separately from NAME.
+     */
+    FEAT_REMOVE = 0x0008,
+    /*
+     * For do_module_features().  Check that any autoloads
+     * for the module are actually provided.
+     */
+    FEAT_CHECKAUTO = 0x0010
 };
 
 /*
@@ -65,7 +91,7 @@ enum {
  *
  * "flags" is a set of the bits above.
  *
- * The return value is 0 for success, a negative value for failure with no
+ * The return value is 0 for success, -1 for failure with no
  * message needed, and one of the following to indicate the calling
  * function should print a message:
  *
@@ -73,7 +99,199 @@ enum {
  * 2:  [feature]: no such [type]
  * 3:  [feature]: [type] is already defined
  */
-typedef int (*autofeaturefn_t)(char *module, char *feature, int flags);
+typedef int (*autofeaturefn_t)(const char *module, const char *feature,
+			       int flags);
+
+/* Bits in the second argument to find_module. */
+enum {
+    /*
+     * Resolve any aliases to the underlying module.
+     */
+    FINDMOD_ALIASP = 0x0001,
+    /*
+     * Create an element for the module in the list if
+     * it is not found.
+     */
+    FINDMOD_CREATE = 0x0002,
+};
+
+static void
+freemodulenode(HashNode hn)
+{
+    Module m = (Module) hn;
+
+    if (m->node.flags & MOD_ALIAS)
+	zsfree(m->u.alias);
+    zsfree(m->node.nam);
+    if (m->autoloads)
+	freelinklist(m->autoloads, freestr);
+    if (m->deps)
+	freelinklist(m->deps, freestr);
+    zfree(m, sizeof(*m));
+}
+
+/* flags argument to printmodulenode */
+enum {
+    /* -L flag, output zmodload commands */
+    PRINTMOD_LIST = 0x0001,
+    /* -e flag */
+    PRINTMOD_EXIST = 0x0002,
+    /* -A flag */
+    PRINTMOD_ALIAS = 0x0004,
+    /* -d flag */
+    PRINTMOD_DEPS = 0x0008,
+    /* -F flag */
+    PRINTMOD_FEATURES = 0x0010,
+    /* -l flag in combination with -L flag */
+    PRINTMOD_LISTALL = 0x0020,
+    /* -a flag */
+    PRINTMOD_AUTO = 0x0040
+};
+
+/* Scan function for printing module details */
+
+static void
+printmodulenode(HashNode hn, int flags)
+{
+    Module m = (Module)hn;
+    /*
+     * If we check for a module loaded under an alias, we
+     * need the name of the alias.  We can use it in other
+     * cases, too.
+     */
+    const char *modname = m->node.nam;
+
+    if (flags & PRINTMOD_DEPS) {
+	/*
+	 * Print the module's dependencies.
+	 */
+	LinkNode n;
+
+	if (!m->deps)
+	    return;
+
+	if (flags & PRINTMOD_LIST) {
+	    printf("zmodload -d ");
+	    if (modname[0] == '-')
+		fputs("-- ", stdout);
+	    quotedzputs(modname, stdout);
+	} else {
+	    nicezputs(modname, stdout);
+	    putchar(':');
+	}
+	for (n = firstnode(m->deps); n; incnode(n)) {
+	    putchar(' ');
+	    if (flags & PRINTMOD_LIST)
+		quotedzputs((char *) getdata(n), stdout);
+	    else
+		nicezputs((char *) getdata(n), stdout);
+	}
+    } else if (flags & PRINTMOD_EXIST) {
+	/*
+	 * Just print the module name, provided the module is
+	 * present under an alias or otherwise.
+	 */
+	if (m->node.flags & MOD_ALIAS) {
+	    if (!(flags & PRINTMOD_ALIAS) ||
+		!(m = find_module(m->u.alias, FINDMOD_ALIASP, NULL)))
+		return;
+	}
+	if (!m->u.handle || (m->node.flags & MOD_UNLOAD))
+	    return;
+	nicezputs(modname, stdout);
+   } else if (m->node.flags & MOD_ALIAS) {
+	/*
+	 * Normal listing, but for aliases.
+	 */
+	if (flags & PRINTMOD_LIST) {
+	    printf("zmodload -A ");
+	    if (modname[0] == '-')
+		fputs("-- ", stdout);
+	    quotedzputs(modname, stdout);
+	    putchar('=');
+	    quotedzputs(m->u.alias, stdout);
+	} else {
+	    nicezputs(modname, stdout);
+	    fputs(" -> ", stdout);
+	    nicezputs(m->u.alias, stdout);
+	}
+    } else if (m->u.handle) {
+	/*
+	 * Loaded module.
+	 */
+	if (flags & PRINTMOD_LIST) {
+	    /*
+	     * List with -L format.  Possibly we are printing
+	     * features, either enables or autoloads.
+	     */
+	    char **features = NULL;
+	    int *enables = NULL;
+	    if (flags & PRINTMOD_AUTO) {
+		if (!m->autoloads || !firstnode(m->autoloads))
+		    return;
+	    } else if (flags & PRINTMOD_FEATURES) {
+		if (features_module(m, &features) ||
+		    enables_module(m, &enables) ||
+		    !*features)
+		    return;
+	    }
+	    printf("zmodload ");
+	    if (flags & PRINTMOD_AUTO) {
+		fputs("-Fa ", stdout);
+	    } else if (features)
+		fputs("-F ", stdout);
+	    if(modname[0] == '-')
+		fputs("-- ", stdout);
+	    quotedzputs(modname, stdout);
+	    if (flags & PRINTMOD_AUTO) {
+		LinkNode an;
+		for (an = firstnode(m->autoloads); an; incnode(an)) {
+		    putchar(' ');
+		    quotedzputs((char *)getdata(an), stdout);
+		}
+	    } else if (features) {
+		const char *f;
+		while ((f = *features++)) {
+		    int on = *enables++;
+		    if (flags & PRINTMOD_LISTALL)
+			printf(" %s", on ? "+" : "-");
+		    else if (!on)
+			continue;
+		    else
+			putchar(' ');
+		    quotedzputs(f, stdout);
+		}
+	    }
+	} else /* -l */
+	    nicezputs(modname, stdout);
+    } else
+	return;
+    putchar('\n');
+}
+
+/**/
+HashTable
+newmoduletable(int size, char const *name)
+{
+    HashTable ht;
+    ht = newhashtable(size, name, NULL);
+
+    ht->hash        = hasher;
+    ht->emptytable  = emptyhashtable;
+    ht->filltable   = NULL;
+    ht->cmpnodes    = strcmp;
+    ht->addnode     = addhashnode;
+    /* DISABLED is not supported */
+    ht->getnode     = gethashnode2;
+    ht->getnode2    = gethashnode2;
+    ht->removenode  = removehashnode;
+    ht->disablenode = NULL;
+    ht->enablenode  = NULL;
+    ht->freenode    = freemodulenode;
+    ht->printnode   = printmodulenode;
+
+    return ht;
+}
 
 /************************************************************************
  * zsh/main standard module functions
@@ -160,27 +378,6 @@ register_module(char *n, Module_void_func setup,
     zaddlinknode(linkedmodules, m);
 }
 
-/* Print an alias. */
-
-/**/
-static void
-printmodalias(Module m, Options ops)
-{
-    if (OPT_ISSET(ops,'L')) {
-	printf("zmodload -A ");
-	if (m->nam[0] == '-')
-	    fputs("-- ", stdout);
-	quotedzputs(m->nam, stdout);
-	putchar('=');
-	quotedzputs(m->u.alias, stdout);
-    } else {
-	nicezputs(m->nam, stdout);
-	fputs(" -> ", stdout);
-	nicezputs(m->u.alias, stdout);
-    }
-    putchar('\n');
-}
-
 /* Check if a module is linked in. */
 
 /**/
@@ -208,7 +405,7 @@ module_linked(char const *name)
  * builtin can be replaced using this function.                       */
 
 /**/
-int
+static int
 addbuiltin(Builtin b)
 {
     Builtin bn = (Builtin) builtintab->getnode2(builtintab, b->node.nam);
@@ -226,16 +423,19 @@ addbuiltin(Builtin b)
 
 /**/
 static int
-add_autobin(char *module, char *bnam, int flags)
+add_autobin(const char *module, const char *bnam, int flags)
 {
     Builtin bn;
+    int ret;
 
     bn = zshcalloc(sizeof(*bn));
     bn->node.nam = ztrdup(bnam);
     bn->optstr = ztrdup(module);
-    if (addbuiltin(bn)) {
+    if (flags & FEAT_AUTOALL)
+	bn->node.flags |= BINF_AUTOALL;
+    if ((ret = addbuiltin(bn))) {
 	builtintab->freenode(&bn->node);
-	if (!(flags & AUTOFEAT_IGNORE))
+	if (!(flags & FEAT_IGNORE))
 	    return 1;
     }
     return 0;
@@ -246,7 +446,7 @@ add_autobin(char *module, char *bnam, int flags)
 
 /**/
 int
-deletebuiltin(char *nam)
+deletebuiltin(const char *nam)
 {
     Builtin bn;
 
@@ -261,14 +461,15 @@ deletebuiltin(char *nam)
 
 /**/
 static int
-del_autobin(UNUSED(char *module), char *bnam, int flags)
+del_autobin(UNUSED(const char *module), const char *bnam, int flags)
 {
     Builtin bn = (Builtin) builtintab->getnode2(builtintab, bnam);
     if (!bn) {
-	if(!(flags & AUTOFEAT_IGNORE))
+	if(!(flags & FEAT_IGNORE))
 	    return 2;
     } else if (bn->node.flags & BINF_ADDED) {
-	return 3;
+	if (!(flags & FEAT_IGNORE))
+	    return 3;
     } else
 	deletebuiltin(bnam);
 
@@ -383,7 +584,7 @@ addwrapper(Module m, FuncWrap w)
      * happen since we usually add wrappers when a real module is
      * loaded.
      */
-    if (m->flags & MOD_ALIAS)
+    if (m->node.flags & MOD_ALIAS)
 	return 1;
 
     if (w->flags & WRAPF_ADDED)
@@ -409,7 +610,7 @@ deletewrapper(Module m, FuncWrap w)
 {
     FuncWrap p, q;
 
-    if (m->flags & MOD_ALIAS)
+    if (m->node.flags & MOD_ALIAS)
 	return 1;
 
     if (w->flags & WRAPF_ADDED) {
@@ -444,7 +645,7 @@ mod_export Conddef condtab;
 
 /**/
 Conddef
-getconddef(int inf, char *name, int autol)
+getconddef(int inf, const char *name, int autol)
 {
     Conddef p;
     int f = 1;
@@ -462,8 +663,8 @@ getconddef(int inf, char *name, int autol)
 	     */
 	    if (f) {
 		(void)ensurefeature(p->module,
-				    (p->flags & CONDF_INFIX) ?
-				    "C:" : "c:", name);
+				    (p->flags & CONDF_INFIX) ? "C:" : "c:",
+				    (p->flags & CONDF_AUTOALL) ? NULL : name);
 		f = 0;
 		p = NULL;
 	    } else {
@@ -577,14 +778,16 @@ setconddefs(char const *nam, Conddef c, int size, int *e)
 
 /**/
 static int
-add_autocond(char *module, char *cnam, int flags)
+add_autocond(const char *module, const char *cnam, int flags)
 {
     Conddef c;
 
     c = (Conddef) zalloc(sizeof(*c));
 
     c->name = ztrdup(cnam);
-    c->flags = ((flags & AUTOFEAT_INFIX) ? CONDF_INFIX : 0);
+    c->flags = ((flags & FEAT_INFIX) ? CONDF_INFIX : 0);
+    if (flags & FEAT_AUTOALL)
+	c->flags |= CONDF_AUTOALL;
     c->module = ztrdup(module);
 
     if (addconddef(c)) {
@@ -592,7 +795,7 @@ add_autocond(char *module, char *cnam, int flags)
 	zsfree(c->module);
 	zfree(c, sizeof(*c));
 
-	if (!(flags & AUTOFEAT_IGNORE))
+	if (!(flags & FEAT_IGNORE))
 	    return 1;
     }
     return 0;
@@ -602,16 +805,17 @@ add_autocond(char *module, char *cnam, int flags)
 
 /**/
 static int
-del_autocond(UNUSED(char *modnam), char *cnam, int flags)
+del_autocond(UNUSED(const char *modnam), const char *cnam, int flags)
 {
-    Conddef cd = getconddef((flags & AUTOFEAT_INFIX) ? 1 : 0, cnam, 0);
+    Conddef cd = getconddef((flags & FEAT_INFIX) ? 1 : 0, cnam, 0);
 
     if (!cd) {
-	if (!(flags & AUTOFEAT_IGNORE)) {
+	if (!(flags & FEAT_IGNORE)) {
 	    return 2;
 	}
     } else if (cd->flags & CONDF_ADDED) {
-	return 3;
+	if (!(flags & FEAT_IGNORE))
+	    return 3;
     } else
 	deleteconddef(cd);
 
@@ -658,17 +862,21 @@ addhookdef(Hookdef h)
     return 0;
 }
 
-/* This adds multiple hook definitions. This is like addbuiltins(). */
+/*
+ * This adds multiple hook definitions. This is like addbuiltins().
+ * This allows a NULL module because we call it from init.c.
+ */
 
 /**/
 mod_export int
-addhookdefs(char const *nam, Hookdef h, int size)
+addhookdefs(Module m, Hookdef h, int size)
 {
     int ret = 0;
 
     while (size--) {
 	if (addhookdef(h)) {
-	    zwarnnam(nam, "name clash when adding hook `%s'", h->name);
+	    zwarnnam(m ? m->node.nam : NULL,
+		     "name clash when adding hook `%s'", h->name);
 	    ret = 1;
 	}
 	h++;
@@ -701,7 +909,7 @@ deletehookdef(Hookdef h)
 
 /**/
 mod_export int
-deletehookdefs(UNUSED(char const *nam), Hookdef h, int size)
+deletehookdefs(UNUSED(Module m), Hookdef h, int size)
 {
     int ret = 0;
 
@@ -804,7 +1012,7 @@ runhookdef(Hookdef h, void *d)
  */
 
 static int
-checkaddparam(char *nam, int opt_i)
+checkaddparam(const char *nam, int opt_i)
 {
     Param pm;
 
@@ -970,13 +1178,13 @@ setparamdefs(char const *nam, Paramdef d, int size, int *e)
 
 /**/
 static int
-add_autoparam(char *module, char *pnam, int flags)
+add_autoparam(const char *module, const char *pnam, int flags)
 {
     Param pm;
     int ret;
 
     queue_signals();
-    if ((ret = checkaddparam(pnam, (flags & AUTOFEAT_IGNORE)))) {
+    if ((ret = checkaddparam(pnam, (flags & FEAT_IGNORE)))) {
 	unqueue_signals();
 	/*
 	 * checkaddparam() has already printed a message if one was
@@ -988,9 +1196,11 @@ add_autoparam(char *module, char *pnam, int flags)
 	return ret == 2 ? 0 : -1;
     }
 
-    pm = setsparam(pnam, ztrdup(module));
+    pm = setsparam(dupstring(pnam), ztrdup(module));
 
     pm->node.flags |= PM_AUTOLOAD;
+    if (flags & FEAT_AUTOALL)
+	pm->node.flags |= PM_AUTOALL;
     unqueue_signals();
 
     return 0;
@@ -1000,15 +1210,16 @@ add_autoparam(char *module, char *pnam, int flags)
 
 /**/
 static int
-del_autoparam(UNUSED(char *modnam), char *pnam, int flags)
+del_autoparam(UNUSED(const char *modnam), const char *pnam, int flags)
 {
     Param pm = (Param) gethashnode2(paramtab, pnam);
 
     if (!pm) {
-	if (!(flags & AUTOFEAT_IGNORE))
+	if (!(flags & FEAT_IGNORE))
 	    return 2;
     } else if (!(pm->node.flags & PM_AUTOLOAD)) {
-	return 3;
+	if (!(flags & FEAT_IGNORE))
+	    return 3;
     } else
 	unsetparam_pm(pm, 0, 1);
 
@@ -1047,7 +1258,7 @@ removemathfunc(MathFunc previous, MathFunc current)
 
 /**/
 MathFunc
-getmathfunc(char *name, int autol)
+getmathfunc(const char *name, int autol)
 {
     MathFunc p, q = NULL;
 
@@ -1058,7 +1269,8 @@ getmathfunc(char *name, int autol)
 
 		removemathfunc(q, p);
 
-		(void)ensurefeature(n, "f:", name);
+		(void)ensurefeature(n, "f:", (p->flags & MFF_AUTOALL) ? NULL :
+				    name);
 
 		return getmathfunc(name, 0);
 	    }
@@ -1171,7 +1383,7 @@ setmathfuncs(char const *nam, MathFunc f, int size, int *e)
 
 /**/
 static int
-add_automathfunc(char *module, char *fnam, int flags)
+add_automathfunc(const char *module, const char *fnam, int flags)
 {
     MathFunc f;
 
@@ -1186,7 +1398,7 @@ add_automathfunc(char *module, char *fnam, int flags)
 	zsfree(f->module);
 	zfree(f, sizeof(*f));
 
-	if (!(flags & AUTOFEAT_IGNORE))
+	if (!(flags & FEAT_IGNORE))
 	    return 1;
     }
 
@@ -1197,15 +1409,16 @@ add_automathfunc(char *module, char *fnam, int flags)
 
 /**/
 static int
-del_automathfunc(UNUSED(char *modnam), char *fnam, int flags)
+del_automathfunc(UNUSED(const char *modnam), const char *fnam, int flags)
 {
     MathFunc f = getmathfunc(fnam, 0);
     
     if (!f) {
-	if (!(flags & AUTOFEAT_IGNORE))
+	if (!(flags & FEAT_IGNORE))
 	    return 2;
     } else if (f->flags & MFF_ADDED) {
-	return 3;
+	if (!(flags & FEAT_IGNORE))
+	    return 3;
     } else
 	deletemathfunc(f);
 
@@ -1233,13 +1446,15 @@ load_and_bind(const char *fn)
     void *ret = (void *) load((char *) fn, L_NOAUTODEFER, NULL);
 
     if (ret) {
-	LinkNode node;
-	int err = loadbind(0, (void *) addbuiltin, ret);
-	for (node = firstnode(modules); !err && node; incnode(node)) {
-	    Module m = (Module) getdata(node);
-	    if (!(m->flags & MOD_ALIAS) &&
-		m->u.handle && !(m->flags & MOD_LINKED))
-		err |= loadbind(0, m->u.handle, ret);
+	Module m;
+	int i, err = loadbind(0, (void *) addbuiltin, ret);
+	for (i = 0; i < modulestab->hsize && !err; i++) {
+	    for (m = (Module)modulestab->nodes[i]; m && !err;
+		 m = m->node.next) {
+		if (!(m->flags & MOD_ALIAS) &&
+		    m->u.handle && !(m->flags & MOD_LINKED))
+		    err |= loadbind(0, m->u.handle, ret);
+	    }
 	}
 
 	if (err) {
@@ -1256,6 +1471,9 @@ load_and_bind(const char *fn)
 #define dlopen(X,Y) load_and_bind(X)
 #define dlclose(X)  unload(X)
 #define dlerror()   (dlerrstr[0])
+#ifndef HAVE_DLERROR
+# define HAVE_DLERROR 1
+#endif
 
 /**/
 #else
@@ -1294,7 +1512,9 @@ hpux_dlsym(void *handle, char *name)
 }
 
 # define dlsym(handle,name) hpux_dlsym(handle,name)
-# define dlerror() 0
+# ifdef HAVE_DLERROR		/* paranoia */
+#  undef HAVE_DLERROR
+# endif
 #else
 # ifndef HAVE_DLCLOSE
 #  define dlclose(X) ((X), 0)
@@ -1366,8 +1586,13 @@ do_load_module(char const *name, int silent)
     void *ret;
 
     ret = try_load_module(name);
-    if (!ret && !silent)
+    if (!ret && !silent) {
+#ifdef HAVE_DLERROR
+	zwarn("failed to load module `%s': %s", name, dlerror());
+#else
 	zwarn("failed to load module: %s", name);
+#endif
+    }
     return ret;
 }
 
@@ -1391,19 +1616,6 @@ do_load_module(char const *name, int silent)
 /**/
 #endif /* !DYNAMIC */
 
-/* Bits in the second argument to find_module. */
-enum {
-    /*
-     * Resolve any aliases to the underlying module.
-     */
-    FINDMOD_ALIASP = 0x0001,
-    /*
-     * Create an element for the module in the list if
-     * it is not found.
-     */
-    FINDMOD_CREATE = 0x0002,
-};
-
 /*
  * Find a module in the list.
  * flags is a set of bits defined in the enum above.
@@ -1413,35 +1625,29 @@ enum {
  * Return NULL if the module named is not stored as a structure, or if we were
  * resolving aliases and the final module named is not stored as a
  * structure.
- *
- * TODO: now we have aliases, there may be some merit in using a hash
- * table instead of a linked list.
  */
 /**/
-static LinkNode
+static Module
 find_module(const char *name, int flags, const char **namep)
 {
     Module m;
-    LinkNode node;
 
-    for (node = firstnode(modules); node; incnode(node)) {
-	m = (Module) getdata(node);
-	if (!strcmp(m->nam, name)) {
-	    if ((flags & FINDMOD_ALIASP) && (m->flags & MOD_ALIAS)) {
-		if (namep)
-		    *namep = m->u.alias;
-		return find_module(m->u.alias, flags, namep);
-	    }
+    m = (Module)modulestab->getnode2(modulestab, name);
+    if (m) {
+	if ((flags & FINDMOD_ALIASP) && (m->node.flags & MOD_ALIAS)) {
 	    if (namep)
-		*namep = m->nam;
-	    return node;
+		*namep = m->u.alias;
+	    return find_module(m->u.alias, flags, namep);
 	}
+	if (namep)
+	    *namep = m->node.nam;
+	return m;
     }
     if (!(flags & FINDMOD_CREATE))
 	return NULL;
     m = zshcalloc(sizeof(*m));
-    m->nam = ztrdup(name);
-    return zaddlinknode(modules, m);
+    modulestab->addnode(modulestab, ztrdup(name), m);
+    return m;
 }
 
 /*
@@ -1450,16 +1656,11 @@ find_module(const char *name, int flags, const char **namep)
 
 /**/
 static void
-delete_module(LinkNode node)
+delete_module(Module m)
 {
-    Module m = (Module) remnode(modules, node);
+    modulestab->removenode(modulestab, m->node.nam);
 
-    if (m->flags & MOD_ALIAS)
-	zsfree(m->u.alias);
-    zsfree(m->nam);
-    if (m->deps)
-	freelinklist(m->deps, freestr);
-    zfree(m, sizeof(*m));
+    modulestab->freenode(&m->node);
 }
 
 /*
@@ -1473,12 +1674,11 @@ delete_module(LinkNode node)
 mod_export int
 module_loaded(const char *name)
 {
-    LinkNode node;
     Module m;
 
-    return ((node = find_module(name, FINDMOD_ALIASP, NULL)) &&
-	    (m = ((Module) getdata(node)))->u.handle &&
-	    !(m->flags & MOD_UNLOAD));
+    return ((m = find_module(name, FINDMOD_ALIASP, NULL)) &&
+	    m->u.handle &&
+	    !(m->node.flags & MOD_UNLOAD));
 }
 
 /*
@@ -1575,7 +1775,7 @@ dyn_setup_module(Module m)
 
     if (fn)
 	return fn(m);
-    zwarnnam(m->nam, "no setup function");
+    zwarnnam(m->node.nam, "no setup function");
     return 1;
 }
 
@@ -1612,7 +1812,7 @@ dyn_boot_module(Module m)
 
     if(fn)
 	return fn(m);
-    zwarnnam(m->nam, "no boot function");
+    zwarnnam(m->node.nam, "no boot function");
     return 1;
 }
 
@@ -1624,7 +1824,7 @@ dyn_cleanup_module(Module m)
 
     if(fn)
 	return fn(m);
-    zwarnnam(m->nam, "no cleanup function");
+    zwarnnam(m->node.nam, "no cleanup function");
     return 1;
 }
 
@@ -1641,7 +1841,7 @@ dyn_finish_module(Module m)
     if (fn)
 	r = fn(m);
     else {
-	zwarnnam(m->nam, "no finish function");
+	zwarnnam(m->node.nam, "no finish function");
 	r = 1;
     }
     dlclose(m->u.handle);
@@ -1655,7 +1855,7 @@ dyn_finish_module(Module m)
 static int
 setup_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ?
+    return ((m->node.flags & MOD_LINKED) ?
 	    (m->u.linked->setup)(m) : dyn_setup_module(m));
 }
 
@@ -1663,7 +1863,7 @@ setup_module(Module m)
 static int
 features_module(Module m, char ***features)
 {
-    return ((m->flags & MOD_LINKED) ?
+    return ((m->node.flags & MOD_LINKED) ?
 	    (m->u.linked->features)(m, features) :
 	    dyn_features_module(m, features));
 }
@@ -1672,7 +1872,7 @@ features_module(Module m, char ***features)
 static int
 enables_module(Module m, int **enables)
 {
-    return ((m->flags & MOD_LINKED) ?
+    return ((m->node.flags & MOD_LINKED) ?
 	    (m->u.linked->enables)(m, enables) :
 	    dyn_enables_module(m, enables));
 }
@@ -1681,7 +1881,7 @@ enables_module(Module m, int **enables)
 static int
 boot_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ?
+    return ((m->node.flags & MOD_LINKED) ?
 	    (m->u.linked->boot)(m) : dyn_boot_module(m));
 }
 
@@ -1689,7 +1889,7 @@ boot_module(Module m)
 static int
 cleanup_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ?
+    return ((m->node.flags & MOD_LINKED) ?
 	    (m->u.linked->cleanup)(m) : dyn_cleanup_module(m));
 }
 
@@ -1697,7 +1897,7 @@ cleanup_module(Module m)
 static int
 finish_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ?
+    return ((m->node.flags & MOD_LINKED) ?
 	    (m->u.linked->finish)(m) : dyn_finish_module(m));
 }
 
@@ -1708,14 +1908,14 @@ finish_module(Module m)
 static int
 setup_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ? (m->u.linked->setup)(m) : 1);
+    return ((m->node.flags & MOD_LINKED) ? (m->u.linked->setup)(m) : 1);
 }
 
 /**/
 static int
 features_module(Module m, char ***features)
 {
-    return ((m->flags & MOD_LINKED) ? (m->u.linked->features)(m, features)
+    return ((m->node.flags & MOD_LINKED) ? (m->u.linked->features)(m, features)
 	    : 1);
 }
 
@@ -1723,7 +1923,7 @@ features_module(Module m, char ***features)
 static int
 enables_module(Module m, int **enables)
 {
-    return ((m->flags & MOD_LINKED) ? (m->u.linked->enables)(m, enables)
+    return ((m->node.flags & MOD_LINKED) ? (m->u.linked->enables)(m, enables)
 	    : 1);
 }
 
@@ -1731,21 +1931,21 @@ enables_module(Module m, int **enables)
 static int
 boot_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ? (m->u.linked->boot)(m) : 1);
+    return ((m->node.flags & MOD_LINKED) ? (m->u.linked->boot)(m) : 1);
 }
 
 /**/
 static int
 cleanup_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ? (m->u.linked->cleanup)(m) : 1);
+    return ((m->node.flags & MOD_LINKED) ? (m->u.linked->cleanup)(m) : 1);
 }
 
 /**/
 static int
 finish_module(Module m)
 {
-    return ((m->flags & MOD_LINKED) ? (m->u.linked->finish)(m) : 1);
+    return ((m->node.flags & MOD_LINKED) ? (m->u.linked->finish)(m) : 1);
 }
 
 /**/
@@ -1761,14 +1961,16 @@ finish_module(Module m)
  * by now (though may not be fully set up).
  *
  * Return 0 for success, 1 for failure, 2 if some features
- * couldn't be set.
+ * couldn't be set by the module itself (non-existent features
+ * are tested here and cause 1 to be returned).
  */
 
 /**/
 static int
-do_module_features(Module m, char **enablesstr, int silent)
+do_module_features(Module m, char **enablesstr, int flags)
 {
     char **features;
+    int ret = 0;
 
     if (features_module(m, &features) == 0) {
 	/*
@@ -1781,12 +1983,62 @@ do_module_features(Module m, char **enablesstr, int silent)
 	int *enables = NULL;
 	if (enables_module(m, &enables)) {
 	    /* If features are supported, enables should be, too */
-	    if (!silent)
+	    if (!(flags & FEAT_IGNORE))
 		zwarn("error getting enabled features for module `%s'",
-		      m->nam);
+		      m->node.nam);
 	    return 1;
 	}
 
+	if ((flags & FEAT_CHECKAUTO) && m->autoloads) {
+	    /*
+	     * Check autoloads are available.  Since these
+	     * have been requested at some other point, they
+	     * don't affect the return status unless something
+	     * in enablesstr doesn't work.
+	     */
+	    LinkNode an, nextn;
+	    for (an = firstnode(m->autoloads); an; an = nextn) {
+		char *al = (char *)getdata(an), **ptr;
+		/* careful, we can delete the current node */
+		nextn = nextnode(an);
+		for (ptr = features; *ptr; ptr++)
+		    if (!strcmp(al, *ptr))
+			break;
+		if (!*ptr) {
+		    char *arg[2];
+		    if (!(flags & FEAT_IGNORE))
+			zwarn(
+		    "module `%s' has no such feature: `%s': autoload cancelled",
+		    m->node.nam, al);
+		    /*
+		     * This shouldn't happen, so it's not worth optimising
+		     * the call to autofeatures...
+		     */
+		    arg[0] = al = dupstring(al);
+		    arg[1] = NULL;
+		    (void)autofeatures(NULL, m->node.nam, arg, 0,
+				       FEAT_IGNORE|FEAT_REMOVE);
+		    /*
+		     * 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)) {
+				/* can't enable it after all, so return 1 */
+				ret = 1;
+				while (*ptr) {
+				    *ptr = ptr[1];
+				    ptr++;
+				}
+				break;
+			    }
+			}
+		    }
+		}
+	    }
+	}
+
 	if (enablesstr) {
 	    char **ep;
 	    for (ep = enablesstr; *ep; ep++) {
@@ -1804,9 +2056,9 @@ do_module_features(Module m, char **enablesstr, int silent)
 			break;
 		    }
 		if (!*fp) {
-		    if (!silent)
-			zwarn("module `%s' has no such feature: %s",
-			      m->nam, esp);
+		    if (!(flags & FEAT_IGNORE))
+			zwarn("module `%s' has no such feature: `%s'",
+			      m->node.nam, esp);
 		    return 1;
 		}
 	    }
@@ -1824,13 +2076,13 @@ do_module_features(Module m, char **enablesstr, int silent)
 	if (enables_module(m, &enables))
 	    return 2;
     } else if (enablesstr) {
-	if (!silent)
-	    zwarn("module `%s' does not support features", m->nam);
+	if (!(flags & FEAT_IGNORE))
+	    zwarn("module `%s' does not support features", m->node.nam);
 	return 1;
     }
     /* Else it doesn't support features but we don't care. */
 
-    return 0;
+    return ret;
 }
 
 /*
@@ -1847,7 +2099,9 @@ do_module_features(Module m, char **enablesstr, int silent)
 static int
 do_boot_module(Module m, char **enablesstr, int silent)
 {
-    int ret = do_module_features(m, enablesstr, silent);
+    int ret = do_module_features(m, enablesstr,
+				 silent ? FEAT_IGNORE|FEAT_CHECKAUTO :
+				 FEAT_CHECKAUTO);
 
     if (ret == 1)
 	return 1;
@@ -1865,7 +2119,7 @@ do_boot_module(Module m, char **enablesstr, int silent)
 static int
 do_cleanup_module(Module m)
 {
-    return (m->flags & MOD_LINKED) ?
+    return (m->node.flags & MOD_LINKED) ?
 	(m->u.linked && m->u.linked->cleanup(m)) :
 	(m->u.handle && cleanup_module(m));
 }
@@ -1910,7 +2164,6 @@ load_module(char const *name, char **enablesstr, int silent)
     Module m;
     void *handle = NULL;
     Linkedmod linked;
-    LinkNode node, n;
     int set, bootret;
 
     if (!modname_ok(name)) {
@@ -1924,66 +2177,65 @@ load_module(char const *name, char **enablesstr, int silent)
      * is the right one.
      */
     queue_signals();
-    if (!(node = find_module(name, FINDMOD_ALIASP, &name))) {
+    if (!(m = find_module(name, FINDMOD_ALIASP, &name))) {
 	if (!(linked = module_linked(name)) &&
 	    !(handle = do_load_module(name, silent))) {
 	    unqueue_signals();
 	    return 1;
 	}
 	m = zshcalloc(sizeof(*m));
-	m->nam = ztrdup(name);
 	if (handle) {
 	    m->u.handle = handle;
-	    m->flags |= MOD_SETUP;
+	    m->node.flags |= MOD_SETUP;
 	} else {
 	    m->u.linked = linked;
-	    m->flags |= MOD_SETUP | MOD_LINKED;
+	    m->node.flags |= MOD_SETUP | MOD_LINKED;
 	}
-	node = zaddlinknode(modules, m);
+	modulestab->addnode(modulestab, ztrdup(name), m);
 
 	if ((set = setup_module(m)) ||
 	    (bootret = do_boot_module(m, enablesstr, silent)) == 1) {
-	    if (!set) {
+	    if (!set)
 		do_cleanup_module(m);
-		finish_module(m);
-	    }
-	    delete_module(node);
+	    finish_module(m);
+	    delete_module(m);
 	    unqueue_signals();
 	    return 1;
 	}
-	m->flags |= MOD_INIT_S | MOD_INIT_B;
-	m->flags &= ~MOD_SETUP;
+	m->node.flags |= MOD_INIT_S | MOD_INIT_B;
+	m->node.flags &= ~MOD_SETUP;
 	unqueue_signals();
 	return bootret;
     }
-    m = (Module) getdata(node);
-    if (m->flags & MOD_SETUP) {
+    if (m->node.flags & MOD_SETUP) {
 	unqueue_signals();
 	return 0;
     }
-    if (m->flags & MOD_UNLOAD)
-	m->flags &= ~MOD_UNLOAD;
-    else if ((m->flags & MOD_LINKED) ? m->u.linked : m->u.handle) {
+    if (m->node.flags & MOD_UNLOAD)
+	m->node.flags &= ~MOD_UNLOAD;
+    else if ((m->node.flags & MOD_LINKED) ? m->u.linked : m->u.handle) {
 	unqueue_signals();
 	return 0;
     }
-    if (m->flags & MOD_BUSY) {
-	zerr("circular dependencies for module %s", name);
+    if (m->node.flags & MOD_BUSY) {
+	zerr("circular dependencies for module ;%s", name);
 	return 1;
     }
-    m->flags |= MOD_BUSY;
+    m->node.flags |= MOD_BUSY;
     /*
      * TODO: shouldn't we unload the module if one of
      * its dependencies fails?
      */
-    if (m->deps)
+    if (m->deps) {
+	LinkNode n;
 	for (n = firstnode(m->deps); n; incnode(n))
 	    if (load_module((char *) getdata(n), NULL, silent) == 1) {
-		m->flags &= ~MOD_BUSY;
+		m->node.flags &= ~MOD_BUSY;
 		unqueue_signals();
 		return 1;
 	    }
-    m->flags &= ~MOD_BUSY;
+    }
+    m->node.flags &= ~MOD_BUSY;
     if (!m->u.handle) {
 	handle = NULL;
 	if (!(linked = module_linked(name)) &&
@@ -1993,36 +2245,37 @@ load_module(char const *name, char **enablesstr, int silent)
 	}
 	if (handle) {
 	    m->u.handle = handle;
-	    m->flags |= MOD_SETUP;
+	    m->node.flags |= MOD_SETUP;
 	} else {
 	    m->u.linked = linked;
-	    m->flags |= MOD_SETUP | MOD_LINKED;
+	    m->node.flags |= MOD_SETUP | MOD_LINKED;
 	}
 	if (setup_module(m)) {
+	    finish_module(m);
 	    if (handle)
 		m->u.handle = NULL;
 	    else
 		m->u.linked = NULL;
-	    m->flags &= ~MOD_SETUP;
+	    m->node.flags &= ~MOD_SETUP;
 	    unqueue_signals();
 	    return 1;
 	}
-	m->flags |= MOD_INIT_S;
+	m->node.flags |= MOD_INIT_S;
     }
-    m->flags |= MOD_SETUP;
+    m->node.flags |= MOD_SETUP;
     if ((bootret = do_boot_module(m, enablesstr, silent)) == 1) {
 	do_cleanup_module(m);
 	finish_module(m);
-	if (m->flags & MOD_LINKED)
+	if (m->node.flags & MOD_LINKED)
 	    m->u.linked = NULL;
 	else
 	    m->u.handle = NULL;
-	m->flags &= ~MOD_SETUP;
+	m->node.flags &= ~MOD_SETUP;
 	unqueue_signals();
 	return 1;
     }
-    m->flags |= MOD_INIT_B;
-    m->flags &= ~MOD_SETUP;
+    m->node.flags |= MOD_INIT_B;
+    m->node.flags &= ~MOD_SETUP;
     unqueue_signals();
     return bootret;
 }
@@ -2030,7 +2283,8 @@ load_module(char const *name, char **enablesstr, int silent)
 /* This ensures that the module with the name given as the first argument
  * is loaded.
  * The other argument is the array of features to set.  If this is NULL
- * and the module needs to be loaded, all features are enabled.
+ * all features are enabled (even if the module was already loaded).
+ *
  * If this is non-NULL the module features are set accordingly
  * whether or not the module is loaded; it is an error if the
  * module does not support the features passed (even if the feature
@@ -2050,14 +2304,13 @@ mod_export int
 require_module(const char *module, char **features)
 {
     Module m = NULL;
-    LinkNode node;
     int ret = 0;
 
     /* Resolve aliases and actual loadable module as for load_module */
     queue_signals();
-    node = find_module(module, 1, &module);
-    if (!node || !(m = ((Module) getdata(node)))->u.handle ||
-	(m->flags & MOD_UNLOAD))
+    m = find_module(module, FINDMOD_ALIASP, &module);
+    if (!m || !m->u.handle ||
+	(m->node.flags & MOD_UNLOAD))
 	ret = load_module(module, features, 0);
     else
 	ret = do_module_features(m, features, 0);
@@ -2090,7 +2343,7 @@ add_dep(const char *name, char *from)
      * Better make sure.  (There's no problem making a an alias which
      * *points* to a module with dependencies, of course.)
      */
-    m = getdata(find_module(name, FINDMOD_ALIASP|FINDMOD_CREATE, &name));
+    m = find_module(name, FINDMOD_ALIASP|FINDMOD_CREATE, &name);
     if (!m->deps)
 	m->deps = znewlinklist();
     for (node = firstnode(m->deps);
@@ -2179,7 +2432,8 @@ bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func))
 	return 1;
     }
     if (OPT_ISSET(ops,'e') && (OPT_ISSET(ops,'I') || OPT_ISSET(ops,'L') || 
-			       OPT_ISSET(ops,'a') || OPT_ISSET(ops,'d') ||
+			       (OPT_ISSET(ops,'a') && !OPT_ISSET(ops,'F'))
+			       || OPT_ISSET(ops,'d') ||
 			       OPT_ISSET(ops,'i') || OPT_ISSET(ops,'u'))) {
 	zwarnnam(nam, "-e cannot be combined with other options");
 	/* except -F ... */
@@ -2233,7 +2487,6 @@ bin_zmodload_alias(char *nam, char **args, Options ops)
      * suppose other names are aliased to the same file?  It might be
      * kettle of fish best left unwormed.
      */
-    LinkNode node;
     Module m;
 
     if (!*args) {
@@ -2241,11 +2494,9 @@ bin_zmodload_alias(char *nam, char **args, Options ops)
 	    zwarnnam(nam, "no module alias to remove");
 	    return 1;
 	}
-	for (node = firstnode(modules); node; incnode(node)) {
-	    m = (Module) getdata(node);
-	    if (m->flags & MOD_ALIAS)
-		printmodalias(m, ops);
-	}
+	scanhashtable(modulestab, 1, MOD_ALIAS, 0,
+		      modulestab->printnode,
+		      OPT_ISSET(ops,'L') ? PRINTMOD_LIST : 0);
 	return 0;
     }
 
@@ -2264,14 +2515,13 @@ bin_zmodload_alias(char *nam, char **args, Options ops)
 			 *args);
 		return 1;
 	    }
-	    node = find_module(*args, 0, NULL);
-	    if (node) {
-		m = (Module) getdata(node);
-		if (!(m->flags & MOD_ALIAS)) {
+	    m = find_module(*args, 0, NULL);
+	    if (m) {
+		if (!(m->node.flags & MOD_ALIAS)) {
 		    zwarnnam(nam, "module is not an alias: %s", *args);
 		    return 1;
 		}
-		delete_module(node);
+		delete_module(m);
 	    } else {
 		zwarnnam(nam, "no such module alias: %s", *args);
 		return 1;
@@ -2289,29 +2539,28 @@ bin_zmodload_alias(char *nam, char **args, Options ops)
 				 *args);
 			return 1;
 		    }
-		} while ((node = find_module(mname, 0, NULL))
-			 && ((m = (Module) getdata(node))->flags & MOD_ALIAS)
+		} while ((m = find_module(mname, 0, NULL))
+			 && (m->node.flags & MOD_ALIAS)
 			 && (mname = m->u.alias));
-		node = find_module(*args, 0, NULL);
-		if (node) {
-		    m = (Module) getdata(node);
-		    if (!(m->flags & MOD_ALIAS)) {
+		m = find_module(*args, 0, NULL);
+		if (m) {
+		    if (!(m->node.flags & MOD_ALIAS)) {
 			zwarnnam(nam, "module is not an alias: %s", *args);
 			return 1;
 		    }
 		    zsfree(m->u.alias);
 		} else {
 		    m = (Module) zshcalloc(sizeof(*m));
-		    m->nam = ztrdup(*args);
-		    m->flags = MOD_ALIAS;
-		    zaddlinknode(modules, m);
+		    m->node.flags = MOD_ALIAS;
+		    modulestab->addnode(modulestab, ztrdup(*args), m);
 		}
 		m->u.alias = ztrdup(aliasname);
 	    } else {
-		if ((node = find_module(*args, 0, NULL))) {
-		    m = (Module) getdata(node);
-		    if (m->flags & MOD_ALIAS)
-			printmodalias(m, ops);
+		if ((m = find_module(*args, 0, NULL))) {
+		    if (m->node.flags & MOD_ALIAS)
+			modulestab->printnode(&m->node,
+					      OPT_ISSET(ops,'L') ?
+					      PRINTMOD_LIST : 0);
 		    else {
 			zwarnnam(nam, "module is not an alias: %s", *args);
 			return 1;
@@ -2333,35 +2582,20 @@ bin_zmodload_alias(char *nam, char **args, Options ops)
 static int
 bin_zmodload_exist(UNUSED(char *nam), char **args, Options ops)
 {
-    LinkNode node;
     Module m;
-    char *modname;
 
     if (!*args) {
-	for (node = firstnode(modules); node; incnode(node)) {
-	    m = (Module) getdata(node);
-	    modname = m->nam;
-	    if (m->flags & MOD_ALIAS) {
-		LinkNode node2;
-		if (OPT_ISSET(ops,'A') && 
-		    (node2 = find_module(m->u.alias, FINDMOD_ALIASP, NULL)))
-		    m = (Module) getdata(node2);
-		else
-		    continue;
-	    }
-	    if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
-		nicezputs(modname, stdout);
-		putchar('\n');
-	    }
-	}
+	scanhashtable(modulestab, 1, 0, 0, modulestab->printnode,
+		      OPT_ISSET(ops,'A') ? PRINTMOD_EXIST|PRINTMOD_ALIAS :
+		      PRINTMOD_EXIST);
 	return 0;
     } else {
 	int ret = 0;
 
 	for (; !ret && *args; args++) {
-	    if (!(node = find_module(*args, FINDMOD_ALIASP, NULL))
-		|| !(m = (Module) getdata(node))->u.handle
-		|| (m->flags & MOD_UNLOAD))
+	    if (!(m = find_module(*args, FINDMOD_ALIASP, NULL))
+		|| !m->u.handle
+		|| (m->node.flags & MOD_UNLOAD))
 		ret = 1;
 	}
 	return ret;
@@ -2374,15 +2608,13 @@ bin_zmodload_exist(UNUSED(char *nam), char **args, Options ops)
 static int
 bin_zmodload_dep(UNUSED(char *nam), char **args, Options ops)
 {
-    LinkNode node;
     Module m;
     if (OPT_ISSET(ops,'u')) {
 	/* remove dependencies, which can't pertain to aliases */
 	const char *tnam = *args++;
-	node = find_module(tnam, FINDMOD_ALIASP, &tnam);
-	if (!node)
+	m = find_module(tnam, FINDMOD_ALIASP, &tnam);
+	if (!m)
 	    return 0;
-	m = (Module) getdata(node);
 	if (*args && m->deps) {
 	    do {
 		LinkNode dnode;
@@ -2404,32 +2636,18 @@ bin_zmodload_dep(UNUSED(char *nam), char **args, Options ops)
 	    }
 	}
 	if (!m->deps && !m->u.handle)
-	    delete_module(node);
+	    delete_module(m);
 	return 0;
     } else if (!args[0] || !args[1]) {
 	/* list dependencies */
-	for (node = firstnode(modules); node; incnode(node)) {
-	    m = (Module) getdata(node);
-	    if (m->deps && (!args[0] || !strcmp(args[0], m->nam))) {
-		LinkNode n;
-		if (OPT_ISSET(ops,'L')) {
-		    printf("zmodload -d ");
-		    if(m->nam[0] == '-')
-			fputs("-- ", stdout);
-		    quotedzputs(m->nam, stdout);
-		} else {
-		    nicezputs(m->nam, stdout);
-		    putchar(':');
-		}
-		for (n = firstnode(m->deps); n; incnode(n)) {
-		    putchar(' ');
-		    if(OPT_ISSET(ops,'L'))
-			quotedzputs((char *) getdata(n), stdout);
-		    else
-			nicezputs((char *) getdata(n), stdout);
-		}
-		putchar('\n');
-	    }
+	int depflags = OPT_ISSET(ops,'L') ?
+	    PRINTMOD_DEPS|PRINTMOD_LIST : PRINTMOD_DEPS;
+	if (args[0]) {
+	    if ((m = (Module)modulestab->getnode2(modulestab, args[0])))
+		modulestab->printnode(&m->node, depflags);
+	} else {
+	    scanhashtable(modulestab, 1, 0, 0, modulestab->printnode,
+			  depflags);
 	}
 	return 0;
     } else {
@@ -2467,7 +2685,7 @@ printautoparams(HashNode hn, int lon)
 static int
 bin_zmodload_auto(char *nam, char **args, Options ops)
 {
-    int fchar;
+    int fchar, flags;
     char *modnam;
 
     if (OPT_ISSET(ops,'c')) {
@@ -2530,9 +2748,12 @@ bin_zmodload_auto(char *nam, char **args, Options ops)
 	fchar = 'b';
     }
 
+    flags = FEAT_AUTOALL;
+    if (OPT_ISSET(ops,'i'))
+	flags |= FEAT_IGNORE;
     if (OPT_ISSET(ops,'u')) {
 	/* remove autoload */
-	fchar *= -1;
+	flags |= FEAT_REMOVE;
 	modnam = NULL;
     } else {
 	/* add autoload */
@@ -2541,94 +2762,113 @@ bin_zmodload_auto(char *nam, char **args, Options ops)
 	if (args[1])
 	    args++;
     }
-    return autofeatures(nam, modnam, args, fchar, OPT_ISSET(ops,'i'));
+    return autofeatures(nam, modnam, args, fchar, flags);
 }
 
 /* Backend handler for zmodload -u */
 
 /**/
 int
-unload_module(Module m, LinkNode node)
+unload_module(Module m)
 {
+    int del;
+
     /*
      * Only unload the real module, so resolve aliases.
      */
-    if (m->flags & MOD_ALIAS) {
-	LinkNode node = find_module(m->u.alias, FINDMOD_ALIASP, NULL);
-	if (!node)
+    if (m->node.flags & MOD_ALIAS) {
+	m = find_module(m->u.alias, FINDMOD_ALIASP, NULL);
+	if (!m)
 	    return 1;
-	m = (Module) getdata(node);
     }
-    if ((m->flags & MOD_INIT_S) &&
-	!(m->flags & MOD_UNLOAD) &&
+    /*
+     * We may need to clean up the module any time setup_ has been
+     * called.  After cleanup_ is successful we are no longer in the
+     * booted state (because features etc. are deregistered), so remove
+     * MOD_INIT_B, and also MOD_INIT_S since we won't need to cleanup
+     * again if this succeeded.
+     */
+    if ((m->node.flags & MOD_INIT_S) &&
+	!(m->node.flags & MOD_UNLOAD) &&
 	do_cleanup_module(m))
 	return 1;
-    else {
-	int del = (m->flags & MOD_UNLOAD);
+    m->node.flags &= ~(MOD_INIT_B|MOD_INIT_S);
 
-	if (m->wrapper) {
-	    m->flags |= MOD_UNLOAD;
-	    return 0;
+    del = (m->node.flags & MOD_UNLOAD);
+
+    if (m->wrapper) {
+	m->node.flags |= MOD_UNLOAD;
+	return 0;
+    }
+    m->node.flags &= ~MOD_UNLOAD;
+
+    /*
+     * We always need to finish the module (and unload it)
+     * if it is present.
+     */
+    if (m->node.flags & MOD_LINKED) {
+	if (m->u.linked) {
+	    m->u.linked->finish(m);
+	    m->u.linked = NULL;
 	}
-	m->flags &= ~MOD_UNLOAD;
-	if (m->flags & MOD_INIT_B) {
-	    if (m->flags & MOD_LINKED) {
-		if (m->u.linked) {
-		    m->u.linked->finish(m);
-		    m->u.linked = NULL;
-		}
-	    } else {
-		if (m->u.handle) {
-		    finish_module(m);
-		    m->u.handle = NULL;
-		}
-	    }
+    } else {
+	if (m->u.handle) {
+	    finish_module(m);
+	    m->u.handle = NULL;
 	}
-	if (del && m->deps) {
-	    /* The module was unloaded delayed, unload all modules *
-	     * on which it depended. */
-	    LinkNode n;
-
-	    for (n = firstnode(m->deps); n; incnode(n)) {
-		LinkNode dn = find_module((char *) getdata(n),
-					  FINDMOD_ALIASP, NULL);
-		Module dm;
-
-		if (dn && (dm = (Module) getdata(dn)) &&
-		    (dm->flags & MOD_UNLOAD)) {
-		    /* See if this is the only module depending on it. */
-
-		    LinkNode an;
-		    Module am;
-		    int du = 1;
-
-		    for (an = firstnode(modules); du && an; incnode(an)) {
-			am = (Module) getdata(an);
-			if (am != m && am->deps &&
-			    ((am->flags & MOD_LINKED) ?
-			     am->u.linked : am->u.handle)) {
-			    LinkNode sn;
-
-			    for (sn = firstnode(am->deps); du && sn;
-				 incnode(sn)) {
-				if (!strcmp((char *) getdata(sn), dm->nam))
-				    du = 0;
-			    }
+    }
+
+    if (del && m->deps) {
+	/* The module was unloaded delayed, unload all modules *
+	 * on which it depended. */
+	LinkNode n;
+
+	for (n = firstnode(m->deps); n; incnode(n)) {
+	    Module dm = find_module((char *) getdata(n),
+				    FINDMOD_ALIASP, NULL);
+
+	    if (dm &&
+		(dm->node.flags & MOD_UNLOAD)) {
+		/* See if this is the only module depending on it. */
+		Module am;
+		int du = 1, i;
+		/* Scan hash table the hard way */
+		for (i = 0; du && i < modulestab->hsize; i++) {
+		    for (am = (Module)modulestab->nodes[i]; du && am;
+			 am = (Module)am->node.next) {
+			LinkNode sn;
+			/*
+			 * Don't scan the module we're unloading;
+			 * ignore if no dependencies.
+			 */
+			if (am == m || !am->deps)
+			    continue;
+			/* Don't scan if not loaded nor linked */
+			if ((am->node.flags & MOD_LINKED) ?
+			    !am->u.linked : !am->u.handle)
+			    continue;
+			for (sn = firstnode(am->deps); du && sn;
+			     incnode(sn)) {
+			    if (!strcmp((char *) getdata(sn),
+					dm->node.nam))
+				du = 0;
 			}
 		    }
-		    if (du)
-			unload_module(dm, NULL);
 		}
+		if (du)
+		    unload_module(dm);
 	    }
 	}
-	if(!m->deps) {
-	    if (!node) {
-		node = linknodebydatum(modules, m);
-		if (!node)
-		    return 1;
-	    }
-	    delete_module(node);
-	}
+    }
+    if (m->autoloads && firstnode(m->autoloads)) {
+	/*
+	 * Module has autoloadable features.  Restore them
+	 * so that the module will be reloaded when needed.
+	 */
+	autofeatures("zsh", m->node.nam,
+		     hlinklist2array(m->autoloads, 0), 0, FEAT_IGNORE);
+    } else if (!m->deps) {
+	delete_module(m);
     }
     return 0;
 }
@@ -2644,32 +2884,35 @@ int
 unload_named_module(char *modname, char *nam, int silent)
 {
     const char *mname;
-    LinkNode node;
     Module m;
     int ret = 0;
 
-    node = find_module(modname, FINDMOD_ALIASP, &mname);
-    if (node) {
-	LinkNode mn, dn;
-	int del = 0;
+    m = find_module(modname, FINDMOD_ALIASP, &mname);
+    if (m) {
+	int i, del = 0;
+	Module dm;
 
-	for (mn = firstnode(modules); mn; incnode(mn)) {
-	    m = (Module) getdata(mn);
-	    if (m->deps && m->u.handle)
-		for (dn = firstnode(m->deps); dn; incnode(dn))
+	for (i = 0; i < modulestab->hsize; i++) {
+	    for (dm = (Module)modulestab->nodes[i]; dm;
+		 dm = (Module)dm->node.next) {
+		LinkNode dn;
+		if (!dm->deps || !dm->u.handle)
+		    continue;
+		for (dn = firstnode(dm->deps); dn; incnode(dn)) {
 		    if (!strcmp((char *) getdata(dn), mname)) {
-			if (m->flags & MOD_UNLOAD)
+			if (dm->node.flags & MOD_UNLOAD)
 			    del = 1;
 			else {
 			    zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", mname);
 			    return 1;
 			}
 		    }
+		}
+	    }
 	}
-	m = (Module) getdata(node);
 	if (del)
 	    m->wrapper++;
-	if (unload_module(m, node))
+	if (unload_module(m))
 	    ret = 1;
 	if (del)
 	    m->wrapper--;
@@ -2687,8 +2930,6 @@ unload_named_module(char *modname, char *nam, int silent)
 static int
 bin_zmodload_load(char *nam, char **args, Options ops)
 {
-    LinkNode node;
-    Module m;
     int ret = 0;
     if(OPT_ISSET(ops,'u')) {
 	/* unload modules */
@@ -2699,19 +2940,9 @@ bin_zmodload_load(char *nam, char **args, Options ops)
 	return ret;
     } else if(!*args) {
 	/* list modules */
-	for (node = firstnode(modules); node; incnode(node)) {
-	    m = (Module) getdata(node);
-	    if (m->u.handle && !(m->flags & (MOD_UNLOAD|MOD_ALIAS))) {
-		if(OPT_ISSET(ops,'L')) {
-		    printf("zmodload ");
-		    if(m->nam[0] == '-')
-			fputs("-- ", stdout);
-		    quotedzputs(m->nam, stdout);
-		} else
-		    nicezputs(m->nam, stdout);
-		putchar('\n');
-	    }
-	}
+	scanhashtable(modulestab, 1, 0, MOD_UNLOAD|MOD_ALIAS,
+		      modulestab->printnode,
+		      OPT_ISSET(ops,'L') ? PRINTMOD_LIST : 0);
 	return 0;
     } else {
 	/* load modules */
@@ -2729,15 +2960,31 @@ bin_zmodload_load(char *nam, char **args, Options ops)
 
 /**/
 static int
-bin_zmodload_features(char *nam, char **args, Options ops)
+bin_zmodload_features(const char *nam, char **args, Options ops)
 {
     char *modname = *args;
 
+    if (modname)
+	args++;
+    else if (OPT_ISSET(ops,'L')) {
+	int printflags = PRINTMOD_LIST|PRINTMOD_FEATURES;
+	if (OPT_ISSET(ops,'P')) {
+	    zwarnnam(nam, "-P is only allowed with a module name");
+	    return 1;
+	}
+	if (OPT_ISSET(ops,'l'))
+	    printflags |= PRINTMOD_LISTALL;
+	if (OPT_ISSET(ops,'a'))
+	    printflags |= PRINTMOD_AUTO;
+	scanhashtable(modulestab, 1, 0, MOD_ALIAS,
+		      modulestab->printnode, printflags);
+	return 0;
+    }
+
     if (!modname) {
 	zwarnnam(nam, "-F requires a module name");
 	return 1;
     }
-    args++;
 
     if (OPT_ISSET(ops,'l') || OPT_ISSET(ops,'L') || OPT_ISSET(ops,'e')) {
 	/*
@@ -2746,32 +2993,74 @@ bin_zmodload_features(char *nam, char **args, Options ops)
 	 * only options turned on.
 	 * With both options, list as zmodload showing options
 	 * to be turned both on and off.
-	 *
-	 * TODO: handle -a, list only autoloads.
 	 */
-	LinkNode node;
-	Module m = NULL;
+	Module m;
 	char **features, **fp, **arrset = NULL, **arrp = NULL;
 	int *enables = NULL, *ep;
 	char *param = OPT_ARG_SAFE(ops,'P');
 
-	node = find_module(modname, FINDMOD_ALIASP, NULL);
-	if (node)
-	    m = ((Module) getdata(node));
-	if (!m || !m->u.handle || (m->flags & MOD_UNLOAD)) {
+	m = find_module(modname, FINDMOD_ALIASP, NULL);
+	if (OPT_ISSET(ops,'a')) {
+	    LinkNode ln;
+	    /*
+	     * If there are no autoloads defined, return status 1.
+	     */
+	    if (!m || !m->autoloads)
+		return 1;
+	    if (OPT_ISSET(ops,'e')) {
+		for (fp = args; *fp; fp++) {
+		    char *fstr = *fp;
+		    int sense = 1;
+		    if (*fstr == '+')
+			fstr++;
+		    else if (*fstr == '-') {
+			fstr++;
+			sense = 0;
+		    }
+		    if ((linknodebystring(m->autoloads, fstr) != NULL) !=
+			sense)
+			return 1;
+		}
+		return 0;
+	    }
+	    if (param) {
+		arrp = arrset = (char **)zalloc(sizeof(char*) *
+				 (countlinknodes(m->autoloads)+1));
+	    } else if (OPT_ISSET(ops,'L')) {
+		printf("zmodload -aF %s%c", m->node.nam,
+		       m->autoloads && firstnode(m->autoloads) ? ' ' : '\n');
+		arrp = NULL;
+	    }
+	    for (ln = firstnode(m->autoloads); ln; incnode(ln)) {
+		char *al = (char *)getdata(ln);
+		if (param)
+		    *arrp++ = ztrdup(al);
+		else
+		    printf("%s%c", al,
+			   OPT_ISSET(ops,'L') && nextnode(ln) ? ' ' : '\n');
+	    }
+	    if (param) {
+		*arrp = NULL;
+		if (!setaparam(param, arrset))
+		    return 1;
+	    }
+	    return 0;
+	}
+	if (!m || !m->u.handle || (m->node.flags & MOD_UNLOAD)) {
 	    if (!OPT_ISSET(ops,'e'))
 		zwarnnam(nam, "module `%s' is not yet loaded", modname);
 	    return 1;
 	}
 	if (features_module(m, &features)) {
 	    if (!OPT_ISSET(ops,'e'))
-		zwarnnam(nam, "module `%s' does not support features", m->nam);
+		zwarnnam(nam, "module `%s' does not support features",
+			 m->node.nam);
 	    return 1;
 	}
 	if (enables_module(m, &enables)) {
 	    /* this shouldn't ever happen, so don't silence this error */
 	    zwarnnam(nam, "error getting enabled features for module `%s'",
-		     m->nam);
+		     m->node.nam);
 	    return 1;
 	}
 	for (arrp = args; *arrp; arrp++) {
@@ -2796,14 +3085,14 @@ bin_zmodload_features(char *nam, char **args, Options ops)
 	    }
 	    if (!*fp) {
 		if (!OPT_ISSET(ops,'e'))
-		    zwarnnam(nam, "module `%s' has no such feature: %s",
+		    zwarnnam(nam, "module `%s' has no such feature: `%s'",
 			     *arrp);
 		return 1;
 	    }
 	}
 	if (OPT_ISSET(ops,'e'))		/* yep, everything we want exists */
 	    return 0;
-	if (OPT_ISSET(ops,'P')) {
+	if (param) {
 	    int arrlen = 0;
 	    for (fp = features, ep = enables; *fp; fp++, ep++) {
 		if (OPT_ISSET(ops, 'L') && !OPT_ISSET(ops, 'l') &&
@@ -2826,7 +3115,7 @@ bin_zmodload_features(char *nam, char **args, Options ops)
 	    }
 	    arrp = arrset = zalloc(sizeof(char *) * (arrlen+1));
 	} else if (OPT_ISSET(ops, 'L'))
-	    printf("zmodload -F %s ", m->nam);
+	    printf("zmodload -F %s ", m->node.nam);
 	for (fp = features, ep = enables; *fp; fp++, ep++) {
 	    char *onoff;
 	    int term;
@@ -2872,7 +3161,18 @@ bin_zmodload_features(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')) {
-	return autofeatures(nam, modname, args, 0, OPT_ISSET(ops,'i'));
+	/*
+	 * With zmodload -aF, we always use the effect of -i.
+	 * The thinking is that marking a feature for
+	 * autoload is separate from enabling or disabling it.
+	 * Arguably we could do this with the zmodload -ab method
+	 * but I've kept it there for old time's sake.
+	 * The decoupling has meant FEAT_IGNORE/-i also
+	 * suppresses an error for attempting to remove an
+	 * autoload when the feature is enabled, which used
+	 * to be a hard error before.
+	 */
+	return autofeatures(nam, modname, args, 0, FEAT_IGNORE);
     }
 
     return require_module(modname, args);
@@ -2894,15 +3194,15 @@ bin_zmodload_features(char *nam, char **args, Options ops)
 
 /**/
 mod_export char **
-featuresarray(char const *nam, Features f)
+featuresarray(UNUSED(Module m), Features f)
 {
     int bn_size = f->bn_size, cd_size = f->cd_size;
-    int pd_size = f->pd_size, mf_size = f->mf_size;
+    int mf_size = f->mf_size, pd_size = f->pd_size;
     int features_size = bn_size + cd_size + pd_size + mf_size + f->n_abstract;
     Builtin bnp = f->bn_list;
     Conddef cdp = f->cd_list;
-    Paramdef pdp = f->pd_list;
     MathFunc mfp = f->mf_list;
+    Paramdef pdp = f->pd_list;
     char **features = (char **)zhalloc((features_size + 1) * sizeof(char *));
     char **featurep = features;
 
@@ -2913,10 +3213,10 @@ featuresarray(char const *nam, Features f)
 			     cdp->name);
 	cdp++;
     }
-    while (pd_size--)
-	*featurep++ = dyncat("p:", (pdp++)->name);
     while (mf_size--)
 	*featurep++ = dyncat("f:", (mfp++)->name);
+    while (pd_size--)
+	*featurep++ = dyncat("p:", (pdp++)->name);
 
     features[features_size] = NULL;
     return features;
@@ -2929,15 +3229,15 @@ featuresarray(char const *nam, Features f)
  */
 /**/
 mod_export int *
-getfeatureenables(char const *nam, Features f)
+getfeatureenables(UNUSED(Module m), Features f)
 {
     int bn_size = f->bn_size, cd_size = f->cd_size;
-    int pd_size = f->pd_size, mf_size = f->mf_size;
-    int features_size = bn_size + cd_size + pd_size + mf_size + f->n_abstract;
+    int mf_size = f->mf_size, pd_size = f->pd_size;
+    int features_size = bn_size + cd_size + mf_size + pd_size + f->n_abstract;
     Builtin bnp = f->bn_list;
     Conddef cdp = f->cd_list;
-    Paramdef pdp = f->pd_list;
     MathFunc mfp = f->mf_list;
+    Paramdef pdp = f->pd_list;
     int *enables = zhalloc(sizeof(int) * features_size);
     int *enablep = enables;
 
@@ -2945,10 +3245,10 @@ getfeatureenables(char const *nam, Features f)
 	*enablep++ = ((bnp++)->node.flags & BINF_ADDED) ? 1 : 0;
     while (cd_size--)
 	*enablep++ = ((cdp++)->flags & CONDF_ADDED) ? 1 : 0;
-    while (pd_size--)
-	*enablep++ = (pdp++)->pm ? 1 : 0;
     while (mf_size--)
 	*enablep++ = ((mfp++)->flags & MFF_ADDED) ? 1 : 0;
+    while (pd_size--)
+	*enablep++ = (pdp++)->pm ? 1 : 0;
 
     return enables;
 }
@@ -2965,32 +3265,32 @@ getfeatureenables(char const *nam, Features f)
 
 /**/
 mod_export int
-setfeatureenables(char const *nam, Features f, int *e)
+setfeatureenables(Module m, Features f, int *e)
 {
     int ret = 0;
 
     if (f->bn_size) {
-	if (setbuiltins(nam, f->bn_list, f->bn_size, e))
+	if (setbuiltins(m->node.nam, f->bn_list, f->bn_size, e))
 	    ret = 1;
 	if (e)
 	    e += f->bn_size;
     }
     if (f->cd_size) {
-	if (setconddefs(nam, f->cd_list, f->cd_size, e))
+	if (setconddefs(m->node.nam, f->cd_list, f->cd_size, e))
 	    ret = 1;
 	if (e)
 	    e += f->cd_size;
     }
+    if (f->mf_size) {
+	if (setmathfuncs(m->node.nam, f->mf_list, f->mf_size, e))
+	    ret = 1;
+    }
     if (f->pd_size) {
-	if (setparamdefs(nam, f->pd_list, f->pd_size, e))
+	if (setparamdefs(m->node.nam, f->pd_list, f->pd_size, e))
 	    ret = 1;
 	if (e)
 	    e += f->pd_size;
     }
-    if (f->mf_size) {
-	if (setmathfuncs(nam, f->mf_list, f->mf_size, e))
-	    ret = 1;
-    }
     return ret;
 }
 
@@ -3001,31 +3301,40 @@ setfeatureenables(char const *nam, Features f, int *e)
 
 /**/
 mod_export int
-handlefeatures(char *nam, Features f, int **enables)
+handlefeatures(Module m, Features f, int **enables)
 {
     if (!enables || *enables)
-	return setfeatureenables(nam, f, *enables);
-    *enables = getfeatureenables(nam, f);
+	return setfeatureenables(m, f, *enables);
+    *enables = getfeatureenables(m, f);
     return 0;
 }
 
 /*
  * Ensure module "modname" is providing feature with "prefix"
- * and "feature" (e.g. "b:", "limit").
+ * and "feature" (e.g. "b:", "limit").  If feature is NULL,
+ * ensure all features are loaded (used for compatibility
+ * with the pre-feature autoloading behaviour).
  *
  * This will usually be called from the main shell to handle
  * loading of an autoloadable feature.
  *
  * Returns 0 on success, 1 for error in module, 2 for error
- * setting the feature.
+ * setting the feature.  However, this isn't actually all
+ * that useful for testing immediately on an autoload since
+ * it could be a failure to autoload a different feature
+ * from the one we want.  We could fix this but it's
+ * possible to test other ways.
  */
 
 /**/
 mod_export int
-ensurefeature(char *modname, char *prefix, char *feature)
+ensurefeature(const char *modname, const char *prefix, const char *feature)
 {
-    char *f = dyncat(prefix, feature);
-    char *features[2];
+    char *f, *features[2];
+
+    if (!feature)
+	return require_module(modname, NULL);
+    f = dyncat(prefix, feature);
 
     features[0] = f;
     features[1] = NULL;
@@ -3038,28 +3347,38 @@ ensurefeature(char *modname, char *prefix, char *feature)
 
 /**/
 int
-autofeatures(char *cmdnam, char *module, char **features, int prefchar,
-	     int opt_i)
+autofeatures(const char *cmdnam, const char *module, char **features,
+	     int prefchar, int defflags)
 {
     int ret = 0, subret;
-    int defflags = opt_i ? AUTOFEAT_IGNORE : 0;
+    Module defm, m;
+    char **modfeatures = NULL;
+    if (module) {
+	defm = (Module)find_module(module,
+				   FINDMOD_ALIASP|FINDMOD_CREATE, NULL);
+	if ((defm->node.flags & MOD_LINKED) ? defm->u.linked :
+	    defm->u.handle)
+	    (void)features_module(defm, &modfeatures);
+    } else
+	defm = NULL;
 
-    while (*features) {
-	char *fnam, *typnam;
+    for (; *features; features++) {
+	char *fnam, *typnam, *feature;
 	int add, fchar, flags = defflags;
 	autofeaturefn_t fn;
 
 	if (prefchar) {
-	    if (prefchar < 0) {
-		add = 0;
-		fchar = - prefchar;
-	    } else {
-		add = 1;
-		fchar = prefchar;
-	    }
+	    /*
+	     * "features" is list of bare features with no
+	     * type prefix; prefchar gives type character.
+	     */
+	    add = 1; 		/* unless overridden by flag */
+	    fchar = prefchar;
 	    fnam = *features;
+	    feature = zhalloc(strlen(fnam) + 3);
+	    sprintf(feature, "%c:%s", fchar, fnam);
 	} else {
-	    char *feature = *features;
+	    feature = *features;
 	    if (*feature == '-') {
 		add = 0;
 		feature++;
@@ -3073,12 +3392,13 @@ autofeatures(char *cmdnam, char *module, char **features, int prefchar,
 		zwarnnam(cmdnam, "bad format for autoloadable feature: `%s'",
 			 feature);
 		ret = 1;
+		continue;
 	    }
 	    fnam = feature + 2;
 	    fchar = feature[0];
 	}
-
-	features++;
+	if (flags & FEAT_REMOVE)
+	    add = 0;
 
 	switch (fchar) {
 	case 'b':
@@ -3087,23 +3407,23 @@ autofeatures(char *cmdnam, char *module, char **features, int prefchar,
 	    break;
 
 	case 'C':
-	    flags |= AUTOFEAT_INFIX;
+	    flags |= FEAT_INFIX;
 	    /* FALLTHROUGH */
 	case 'c':
 	    fn = add ? add_autocond : del_autocond;
 	    typnam = "condition";
 	    break;
 
-	case 'p':
-	    fn = add ? add_autoparam : del_autoparam;
-	    typnam = "parameter";
-	    break;
-
 	case 'f':
 	    fn = add ? add_automathfunc : del_automathfunc;
 	    typnam = "math function";
 	    break;
 
+	case 'p':
+	    fn = add ? add_autoparam : del_autoparam;
+	    typnam = "parameter";
+	    break;
+
 	default:
 	    zwarnnam(cmdnam, "bad autoloadable feature type: `%c'",
 		     fchar);
@@ -3116,10 +3436,91 @@ autofeatures(char *cmdnam, char *module, char **features, int prefchar,
 	    ret = 1;
 	    continue;
 	} 
-	subret = fn(module, fnam, flags);
+
+	if (!module) {
+	    /*
+	     * Traditional un-autoload syntax doesn't tell us
+	     * which module this came from.
+	     */
+	    int i;
+	    for (i = 0, m = NULL; !m && i < modulestab->hsize; i++) {
+		for (m = (Module)modulestab->nodes[i]; m;
+		     m = (Module)m->node.next) {
+		    if (m->autoloads &&
+			linknodebystring(m->autoloads, feature))
+			break;
+		}
+	    }
+	    if (!m) {
+		if (!(flags & FEAT_IGNORE)) {
+		    ret = 1;
+		    zwarnnam(cmdnam, "%s: no such %s", fnam, typnam);
+		}
+		continue;
+	    }
+	} else
+	    m = defm;
+
+	subret = 0;
+	if (add) {
+	    char **ptr;
+	    if (modfeatures) {
+		/*
+		 * If the module is already available, check that
+		 * it does in fact provide the necessary feature.
+		 */
+		for (ptr = modfeatures; *ptr; ptr++)
+		    if (!strcmp(*ptr, feature))
+			break;
+		if (!*ptr) {
+		    zwarnnam(cmdnam, "module `%s' has no such feature: `%s'",
+			     m->node.nam, feature);
+		    ret = 1;
+		    continue;
+		}
+	    }
+	    if (!m->autoloads) {
+		m->autoloads = znewlinklist();
+		zaddlinknode(m->autoloads, ztrdup(feature));
+	    } else {
+		/* Insert in lexical order */
+		LinkNode ln, prev = (LinkNode)m->autoloads;
+		while ((ln = nextnode(prev))) {
+		    int cmp = strcmp(feature, (char *)getdata(ln));
+		    if (cmp == 0) {
+			/* Already there.  Never an error. */
+			break;
+		    }
+		    if (cmp < 0) {
+			zinsertlinknode(m->autoloads, prev,
+					ztrdup(feature));
+			break;
+		    }
+		    prev = ln;
+		}
+		if (!ln)
+		    zaddlinknode(m->autoloads, ztrdup(feature));
+	    }
+	} else if (m->autoloads) {
+	    LinkNode ln;
+	    if ((ln = linknodebystring(m->autoloads, feature)))
+		zsfree((char *)remnode(m->autoloads, ln));
+	    else {
+		/*
+		 * With -i (or zmodload -Fa), removing an autoload
+		 * that's not there is not an error.
+		 */
+		subret = (flags & FEAT_IGNORE) ? -2 : 2;
+	    }
+	}
+
+	if (subret == 0)
+	    subret = fn(module, fnam, flags);
 
 	if (subret != 0) {
-	    ret = 1;
+	    /* -2 indicates not an error, just skip running fn() */
+	    if (subret != -2)
+		ret = 1;
 	    switch (subret) {
 	    case 1:
 		zwarnnam(cmdnam, "failed to add %s `%s'", typnam, fnam);
diff --git a/Src/params.c b/Src/params.c
index 5609437a2..46da87580 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -411,7 +411,7 @@ newparamtable(int size, char const *name)
 
 /**/
 static HashNode
-getparamnode(HashTable ht, char *nam)
+getparamnode(HashTable ht, const char *nam)
 {
     HashNode hn = gethashnode2(ht, nam);
     Param pm = (Param) hn;
@@ -419,12 +419,16 @@ getparamnode(HashTable ht, char *nam)
     if (pm && pm->u.str && (pm->node.flags & PM_AUTOLOAD)) {
 	char *mn = dupstring(pm->u.str);
 
-	if (ensurefeature(mn, "p:", nam))
-	    return NULL;
+	(void)ensurefeature(mn, "p:", (pm->node.flags & PM_AUTOALL) ? NULL :
+			    nam);
 	hn = gethashnode2(ht, nam);
-	if (((Param) hn) == pm && (pm->node.flags & PM_AUTOLOAD)) {
-	    pm->node.flags &= ~PM_AUTOLOAD;
-	    zwarnnam(nam, "autoload failed");
+	if (!hn) {
+	    /*
+	     * This used to be a warning, but surely if we allow
+	     * stuff to go ahead with the autoload stub with
+	     * no error status we're in for all sorts of mayhem?
+	     */
+	    zerr("unknown parameter: %s", nam);
 	}
     }
     return hn;
diff --git a/Src/string.c b/Src/string.c
index 190ca2d57..2bd1baea3 100644
--- a/Src/string.c
+++ b/Src/string.c
@@ -109,7 +109,7 @@ zhtricat(char const *s1, char const *s2, char const *s3)
 
 /**/
 mod_export char *
-dyncat(char *s1, char *s2)
+dyncat(const char *s1, const char *s2)
 {
     /* This version always uses space from the current heap. */
     char *ptr;
diff --git a/Src/zsh.h b/Src/zsh.h
index 4f11b19ad..5354e9663 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -92,6 +92,8 @@ struct mathfunc {
 #define MFF_ADDED    2
 /* Math function is implemented by a shell function */
 #define MFF_USERFUNC 4
+/* When autoloading, enable all features in module */
+#define MFF_AUTOALL  8
 
 
 #define NUMMATHFUNC(name, func, min, max, id) \
@@ -538,8 +540,12 @@ struct conddef {
     char *module;		/* module to autoload                 */
 };
 
-#define CONDF_INFIX  1
-#define CONDF_ADDED  2
+/* Condition is an infix */
+#define CONDF_INFIX   1
+/* Condition has been loaded from library */
+#define CONDF_ADDED   2
+/* When autoloading, enable all features in library */
+#define CONDF_AUTOALL 4
 
 #define CONDDEF(name, flags, handler, min, max, condid) \
     { NULL, name, flags, handler, min, max, condid, NULL }
@@ -928,11 +934,16 @@ struct dirsav {
 typedef void *(*VFunc) _((void *));
 typedef void (*FreeFunc) _((void *));
 
-typedef unsigned (*HashFunc)       _((char *));
+typedef unsigned (*HashFunc)       _((const char *));
 typedef void     (*TableFunc)      _((HashTable));
+/*
+ * Note that this is deliberately "char *", not "const char *",
+ * since the AddNodeFunc is passed a pointer to a string that
+ * will be stored and later freed.
+ */
 typedef void     (*AddNodeFunc)    _((HashTable, char *, void *));
-typedef HashNode (*GetNodeFunc)    _((HashTable, char *));
-typedef HashNode (*RemoveNodeFunc) _((HashTable, char *));
+typedef HashNode (*GetNodeFunc)    _((HashTable, const char *));
+typedef HashNode (*RemoveNodeFunc) _((HashTable, const char *));
 typedef void     (*FreeNodeFunc)   _((HashNode));
 typedef int      (*CompareFunc)    _((const char *, const char *));
 
@@ -1152,25 +1163,37 @@ struct builtin {
 #define BINF_SKIPDASH		(1<<14) /* Treat `-' as argument (maybe `+') */
 #define BINF_DASHDASHVALID	(1<<15) /* Handle `--' even if SKIPINVALD */
 #define BINF_CLEARENV		(1<<16) /* new process started with cleared env */
+#define BINF_AUTOALL		(1<<17) /* autoload all features at once */
 
 struct module {
-    char *nam;
-    int flags;
+    struct hashnode node;
     union {
 	void *handle;
 	Linkedmod linked;
 	char *alias;
     } u;
+    LinkList autoloads;
     LinkList deps;
     int wrapper;
 };
 
+/* We are in the process of loading the module */
 #define MOD_BUSY    (1<<0)
+/*
+ * We are in the process of unloading the module.
+ * Note this is not needed to indicate a module is actually
+ * unloaded: for that, the handle (or linked pointer) is set to NULL.
+ */
 #define MOD_UNLOAD  (1<<1)
+/* We are in the process of setting up the module */
 #define MOD_SETUP   (1<<2)
+/* Module is statically linked into the main binary */
 #define MOD_LINKED  (1<<3)
+/* Module setup has been carried out (and module has not been finished) */
 #define MOD_INIT_S  (1<<4)
+/* Module boot has been carried out (and module has not been finished) */
 #define MOD_INIT_B  (1<<5)
+/* Module record is an alias */
 #define MOD_ALIAS   (1<<6)
 
 typedef int (*Module_generic_func) _((void));
@@ -1199,12 +1222,12 @@ struct features {
     /* List of conditions provided by the module and the size thereof */
     Conddef cd_list;
     int cd_size;
-    /* List of parameters provided by the module and the size thereof */
-    Paramdef pd_list;
-    int pd_size;
     /* List of math functions provided by the module and the size thereof */
     MathFunc mf_list;
     int mf_size;
+    /* List of parameters provided by the module and the size thereof */
+    Paramdef pd_list;
+    int pd_size;
     /* Number of abstract features */
     int n_abstract;
 };
@@ -1408,6 +1431,10 @@ struct tieddata {
 #define PM_REMOVABLE	(1<<26)	/* special can be removed from paramtab     */
 #define PM_AUTOLOAD	(1<<27) /* autoloaded from module                   */
 #define PM_NORESTORE	(1<<28)	/* do not restore value of local special    */
+#define PM_AUTOALL	(1<<28) /* autoload all features in module
+				 * when loading: valid only if PM_AUTOLOAD
+				 * is also present.
+				 */
 #define PM_HASHELEM     (1<<29) /* is a hash-element */
 #define PM_NAMEDDIR     (1<<30) /* has a corresponding nameddirtab entry    */
 
diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst
index 2308d3271..cbfde12d6 100644
--- a/Test/V01zmodload.ztst
+++ b/Test/V01zmodload.ztst
@@ -39,6 +39,9 @@
    fi
  }
 
+ mkdir zmodload.tmp
+ cd zmodload.tmp
+
 %test
 
 # This first test depends on knowing that zsh is run with +Z from the
@@ -118,10 +121,85 @@
    zmodload -ab zsh/example example
    builtin example
    zmodload -e zsh/example
- else print -u8 Warning: zsh/example not linked: not checking autoloading
+ else print -u$ZTST_fd Warning: zsh/example not linked: not checking autoloading
  fi
 0d:Autoload a module via a builtin
 
+  zmodload -u zsh/example
+  builtin example
+0d:Autoloads are persistent
+
+  (zmodload -u zsh/parameter
+  zmodload -aF zsh/parameter b:fail
+  fail
+  print "Shouldn't get here.")
+1:Failed builtin autoload
+?(eval):3: module `zsh/parameter' has no such feature: `b:fail': autoload cancelled
+?(eval):3: unknown builtin: fail
+
+  (zmodload -u zsh/parameter
+  zmodload -aF zsh/parameter p:fail
+  print $fail
+  print "Shouldn't get here.")
+1:Failed parameter autoload
+?(eval):3: module `zsh/parameter' has no such feature: `p:fail': autoload cancelled
+?(eval):3: unknown parameter: fail
+
+  (zmodload -u zsh/parameter
+  zmodload -aF zsh/parameter c:fail
+  [[ -fail foo ]]
+  print "Shouldn't get here.")
+2:Failed condition autoload
+?(eval):3: module `zsh/parameter' has no such feature: `c:fail': autoload cancelled
+?(eval):3: unknown condition: -foo
+
+  (zmodload -u zsh/parameter
+  zmodload -aF zsh/parameter f:fail
+  (( fail() )) )
+2:Failed math function autoload
+?(eval):3: module `zsh/parameter' has no such feature: `f:fail': autoload cancelled
+?(eval):3: unknown function: fail
+
+  zmodload -aF zsh/parameter f:fail2
+1:Immediate autoload failure on non-existent feature when module loaded
+?(eval):zmodload:1: module `zsh/parameter' has no such feature: `f:fail2'
+
+  (zmodload -u zsh/parameter
+  zmodload -aF zsh/parameter p:fail
+  print $(( ${#modules} > 1 )) )
+0:Autoloads checked on loading but don't necessarily effect current command
+>1
+?(eval):3: module `zsh/parameter' has no such feature: `p:fail': autoload cancelled
+
+  zmodload -laF zsh/parameter
+0:List default autoloads
+>p:aliases
+>p:builtins
+>p:commands
+>p:dirstack
+>p:dis_aliases
+>p:dis_builtins
+>p:dis_functions
+>p:dis_galiases
+>p:dis_reswords
+>p:dis_saliases
+>p:funcstack
+>p:functions
+>p:functrace
+>p:galiases
+>p:history
+>p:historywords
+>p:jobdirs
+>p:jobstates
+>p:jobtexts
+>p:modules
+>p:nameddirs
+>p:options
+>p:parameters
+>p:reswords
+>p:saliases
+>p:userdirs
+
  if [[ $mods[(r)zsh/example] == zsh/example ]]; then
    zmodload -u zsh/example
    zmodload -ac -I zsh/example ex
@@ -169,6 +247,11 @@
  zmodload -e example
 1:Delete the module alias again
 
+  zmodload >zmodload_list
+  print -l ${(o)mods} >mods_list
+  diff zmodload_list mods_list
+0:Listing with zmodload should give all our modules.
+
 # Don't unload the main module.
 # Do unload zsh/parameter, but reload it as it is needed.