about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-11-24 16:20:58 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-11-24 16:20:58 +0000
commitf8b0dee88051065d4667fe41dd1bc81905c2b07c (patch)
treed305a5589d775d1fa38f7486a2b58bfc567d9379
parentf853592fa0e6dc1246c8c23932bbd3265e537728 (diff)
downloadzsh-f8b0dee88051065d4667fe41dd1bc81905c2b07c.tar.gz
zsh-f8b0dee88051065d4667fe41dd1bc81905c2b07c.tar.xz
zsh-f8b0dee88051065d4667fe41dd1bc81905c2b07c.zip
zsh-workers/8770
-rw-r--r--Doc/Zsh/builtins.yo22
-rw-r--r--Etc/zsh-development-guide4
-rw-r--r--Src/Builtins/rlimits.c4
-rw-r--r--Src/Builtins/sched.c4
-rw-r--r--Src/Modules/cap.c4
-rw-r--r--Src/Modules/clone.c4
-rw-r--r--Src/Modules/example.c4
-rw-r--r--Src/Modules/files.c4
-rw-r--r--Src/Modules/mapfile.c4
-rw-r--r--Src/Modules/mathfunc.c4
-rw-r--r--Src/Modules/parameter.c22
-rw-r--r--Src/Modules/stat.c4
-rw-r--r--Src/Modules/zftp.c4
-rw-r--r--Src/Zle/compctl.c4
-rw-r--r--Src/Zle/complete.c7
-rw-r--r--Src/Zle/complist.c4
-rw-r--r--Src/Zle/computil.c4
-rw-r--r--Src/Zle/deltochar.c4
-rw-r--r--Src/Zle/zle_hist.c6
-rw-r--r--Src/Zle/zle_keymap.c4
-rw-r--r--Src/Zle/zle_main.c4
-rw-r--r--Src/Zle/zle_thingy.c12
-rw-r--r--Src/Zle/zleparameter.c4
-rw-r--r--Src/builtin.c10
-rw-r--r--Src/exec.c12
-rw-r--r--Src/init.c27
-rw-r--r--Src/mkbltnmlst.sh68
-rw-r--r--Src/module.c385
-rw-r--r--Src/params.c12
-rw-r--r--Src/zsh.h19
30 files changed, 338 insertions, 336 deletions
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 9bc5b0a81..072316256 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1390,20 +1390,20 @@ item(tt(zmodload) tt(-ua) [ tt(-i) ] var(builtin) ...)(
 Equivalent to tt(-ab) and tt(-ub).
 )
 item(tt(zmodload -e) [ var(string) ... ])(
-The tt(-e) option without arguments lists all modules loaded or linked 
-into the shell. With arguments only the return status is set to zero
-if all var(string)s given as arguments are names of modules loaded or
-linked in and to one if at least on var(string) is not the name of a
-module loaded or linked. This can be used to test for the availability 
+The tt(-e) option without arguments lists all loaded modules loaded.
+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.
 )
 enditem()
 
-In a shell without dynamic loading only the tt(-e) option is
-supported and the tt(-i) option is ignored. In such a shell the return
-status of tt(zmodload) without arguments or options is one whereas in
-a shell with dynamic loading the return status without arguments or
-options is always zero. This can be used to test if the shell supports
-dynamic loading of modules or not.
+Note that tt(zsh) makes no difference between modules that were linked 
+into the shell and modules that are loaded dynamically. In both cases
+this builtin command has to be used to make available the builtins and
+other things defined by modules (unless the module is autoloaded on
+these definitions). This is even true for systems that don't support
+dynamic loading of modules.
 )
 enditem()
