aboutsummaryrefslogtreecommitdiff
path: root/Src/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/module.c')
-rw-r--r--Src/module.c413
1 files changed, 336 insertions, 77 deletions
diff --git a/Src/module.c b/Src/module.c
index 63e0dc2f6..e943fb397 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -88,6 +88,27 @@ register_module(char *n, Module_func setup, Module_func boot,
zaddlinknode(linkedmodules, m);
}
+/* Print an alias. */
+
+/**/
+static void
+printmodalias(Module m, char *ops)
+{
+ if (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. */
/**/
@@ -164,6 +185,15 @@ addwrapper(Module m, FuncWrap w)
{
FuncWrap p, q;
+ /*
+ * We can't add a wrapper to an alias, since it's supposed
+ * to behave identically to the resolved module. This shouldn't
+ * happen since we usually add wrappers when a real module is
+ * loaded.
+ */
+ if (m->flags & MOD_ALIAS)
+ return 1;
+
if (w->flags & WRAPF_ADDED)
return 1;
for (p = wrappers, q = NULL; p; q = p, p = p->next);
@@ -196,7 +226,7 @@ mod_export LinkList modules;
int
add_autobin(char *nam, char *module)
{
- Builtin bn = zcalloc(sizeof(*bn));
+ Builtin bn = zshcalloc(sizeof(*bn));
bn->nam = ztrdup(nam);
bn->optstr = ztrdup(module);
return addbuiltin(bn);
@@ -256,6 +286,9 @@ deletewrapper(Module m, FuncWrap w)
{
FuncWrap p, q;
+ if (m->flags & MOD_ALIAS)
+ return 1;
+
if (w->flags & WRAPF_ADDED) {
for (p = wrappers, q = NULL; p && p != w; q = p, p = p->next);
@@ -292,7 +325,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->u.handle && !(m->flags & MOD_LINKED))
+ if (!(m->flags & MOD_ALIAS) &&
+ m->u.handle && !(m->flags & MOD_LINKED))
err |= loadbind(0, m->u.handle, ret);
}
@@ -431,21 +465,78 @@ do_load_module(char const *name)
/**/
#endif /* !DYNAMIC */
+/*
+ * Find a module in the list.
+ * If aliasp is non-zero, resolve any aliases to the underlying module.
+ * If namep is set, this is set to point to the last alias value resolved,
+ * even if that module was not loaded. or the module name if no aliases.
+ * Hence this is always the physical module to load in a chain of aliases.
+ * 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
-find_module(const char *name)
+find_module(const char *name, int aliasp, const char **namep)
{
Module m;
LinkNode node;
for (node = firstnode(modules); node; incnode(node)) {
m = (Module) getdata(node);
- if (!strcmp(m->nam, name))
+ if (!strcmp(m->nam, name)) {
+ if (aliasp && (m->flags & MOD_ALIAS)) {
+ if (namep)
+ *namep = m->u.alias;
+ return find_module(m->u.alias, 1, namep);
+ }
+ if (namep)
+ *namep = m->nam;
return node;
+ }
}
return NULL;
}
+/*
+ * Unlink and free a module node from the linked list.
+ */
+
+/**/
+static void
+delete_module(LinkNode node)
+{
+ Module m = (Module) remnode(modules, node);
+
+ if (m->flags & MOD_ALIAS)
+ zsfree(m->u.alias);
+ zsfree(m->nam);
+ if (m->deps)
+ freelinklist(m->deps, freestr);
+ zfree(m, sizeof(*m));
+}
+
+/**/
+mod_export int
+module_loaded(const char *name)
+{
+ LinkNode node;
+ Module m;
+
+ return ((node = find_module(name, 1, NULL)) &&
+ (m = ((Module) getdata(node)))->u.handle &&
+ !(m->flags & MOD_UNLOAD));
+}
+
+/*
+ * Setup and cleanup functions: we don't search for aliases here,
+ * since they should have been resolved before we try to load or unload
+ * the module.
+ */
+
/**/
#ifdef DYNAMIC
@@ -654,7 +745,7 @@ modname_ok(char const *p)
}
/**/
-int
+mod_export int
load_module(char const *name)
{
Module m;
@@ -667,11 +758,19 @@ load_module(char const *name)
zerr("invalid module name `%s'", name, 0);
return 0;
}
- if (!(node = find_module(name))) {
+ /*
+ * The following function call may alter name to the final name in a
+ * chain of aliases. This makes sure the actual module loaded
+ * is the right one.
+ */
+ queue_signals();
+ if (!(node = find_module(name, 1, &name))) {
if (!(linked = module_linked(name)) &&
- !(handle = do_load_module(name)))
+ !(handle = do_load_module(name))) {
+ unqueue_signals();
return 0;
- m = zcalloc(sizeof(*m));
+ }
+ m = zshcalloc(sizeof(*m));
m->nam = ztrdup(name);
if (handle) {
m->u.handle = handle;
@@ -685,23 +784,26 @@ load_module(char const *name)
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;
+ delete_module(node);
+ unqueue_signals();
return 0;
}
m->flags |= MOD_INIT_S | MOD_INIT_B;
m->flags &= ~MOD_SETUP;
+ unqueue_signals();
return 1;
}
m = (Module) getdata(node);
- if (m->flags & MOD_SETUP)
+ if (m->flags & MOD_SETUP) {
+ unqueue_signals();
return 1;
+ }
if (m->flags & MOD_UNLOAD)
m->flags &= ~MOD_UNLOAD;
- else if ((m->flags & MOD_LINKED) ? m->u.linked : m->u.handle)
+ else if ((m->flags & MOD_LINKED) ? m->u.linked : m->u.handle) {
+ unqueue_signals();
return 1;
+ }
if (m->flags & MOD_BUSY) {
zerr("circular dependencies for module %s", name, 0);
return 0;
@@ -711,14 +813,17 @@ load_module(char const *name)
for (n = firstnode(m->deps); n; incnode(n))
if (!load_module((char *) getdata(n))) {
m->flags &= ~MOD_BUSY;
+ unqueue_signals();
return 0;
}
m->flags &= ~MOD_BUSY;
if (!m->u.handle) {
handle = NULL;
if (!(linked = module_linked(name)) &&
- !(handle = do_load_module(name)))
+ !(handle = do_load_module(name))) {
+ unqueue_signals();
return 0;
+ }
if (handle) {
m->u.handle = handle;
m->flags |= MOD_SETUP;
@@ -732,6 +837,7 @@ load_module(char const *name)
else
m->u.linked = NULL;
m->flags &= ~MOD_SETUP;
+ unqueue_signals();
return 0;
}
m->flags |= MOD_INIT_S;
@@ -744,10 +850,12 @@ load_module(char const *name)
else
m->u.handle = NULL;
m->flags &= ~MOD_SETUP;
+ unqueue_signals();
return 0;
}
m->flags |= MOD_INIT_B;
m->flags &= ~MOD_SETUP;
+ unqueue_signals();
return 1;
}
@@ -761,38 +869,50 @@ load_module(char const *name)
/**/
mod_export int
-require_module(char *nam, char *module, int res, int test)
+require_module(char *nam, const char *module, int res, int test)
{
Module m = NULL;
LinkNode node;
+ int ret = 1;
- /* First see if the module is linked in. */
- for (node = firstnode(linkedmodules); node; incnode(node)) {
- if (!strcmp((char *) getdata(node), nam))
- return 1;
- }
- node = find_module(module);
+ /* 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)) {
if (test) {
+ unqueue_signals();
zwarnnam(nam, "module %s already loaded.", module, 0);
return 0;
}
} else
- return load_module(module);
+ ret = load_module(module);
+ unqueue_signals();
- return 1;
+ return ret;
}
/**/
void
-add_dep(char *name, char *from)
+add_dep(const char *name, char *from)
{
LinkNode node;
Module m;
- if (!(node = find_module(name))) {
- m = zcalloc(sizeof(*m));
+ /*
+ * If we were passed an alias, we must resolve it to a final
+ * module name (and maybe add the corresponding struct), since otherwise
+ * we would need to check all modules to see if they happen
+ * to be aliased to the same thing to implement depencies properly.
+ *
+ * This should mean that an attempt to add an alias which would
+ * have the same name as a module which has dependencies is correctly
+ * rejected, because then the module named already exists as a non-alias.
+ * Better make sure. (There's no problem making a an alias which
+ * *points* to a module with dependencies, of course.)
+ */
+ if (!(node = find_module(name, 1, &name))) {
+ m = zshcalloc(sizeof(*m));
m->nam = ztrdup(name);
zaddlinknode(modules, m);
} else
@@ -838,12 +958,23 @@ autoloadscan(HashNode hn, int printflags)
int
bin_zmodload(char *nam, char **args, char *ops, int func)
{
- if ((ops['b'] || ops['c'] || ops['p'] || ops['f']) &&
- !(ops['a'] || ops['u'])) {
+ int ops_bcpf = ops['b'] || ops['c'] || ops['p'] || ops['f'];
+ int ops_au = ops['a'] || ops['u'];
+ int ret = 1;
+
+ if (ops_bcpf && !ops_au) {
zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u",
NULL, 0);
return 1;
}
+ if (ops['A'] || ops['R']) {
+ if (ops_bcpf || ops_au || ops['d'] || (ops['R'] && ops['e'])) {
+ zwarnnam(nam, "illegal flags combined with -A or -R", NULL, 0);
+ return 1;
+ }
+ if (!ops['e'])
+ return bin_zmodload_alias(nam, args, ops);
+ }
if (ops['d'] && ops['a']) {
zwarnnam(nam, "-d cannot be combined with -a", NULL, 0);
return 1;
@@ -857,24 +988,137 @@ bin_zmodload(char *nam, char **args, char *ops, int func)
zwarnnam(nam, "-e cannot be combined with other options", NULL, 0);
return 1;
}
+ queue_signals();
if (ops['e'])
- return bin_zmodload_exist(nam, args, ops);
+ ret = bin_zmodload_exist(nam, args, ops);
else if (ops['d'])
- return bin_zmodload_dep(nam, args, ops);
+ ret = bin_zmodload_dep(nam, args, ops);
else if ((ops['a'] || ops['b']) && !(ops['c'] || ops['p'] || ops['f']))
- return bin_zmodload_auto(nam, args, ops);
+ ret = bin_zmodload_auto(nam, args, ops);
else if (ops['c'] && !(ops['b'] || ops['p']))
- return bin_zmodload_cond(nam, args, ops);
+ ret = bin_zmodload_cond(nam, args, ops);
else if (ops['f'] && !(ops['b'] || ops['p']))
- return bin_zmodload_math(nam, args, ops);
+ ret = bin_zmodload_math(nam, args, ops);
else if (ops['p'] && !(ops['b'] || ops['c']))
- return bin_zmodload_param(nam, args, ops);
+ ret = bin_zmodload_param(nam, args, ops);
else if (!(ops['a'] || ops['b'] || ops['c'] || ops['p']))
- return bin_zmodload_load(nam, args, ops);
+ ret = bin_zmodload_load(nam, args, ops);
else
zwarnnam(nam, "use only one of -b, -c, or -p", NULL, 0);
+ unqueue_signals();
- return 1;
+ return ret;
+}
+
+/**/
+static int
+bin_zmodload_alias(char *nam, char **args, char *ops)
+{
+ /*
+ * TODO: while it would be too nasty to have aliases, as opposed
+ * to real loadable modules, with dependencies --- just what would
+ * we need to load when, exactly? --- there is in principle no objection
+ * to making it possible to force an alias onto an existing unloaded
+ * module which has dependencies. This would simply transfer
+ * the dependencies down the line to the aliased-to module name.
+ * This is actually useful, since then you can alias zsh/zle=mytestzle
+ * to load another version of zle. But then what happens when the
+ * alias is removed? Do you transfer the dependencies back? And
+ * suppose other names are aliased to the same file? It might be
+ * kettle of fish best left unwormed.
+ */
+ LinkNode node;
+ Module m;
+ int ret = 0;
+
+ if (!*args) {
+ if (ops['R']) {
+ zwarnnam(nam, "no module alias to remove", NULL, 0);
+ return 1;
+ }
+ for (node = firstnode(modules); node; incnode(node)) {
+ m = (Module) getdata(node);
+ if (m->flags & MOD_ALIAS)
+ printmodalias(m, ops);
+ }
+ return 0;
+ }
+
+ for (; !ret && *args; args++) {
+ char *eqpos = strchr(*args, '=');
+ char *aliasname = eqpos ? eqpos+1 : NULL;
+ if (eqpos)
+ *eqpos = '\0';
+ if (!modname_ok(*args)) {
+ zwarnnam(nam, "invalid module name `%s'", *args, 0);
+ return 1;
+ }
+ if (ops['R']) {
+ if (aliasname) {
+ zwarnnam(nam, "bad syntax for removing module alias: %s",
+ *args, 0);
+ return 1;
+ }
+ node = find_module(*args, 0, NULL);
+ if (node) {
+ m = (Module) getdata(node);
+ if (!(m->flags & MOD_ALIAS)) {
+ zwarnnam(nam, "module is not an alias: %s", *args, 0);
+ ret = 1;
+ break;
+ }
+ delete_module(node);
+ } else {
+ zwarnnam(nam, "no such module alias: %s", *args, 0);
+ return 1;
+ }
+ } else {
+ if (aliasname) {
+ const char *mname = aliasname;
+ if (!modname_ok(aliasname)) {
+ zwarnnam(nam, "invalid module name `%s'", aliasname, 0);
+ return 1;
+ }
+ find_module(aliasname, 1, &mname);
+ if (!strcmp(mname, *args)) {
+ zwarnnam(nam, "module alias would refer to itself: %s",
+ *args, 0);
+ return 1;
+ }
+ node = find_module(*args, 0, NULL);
+ if (node) {
+ m = (Module) getdata(node);
+ if (!(m->flags & MOD_ALIAS)) {
+ zwarnnam(nam, "module is not an alias: %s", *args, 0);
+ return 1;
+ }
+ zsfree(m->u.alias);
+ } else {
+ m = (Module) zshcalloc(sizeof(*m));
+ m->nam = ztrdup(*args);
+ m->flags = MOD_ALIAS;
+ zaddlinknode(modules, 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);
+ else {
+ zwarnnam(nam, "module is not an alias: %s",
+ *args, 0);
+ return 1;
+ }
+ } else {
+ zwarnnam(nam, "no such module alias: %s", *args, 0);
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
}
/**/
@@ -883,28 +1127,33 @@ bin_zmodload_exist(char *nam, char **args, char *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 (ops['A'] && (node2 = find_module(m->u.alias, 1, NULL)))
+ m = (Module) getdata(node2);
+ else
+ continue;
+ }
if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
- nicezputs(m->nam, stdout);
+ nicezputs(modname, stdout);
putchar('\n');
}
}
return 0;
} else {
- int ret = 0, f;
+ int ret = 0;
for (; !ret && *args; args++) {
- f = 0;
- for (node = firstnode(modules);
- !f && node; incnode(node)) {
- m = (Module) getdata(node);
- if (m->u.handle && !(m->flags & MOD_UNLOAD))
- f = !strcmp(*args, m->nam);
- }
- ret = !f;
+ if (!(node = find_module(*args, 1, NULL))
+ || !(m = (Module) getdata(node))->u.handle
+ || (m->flags & MOD_UNLOAD))
+ ret = 1;
}
return ret;
}
@@ -916,23 +1165,24 @@ bin_zmodload_dep(char *nam, char **args, char *ops)
{
LinkNode node;
Module m;
- if(ops['u']) {
- /* remove dependencies */
- char *tnam = *args++;
- node = find_module(tnam);
+ if (ops['u']) {
+ /* remove dependencies, which can't pertain to aliases */
+ const char *tnam = *args++;
+ node = find_module(tnam, 1, &tnam);
if (!node)
return 0;
m = (Module) getdata(node);
- if(*args && m->deps) {
+ if (*args && m->deps) {
do {
- for(node = firstnode(m->deps); node; incnode(node))
- if(!strcmp(*args, getdata(node))) {
- zsfree(getdata(node));
- remnode(m->deps, node);
+ LinkNode dnode;
+ for (dnode = firstnode(m->deps); dnode; incnode(dnode))
+ if (!strcmp(*args, getdata(dnode))) {
+ zsfree(getdata(dnode));
+ remnode(m->deps, dnode);
break;
}
} while(*++args);
- if(empty(m->deps)) {
+ if (empty(m->deps)) {
freelinklist(m->deps, freestr);
m->deps = NULL;
}
@@ -942,19 +1192,16 @@ bin_zmodload_dep(char *nam, char **args, char *ops)
m->deps = NULL;
}
}
- if (!m->deps && !m->u.handle) {
- remnode(modules, node);
- zsfree(m->nam);
- zfree(m, sizeof(*m));
- }
+ if (!m->deps && !m->u.handle)
+ delete_module(node);
return 0;
- } else if(!args[0] || !args[1]) {
+ } 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(ops['L']) {
+ if (ops['L']) {
printf("zmodload -d ");
if(m->nam[0] == '-')
fputs("-- ", stdout);
@@ -979,7 +1226,7 @@ bin_zmodload_dep(char *nam, char **args, char *ops)
int ret = 0;
char *tnam = *args++;
- for(; *args; args++)
+ for (; *args; args++)
add_dep(tnam, *args);
return ret;
}
@@ -1099,7 +1346,7 @@ bin_zmodload_math(char *nam, char **args, char *ops)
int ret = 0;
if (ops['u']) {
- /* remove autoloaded conditions */
+ /* remove autoloaded math functions */
for (; *args; args++) {
MathFunc f = getmathfunc(*args, 0);
@@ -1108,7 +1355,7 @@ bin_zmodload_math(char *nam, char **args, char *ops)
zwarnnam(nam, "%s: no such math function", *args, 0);
ret = 1;
}
- } else if (f->flags & CONDF_ADDED) {
+ } else if (f->flags & MFF_ADDED) {
zwarnnam(nam, "%s: math function is already defined", *args, 0);
ret = 1;
} else
@@ -1130,7 +1377,7 @@ bin_zmodload_math(char *nam, char **args, char *ops)
}
return 0;
} else {
- /* add autoloaded conditions */
+ /* add autoloaded math functions */
char *modnam;
modnam = *args++;
@@ -1209,6 +1456,15 @@ bin_zmodload_param(char *nam, char **args, char *ops)
int
unload_module(Module m, LinkNode node)
{
+ /*
+ * Only unload the real module, so resolve aliases.
+ */
+ if (m->flags & MOD_ALIAS) {
+ LinkNode node = find_module(m->u.alias, 1, NULL);
+ if (!node)
+ return 1;
+ m = (Module) getdata(node);
+ }
if ((m->flags & MOD_INIT_S) &&
!(m->flags & MOD_UNLOAD) &&
((m->flags & MOD_LINKED) ?
@@ -1242,7 +1498,7 @@ unload_module(Module m, LinkNode node)
LinkNode n;
for (n = firstnode(m->deps); n; incnode(n)) {
- LinkNode dn = find_module((char *) getdata(n));
+ LinkNode dn = find_module((char *) getdata(n), 1, NULL);
Module dm;
if (dn && (dm = (Module) getdata(dn)) &&
@@ -1280,9 +1536,7 @@ unload_module(Module m, LinkNode node)
if (!node)
return 1;
}
- remnode(modules, node);
- zsfree(m->nam);
- zfree(m, sizeof(*m));
+ delete_module(node);
}
}
return 0;
@@ -1297,8 +1551,9 @@ bin_zmodload_load(char *nam, char **args, char *ops)
int ret = 0;
if(ops['u']) {
/* unload modules */
+ const char *mname = *args;
for(; *args; args++) {
- node = find_module(*args);
+ node = find_module(*args, 1, &mname);
if (node) {
LinkNode mn, dn;
int del = 0;
@@ -1307,11 +1562,11 @@ bin_zmodload_load(char *nam, char **args, char *ops)
m = (Module) getdata(mn);
if (m->deps && m->u.handle)
for (dn = firstnode(m->deps); dn; incnode(dn))
- if (!strcmp((char *) getdata(dn), *args)) {
+ if (!strcmp((char *) getdata(dn), mname)) {
if (m->flags & MOD_UNLOAD)
del = 1;
else {
- zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", *args, 0);
+ zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", mname, 0);
ret = 1;
goto cont;
}
@@ -1335,7 +1590,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->u.handle && !(m->flags & MOD_UNLOAD)) {
+ if (m->u.handle && !(m->flags & (MOD_UNLOAD|MOD_ALIAS))) {
if(ops['L']) {
printf("zmodload ");
if(m->nam[0] == '-')
@@ -1761,12 +2016,14 @@ add_autoparam(char *nam, char *module)
{
Param pm;
+ queue_signals();
if ((pm = (Param) gethashnode2(paramtab, nam)))
unsetparam_pm(pm, 0, 1);
- pm = setsparam(ztrdup(nam), ztrdup(module));
+ pm = setsparam(nam, ztrdup(module));
pm->flags |= PM_AUTOLOAD;
+ unqueue_signals();
}
/* List of math functions. */
@@ -1862,6 +2119,8 @@ add_automathfunc(char *nam, char *module)
return 1;
}
+ f->flags &= ~MFF_ADDED; /* still to autoload, not added yet */
+
return 0;
}