diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/builtin.c | 2 | ||||
-rw-r--r-- | Src/module.c | 306 | ||||
-rw-r--r-- | Src/zsh.h | 2 |
3 files changed, 268 insertions, 42 deletions
diff --git a/Src/builtin.c b/Src/builtin.c index 477e984cd..864fd41b9 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -123,7 +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"), - BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ILabcfdipue", NULL), + BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ARILabcfdipue", NULL), BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL), }; diff --git a/Src/module.c b/Src/module.c index 2d8f6ce6f..bac8f5c42 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); @@ -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,60 @@ 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) @@ -453,11 +526,17 @@ module_loaded(const char *name) LinkNode node; Module m; - return ((node = find_module(name)) && + 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 @@ -679,7 +758,12 @@ 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. + */ + if (!(node = find_module(name, 1, &name))) { if (!(linked = module_linked(name)) && !(handle = do_load_module(name))) return 0; @@ -697,10 +781,7 @@ 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); return 0; } m->flags |= MOD_INIT_S | MOD_INIT_B; @@ -773,12 +854,13 @@ 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; - node = find_module(module); + /* Resolve aliases and actual loadable module as for load_module */ + node = find_module(module, 1, &module); if (node && (m = ((Module) getdata(node)))->u.handle && !(m->flags & MOD_UNLOAD)) { if (test) { @@ -793,12 +875,24 @@ require_module(char *nam, char *module, int res, int test) /**/ void -add_dep(char *name, char *from) +add_dep(const char *name, char *from) { LinkNode node; Module m; - if (!(node = find_module(name))) { + /* + * 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 = zcalloc(sizeof(*m)); m->nam = ztrdup(name); zaddlinknode(modules, m); @@ -845,12 +939,21 @@ 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']; + 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; @@ -886,32 +989,148 @@ bin_zmodload(char *nam, char **args, char *ops, int func) /**/ 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) zcalloc(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; +} + +/**/ +static int 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; } @@ -924,9 +1143,9 @@ 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); + /* 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); @@ -949,11 +1168,8 @@ 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]) { /* list dependencies */ @@ -1216,6 +1432,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) ? @@ -1249,7 +1474,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)) && @@ -1287,9 +1512,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; @@ -1304,8 +1527,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; @@ -1314,11 +1538,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; } @@ -1342,7 +1566,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] == '-') diff --git a/Src/zsh.h b/Src/zsh.h index fe17d6cd6..bf59641b5 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -957,6 +957,7 @@ struct module { union { void *handle; Linkedmod linked; + char *alias; } u; LinkList deps; int wrapper; @@ -968,6 +969,7 @@ struct module { #define MOD_LINKED (1<<3) #define MOD_INIT_S (1<<4) #define MOD_INIT_B (1<<5) +#define MOD_ALIAS (1<<6) typedef int (*Module_func) _((Module)); |