diff --git a/Etc/zsh-development-guide b/Etc/zsh-development-guide
index 7223af07b..fa0ad8e76 100644
--- a/Etc/zsh-development-guide
+++ b/Etc/zsh-development-guide
@@ -151,9 +151,7 @@ The third one, named `cleanup_foo' for module `foo' is called when the
 user tries to unload a module and should de-register the builtins
 etc. The last function, `finish_foo' is called when the module is
 actually unloaded and should finalize all the data initialized in the 
-`setup'-function. Since the last two functions are only executed when
-the module is used as an dynamically loaded module you can surround
-it with `#ifdef MODULE' and `#endif'.
+`setup'-function.
 In short, the `cleanup'-function should undo what the `boot'-function
 did, and the `finish'-function should undo what the `setup'-function
 did.
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 115f7d5b5..8a13fefdf 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -637,8 +637,6 @@ boot_rlimits(Module m)
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_rlimits(Module m)
@@ -653,5 +651,3 @@ finish_rlimits(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c
index 94661ccef..77cc27261 100644
--- a/Src/Builtins/sched.c
+++ b/Src/Builtins/sched.c
@@ -200,8 +200,6 @@ boot_sched(Module m)
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_sched(Module m)
@@ -224,5 +222,3 @@ finish_sched(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/cap.c b/Src/Modules/cap.c
index b43ed5c4d..e2f01ddee 100644
--- a/Src/Modules/cap.c
+++ b/Src/Modules/cap.c
@@ -136,8 +136,6 @@ boot_cap(Module m)
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_cap(Module m)
@@ -152,5 +150,3 @@ finish_cap(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index d9dd6c316..59f66e1b5 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -110,8 +110,6 @@ boot_clone(Module m)
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_clone(Module m)
@@ -126,5 +124,3 @@ finish_clone(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
index fbe392e94..43199e350 100644
--- a/Src/Modules/example.c
+++ b/Src/Modules/example.c
@@ -212,8 +212,6 @@ boot_example(Module m)
 	     !addwrapper(m, wrapper));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_example(Module m)
@@ -234,5 +232,3 @@ finish_example(Module m)
     fflush(stdout);
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index c1948e1fd..dc91227f8 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -523,8 +523,6 @@ boot_files(Module m)
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_files(Module m)
@@ -539,5 +537,3 @@ finish_files(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/mapfile.c b/Src/Modules/mapfile.c
index 431c488e6..11553609c 100644
--- a/Src/Modules/mapfile.c
+++ b/Src/Modules/mapfile.c
@@ -346,8 +346,6 @@ boot_mapfile(Module m)
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_mapfile(Module m)
@@ -370,5 +368,3 @@ finish_mapfile(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c
index 67d5fd7d1..06184fd96 100644
--- a/Src/Modules/mathfunc.c
+++ b/Src/Modules/mathfunc.c
@@ -462,8 +462,6 @@ boot_mathfunc(Module m)
     return !addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_mathfunc(Module m)
@@ -478,5 +476,3 @@ finish_mathfunc(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 1482bedf2..ab8276979 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -901,18 +901,12 @@ getpmmodule(HashTable ht, char *name)
 	pm->old = NULL;
 	pm->level = 0;
 
-	for (node = firstnode(bltinmodules); node; incnode(node))
-	    if (!strcmp(name, (char *) getdata(node))) {
-		type = "builtin";
-		break;
-	    }
-#ifdef DYNAMIC
 	if (!type) {
 	    Module m;
 
 	    for (node = firstnode(modules); node; incnode(node)) {
 		m = (Module) getdata(node);
-		if (m->handle && !(m->flags & MOD_UNLOAD) &&
+		if (m->u.handle && !(m->flags & MOD_UNLOAD) &&
 		    !strcmp(name, m->nam)) {
 		    type = "loaded";
 		    break;
@@ -937,7 +931,6 @@ getpmmodule(HashTable ht, char *name)
 	    if (modpmfound)
 		type = "autoloaded";
 	}
-#endif
 	if (type)
 	    pm->u.str = dupstring(type);
 	else {
@@ -972,16 +965,10 @@ scanpmmodules(HashTable ht, ScanFunc func, int flags)
     pm.level = 0;
 
     pm.u.str = dupstring("builtin");
-    for (node = firstnode(bltinmodules); node; incnode(node)) {
-	pm.nam = (char *) getdata(node);
-	addlinknode(done, pm.nam);
-	func((HashNode) &pm, flags);
-    }
-#ifdef DYNAMIC
     pm.u.str = dupstring("loaded");
     for (node = firstnode(modules); node; incnode(node)) {
 	m = (Module) getdata(node);
-	if (m->handle && !(m->flags & MOD_UNLOAD)) {
+	if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
 	    pm.nam = m->nam;
 	    addlinknode(done, pm.nam);
 	    func((HashNode) &pm, flags);
@@ -1012,7 +999,6 @@ scanpmmodules(HashTable ht, ScanFunc func, int flags)
 		func((HashNode) &pm, flags);
 	    }
 	}
-#endif
 }
 
 /* Functions for the dirstack special parameter. */
@@ -1919,8 +1905,6 @@ boot_parameter(Module m)
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_parameter(Module m)
@@ -1949,5 +1933,3 @@ finish_parameter(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 5b482cf6c..3a98db0e3 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -602,8 +602,6 @@ boot_stat(Module m)
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_stat(Module m)
@@ -618,5 +616,3 @@ finish_stat(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 0cc3d2b45..b334c878a 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -3213,8 +3213,6 @@ boot_zftp(Module m)
     return !ret;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_zftp(Module m)
@@ -3249,5 +3247,3 @@ finish_zftp(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index cab0f55a4..cb8f32a3a 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -3764,8 +3764,6 @@ boot_compctl(Module m)
     return (addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) != 1);
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_compctl(Module m)
@@ -3789,5 +3787,3 @@ finish_compctl(Module m)
     compctlreadptr = fallback_compctlread;
     return 0;
 }
-
-#endif
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index bf558f352..f52ac98ef 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -1389,8 +1389,6 @@ boot_complete(Module m)
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_complete(Module m)
@@ -1414,7 +1412,8 @@ cleanup_complete(Module m)
 int
 finish_complete(Module m)
 {
-    freearray(compwords);
+    if (compwords)
+	freearray(compwords);
     zsfree(compprefix);
     zsfree(compsuffix);
     zsfree(compiprefix);
@@ -1446,5 +1445,3 @@ finish_complete(Module m)
 
     return 0;
 }
-
-#endif
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 5f40ffb9a..612191913 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -935,8 +935,6 @@ boot_complist(Module m)
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_complist(Module m)
@@ -957,5 +955,3 @@ finish_complist(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index fd39e255b..f39a65b48 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -2837,8 +2837,6 @@ boot_computil(Module m)
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_computil(Module m)
@@ -2865,5 +2863,3 @@ finish_computil(Module m)
 
     return 0;
 }
-
-#endif
diff --git a/Src/Zle/deltochar.c b/Src/Zle/deltochar.c
index 566a578f1..e3f9def0c 100644
--- a/Src/Zle/deltochar.c
+++ b/Src/Zle/deltochar.c
@@ -98,8 +98,6 @@ boot_deltochar(Module m)
     return -1;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_deltochar(Module m)
@@ -115,5 +113,3 @@ finish_deltochar(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index f85fa00a6..d6dc2a794 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -612,9 +612,6 @@ static struct isrch_spot {
 static int max_spot = 0;
 
 /**/
-#ifdef MODULE
-
-/**/
 void
 free_isrch_spots(void)
 {
@@ -622,9 +619,6 @@ free_isrch_spots(void)
 }
 
 /**/
-#endif /* MODULE */
-
-/**/
 static void
 set_isrch_spot(int num, int hl, int pos, int cs, int len, int dir, int nomatch)
 {
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 37c32d581..ccfbd4043 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -1000,8 +1000,6 @@ init_keymaps(void)
     lastnamed = refthingy(t_undefinedkey);
 }
 
-#ifdef MODULE
-
 /* cleanup entry point (for unloading the zle module) */
 
 /**/
@@ -1013,8 +1011,6 @@ cleanup_keymaps(void)
     zfree(keybuf, keybufsz);
 }
 
-#endif /* MODULE */
-
 /* Create the default keymaps.  For efficiency reasons, this function   *
  * assigns directly to the km->first array.  It knows that there are no *
  * prefix bindings in the way, and that it is using a simple keymap.    */
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 42b4e21e4..4f5729818 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1043,8 +1043,6 @@ boot_zle(Module m)
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_zle(Module m)
@@ -1093,5 +1091,3 @@ finish_zle(Module m)
 
     return 0;
 }
-
-#endif /* MODULE */
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index a4191a9a4..1e0d483e2 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -286,8 +286,6 @@ addzlefunction(char *name, ZleIntFunc ifunc, int flags)
     return w;
 }
 
-#ifdef DYNAMIC
-
 /* Delete an internal widget provided by a module.  Don't try to delete *
  * a widget from the fixed table -- it would be bad.  (Thanks, Egon.)   */
 
@@ -309,8 +307,6 @@ deletezlefunction(Widget w)
     }
 }
 
-#endif /* DYNAMIC */
-
 /***************/
 /* zle builtin */
 /***************/
@@ -550,18 +546,10 @@ bin_zle_complete(char *name, char **args, char *ops, char func)
     Thingy t;
     Widget w, cw;
 
-#ifdef DYNAMIC
     if (!require_module(name, "complete", 0, 0)) {
 	zerrnam(name, "can't load complete module", NULL, 0);
 	return 1;
     }
-#else
-    if (!module_linked("complete")) {
-	zerrnam(name, "complete module not available", NULL, 0);
-	return 1;
-    }
-#endif
-    
     t = rthingy((args[1][0] == '.') ? args[1] : dyncat(".", args[1]));
     cw = t->widget;
     unrefthingy(t);
diff --git a/Src/Zle/zleparameter.c b/Src/Zle/zleparameter.c
index 9103916bb..c4347de6b 100644
--- a/Src/Zle/zleparameter.c
+++ b/Src/Zle/zleparameter.c
@@ -230,8 +230,6 @@ boot_zleparameter(Module m)
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
 cleanup_zleparameter(Module m)
@@ -255,5 +253,3 @@ finish_zleparameter(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/builtin.c b/Src/builtin.c
index 075a03b17..5d4b2be2c 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -123,12 +123,7 @@ static struct builtin builtins[] =
     BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL),
     BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"),
     BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
-
-#ifdef DYNAMIC
     BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ILabcfdipue", NULL),
-#else
-    BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ei", NULL),
-#endif
 };
 
 /****************************************/
@@ -229,14 +224,11 @@ execbuiltin(LinkList args, Builtin bn)
 
     arg = (char *) ugetnode(args);
 
-#ifdef DYNAMIC
     if (!bn->handlerfunc) {
 	zwarnnam(name, "autoload failed", NULL, 0);
 	deletebuiltin(bn->nam);
 	return 1;
     }
-#endif
-
     /* get some information about the command */
     flags = bn->flags;
     optstr = bn->optstr;
@@ -3209,6 +3201,8 @@ zexit(int val, int from_signal)
 	if (in_exit++ && from_signal) {
 	    LASTALLOC_RETURN;
 	}
+	exit_modules();
+
 	if (isset(MONITOR)) {
 	    /* send SIGHUP to any jobs left running  */
 	    killrunjobs(from_signal);
diff --git a/Src/exec.c b/Src/exec.c
index 9ee1c313f..0bc8ff923 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1504,13 +1504,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    }
 	    if (!(hn->flags & BINF_PREFIX)) {
 		is_builtin = 1;
-#ifdef DYNAMIC
+
 		/* autoload the builtin if necessary */
 		if (!((Builtin) hn)->handlerfunc) {
 		    load_module(((Builtin) hn)->optstr);
 		    hn = builtintab->getnode(builtintab, cmdarg);
 		}
-#endif
 		assign = (hn->flags & BINF_MAGICEQUALS);
 		break;
 	    }
@@ -1619,13 +1618,12 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    }
 	    if (!(hn->flags & BINF_PREFIX)) {
 		is_builtin = 1;
-#ifdef DYNAMIC
+
 		/* autoload the builtin if necessary */
 		if (!((Builtin) hn)->handlerfunc) {
 		    load_module(((Builtin) hn)->optstr);
 		    hn = builtintab->getnode(builtintab, cmdarg);
 		}
-#endif
 		break;
 	    }
 	    cflags &= ~BINF_BUILTIN & ~BINF_COMMAND;
@@ -3072,11 +3070,11 @@ runshfunc(List list, FuncWrap wrap, char *name)
 	wrap->module->wrapper++;
 	cont = wrap->handler(list, wrap->next, name);
 	wrap->module->wrapper--;
-#ifdef DYNAMIC
+
 	if (!wrap->module->wrapper &&
 	    (wrap->module->flags & MOD_UNLOAD))
-	    unload_module(wrap->module, NULL);
-#endif
+	    unload_module(wrap->module, NULL, 0);
+
 	if (!cont)
 	    return;
 	wrap = wrap->next;
diff --git a/Src/init.c b/Src/init.c
index 1860fdd8d..97627c4d6 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -599,11 +599,9 @@ setupvals(void)
     mailpath = mkarray(NULL);
     watch    = mkarray(NULL);
     psvar    = mkarray(NULL);
-#ifdef DYNAMIC
     module_path = mkarray(ztrdup(MODULE_DIR));
     modules = newlinklist();
-#endif
-    bltinmodules = newlinklist();
+    linkedmodules = newlinklist();
 
     /* Set default prompts */
     if(unset(INTERACTIVE)) {
@@ -940,9 +938,10 @@ sourcehome(char *s)
 void
 init_bltinmods(void)
 {
-    static struct module mod = { NULL, 0, NULL, NULL };
+
 #include "bltinmods.list"
-    mod.nam = NULL;
+
+    load_module("zsh");
 }
 
 /**/
@@ -969,13 +968,13 @@ noop_function_int(int nothing)
 /**/
 ZleVoidFn trashzleptr = noop_function;
 /**/
-ZleVoidFn gotwordptr;
+ZleVoidFn gotwordptr = noop_function;
 /**/
-ZleVoidFn refreshptr;
+ZleVoidFn refreshptr = noop_function;
 /**/
-ZleVoidIntFn spaceinlineptr;
+ZleVoidIntFn spaceinlineptr = noop_function_int;
 /**/
-ZleReadFn zlereadptr;
+ZleReadFn zlereadptr = autoload_zleread;
 
 #else /* !LINKED_XMOD_zle */
 
@@ -989,11 +988,10 @@ ZleReadFn zlereadptr = autoload_zleread;
 ZleReadFn zlereadptr = fallback_zleread;
 # endif /* !UNLINKED_XMOD_zle */
 
-/**/
-# ifdef UNLINKED_XMOD_zle
+#endif /* !LINKED_XMOD_zle */
 
 /**/
-static unsigned char *
+unsigned char *
 autoload_zleread(char *lp, char *rp, int ha)
 {
     zlereadptr = fallback_zleread;
@@ -1002,9 +1000,6 @@ autoload_zleread(char *lp, char *rp, int ha)
 }
 
 /**/
-# endif /* UNLINKED_XMOD_zle */
-
-/**/
 unsigned char *
 fallback_zleread(char *lp, char *rp, int ha)
 {
@@ -1017,8 +1012,6 @@ fallback_zleread(char *lp, char *rp, int ha)
     return (unsigned char *)shingetline();
 }
 
-#endif /* !LINKED_XMOD_zle */
-
 /* compctl entry point pointers.  Similar to the ZLE ones. */
 
 /**/
diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh
index e11972794..be78f1720 100644
--- a/Src/mkbltnmlst.sh
+++ b/Src/mkbltnmlst.sh
@@ -4,6 +4,7 @@
 #
 # Written by Andrew Main
 #
+
 srcdir=${srcdir-`echo $0|sed 's%/[^/][^/]*$%%'`}
 test "x$srcdir" = "x$0" && srcdir=.
 test "x$srcdir" = "x"   && srcdir=.
@@ -18,40 +19,32 @@ trap "rm -f $1; exit 1" 1 2 15
 
 exec > $1
 
-echo "#ifdef DYNAMIC"
 for x_mod in $x_mods; do
-    case $bin_mods in
-	*" $x_mod "*) ;;
-	*)  echo "/* non-linked-in known module \`$x_mod' */"
-	    eval "loc=\$loc_$x_mod"
-	    unset moddeps autobins autoinfixconds autoprefixconds autoparams
-	    unset automathfuncs
-	    . $srcdir/../$loc/${x_mod}.mdd
-	    for bin in $autobins; do
-		echo "    add_autobin(\"$bin\", \"$x_mod\");"
-	    done
-	    for cond in $autoinfixconds; do
-		echo "    add_autocond(\"$cond\", 1, \"$x_mod\");"
-	    done
-	    for cond in $autoprefixconds; do
-		echo "    add_autocond(\"$cond\", 0, \"$x_mod\");"
-	    done
-	    for param in $autoparams; do
-		echo "    add_autoparam(\"$param\", \"$x_mod\");"
-	    done
-	    for mfunc in $automathfuncs; do
-		echo "    add_automath(\"$mfunc\", \"$x_mod\");"
-	    done
-	    for dep in $moddeps; do
-		case $bin_mods in
-		    *" $dep "*)
-			echo "    /* depends on \`$dep' */" ;;
-		    *)	echo "    add_dep(\"$x_mod\", \"$dep\");" ;;
-		esac
-	    done ;;
-    esac
+    echo "/* non-linked-in known module \`$x_mod' */"
+    eval "loc=\$loc_$x_mod"
+    unset moddeps autobins autoinfixconds autoprefixconds autoparams
+    unset automathfuncs
+    . $srcdir/../$loc/${x_mod}.mdd
+    for bin in $autobins; do
+	echo "    add_autobin(\"$bin\", \"$x_mod\");"
+    done
+    for cond in $autoinfixconds; do
+	echo "    add_autocond(\"$cond\", 1, \"$x_mod\");"
+    done
+    for cond in $autoprefixconds; do
+	echo "    add_autocond(\"$cond\", 0, \"$x_mod\");"
+    done
+    for param in $autoparams; do
+	echo "    add_autoparam(\"$param\", \"$x_mod\");"
+    done
+    for mfunc in $automathfuncs; do
+	echo "    add_automath(\"$mfunc\", \"$x_mod\");"
+    done
+    for dep in $moddeps; do
+	echo "    add_dep(\"$x_mod\", \"$dep\");"
+    done
 done
-echo "#endif /* DYNAMIC */"
+
 echo
 done_mods=" "
 for bin_mod in $bin_mods; do
@@ -68,6 +61,15 @@ for bin_mod in $bin_mods; do
 		exit 1 ;;
 	esac
     done
-    echo "    register_module(mod.nam = \"$bin_mod\"); setup_$bin_mod(&mod); boot_$bin_mod(&mod);"
+    echo "    {"
+    echo "        extern int setup_${bin_mod} _((Module));"
+    echo "        extern int boot_${bin_mod} _((Module));"
+    echo "        extern int cleanup_${bin_mod} _((Module));"
+    echo "        extern int finish_${bin_mod} _((Module));"
+    echo
+    echo "        register_module(\"$bin_mod\","
+    echo "                        setup_${bin_mod}, boot_${bin_mod},"
+    echo "                        cleanup_${bin_mod}, finish_${bin_mod});"
+    echo "    }"
     done_mods="$done_mods$bin_mod "
 done
diff --git a/Src/module.c b/Src/module.c
index f5beffbc5..3b21bdbc9 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -30,10 +30,10 @@
 #include "zsh.mdh"
 #include "module.pro"
 
-/* List of builtin modules. */
+/* List of linked-in modules. */
 
 /**/
-LinkList bltinmodules;
+LinkList linkedmodules;
 
 
 /* The `zsh' module contains all the base code that can't actually be built *
@@ -54,30 +54,55 @@ boot_zsh(Module m)
     return 0;
 }
 
+/**/
+int
+cleanup_zsh(Module m)
+{
+    return 0;
+}
+
+/**/
+int
+finish_zsh(Module m)
+{
+    return 0;
+}
+
 /* This registers a builtin module.                                   */
 
 /**/
 void
-register_module(char *n)
+register_module(char *n, Module_func setup, Module_func boot,
+		Module_func cleanup, Module_func finish)
 {
+    Linkedmod m;
+
     PERMALLOC {
-	addlinknode(bltinmodules, n);
+	m = (Linkedmod) zalloc(sizeof(*m));
+
+	m->name = ztrdup(n);
+	m->setup = setup;
+	m->boot = boot;
+	m->cleanup = cleanup;
+	m->finish = finish;
+
+	addlinknode(linkedmodules, m);
     } LASTALLOC;
 }
 
 /* Check if a module is linked in. */
 
 /**/
-int
-module_linked(char *name)
+Linkedmod
+module_linked(char const *name)
 {
     LinkNode node;
 
-    for (node = firstnode(bltinmodules); node; incnode(node))
-	if (!strcmp((char *) getdata(node), name))
-	    return 1;
+    for (node = firstnode(linkedmodules); node; incnode(node))
+	if (!strcmp(((Linkedmod) getdata(node))->name, name))
+	    return (Linkedmod) getdata(node);
 
-    return 0;
+    return NULL;
 }
 
 /* addbuiltin() can be used to add a new builtin.  It returns zero on *
@@ -157,9 +182,6 @@ addwrapper(Module m, FuncWrap w)
     return 0;
 }
 
-/**/
-#ifdef DYNAMIC
-
 /* $module_path ($MODULE_PATH) */
 
 /**/
@@ -255,6 +277,9 @@ deletewrapper(Module m, FuncWrap w)
 }
 
 /**/
+#ifdef DYNAMIC
+
+/**/
 #ifdef AIXDYNAMIC
 
 #include <sys/ldr.h>
@@ -271,8 +296,8 @@ load_and_bind(const char *fn)
 	int err = loadbind(0, (void *) addbuiltin, ret);
 	for (node = firstnode(modules); !err && node; incnode(node)) {
 	    Module m = (Module) getdata(node);
-	    if (m->handle)
-		err |= loadbind(0, m->handle, ret);
+	    if (m->u.handle)
+		err |= loadbind(0, m->u.handle, ret);
 	}
 
 	if (err) {
@@ -361,8 +386,6 @@ hpux_dlsym(void *handle, char *name)
 # define RTLD_GLOBAL 0
 #endif
 
-typedef int (*Module_func) _((Module));
-
 /**/
 static void *
 try_load_module(char const *name)
@@ -415,6 +438,19 @@ do_load_module(char const *name)
 }
 
 /**/
+#else /* !DYNAMIC */
+
+/**/
+static void *
+do_load_module(char const *name)
+{
+    return NULL;
+}
+
+/**/
+#endif /* !DYNAMIC */
+
+/**/
 static LinkNode
 find_module(const char *name)
 {
@@ -430,34 +466,37 @@ find_module(const char *name)
 }
 
 /**/
+#ifdef DYNAMIC
+
+/**/
 #ifdef AIXDYNAMIC
 
 /**/
 static int
-setup_module(Module m)
+dyn_setup_module(Module m)
 {
-    return ((int (*)_((int,Module))) m->handle)(0, m);
+    return ((int (*)_((int,Module))) m->u.handle)(0, m);
 }
 
 /**/
 static int
-init_module(Module m)
+dyn_boot_module(Module m)
 {
-    return ((int (*)_((int,Module))) m->handle)(1, m);
+    return ((int (*)_((int,Module))) m->u.handle)(1, m);
 }
 
 /**/
 static int
-cleanup_module(Module m)
+dyn_cleanup_module(Module m)
 {
-    return ((int (*)_((int,Module))) m->handle)(2, m);
+    return ((int (*)_((int,Module))) m->u.handle)(2, m);
 }
 
 /**/
 static int
-finish_module(Module m)
+dyn_finish_module(Module m)
 {
-    return ((int (*)_((int,Module))) m->handle)(3, m);
+    return ((int (*)_((int,Module))) m->u.handle)(3, m);
 }
 
 /**/
@@ -480,19 +519,19 @@ module_func(Module m, char *name, char *name_s)
     if ((t = strrchr(s, '.')))
 	*t = '\0';
 #ifdef DYNAMIC_NAME_CLASH_OK
-    fn = (Module_func) dlsym(m->handle, name);
+    fn = (Module_func) dlsym(m->u.handle, name);
 #else /* !DYNAMIC_NAME_CLASH_OK */
     if (strlen(s) + 6 > PATH_MAX)
 	return NULL;
     sprintf(buf, name_s, s);
-    fn = (Module_func) dlsym(m->handle, buf);
+    fn = (Module_func) dlsym(m->u.handle, buf);
 #endif /* !DYNAMIC_NAME_CLASH_OK */
     return fn;
 }
 
 /**/
 static int
-setup_module(Module m)
+dyn_setup_module(Module m)
 {
     Module_func fn = module_func(m, STR_SETUP, STR_SETUP_S);
 
@@ -504,7 +543,7 @@ setup_module(Module m)
 
 /**/
 static int
-init_module(Module m)
+dyn_boot_module(Module m)
 {
     Module_func fn = module_func(m, STR_BOOT, STR_BOOT_S);
 
@@ -516,7 +555,7 @@ init_module(Module m)
 
 /**/
 static int
-cleanup_module(Module m)
+dyn_cleanup_module(Module m)
 {
     Module_func fn = module_func(m, STR_CLEANUP, STR_CLEANUP_S);
 
@@ -531,7 +570,7 @@ cleanup_module(Module m)
 
 /**/
 static int
-finish_module(Module m)
+dyn_finish_module(Module m)
 {
     Module_func fn = module_func(m, STR_FINISH, STR_FINISH_S);
     int r;
@@ -542,7 +581,7 @@ finish_module(Module m)
 	zwarnnam(m->nam, "no finish function", NULL, 0);
 	r = 1;
     }
-    dlclose(m->handle);
+    dlclose(m->u.handle);
     return r;
 }
 
@@ -550,34 +589,107 @@ finish_module(Module m)
 #endif /* !AIXDYNAMIC */
 
 /**/
+static int
+setup_module(Module m)
+{
+    return ((m->flags & MOD_LINKED) ?
+	    (m->u.linked->setup)(m) : dyn_setup_module(m));
+}
+
+/**/
+static int
+boot_module(Module m)
+{
+    return ((m->flags & MOD_LINKED) ?
+	    (m->u.linked->boot)(m) : dyn_boot_module(m));
+}
+
+/**/
+static int
+cleanup_module(Module m)
+{
+    return ((m->flags & MOD_LINKED) ?
+	    (m->u.linked->cleanup)(m) : dyn_cleanup_module(m));
+}
+
+/**/
+static int
+finish_module(Module m)
+{
+    return ((m->flags & MOD_LINKED) ?
+	    (m->u.linked->finish)(m) : dyn_finish_module(m));
+}
+
+/**/
+#else /* !DYNAMIC */
+
+/**/
+static int
+setup_module(Module m)
+{
+    return ((m->flags & MOD_LINKED) ? (m->u.linked->setup)(m) : 1);
+}
+
+/**/
+static int
+boot_module(Module m)
+{
+    return ((m->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);
+}
+
+/**/
+static int
+finish_module(Module m)
+{
+    return ((m->flags & MOD_LINKED) ? (m->u.linked->finish)(m) : 1);
+}
+
+/**/
+#endif /* !DYNAMIC */
+
+/**/
 int
 load_module(char const *name)
 {
     Module m;
-    void *handle;
+    void *handle = NULL;
+    Linkedmod linked;
     LinkNode node, n;
-
-    if (module_linked(name))
-	return 1;
+    int set;
 
     if (!(node = find_module(name))) {
-	if (!(handle = do_load_module(name)))
-	    return NULL;
+	if (!(linked = module_linked(name)) &&
+	    !(handle = do_load_module(name)))
+	    return 0;
 	m = zcalloc(sizeof(*m));
 	m->nam = ztrdup(name);
-	m->handle = handle;
-	m->flags |= MOD_SETUP;
+	if (handle) {
+	    m->u.handle = handle;
+	    m->flags |= MOD_SETUP;
+	} else {
+	    m->u.linked = linked;
+	    m->flags |= MOD_SETUP | MOD_LINKED;
+	}
 	PERMALLOC {
 	    node = addlinknode(modules, m);
 	} LASTALLOC;
-	if (setup_module(m) || init_module(m)) {
-	    finish_module(m);
+	if ((set = setup_module(m)) || boot_module(m)) {
+	    if (!set)
+		finish_module(m);
 	    remnode(modules, node);
 	    zsfree(m->nam);
 	    zfree(m, sizeof(*m));
 	    m->flags &= ~MOD_SETUP;
-	    return NULL;
+	    return 0;
 	}
+	m->flags |= MOD_INIT_S | MOD_INIT_B;
 	m->flags &= ~MOD_SETUP;
 	return 1;
     } 
@@ -586,7 +698,7 @@ load_module(char const *name)
 	return 1;
     if (m->flags & MOD_UNLOAD)
 	m->flags &= ~MOD_UNLOAD;
-    else if (m->handle)
+    else if ((m->flags & MOD_LINKED) ? m->u.linked : m->u.handle)
 	return 1;
     if (m->flags & MOD_BUSY) {
 	zerr("circular dependencies for module %s", name, 0);
@@ -600,24 +712,39 @@ load_module(char const *name)
 		return 0;
 	    }
     m->flags &= ~MOD_BUSY;
-    if (!m->handle) {
-	if (!(m->handle = do_load_module(name)))
+    if (!m->u.handle) {
+	handle = NULL;
+	if (!(linked = module_linked(name)) &&
+	    !(handle = do_load_module(name)))
 	    return 0;
-	m->flags |= MOD_SETUP;
+	if (handle) {
+	    m->u.handle = handle;
+	    m->flags |= MOD_SETUP;
+	} else {
+	    m->u.linked = linked;
+	    m->flags |= MOD_SETUP | MOD_LINKED;
+	}
 	if (setup_module(m)) {
-	    finish_module(m->handle);
-	    m->handle = NULL;
+	    if (handle)
+		m->u.handle = NULL;
+	    else
+		m->u.linked = NULL;
 	    m->flags &= ~MOD_SETUP;
 	    return 0;
 	}
+	m->flags |= MOD_INIT_S;
     }
     m->flags |= MOD_SETUP;
-    if (init_module(m)) {
-	finish_module(m->handle);
-	m->handle = NULL;
+    if (boot_module(m)) {
+	finish_module(m);
+	if (m->flags & MOD_LINKED)
+	    m->u.linked = NULL;
+	else
+	    m->u.handle = NULL;
 	m->flags &= ~MOD_SETUP;
 	return 0;
     }
+    m->flags |= MOD_INIT_B;
     m->flags &= ~MOD_SETUP;
     return 1;
 }
@@ -638,12 +765,12 @@ require_module(char *nam, char *module, int res, int test)
     LinkNode node;
 
     /* First see if the module is linked in. */
-    for (node = firstnode(bltinmodules); node; incnode(node)) {
+    for (node = firstnode(linkedmodules); node; incnode(node)) {
 	if (!strcmp((char *) getdata(node), nam))
 	    return 1;
     }
     node = find_module(module);
-    if (node && (m = ((Module) getdata(node)))->handle &&
+    if (node && (m = ((Module) getdata(node)))->u.handle &&
 	!(m->flags & MOD_UNLOAD)) {
 	if (test) {
 	    zwarnnam(nam, "module %s already loaded.", module, 0);
@@ -710,6 +837,47 @@ autoloadscan(HashNode hn, int printflags)
     putchar('\n');
 }
 
+/* Cleanup and finish all modules. */
+
+/**/
+void
+exit_modules(void)
+{
+    Module m;
+    char *name;
+    LinkNode node, next, mn, dn;
+    int del, used;
+
+    while (nonempty(modules)) {
+	for (node = firstnode(modules); (next = node); node = next) {
+	    incnode(next);
+	    del = used = 0;
+	    name = ((Module) getdata(node))->nam;
+	    for (mn = firstnode(modules); !used && mn; incnode(mn)) {
+		m = (Module) getdata(mn);
+		if (m->deps && m->u.handle)
+		    for (dn = firstnode(m->deps); dn; incnode(dn))
+			if (!strcmp((char *) getdata(dn), name)) {
+			    if (m->flags & MOD_UNLOAD)
+				del = 1;
+			    else {
+				used = 1;
+				break;
+			    }
+			}
+	    }
+	    if (!used) {
+		m = (Module) getdata(node);
+		if (del)
+		    m->wrapper++;
+		unload_module(m, NULL, 1);
+		if (del)
+		    m->wrapper--;
+	    }
+	}
+    }
+}
+
 /**/
 int
 bin_zmodload(char *nam, char **args, char *ops, int func)
@@ -761,13 +929,9 @@ bin_zmodload_exist(char *nam, char **args, char *ops)
     Module m;
 
     if (!*args) {
-	for (node = firstnode(bltinmodules); node; incnode(node)) {
-	    nicezputs((char *) getdata(node), stdout);
-	    putchar('\n');
-	}
 	for (node = firstnode(modules); node; incnode(node)) {
 	    m = (Module) getdata(node);
-	    if (m->handle && !(m->flags & MOD_UNLOAD)) {
+	    if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
 		nicezputs(m->nam, stdout);
 		putchar('\n');
 	    }
@@ -778,13 +942,10 @@ bin_zmodload_exist(char *nam, char **args, char *ops)
 
 	for (; !ret && *args; args++) {
 	    f = 0;
-	    for (node = firstnode(bltinmodules);
-		 !f && node; incnode(node))
-		f = !strcmp(*args, (char *) getdata(node));
 	    for (node = firstnode(modules);
 		 !f && node; incnode(node)) {
 		m = (Module) getdata(node);
-		if (m->handle && !(m->flags & MOD_UNLOAD))
+		if (m->u.handle && !(m->flags & MOD_UNLOAD))
 		    f = !strcmp(*args, m->nam);
 	    }
 	    ret = !f;
@@ -825,7 +986,7 @@ bin_zmodload_dep(char *nam, char **args, char *ops)
 		m->deps = NULL;
 	    }
 	}
-	if (!m->deps && !m->handle) {
+	if (!m->deps && !m->u.handle) {
 	    remnode(modules, node);
 	    zsfree(m->nam);
 	    zfree(m, sizeof(*m));
@@ -1111,9 +1272,13 @@ bin_zmodload_param(char *nam, char **args, char *ops)
 
 /**/
 int
-unload_module(Module m, LinkNode node)
+unload_module(Module m, LinkNode node, int force)
 {
-    if (m->handle && !(m->flags & MOD_UNLOAD) && cleanup_module(m))
+    if ((m->flags & MOD_INIT_S) &&
+	!(m->flags & MOD_UNLOAD) &&
+	((m->flags & MOD_LINKED) ?
+	 (m->u.linked && m->u.linked->cleanup(m)) :
+	 (m->u.handle && cleanup_module(m))))
 	return 1;
     else {
 	int del = (m->flags & MOD_UNLOAD);
@@ -1123,9 +1288,19 @@ unload_module(Module m, LinkNode node)
 	    return 0;
 	}
 	m->flags &= ~MOD_UNLOAD;
-	if (m->handle)
-	    finish_module(m);
-	m->handle = NULL;
+	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;
+		}
+	    }
+	}
 	if (del && m->deps) {
 	    /* The module was unloaded delayed, unload all modules *
 	     * on which it depended. */
@@ -1145,7 +1320,9 @@ unload_module(Module m, LinkNode node)
 
 		    for (an = firstnode(modules); du && an; incnode(an)) {
 			am = (Module) getdata(an);
-			if (am != m && am->handle && am->deps) {
+			if (am != m && am->deps &&
+			    ((am->flags & MOD_LINKED) ?
+			     am->u.linked : am->u.handle)) {
 			    LinkNode sn;
 
 			    for (sn = firstnode(am->deps); du && sn;
@@ -1156,11 +1333,11 @@ unload_module(Module m, LinkNode node)
 			}
 		    }
 		    if (du)
-			unload_module(dm, NULL);
+			unload_module(dm, NULL, 0);
 		}
 	    }
 	}
-	if(!m->deps) {
+	if(!m->deps || force) {
 	    if (!node) {
 		for (node = firstnode(modules); node; incnode(node))
 		    if (m == (Module) getdata(node))
@@ -1193,7 +1370,7 @@ bin_zmodload_load(char *nam, char **args, char *ops)
 
 		for (mn = firstnode(modules); mn; incnode(mn)) {
 		    m = (Module) getdata(mn);
-		    if (m->deps && m->handle)
+		    if (m->deps && m->u.handle)
 			for (dn = firstnode(m->deps); dn; incnode(dn))
 			    if (!strcmp((char *) getdata(dn), *args)) {
 				if (m->flags & MOD_UNLOAD)
@@ -1208,7 +1385,7 @@ bin_zmodload_load(char *nam, char **args, char *ops)
 		m = (Module) getdata(node);
 		if (del)
 		    m->wrapper++;
-		if (unload_module(m, node))
+		if (unload_module(m, node, 0))
 		    ret = 1;
 		if (del)
 		    m->wrapper--;
@@ -1223,7 +1400,7 @@ bin_zmodload_load(char *nam, char **args, char *ops)
 	/* list modules */
 	for (node = firstnode(modules); node; incnode(node)) {
 	    m = (Module) getdata(node);
-	    if (m->handle && !(m->flags & MOD_UNLOAD)) {
+	    if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
 		if(ops['L']) {
 		    printf("zmodload ");
 		    if(m->nam[0] == '-')
@@ -1245,46 +1422,6 @@ bin_zmodload_load(char *nam, char **args, char *ops)
     }
 }
 
-/**/
-#else /* DYNAMIC */
-
-/* This is the version for shells without dynamic linking. */
-
-/**/
-int
-bin_zmodload(char *nam, char **args, char *ops, int func)
-{
-    /* We understand only the -e option (and ignore -i). */
-
-    if (ops['e'] || *args) {
-	LinkNode node;
-
-	if (!*args) {
-	    for (node = firstnode(bltinmodules); node; incnode(node)) {
-		nicezputs((char *) getdata(node), stdout);
-		putchar('\n');
-	    }
-	} else {
-	    for (; *args; args++) {
-		for (node = firstnode(bltinmodules); node; incnode(node))
-		    if (!strcmp(*args, (char *) getdata(node)))
-			break;
-		if (!node) {
-		    if (!ops['e'])
-			zerrnam(nam, "cannot load module: `%s'", *args, 0);
-		    return 1;
-		}
-	    }
-	}
-	return 0;
-    }
-    /* Otherwise we return 1 -- different from the dynamic version. */
-    return 1;
-}
-
-/**/
-#endif /* DYNAMIC */
-
 /* The list of module-defined conditions. */
 
 /**/
@@ -1299,9 +1436,7 @@ Conddef
 getconddef(int inf, char *name, int autol)
 {
     Conddef p;
-#ifdef DYNAMIC
     int f = 1;
-#endif
 
     do {
 	for (p = condtab; p; p = p->next) {
@@ -1309,7 +1444,6 @@ getconddef(int inf, char *name, int autol)
 		!strcmp(name, p->name))
 		break;
 	}
-#ifdef DYNAMIC
 	if (autol && p && p->module) {
 	    /* This is a definition for an autoloaded condition, load the *
 	     * module if we haven't tried that already. */
@@ -1322,7 +1456,6 @@ getconddef(int inf, char *name, int autol)
 		return NULL;
 	    }
 	} else
-#endif
 	    break;
     } while (!p);
     return p;
@@ -1341,11 +1474,9 @@ addconddef(Conddef c)
     if (p) {
 	if (!p->module || (p->flags & CONDF_ADDED))
 	    return 1;
-#ifdef DYNAMIC
 	/* There is an autoload definition. */
 
 	deleteconddef(p);
-#endif
     }
     c->next = condtab;
     condtab = c;
@@ -1616,9 +1747,6 @@ deleteparamdefs(char const *nam, Paramdef d, int size)
     return 1;
 }
 
-/**/
-#ifdef DYNAMIC
-
 /* This adds a definition for autoloading a module for a condition. */
 
 /**/
@@ -1709,9 +1837,6 @@ add_autoparam(char *nam, char *module)
     pm->flags |= PM_AUTOLOAD;
 }
 
-/**/
-#endif
-
 /* List of math functions. */
 
 /**/
@@ -1725,7 +1850,6 @@ getmathfunc(char *name, int autol)
 
     for (p = mathfuncs; p; q = p, p = p->next)
 	if (!strcmp(name, p->name)) {
-#ifdef DYNAMIC
 	    if (autol && p->module) {
 		char *n = dupstring(p->module);
 
@@ -1741,7 +1865,6 @@ getmathfunc(char *name, int autol)
 
 		return getmathfunc(name, 0);
 	    }
-#endif
 	    return p;
 	}
 
@@ -1790,8 +1913,6 @@ addmathfuncs(char const *nam, MathFunc f, int size)
     return hadf ? hads : 1;
 }
 
-#ifdef DYNAMIC
-
 /**/
 int
 add_automathfunc(char *nam, char *module)
@@ -1859,5 +1980,3 @@ deletemathfuncs(char const *nam, MathFunc f, int size)
     }
     return hadf ? hads : 1;
 }
-
-#endif /* DYNAMIC */
diff --git a/Src/params.c b/Src/params.c
index 5dcdeb986..c8778db3a 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -203,10 +203,8 @@ IPDEF8("WATCH", &watch, "watch", 0),
 IPDEF8("PATH", &path, "path", PM_RESTRICTED),
 IPDEF8("PSVAR", &psvar, "psvar", 0),
 
-#ifdef DYNAMIC
 /* MODULE_PATH is not imported for security reasons */
 IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
-#endif
 
 #define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,BR((void *)B),SFN(arrvarsetfn),GFN(arrvargetfn),stdunsetfn,0,NULL,C,NULL,0}
 #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
@@ -234,9 +232,7 @@ IPDEF9("manpath", &manpath, "MANPATH"),
 IPDEF9("psvar", &psvar, "PSVAR"),
 IPDEF9("watch", &watch, "WATCH"),
 
-#ifdef DYNAMIC
 IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
-#endif
 IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
 
 {NULL, NULL}
@@ -254,10 +250,6 @@ static Param argvparam;
 /**/
 HashTable paramtab, realparamtab;
 
-#ifndef DYNAMIC
-#define getparamnode gethashnode2
-#endif /* DYNAMIC */
-
 /**/
 HashTable
 newparamtable(int size, char const *name)
@@ -281,8 +273,6 @@ newparamtable(int size, char const *name)
 }
 
 /**/
-#ifdef DYNAMIC
-/**/
 static HashNode
 getparamnode(HashTable ht, char *nam)
 {
@@ -302,8 +292,6 @@ getparamnode(HashTable ht, char *nam)
     }
     return hn;
 }
-/**/
-#endif /* DYNAMIC */
 
 /* Copy a parameter hash table */
 
diff --git a/Src/zsh.h b/Src/zsh.h
index 2cf632abf..a9e8e00ed 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -300,6 +300,7 @@ typedef struct funcwrap  *FuncWrap;
 typedef struct builtin   *Builtin;
 typedef struct nameddir  *Nameddir;
 typedef struct module    *Module;
+typedef struct linkedmod *Linkedmod;
 
 typedef struct patprog   *Patprog;
 typedef struct process   *Process;
@@ -917,7 +918,10 @@ struct builtin {
 struct module {
     char *nam;
     int flags;
-    void *handle;
+    union {
+	void *handle;
+	Linkedmod linked;
+    } u;
     LinkList deps;
     int wrapper;
 };
@@ -925,6 +929,19 @@ struct module {
 #define MOD_BUSY    (1<<0)
 #define MOD_UNLOAD  (1<<1)
 #define MOD_SETUP   (1<<2)
+#define MOD_LINKED  (1<<3)
+#define MOD_INIT_S  (1<<4)
+#define MOD_INIT_B  (1<<5)
+
+typedef int (*Module_func) _((Module));
+
+struct linkedmod {
+    char *name;
+    Module_func setup;
+    Module_func boot;
+    Module_func cleanup;
+    Module_func finish;
+};
 
 /* C-function hooks */