diff options
Diffstat (limited to 'dotfiles/system/.zsh/modules/Src/module.c')
| -rw-r--r-- | dotfiles/system/.zsh/modules/Src/module.c | 3641 |
1 files changed, 0 insertions, 3641 deletions
diff --git a/dotfiles/system/.zsh/modules/Src/module.c b/dotfiles/system/.zsh/modules/Src/module.c deleted file mode 100644 index 4ae7831..0000000 --- a/dotfiles/system/.zsh/modules/Src/module.c +++ /dev/null @@ -1,3641 +0,0 @@ -/* - * module.c - deal with dynamic modules - * - * This file is part of zsh, the Z shell. - * - * Copyright (c) 1996-1997 Zoltán Hidvégi - * All rights reserved. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and to distribute modified versions of this software for any - * purpose, provided that the above copyright notice and the following - * two paragraphs appear in all copies of this software. - * - * In no event shall Zoltán Hidvégi or the Zsh Development Group be liable - * to any party for direct, indirect, special, incidental, or consequential - * damages arising out of the use of this software and its documentation, - * even if Zoltán Hidvégi and the Zsh Development Group have been advised of - * the possibility of such damage. - * - * Zoltán Hidvégi and the Zsh Development Group specifically disclaim any - * warranties, including, but not limited to, the implied warranties of - * merchantability and fitness for a particular purpose. The software - * 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. - * This is set up at boot and remains for the life of the shell; - * entries do not appear in "zmodload" listings. - */ - -/**/ -LinkList linkedmodules; - -/* $module_path ($MODULE_PATH) */ - -/**/ -char **module_path; - -/* Hash of 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, - * or indicate to do_module_features() that it should be - * silent. - */ - FEAT_IGNORE = 0x0001, - /* If a condition, condition is infix rather than prefix */ - 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 -}; - -/* - * All functions to add or remove autoloadable features fit - * the following prototype. - * - * "module" is the name of the module. - * - * "feature" is the name of the feature, minus any type prefix. - * - * "flags" is a set of the bits above. - * - * 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: - * - * 1: failed to add [type] `[feature]' - * 2: [feature]: no such [type] - * 3: [feature]: [type] is already defined - */ -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 || (flags & PRINTMOD_AUTO)) { - /* - * 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 - ************************************************************************/ - -/* The `zsh/main' module contains all the base code that can't actually be * - * built as a separate module. It is initialised by main(), so there's * - * nothing for the boot function to do. */ - -/**/ -int -setup_(UNUSED(Module m)) -{ - return 0; -} - -/**/ -int -features_(UNUSED(Module m), UNUSED(char ***features)) -{ - /* - * There are lots and lots of features, but they're not - * handled here. - */ - return 1; -} - -/**/ -int -enables_(UNUSED(Module m), UNUSED(int **enables)) -{ - return 1; -} - -/**/ -int -boot_(UNUSED(Module m)) -{ - return 0; -} - -/**/ -int -cleanup_(UNUSED(Module m)) -{ - return 0; -} - -/**/ -int -finish_(UNUSED(Module m)) -{ - return 0; -} - - -/************************************************************************ - * Module utility functions - ************************************************************************/ - -/* This registers a builtin module. */ - -/**/ -void -register_module(char *n, Module_void_func setup, - Module_features_func features, - Module_enables_func enables, - Module_void_func boot, - Module_void_func cleanup, - Module_void_func finish) -{ - Linkedmod m; - - m = (Linkedmod) zalloc(sizeof(*m)); - - m->name = ztrdup(n); - m->setup = setup; - m->features = features; - m->enables = enables; - m->boot = boot; - m->cleanup = cleanup; - m->finish = finish; - - zaddlinknode(linkedmodules, m); -} - -/* Check if a module is linked in. */ - -/**/ -Linkedmod -module_linked(char const *name) -{ - LinkNode node; - - for (node = firstnode(linkedmodules); node; incnode(node)) - if (!strcmp(((Linkedmod) getdata(node))->name, name)) - return (Linkedmod) getdata(node); - - return NULL; -} - - -/************************************************************************ - * Support for the various feature types. - * First, builtins. - ************************************************************************/ - -/* addbuiltin() can be used to add a new builtin. It returns zero on * - * success, 1 on failure. The only possible type of failure is that * - * a builtin with the specified name already exists. An autoloaded * - * builtin can be replaced using this function. */ - -/**/ -static int -addbuiltin(Builtin b) -{ - Builtin bn = (Builtin) builtintab->getnode2(builtintab, b->node.nam); - if (bn && (bn->node.flags & BINF_ADDED)) - return 1; - if (bn) - builtintab->freenode(builtintab->removenode(builtintab, b->node.nam)); - builtintab->addnode(builtintab, b->node.nam, b); - return 0; -} - -/* Define an autoloadable builtin. It returns 0 on success, or 1 on * - * failure. The only possible cause of failure is that a builtin * - * with the specified name already exists. */ - -/**/ -static int -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 (flags & FEAT_AUTOALL) - bn->node.flags |= BINF_AUTOALL; - if ((ret = addbuiltin(bn))) { - builtintab->freenode(&bn->node); - if (!(flags & FEAT_IGNORE)) - return 1; - } - return 0; -} - -/* Remove the builtin added previously by addbuiltin(). Returns * - * zero on succes and -1 if there is no builtin with that name. */ - -/**/ -int -deletebuiltin(const char *nam) -{ - Builtin bn; - - bn = (Builtin) builtintab->removenode(builtintab, nam); - if (!bn) - return -1; - builtintab->freenode(&bn->node); - return 0; -} - -/* Remove an autoloaded added by add_autobin */ - -/**/ -static int -del_autobin(UNUSED(const char *module), const char *bnam, int flags) -{ - Builtin bn = (Builtin) builtintab->getnode2(builtintab, bnam); - if (!bn) { - if(!(flags & FEAT_IGNORE)) - return 2; - } else if (bn->node.flags & BINF_ADDED) { - if (!(flags & FEAT_IGNORE)) - return 3; - } else - deletebuiltin(bnam); - - return 0; -} - -/* - * Manipulate a set of builtins. This should be called - * via setfeatureenables() (or, usually, via the next level up, - * handlefeatures()). - * - * "nam" is the name of the calling code builtin, probably "zmodload". - * - * "binl" is the builtin table containing an array of "size" builtins. - * - * "e" is either NULL, in which case all builtins in the - * table are removed, or else an array corresponding to "binl" - * with a 1 for builtins that are to be added and a 0 for builtins - * that are to be removed. Any builtin already in the appropriate - * state is left alone. - * - * Returns 1 on any error, 0 for success. The recommended way - * of handling errors is to compare the enables passed down - * with the set retrieved after the error to find what failed. - */ - -/**/ -static int -setbuiltins(char const *nam, Builtin binl, int size, int *e) -{ - int ret = 0, n; - - for(n = 0; n < size; n++) { - Builtin b = &binl[n]; - if (e && *e++) { - if (b->node.flags & BINF_ADDED) - continue; - if (addbuiltin(b)) { - zwarnnam(nam, - "name clash when adding builtin `%s'", b->node.nam); - ret = 1; - } else { - b->node.flags |= BINF_ADDED; - } - } else { - if (!(b->node.flags & BINF_ADDED)) - continue; - if (deletebuiltin(b->node.nam)) { - zwarnnam(nam, "builtin `%s' already deleted", b->node.nam); - ret = 1; - } else { - b->node.flags &= ~BINF_ADDED; - } - } - } - return ret; -} - -/* - * Add multiple builtins. binl points to a table of `size' builtin - * structures. Those for which (.flags & BINF_ADDED) is false are to be - * added; that flag is set if they succeed. - * - * If any fail, an error message is printed, using nam as the leading name. - * Returns 0 on success, 1 for any failure. - * - * This should not be used from a module; instead, use handlefeatures(). - */ - -/**/ -mod_export int -addbuiltins(char const *nam, Builtin binl, int size) -{ - int ret = 0, n; - - for(n = 0; n < size; n++) { - Builtin b = &binl[n]; - if(b->node.flags & BINF_ADDED) - continue; - if(addbuiltin(b)) { - zwarnnam(nam, "name clash when adding builtin `%s'", b->node.nam); - ret = 1; - } else { - b->node.flags |= BINF_ADDED; - } - } - return ret; -} - - -/************************************************************************ - * Function wrappers. - ************************************************************************/ - -/* The list of function wrappers defined. */ - -/**/ -FuncWrap wrappers; - -/* This adds a definition for a wrapper. Return value is one in case of * - * error and zero if all went fine. */ - -/**/ -mod_export int -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->node.flags & MOD_ALIAS) - return 1; - - if (w->flags & WRAPF_ADDED) - return 1; - for (p = wrappers, q = NULL; p; q = p, p = p->next); - if (q) - q->next = w; - else - wrappers = w; - w->next = NULL; - w->flags |= WRAPF_ADDED; - w->module = m; - - return 0; -} - -/* This removes the given wrapper definition from the list. Returned is * - * one in case of error and zero otherwise. */ - -/**/ -mod_export int -deletewrapper(Module m, FuncWrap w) -{ - FuncWrap p, q; - - if (m->node.flags & MOD_ALIAS) - return 1; - - if (w->flags & WRAPF_ADDED) { - for (p = wrappers, q = NULL; p && p != w; q = p, p = p->next); - - if (p) { - if (q) - q->next = p->next; - else - wrappers = p->next; - p->flags &= ~WRAPF_ADDED; - - return 0; - } - } - return 1; -} - - -/************************************************************************ - * Conditions. - ************************************************************************/ - -/* The list of module-defined conditions. */ - -/**/ -mod_export Conddef condtab; - -/* This gets a condition definition with the given name. The first * - * argument says if we have to look for an infix condition. The last * - * argument is non-zero if we should autoload modules if needed. */ - -/**/ -Conddef -getconddef(int inf, const char *name, int autol) -{ - Conddef p; - int f = 1; - char *lookup, *s; - - /* detokenize the Dash to the form encoded in lookup tables */ - lookup = dupstring(name); - if (!lookup) - return NULL; - for (s = lookup; *s != '\0'; s++) { - if (*s == Dash) - *s = '-'; - } - - do { - for (p = condtab; p; p = p->next) { - if ((!!inf == !!(p->flags & CONDF_INFIX)) && - !strcmp(lookup, p->name)) - break; - } - if (autol && p && p->module) { - /* - * This is a definition for an autoloaded condition; load the - * module if we haven't tried that already. - */ - if (f) { - (void)ensurefeature(p->module, - (p->flags & CONDF_INFIX) ? "C:" : "c:", - (p->flags & CONDF_AUTOALL) ? NULL : lookup); - f = 0; - p = NULL; - } else { - deleteconddef(p); - return NULL; - } - } else - break; - } while (!p); - - return p; -} - -/* - * This adds the given condition definition. The return value is zero on * - * success and 1 on failure. If there is a matching definition for an * - * autoloaded condition, it is removed. - * - * This is used for adding both an autoload definition or - * a real condition. In the latter case the caller is responsible - * for setting the CONDF_ADDED flag. - */ - -/**/ -static int -addconddef(Conddef c) -{ - Conddef p = getconddef((c->flags & CONDF_INFIX), c->name, 0); - - if (p) { - if (!p->module || (p->flags & CONDF_ADDED)) - return 1; - /* There is an autoload definition. */ - - deleteconddef(p); - } - c->next = condtab; - condtab = c; - return 0; -} - -/* This removes the given condition definition from the list(s). If this * - * is a definition for a autoloaded condition, the memory is freed. */ - -/**/ -int -deleteconddef(Conddef c) -{ - Conddef p, q; - - for (p = condtab, q = NULL; p && p != c; q = p, p = p->next); - - if (p) { - if (q) - q->next = p->next; - else - condtab = p->next; - - if (p->module) { - /* autoloaded, free it */ - zsfree(p->name); - zsfree(p->module); - zfree(p, sizeof(*p)); - } - return 0; - } - return -1; -} - -/* - * Add or remove sets of conditions. The interface is - * identical to setbuiltins(). - */ - -/**/ -static int -setconddefs(char const *nam, Conddef c, int size, int *e) -{ - int ret = 0; - - while (size--) { - if (e && *e++) { - if (c->flags & CONDF_ADDED) { - c++; - continue; - } - if (addconddef(c)) { - zwarnnam(nam, "name clash when adding condition `%s'", - c->name); - ret = 1; - } else { - c->flags |= CONDF_ADDED; - } - } else { - if (!(c->flags & CONDF_ADDED)) { - c++; - continue; - } - if (deleteconddef(c)) { - zwarnnam(nam, "condition `%s' already deleted", c->name); - ret = 1; - } else { - c->flags &= ~CONDF_ADDED; - } - } - c++; - } - return ret; -} - -/* This adds a definition for autoloading a module for a condition. */ - -/**/ -static int -add_autocond(const char *module, const char *cnam, int flags) -{ - Conddef c; - - c = (Conddef) zalloc(sizeof(*c)); - - c->name = ztrdup(cnam); - c->flags = ((flags & FEAT_INFIX) ? CONDF_INFIX : 0); - if (flags & FEAT_AUTOALL) - c->flags |= CONDF_AUTOALL; - c->module = ztrdup(module); - - if (addconddef(c)) { - zsfree(c->name); - zsfree(c->module); - zfree(c, sizeof(*c)); - - if (!(flags & FEAT_IGNORE)) - return 1; - } - return 0; -} - -/* Remove a condition added with add_autocond */ - -/**/ -static int -del_autocond(UNUSED(const char *modnam), const char *cnam, int flags) -{ - Conddef cd = getconddef((flags & FEAT_INFIX) ? 1 : 0, cnam, 0); - - if (!cd) { - if (!(flags & FEAT_IGNORE)) { - return 2; - } - } else if (cd->flags & CONDF_ADDED) { - if (!(flags & FEAT_IGNORE)) - return 3; - } else - deleteconddef(cd); - - return 0; -} - -/************************************************************************ - * Hook functions. - ************************************************************************/ - -/* This list of hook functions defined. */ - -/**/ -Hookdef hooktab; - -/* Find a hook definition given the name. */ - -/**/ -Hookdef -gethookdef(char *n) -{ - Hookdef p; - - for (p = hooktab; p; p = p->next) - if (!strcmp(n, p->name)) - return p; - return NULL; -} - -/* This adds the given hook definition. The return value is zero on * - * success and 1 on failure. */ - -/**/ -int -addhookdef(Hookdef h) -{ - if (gethookdef(h->name)) - return 1; - - h->next = hooktab; - hooktab = h; - h->funcs = znewlinklist(); - - return 0; -} - -/* - * 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(Module m, Hookdef h, int size) -{ - int ret = 0; - - while (size--) { - if (addhookdef(h)) { - zwarnnam(m ? m->node.nam : NULL, - "name clash when adding hook `%s'", h->name); - ret = 1; - } - h++; - } - return ret; -} - -/* Delete hook definitions. */ - -/**/ -int -deletehookdef(Hookdef h) -{ - Hookdef p, q; - - for (p = hooktab, q = NULL; p && p != h; q = p, p = p->next); - - if (!p) - return 1; - - if (q) - q->next = p->next; - else - hooktab = p->next; - freelinklist(p->funcs, NULL); - return 0; -} - -/* Remove multiple hook definitions. */ - -/**/ -mod_export int -deletehookdefs(UNUSED(Module m), Hookdef h, int size) -{ - int ret = 0; - - while (size--) { - if (deletehookdef(h)) - ret = 1; - h++; - } - return ret; -} - -/* Add a function to a hook. */ - -/**/ -int -addhookdeffunc(Hookdef h, Hookfn f) -{ - zaddlinknode(h->funcs, (void *) f); - - return 0; -} - -/**/ -mod_export int -addhookfunc(char *n, Hookfn f) -{ - Hookdef h = gethookdef(n); - - if (h) - return addhookdeffunc(h, f); - return 1; -} - -/* Delete a function from a hook. */ - -/**/ -int -deletehookdeffunc(Hookdef h, Hookfn f) -{ - LinkNode p; - - for (p = firstnode(h->funcs); p; incnode(p)) - if (f == (Hookfn) getdata(p)) { - remnode(h->funcs, p); - return 0; - } - return 1; -} - -/* Delete a hook. */ - -/**/ -mod_export int -deletehookfunc(char *n, Hookfn f) -{ - Hookdef h = gethookdef(n); - - if (h) - return deletehookdeffunc(h, f); - return 1; -} - -/* Run the function(s) for a hook. */ - -/**/ -mod_export int -runhookdef(Hookdef h, void *d) -{ - if (empty(h->funcs)) { - if (h->def) - return h->def(h, d); - return 0; - } else if (h->flags & HOOKF_ALL) { - LinkNode p; - int r; - - for (p = firstnode(h->funcs); p; incnode(p)) - if ((r = ((Hookfn) getdata(p))(h, d))) - return r; - if (h->def) - return h->def(h, d); - return 0; - } else - return ((Hookfn) getdata(lastnode(h->funcs)))(h, d); -} - - - -/************************************************************************ - * Shell parameters. - ************************************************************************/ - -/* - * Check that it's possible to add a parameter. This - * requires that either there's no parameter already present, - * or it's a global parameter marked for autoloading. - * - * The special status 2 is to indicate it didn't work but - * -i was in use so we didn't print a warning. - */ - -static int -checkaddparam(const char *nam, int opt_i) -{ - Param pm; - - if (!(pm = (Param) gethashnode2(paramtab, nam))) - return 0; - - if (pm->level || !(pm->node.flags & PM_AUTOLOAD)) { - /* - * -i suppresses "it's already that way" warnings, - * but not "this can't possibly work" warnings, so we print - * the message anyway if there's a local parameter blocking - * the parameter we want to add, not if there's a - * non-autoloadable parameter already there. This - * is consistent with the way add_auto* functions work. - */ - if (!opt_i || !pm->level) { - zwarn("Can't add module parameter `%s': %s", - nam, pm->level ? - "local parameter exists" : - "parameter already exists"); - return 1; - } - return 2; - } - - unsetparam_pm(pm, 0, 1); - return 0; -} - -/* This adds the given parameter definition. The return value is zero on * - * success and 1 on failure. */ - -/**/ -int -addparamdef(Paramdef d) -{ - Param pm; - - if (checkaddparam(d->name, 0)) - return 1; - - if (d->getnfn) { - if (!(pm = createspecialhash(d->name, d->getnfn, - d->scantfn, d->flags))) - return 1; - } - else if (!(pm = createparam(d->name, d->flags)) && - !(pm = (Param) paramtab->getnode(paramtab, d->name))) - return 1; - - d->pm = pm; - pm->level = 0; - if (d->var) - pm->u.data = d->var; - if (d->var || d->gsu) { - /* - * If no get/set/unset class, use the appropriate - * variable type, else use the one supplied. - */ - switch (PM_TYPE(pm->node.flags)) { - case PM_SCALAR: - pm->gsu.s = d->gsu ? (GsuScalar)d->gsu : &varscalar_gsu; - break; - - case PM_INTEGER: - pm->gsu.i = d->gsu ? (GsuInteger)d->gsu : &varinteger_gsu; - break; - - case PM_FFLOAT: - case PM_EFLOAT: - pm->gsu.f = d->gsu; - break; - - case PM_ARRAY: - pm->gsu.a = d->gsu ? (GsuArray)d->gsu : &vararray_gsu; - break; - - case PM_HASHED: - /* hashes may behave like standard hashes */ - if (d->gsu) - pm->gsu.h = (GsuHash)d->gsu; - break; - - default: - unsetparam_pm(pm, 0, 1); - return 1; - } - } - - return 0; -} - -/* Delete parameters defined. No error checking yet. */ - -/**/ -int -deleteparamdef(Paramdef d) -{ - Param pm = (Param) paramtab->getnode(paramtab, d->name); - - if (!pm) - return 1; - if (pm != d->pm) { - /* - * See if the parameter has been hidden. If so, - * bring it to the front to unset it. - */ - Param prevpm, searchpm; - for (prevpm = pm, searchpm = pm->old; - searchpm; - prevpm = searchpm, searchpm = searchpm->old) - if (searchpm == d->pm) - break; - - if (!searchpm) - return 1; - - paramtab->removenode(paramtab, pm->node.nam); - prevpm->old = searchpm->old; - searchpm->old = pm; - paramtab->addnode(paramtab, searchpm->node.nam, searchpm); - - pm = searchpm; - } - pm->node.flags = (pm->node.flags & ~PM_READONLY) | PM_REMOVABLE; - unsetparam_pm(pm, 0, 1); - d->pm = NULL; - return 0; -} - -/* - * Add or remove sets of parameters. The interface is - * identical to setbuiltins(). - */ - -/**/ -static int -setparamdefs(char const *nam, Paramdef d, int size, int *e) -{ - int ret = 0; - - while (size--) { - if (e && *e++) { - if (d->pm) { - d++; - continue; - } - if (addparamdef(d)) { - zwarnnam(nam, "error when adding parameter `%s'", d->name); - ret = 1; - } - } else { - if (!d->pm) { - d++; - continue; - } - if (deleteparamdef(d)) { - zwarnnam(nam, "parameter `%s' already deleted", d->name); - ret = 1; - } - } - d++; - } - return ret; -} - -/* This adds a definition for autoloading a module for a parameter. */ - -/**/ -static int -add_autoparam(const char *module, const char *pnam, int flags) -{ - Param pm; - int ret; - - queue_signals(); - if ((ret = checkaddparam(pnam, (flags & FEAT_IGNORE)))) { - unqueue_signals(); - /* - * checkaddparam() has already printed a message if one was - * needed. If it wasn't owing to the presence of -i, ret is 2; - * for consistency with other add_auto* functions we return - * status 0 to indicate there's already such a parameter and - * we've been told not to worry if so. - */ - return ret == 2 ? 0 : -1; - } - - pm = setsparam(dupstring(pnam), ztrdup(module)); - - pm->node.flags |= PM_AUTOLOAD; - if (flags & FEAT_AUTOALL) - pm->node.flags |= PM_AUTOALL; - unqueue_signals(); - - return 0; -} - -/* Remove a parameter added with add_autoparam() */ - -/**/ -static int -del_autoparam(UNUSED(const char *modnam), const char *pnam, int flags) -{ - Param pm = (Param) gethashnode2(paramtab, pnam); - - if (!pm) { - if (!(flags & FEAT_IGNORE)) - return 2; - } else if (!(pm->node.flags & PM_AUTOLOAD)) { - if (!(flags & FEAT_IGNORE)) - return 3; - } else - unsetparam_pm(pm, 0, 1); - - return 0; -} - -/************************************************************************ - * Math functions. - ************************************************************************/ - -/* List of math functions. */ - -/**/ -MathFunc mathfuncs; - -/* - * Remove a single math function form the list (utility function). - * This does not delete a module math function, that's deletemathfunc(). - */ - -/**/ -void -removemathfunc(MathFunc previous, MathFunc current) -{ - if (previous) - previous->next = current->next; - else - mathfuncs = current->next; - - zsfree(current->name); - zsfree(current->module); - zfree(current, sizeof(*current)); -} - -/* Find a math function in the list, handling autoload if necessary. */ - -/**/ -MathFunc -getmathfunc(const char *name, int autol) -{ - MathFunc p, q = NULL; - - for (p = mathfuncs; p; q = p, p = p->next) - if (!strcmp(name, p->name)) { - if (autol && p->module && !(p->flags & MFF_USERFUNC)) { - char *n = dupstring(p->module); - int flags = p->flags; - - removemathfunc(q, p); - - (void)ensurefeature(n, "f:", (flags & MFF_AUTOALL) ? NULL : - name); - - p = getmathfunc(name, 0); - if (!p) { - zerr("autoloading module %s failed to define math function: %s", n, name); - } - } - return p; - } - - return NULL; -} - -/* Add a single math function */ - -/**/ -static int -addmathfunc(MathFunc f) -{ - MathFunc p, q = NULL; - - if (f->flags & MFF_ADDED) - return 1; - - for (p = mathfuncs; p; q = p, p = p->next) - if (!strcmp(f->name, p->name)) { - if (p->module && !(p->flags & MFF_USERFUNC)) { - /* - * Autoloadable, replace. - */ - removemathfunc(q, p); - break; - } - return 1; - } - - f->next = mathfuncs; - mathfuncs = f; - - return 0; -} - -/* Delete a single math function */ - -/**/ -mod_export int -deletemathfunc(MathFunc f) -{ - MathFunc p, q; - - for (p = mathfuncs, q = NULL; p && p != f; q = p, p = p->next); - - if (p) { - if (q) - q->next = f->next; - else - mathfuncs = f->next; - - /* the following applies to both unloaded and user-defined functions */ - if (f->module) { - zsfree(f->name); - zsfree(f->module); - zfree(f, sizeof(*f)); - } else - f->flags &= ~MFF_ADDED; - - return 0; - } - return -1; -} - -/* - * Add or remove sets of math functions. The interface is - * identical to setbuiltins(). - */ - -/**/ -static int -setmathfuncs(char const *nam, MathFunc f, int size, int *e) -{ - int ret = 0; - - while (size--) { - if (e && *e++) { - if (f->flags & MFF_ADDED) { - f++; - continue; - } - if (addmathfunc(f)) { - zwarnnam(nam, "name clash when adding math function `%s'", - f->name); - ret = 1; - } else { - f->flags |= MFF_ADDED; - } - } else { - if (!(f->flags & MFF_ADDED)) { - f++; - continue; - } - if (deletemathfunc(f)) { - zwarnnam(nam, "math function `%s' already deleted", f->name); - ret = 1; - } else { - f->flags &= ~MFF_ADDED; - } - } - f++; - } - return ret; -} - -/* Add an autoload definition for a math function. */ - -/**/ -static int -add_automathfunc(const char *module, const char *fnam, int flags) -{ - MathFunc f; - - f = (MathFunc) zalloc(sizeof(*f)); - - f->name = ztrdup(fnam); - f->module = ztrdup(module); - f->flags = 0; - - if (addmathfunc(f)) { - zsfree(f->name); - zsfree(f->module); - zfree(f, sizeof(*f)); - - if (!(flags & FEAT_IGNORE)) - return 1; - } - - return 0; -} - -/* Remove a math function added with add_automathfunc() */ - -/**/ -static int -del_automathfunc(UNUSED(const char *modnam), const char *fnam, int flags) -{ - MathFunc f = getmathfunc(fnam, 0); - - if (!f) { - if (!(flags & FEAT_IGNORE)) - return 2; - } else if (f->flags & MFF_ADDED) { - if (!(flags & FEAT_IGNORE)) - return 3; - } else - deletemathfunc(f); - - return 0; -} - -/************************************************************************ - * Now support for dynamical loading and the fallback functions - * we use for loading if dynamical loading is not available. - ************************************************************************/ - -/**/ -#ifdef DYNAMIC - -/**/ -#ifdef AIXDYNAMIC - -#include <sys/ldr.h> - -static char *dlerrstr[256]; - -static void * -load_and_bind(const char *fn) -{ - void *ret = (void *) load((char *) fn, L_NOAUTODEFER, NULL); - - if (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 = (Module)m->node.next) { - if (!(m->node.flags & MOD_ALIAS) && - m->u.handle && !(m->node.flags & MOD_LINKED)) - err |= loadbind(0, m->u.handle, ret); - } - } - - if (err) { - loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr)); - unload(ret); - ret = NULL; - } - } else - loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr)); - - return ret; -} - -#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 - -#ifdef HAVE_DLFCN_H -# if defined(HAVE_DL_H) && defined(HPUX10DYNAMIC) -# include <dl.h> -# else -# include <dlfcn.h> -# endif -#else -# ifdef HAVE_DL_H -# include <dl.h> -# define RTLD_LAZY BIND_DEFERRED -# define RTLD_GLOBAL DYNAMIC_PATH -# else -# include <sys/types.h> -# include <nlist.h> -# include <link.h> -# endif -#endif - -/**/ -#ifdef HPUX10DYNAMIC -# define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0) -# define dlclose(handle) shl_unload((shl_t)(handle)) - -static -void * -hpux_dlsym(void *handle, char *name) -{ - void *sym_addr; - if (!shl_findsym((shl_t *)&handle, name, TYPE_UNDEFINED, &sym_addr)) - return sym_addr; - return NULL; -} - -# define dlsym(handle,name) hpux_dlsym(handle,name) -# ifdef HAVE_DLERROR /* paranoia */ -# undef HAVE_DLERROR -# endif -#else -# ifndef HAVE_DLCLOSE -# define dlclose(X) ((X), 0) -# endif -/**/ -#endif - -#ifdef DLSYM_NEEDS_UNDERSCORE -# define STR_SETUP "_setup_" -# define STR_FEATURES "_features_" -# define STR_ENABLES "_enables_" -# define STR_BOOT "_boot_" -# define STR_CLEANUP "_cleanup_" -# define STR_FINISH "_finish_" -#else /* !DLSYM_NEEDS_UNDERSCORE */ -# define STR_SETUP "setup_" -# define STR_FEATURES "features_" -# define STR_ENABLES "enables_" -# define STR_BOOT "boot_" -# define STR_CLEANUP "cleanup_" -# define STR_FINISH "finish_" -#endif /* !DLSYM_NEEDS_UNDERSCORE */ - -/**/ -#endif /* !AIXDYNAMIC */ - -#ifndef RTLD_LAZY -# define RTLD_LAZY 1 -#endif -#ifndef RTLD_GLOBAL -# define RTLD_GLOBAL 0 -#endif - -/* - * Attempt to load a module. This is the lowest level of - * zsh function for dynamical modules. Returns the handle - * from the dynamic loader. - */ - -/**/ -static void * -try_load_module(char const *name) -{ - char buf[PATH_MAX + 1]; - char **pp; - void *ret = NULL; - int l; - - l = 1 + strlen(name) + 1 + strlen(DL_EXT); - for (pp = module_path; !ret && *pp; pp++) { - if (l + (**pp ? strlen(*pp) : 1) > PATH_MAX) - continue; - sprintf(buf, "%s/%s.%s", **pp ? *pp : ".", name, DL_EXT); - unmetafy(buf, NULL); - if (*buf) /* dlopen(NULL) returns a handle to the main binary */ - ret = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL); - } - - return ret; -} - -/* - * Load a module, with option to complain or not. - * Returns the handle from the dynamic loader. - */ - -/**/ -static void * -do_load_module(char const *name, int silent) -{ - void *ret; - - ret = try_load_module(name); - if (!ret && !silent) { -#ifdef HAVE_DLERROR - char *errstr = dlerror(); - zwarn("failed to load module `%s': %s", name, - errstr ? metafy(errstr, -1, META_HEAPDUP) : "empty module path"); -#else - zwarn("failed to load module: %s", name); -#endif - } - return ret; -} - -/**/ -#else /* !DYNAMIC */ - -/* - * Dummy loader when no dynamic loading available; always fails. - */ - -/**/ -static void * -do_load_module(char const *name, int silent) -{ - if (!silent) - zwarn("failed to load module: %s", name); - - return NULL; -} - -/**/ -#endif /* !DYNAMIC */ - -/* - * Find a module in the list. - * flags is a set of bits defined in the enum above. - * 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. - */ -/**/ -static Module -find_module(const char *name, int flags, const char **namep) -{ - Module m; - - m = (Module)modulestab->getnode2(modulestab, name); - if (m) { - if ((flags & FINDMOD_ALIASP) && (m->node.flags & MOD_ALIAS)) { - if (namep) - *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)); - modulestab->addnode(modulestab, ztrdup(name), m); - return m; -} - -/* - * Unlink and free a module node from the linked list. - */ - -/**/ -static void -delete_module(Module m) -{ - modulestab->removenode(modulestab, m->node.nam); - - modulestab->freenode(&m->node); -} - -/* - * Return 1 if a module is fully loaded else zero. - * A linked module may be marked as unloaded even though - * we can't fully unload it; this returns 0 to try to - * make that state transparently like an unloaded module. - */ - -/**/ -mod_export int -module_loaded(const char *name) -{ - Module m; - - return ((m = find_module(name, FINDMOD_ALIASP, NULL)) && - m->u.handle && - !(m->node.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 - -/**/ -#ifdef AIXDYNAMIC - -/**/ -static int -dyn_setup_module(Module m) -{ - return ((int (*)_((int,Module, void*))) m->u.handle)(0, m, NULL); -} - -/**/ -static int -dyn_features_module(Module m, char ***features) -{ - return ((int (*)_((int,Module, void*))) m->u.handle)(4, m, features); -} - -/**/ -static int -dyn_enables_module(Module m, int **enables) -{ - return ((int (*)_((int,Module, void*))) m->u.handle)(5, m, enables); -} - -/**/ -static int -dyn_boot_module(Module m) -{ - return ((int (*)_((int,Module, void*))) m->u.handle)(1, m, NULL); -} - -/**/ -static int -dyn_cleanup_module(Module m) -{ - return ((int (*)_((int,Module, void*))) m->u.handle)(2, m, NULL); -} - -/**/ -static int -dyn_finish_module(Module m) -{ - return ((int (*)_((int,Module,void *))) m->u.handle)(3, m, NULL); -} - -/**/ -#else - -static Module_generic_func -module_func(Module m, char *name) -{ -#ifdef DYNAMIC_NAME_CLASH_OK - return (Module_generic_func) dlsym(m->u.handle, name); -#else /* !DYNAMIC_NAME_CLASH_OK */ - VARARR(char, buf, strlen(name) + strlen(m->node.nam)*2 + 1); - char const *p; - char *q; - strcpy(buf, name); - q = strchr(buf, 0); - for(p = m->node.nam; *p; p++) { - if(*p == '/') { - *q++ = 'Q'; - *q++ = 's'; - } else if(*p == '_') { - *q++ = 'Q'; - *q++ = 'u'; - } else if(*p == 'Q') { - *q++ = 'Q'; - *q++ = 'q'; - } else - *q++ = *p; - } - *q = 0; - return (Module_generic_func) dlsym(m->u.handle, buf); -#endif /* !DYNAMIC_NAME_CLASH_OK */ -} - -/**/ -static int -dyn_setup_module(Module m) -{ - Module_void_func fn = (Module_void_func)module_func(m, STR_SETUP); - - if (fn) - return fn(m); - zwarnnam(m->node.nam, "no setup function"); - return 1; -} - -/**/ -static int -dyn_features_module(Module m, char ***features) -{ - Module_features_func fn = - (Module_features_func)module_func(m, STR_FEATURES); - - if (fn) - return fn(m, features); - /* not a user-visible error if no features function */ - return 1; -} - -/**/ -static int -dyn_enables_module(Module m, int **enables) -{ - Module_enables_func fn = (Module_enables_func)module_func(m, STR_ENABLES); - - if (fn) - return fn(m, enables); - /* not a user-visible error if no enables function */ - return 1; -} - -/**/ -static int -dyn_boot_module(Module m) -{ - Module_void_func fn = (Module_void_func)module_func(m, STR_BOOT); - - if(fn) - return fn(m); - zwarnnam(m->node.nam, "no boot function"); - return 1; -} - -/**/ -static int -dyn_cleanup_module(Module m) -{ - Module_void_func fn = (Module_void_func)module_func(m, STR_CLEANUP); - - if(fn) - return fn(m); - zwarnnam(m->node.nam, "no cleanup function"); - return 1; -} - -/* Note that this function does more than just calling finish_foo(), * - * it really unloads the module. */ - -/**/ -static int -dyn_finish_module(Module m) -{ - Module_void_func fn = (Module_void_func)module_func(m, STR_FINISH); - int r; - - if (fn) - r = fn(m); - else { - zwarnnam(m->node.nam, "no finish function"); - r = 1; - } - dlclose(m->u.handle); - return r; -} - -/**/ -#endif /* !AIXDYNAMIC */ - -/**/ -static int -setup_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? - (m->u.linked->setup)(m) : dyn_setup_module(m)); -} - -/**/ -static int -features_module(Module m, char ***features) -{ - return ((m->node.flags & MOD_LINKED) ? - (m->u.linked->features)(m, features) : - dyn_features_module(m, features)); -} - -/**/ -static int -enables_module(Module m, int **enables) -{ - return ((m->node.flags & MOD_LINKED) ? - (m->u.linked->enables)(m, enables) : - dyn_enables_module(m, enables)); -} - -/**/ -static int -boot_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? - (m->u.linked->boot)(m) : dyn_boot_module(m)); -} - -/**/ -static int -cleanup_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? - (m->u.linked->cleanup)(m) : dyn_cleanup_module(m)); -} - -/**/ -static int -finish_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? - (m->u.linked->finish)(m) : dyn_finish_module(m)); -} - -/**/ -#else /* !DYNAMIC */ - -/**/ -static int -setup_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? (m->u.linked->setup)(m) : 1); -} - -/**/ -static int -features_module(Module m, char ***features) -{ - return ((m->node.flags & MOD_LINKED) ? (m->u.linked->features)(m, features) - : 1); -} - -/**/ -static int -enables_module(Module m, int **enables) -{ - return ((m->node.flags & MOD_LINKED) ? (m->u.linked->enables)(m, enables) - : 1); -} - -/**/ -static int -boot_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? (m->u.linked->boot)(m) : 1); -} - -/**/ -static int -cleanup_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? (m->u.linked->cleanup)(m) : 1); -} - -/**/ -static int -finish_module(Module m) -{ - return ((m->node.flags & MOD_LINKED) ? (m->u.linked->finish)(m) : 1); -} - -/**/ -#endif /* !DYNAMIC */ - - -/************************************************************************ - * Functions called when manipulating modules - ************************************************************************/ - -/* - * Set the features for the module, which must be loaded - * by now (though may not be fully set up). - * - * Return 0 for success, 1 for failure, 2 if some features - * 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, Feature_enables enablesarr, int flags) -{ - char **features; - int ret = 0; - - if (features_module(m, &features) == 0) { - /* - * Features are supported. If we were passed - * a NULL array, enable all features, else - * enable only the features listed. - * (This may in principle be an empty array, - * although that's not very pointful.) - */ - int *enables = NULL; - if (enables_module(m, &enables)) { - /* If features are supported, enables should be, too */ - if (!(flags & FEAT_IGNORE)) - zwarn("error getting enabled features for module `%s'", - 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 (enablesarr) { - Feature_enables fep; - for (fep = enablesarr; fep->str; fep++) { - char *str = fep->str; - if (*str == '+' || *str == '-') - str++; - if (fep->pat ? pattry(fep->pat, al) : - !strcmp(al, str)) { - /* can't enable it after all, so return 1 */ - ret = 1; - while (fep->str) { - fep->str = fep[1].str; - fep->pat = fep[1].pat; - fep++; - } - if (!fep->pat) - break; - } - } - } - } - } - } - - if (enablesarr) { - Feature_enables fep; - for (fep = enablesarr; fep->str; fep++) { - char **fp, *esp = fep->str; - int on = 1, found = 0; - if (*esp == '+') - esp++; - else if (*esp == '-') { - on = 0; - esp++; - } - for (fp = features; *fp; fp++) - if (fep->pat ? pattry(fep->pat, *fp) : !strcmp(*fp, esp)) { - enables[fp - features] = on; - found++; - if (!fep->pat) - break; - } - if (!found) { - if (!(flags & FEAT_IGNORE)) - zwarn(fep->pat ? - "module `%s' has no feature matching: `%s'" : - "module `%s' has no such feature: `%s'", - m->node.nam, esp); - return 1; - } - } - } else { - /* - * Enable all features. This is used when loading - * without using zmodload -F. - */ - int n_features = arrlen(features); - int *ep; - for (ep = enables; n_features--; ep++) - *ep = 1; - } - - if (enables_module(m, &enables)) - return 2; - } else if (enablesarr) { - 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 ret; -} - -/* - * Boot the module, including setting up features. - * As we've only just loaded the module, we don't yet - * know what features it supports, so we get them passed - * as a string. - * - * Returns 0 if OK, 1 if completely failed, 2 if some features - * couldn't be set up. - */ - -/**/ -static int -do_boot_module(Module m, Feature_enables enablesarr, int silent) -{ - int ret = do_module_features(m, enablesarr, - silent ? FEAT_IGNORE|FEAT_CHECKAUTO : - FEAT_CHECKAUTO); - - if (ret == 1) - return 1; - - if (boot_module(m)) - return 1; - return ret; -} - -/* - * Cleanup the module. - */ - -/**/ -static int -do_cleanup_module(Module m) -{ - return (m->node.flags & MOD_LINKED) ? - (m->u.linked && m->u.linked->cleanup(m)) : - (m->u.handle && cleanup_module(m)); -} - -/* - * Test a module name contains only valid characters: those - * allowed in a shell identifier plus slash. Return 1 if so. - */ - -/**/ -static int -modname_ok(char const *p) -{ - do { - p = itype_end(p, IIDENT, 0); - if (!*p) - return 1; - } while(*p++ == '/'); - return 0; -} - -/* - * High level function to load a module, encapsulating - * all the handling of module functions. - * - * "*enablesstr" is NULL if the caller is not feature-aware; - * then the module should turn on all features. If it - * is not NULL it points to an array of features to be - * turned on. This function is responsible for testing whether - * the module supports those features. - * - * If "silent" is 1, don't issue warnings for errors. - * - * Now returns 0 for success (changed post-4.3.4), - * 1 for complete failure, 2 if some features couldn't be set. - */ - -/**/ -mod_export int -load_module(char const *name, Feature_enables enablesarr, int silent) -{ - Module m; - void *handle = NULL; - Linkedmod linked; - int set, bootret; - - if (!modname_ok(name)) { - if (!silent) - zerr("invalid module name `%s'", name); - return 1; - } - /* - * 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 (!(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)); - if (handle) { - m->u.handle = handle; - m->node.flags |= MOD_SETUP; - } else { - m->u.linked = linked; - m->node.flags |= MOD_SETUP | MOD_LINKED; - } - modulestab->addnode(modulestab, ztrdup(name), m); - - if ((set = setup_module(m)) || - (bootret = do_boot_module(m, enablesarr, silent)) == 1) { - if (!set) - do_cleanup_module(m); - finish_module(m); - delete_module(m); - unqueue_signals(); - return 1; - } - m->node.flags |= MOD_INIT_S | MOD_INIT_B; - m->node.flags &= ~MOD_SETUP; - unqueue_signals(); - return bootret; - } - if (m->node.flags & MOD_SETUP) { - unqueue_signals(); - return 0; - } - 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->node.flags & MOD_BUSY) { - unqueue_signals(); - zerr("circular dependencies for module ;%s", name); - return 1; - } - m->node.flags |= MOD_BUSY; - /* - * TODO: shouldn't we unload the module if one of - * its dependencies fails? - */ - if (m->deps) { - LinkNode n; - for (n = firstnode(m->deps); n; incnode(n)) - if (load_module((char *) getdata(n), NULL, silent) == 1) { - m->node.flags &= ~MOD_BUSY; - unqueue_signals(); - return 1; - } - } - m->node.flags &= ~MOD_BUSY; - if (!m->u.handle) { - handle = NULL; - if (!(linked = module_linked(name)) && - !(handle = do_load_module(name, silent))) { - unqueue_signals(); - return 1; - } - if (handle) { - m->u.handle = handle; - m->node.flags |= MOD_SETUP; - } else { - m->u.linked = 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->node.flags &= ~MOD_SETUP; - unqueue_signals(); - return 1; - } - m->node.flags |= MOD_INIT_S; - } - m->node.flags |= MOD_SETUP; - if ((bootret = do_boot_module(m, enablesarr, silent)) == 1) { - do_cleanup_module(m); - finish_module(m); - if (m->node.flags & MOD_LINKED) - m->u.linked = NULL; - else - m->u.handle = NULL; - m->node.flags &= ~MOD_SETUP; - unqueue_signals(); - return 1; - } - m->node.flags |= MOD_INIT_B; - m->node.flags &= ~MOD_SETUP; - unqueue_signals(); - return bootret; -} - -/* 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 - * 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 - * is to be turned off) or if the module does not support features - * at all. - * The return value is 0 if the module was found or loaded - * (this changed post-4.3.4, because I got so confused---pws), - * 1 if loading failed completely, 2 if some features couldn't be set. - * - * This function behaves like load_module() except that it - * handles the case where the module was already loaded, and - * sets features accordingly. - */ - -/**/ -mod_export int -require_module(const char *module, Feature_enables features, int silent) -{ - Module m = NULL; - int ret = 0; - - /* Resolve aliases and actual loadable module as for load_module */ - queue_signals(); - m = find_module(module, FINDMOD_ALIASP, &module); - if (!m || !m->u.handle || - (m->node.flags & MOD_UNLOAD)) - ret = load_module(module, features, silent); - else - ret = do_module_features(m, features, 0); - unqueue_signals(); - - return ret; -} - -/* - * Indicate that the module named "name" depends on the module - * named "from". - */ - -/**/ -void -add_dep(const char *name, char *from) -{ - LinkNode node; - Module 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 dependencies 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.) - */ - m = find_module(name, FINDMOD_ALIASP|FINDMOD_CREATE, &name); - if (!m->deps) - m->deps = znewlinklist(); - for (node = firstnode(m->deps); - node && strcmp((char *) getdata(node), from); - incnode(node)); - if (!node) - zaddlinknode(m->deps, ztrdup(from)); -} - -/* - * Function to be used when scanning the builtins table to - * find and print autoloadable builtins. - */ - -/**/ -static void -autoloadscan(HashNode hn, int printflags) -{ - Builtin bn = (Builtin) hn; - - if(bn->node.flags & BINF_ADDED) - return; - if(printflags & PRINT_LIST) { - fputs("zmodload -ab ", stdout); - if(bn->optstr[0] == '-') - fputs("-- ", stdout); - quotedzputs(bn->optstr, stdout); - if(strcmp(bn->node.nam, bn->optstr)) { - putchar(' '); - quotedzputs(bn->node.nam, stdout); - } - } else { - nicezputs(bn->node.nam, stdout); - if(strcmp(bn->node.nam, bn->optstr)) { - fputs(" (", stdout); - nicezputs(bn->optstr, stdout); - putchar(')'); - } - } - putchar('\n'); -} - - -/************************************************************************ - * Handling for the zmodload builtin and its various options. - ************************************************************************/ - -/* - * Main builtin entry point for zmodload. - */ - -/**/ -int -bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func)) -{ - int ops_bcpf = OPT_ISSET(ops,'b') || OPT_ISSET(ops,'c') || - OPT_ISSET(ops,'p') || OPT_ISSET(ops,'f'); - int ops_au = OPT_ISSET(ops,'a') || OPT_ISSET(ops,'u'); - int ret = 1, autoopts; - /* options only allowed with -F */ - char *fonly = "lP", *fp; - - if (ops_bcpf && !ops_au) { - zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u"); - return 1; - } - if (OPT_ISSET(ops,'F') && (ops_bcpf || OPT_ISSET(ops,'u'))) { - zwarnnam(nam, "-b, -c, -f, -p and -u cannot be combined with -F"); - return 1; - } - if (OPT_ISSET(ops,'A') || OPT_ISSET(ops,'R')) { - if (ops_bcpf || ops_au || OPT_ISSET(ops,'d') || - (OPT_ISSET(ops,'R') && OPT_ISSET(ops,'e'))) { - zwarnnam(nam, "illegal flags combined with -A or -R"); - return 1; - } - if (!OPT_ISSET(ops,'e')) - return bin_zmodload_alias(nam, args, ops); - } - if (OPT_ISSET(ops,'d') && OPT_ISSET(ops,'a')) { - zwarnnam(nam, "-d cannot be combined with -a"); - return 1; - } - if (OPT_ISSET(ops,'u') && !*args) { - zwarnnam(nam, "what do you want to unload?"); - return 1; - } - if (OPT_ISSET(ops,'e') && (OPT_ISSET(ops,'I') || OPT_ISSET(ops,'L') || - (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 ... */ - return 1; - } - for (fp = fonly; *fp; fp++) { - if (OPT_ISSET(ops,STOUC(*fp)) && !OPT_ISSET(ops,'F')) { - zwarnnam(nam, "-%c is only allowed with -F", *fp); - return 1; - } - } - queue_signals(); - if (OPT_ISSET(ops, 'F')) - ret = bin_zmodload_features(nam, args, ops); - else if (OPT_ISSET(ops,'e')) - ret = bin_zmodload_exist(nam, args, ops); - else if (OPT_ISSET(ops,'d')) - ret = bin_zmodload_dep(nam, args, ops); - else if ((autoopts = OPT_ISSET(ops, 'b') + OPT_ISSET(ops, 'c') + - OPT_ISSET(ops, 'p') + OPT_ISSET(ops, 'f')) || - /* zmodload -a is equivalent to zmodload -ab, annoyingly */ - OPT_ISSET(ops, 'a')) { - if (autoopts > 1) { - zwarnnam(nam, "use only one of -b, -c, or -p"); - ret = 1; - } else - ret = bin_zmodload_auto(nam, args, ops); - } else - ret = bin_zmodload_load(nam, args, ops); - unqueue_signals(); - - return ret; -} - -/* zmodload -A */ - -/**/ -static int -bin_zmodload_alias(char *nam, char **args, Options 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. - */ - Module m; - - if (!*args) { - if (OPT_ISSET(ops,'R')) { - zwarnnam(nam, "no module alias to remove"); - return 1; - } - scanhashtable(modulestab, 1, MOD_ALIAS, 0, - modulestab->printnode, - OPT_ISSET(ops,'L') ? PRINTMOD_LIST : 0); - return 0; - } - - for (; *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); - return 1; - } - if (OPT_ISSET(ops,'R')) { - if (aliasname) { - zwarnnam(nam, "bad syntax for removing module alias: %s", - *args); - return 1; - } - 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(m); - } else { - zwarnnam(nam, "no such module alias: %s", *args); - return 1; - } - } else { - if (aliasname) { - const char *mname = aliasname; - if (!modname_ok(aliasname)) { - zwarnnam(nam, "invalid module name `%s'", aliasname); - return 1; - } - do { - if (!strcmp(mname, *args)) { - zwarnnam(nam, "module alias would refer to itself: %s", - *args); - return 1; - } - } while ((m = find_module(mname, 0, NULL)) - && (m->node.flags & MOD_ALIAS) - && (mname = m->u.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->node.flags = MOD_ALIAS; - modulestab->addnode(modulestab, ztrdup(*args), m); - } - m->u.alias = ztrdup(aliasname); - } else { - 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; - } - } else { - zwarnnam(nam, "no such module alias: %s", *args); - return 1; - } - } - } - } - - return 0; -} - -/* zmodload -e (without -F) */ - -/**/ -static int -bin_zmodload_exist(UNUSED(char *nam), char **args, Options ops) -{ - Module m; - - if (!*args) { - 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 (!(m = find_module(*args, FINDMOD_ALIASP, NULL)) - || !m->u.handle - || (m->node.flags & MOD_UNLOAD)) - ret = 1; - } - return ret; - } -} - -/* zmodload -d */ - -/**/ -static int -bin_zmodload_dep(UNUSED(char *nam), char **args, Options ops) -{ - Module m; - if (OPT_ISSET(ops,'u')) { - /* remove dependencies, which can't pertain to aliases */ - const char *tnam = *args++; - m = find_module(tnam, FINDMOD_ALIASP, &tnam); - if (!m) - return 0; - if (*args && m->deps) { - do { - 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)) { - freelinklist(m->deps, freestr); - m->deps = NULL; - } - } else { - if (m->deps) { - freelinklist(m->deps, freestr); - m->deps = NULL; - } - } - if (!m->deps && !m->u.handle) - delete_module(m); - return 0; - } else if (!args[0] || !args[1]) { - /* list dependencies */ - 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 { - /* add dependencies */ - int ret = 0; - char *tnam = *args++; - - for (; *args; args++) - add_dep(tnam, *args); - return ret; - } -} - -/* - * Function for scanning the parameter table to find and print - * out autoloadable parameters. - */ - -static void -printautoparams(HashNode hn, int lon) -{ - Param pm = (Param) hn; - - if (pm->node.flags & PM_AUTOLOAD) { - if (lon) - printf("zmodload -ap %s %s\n", pm->u.str, pm->node.nam); - else - printf("%s (%s)\n", pm->node.nam, pm->u.str); - } -} - -/* zmodload -a/u [bcpf] */ - -/**/ -static int -bin_zmodload_auto(char *nam, char **args, Options ops) -{ - int fchar, flags; - char *modnam; - - if (OPT_ISSET(ops,'c')) { - if (!*args) { - /* list autoloaded conditions */ - Conddef p; - - for (p = condtab; p; p = p->next) { - if (p->module) { - if (OPT_ISSET(ops,'L')) { - fputs("zmodload -ac", stdout); - if (p->flags & CONDF_INFIX) - putchar('I'); - printf(" %s %s\n", p->module, p->name); - } else { - if (p->flags & CONDF_INFIX) - fputs("infix ", stdout); - else - fputs("post ", stdout); - printf("%s (%s)\n",p->name, p->module); - } - } - } - return 0; - } - fchar = OPT_ISSET(ops,'I') ? 'C' : 'c'; - } else if (OPT_ISSET(ops,'p')) { - if (!*args) { - /* list autoloaded parameters */ - scanhashtable(paramtab, 1, 0, 0, printautoparams, - OPT_ISSET(ops,'L')); - return 0; - } - fchar = 'p'; - } else if (OPT_ISSET(ops,'f')) { - if (!*args) { - /* list autoloaded math functions */ - MathFunc p; - - for (p = mathfuncs; p; p = p->next) { - if (!(p->flags & MFF_USERFUNC) && p->module) { - if (OPT_ISSET(ops,'L')) { - fputs("zmodload -af", stdout); - printf(" %s %s\n", p->module, p->name); - } else - printf("%s (%s)\n",p->name, p->module); - } - } - return 0; - } - fchar = 'f'; - } else { - /* builtins are the default; zmodload -ab or just zmodload -a */ - if (!*args) { - /* list autoloaded builtins */ - scanhashtable(builtintab, 1, 0, 0, - autoloadscan, OPT_ISSET(ops,'L') ? PRINT_LIST : 0); - return 0; - } - fchar = 'b'; - } - - flags = FEAT_AUTOALL; - if (OPT_ISSET(ops,'i')) - flags |= FEAT_IGNORE; - if (OPT_ISSET(ops,'u')) { - /* remove autoload */ - flags |= FEAT_REMOVE; - modnam = NULL; - } else { - /* add autoload */ - modnam = *args; - - if (args[1]) - args++; - } - return autofeatures(nam, modnam, args, fchar, flags); -} - -/* Backend handler for zmodload -u */ - -/**/ -int -unload_module(Module m) -{ - int del; - - /* - * Only unload the real module, so resolve aliases. - */ - if (m->node.flags & MOD_ALIAS) { - m = find_module(m->u.alias, FINDMOD_ALIASP, NULL); - if (!m) - return 1; - } - /* - * 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; - m->node.flags &= ~(MOD_INIT_B|MOD_INIT_S); - - 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; - } - } 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)) { - 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); - } - } - } - 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; -} - -/* - * Unload a module by name (modname); nam is the command name. - * Optionally don't print some error messages (always print - * dependency errors). - */ - -/**/ -int -unload_named_module(char *modname, char *nam, int silent) -{ - const char *mname; - Module m; - int ret = 0; - - m = find_module(modname, FINDMOD_ALIASP, &mname); - if (m) { - int i, del = 0; - Module dm; - - 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 (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; - } - } - } - } - } - if (del) - m->wrapper++; - if (unload_module(m)) - ret = 1; - if (del) - m->wrapper--; - } else if (!silent) { - zwarnnam(nam, "no such module %s", modname); - ret = 1; - } - - return ret; -} - -/* zmodload -u without -d */ - -/**/ -static int -bin_zmodload_load(char *nam, char **args, Options ops) -{ - int ret = 0; - if(OPT_ISSET(ops,'u')) { - /* unload modules */ - for(; *args; args++) { - if (unload_named_module(*args, nam, OPT_ISSET(ops,'i'))) - ret = 1; - } - return ret; - } else if(!*args) { - /* list modules */ - scanhashtable(modulestab, 1, 0, MOD_UNLOAD|MOD_ALIAS, - modulestab->printnode, - OPT_ISSET(ops,'L') ? PRINTMOD_LIST : 0); - return 0; - } else { - /* load modules */ - for (; *args; args++) { - int tmpret = require_module(*args, NULL, OPT_ISSET(ops,'s')); - if (tmpret && ret != 1) - ret = tmpret; - } - - return ret; - } -} - -/* zmodload -F */ - -/**/ -static int -bin_zmodload_features(const char *nam, char **args, Options ops) -{ - int iarg; - char *modname = *args; - Patprog *patprogs; - Feature_enables features, fep; - - 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; - } - - if (OPT_ISSET(ops,'m')) { - char **argp; - Patprog *patprogp; - - /* not NULL terminated */ - patprogp = patprogs = - (Patprog *)zhalloc(arrlen(args)*sizeof(Patprog)); - for (argp = args; *argp; argp++, patprogp++) { - char *arg = *argp; - if (*arg == '+' || *arg == '-') - arg++; - tokenize(arg); - *patprogp = patcompile(arg, 0, 0); - } - } else - patprogs = NULL; - - if (OPT_ISSET(ops,'l') || OPT_ISSET(ops,'L') || OPT_ISSET(ops,'e')) { - /* - * With option 'l', list all features one per line with + or -. - * With option 'L', list as zmodload statement showing - * only options turned on. - * With both options, list as zmodload showing options - * to be turned both on and off. - */ - Module m; - char **features, **fp, **arrset = NULL, **arrp = NULL; - int *enables = NULL, *ep; - char *param = OPT_ARG_SAFE(ops,'P'); - - 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->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->node.nam); - return 1; - } - for (arrp = args, iarg = 0; *arrp; arrp++, iarg++) { - char *arg = *arrp; - int on, found = 0; - if (*arg == '-') { - on = 0; - arg++; - } else if (*arg == '+') { - on = 1; - arg++; - } else - on = -1; - for (fp = features, ep = enables; *fp; fp++, ep++) { - if (patprogs ? pattry(patprogs[iarg], *fp) : - !strcmp(arg, *fp)) { - /* for -e, check given state, if any */ - if (OPT_ISSET(ops,'e') && on != -1 && - on != (*ep & 1)) - return 1; - found++; - if (!patprogs) - break; - } - } - if (!found) { - if (!OPT_ISSET(ops,'e')) - zwarnnam(nam, patprogs ? - "module `%s' has no feature matching: `%s'" : - "module `%s' has no such feature: `%s'", - modname, *arrp); - return 1; - } - } - if (OPT_ISSET(ops,'e')) /* yep, everything we want exists */ - return 0; - if (param) { - int arrlen = 0; - for (fp = features, ep = enables; *fp; fp++, ep++) { - if (OPT_ISSET(ops, 'L') && !OPT_ISSET(ops, 'l') && - !*ep) - continue; - if (*args) { - char **argp; - for (argp = args, iarg = 0; *argp; argp++, iarg++) { - char *arg = *argp; - /* ignore +/- for consistency */ - if (*arg == '+' || *arg == '-') - arg++; - if (patprogs ? pattry(patprogs[iarg], *fp) : - !strcmp(*fp, arg)) - break; - } - if (!*argp) - continue; - } - arrlen++; - } - arrp = arrset = zalloc(sizeof(char *) * (arrlen+1)); - } else if (OPT_ISSET(ops, 'L')) - printf("zmodload -F %s ", m->node.nam); - for (fp = features, ep = enables; *fp; fp++, ep++) { - char *onoff; - int term; - if (*args) { - char **argp; - for (argp = args, iarg = 0; *argp; argp++, iarg++) { - char *arg = *argp; - if (*arg == '+' || *arg == '-') - arg++; - if (patprogs ? pattry(patprogs[iarg], *fp) : - !strcmp(*fp, *argp)) - break; - } - if (!*argp) - continue; - } - if (OPT_ISSET(ops, 'L') && !OPT_ISSET(ops, 'l')) { - if (!*ep) - continue; - onoff = ""; - } else if (*ep) { - onoff = "+"; - } else { - onoff = "-"; - } - if (param) { - *arrp++ = bicat(onoff, *fp); - } else { - if (OPT_ISSET(ops, 'L') && fp[1]) { - term = ' '; - } else { - term = '\n'; - } - printf("%s%s%c", onoff, *fp, term); - } - } - if (param) { - *arrp = NULL; - if (!setaparam(param, arrset)) - return 1; - } - return 0; - } else if (OPT_ISSET(ops,'P')) { - zwarnnam(nam, "-P can only be used with -l or -L"); - return 1; - } else if (OPT_ISSET(ops,'a')) { - if (OPT_ISSET(ops,'m')) { - zwarnnam(nam, "-m cannot be used with -a"); - return 1; - } - /* - * 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); - } - - fep = features = - (Feature_enables)zhalloc((arrlen(args)+1)*sizeof(*fep)); - - while (*args) { - fep->str = *args++; - fep->pat = patprogs ? *patprogs++ : NULL; - fep++; - } - fep->str = NULL; - fep->pat = NULL; - - return require_module(modname, features, OPT_ISSET(ops,'s')); -} - - -/************************************************************************ - * Generic feature support. - * These functions are designed to be called by modules. - ************************************************************************/ - -/* - * Construct a features array out of the list of concrete - * features given, leaving space for any abstract features - * to be added by the module itself. - * - * Note the memory is from the heap. - */ - -/**/ -mod_export char ** -featuresarray(UNUSED(Module m), Features f) -{ - int bn_size = f->bn_size, cd_size = f->cd_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; - MathFunc mfp = f->mf_list; - Paramdef pdp = f->pd_list; - char **features = (char **)zhalloc((features_size + 1) * sizeof(char *)); - char **featurep = features; - - while (bn_size--) - *featurep++ = dyncat("b:", (bnp++)->node.nam); - while (cd_size--) { - *featurep++ = dyncat((cdp->flags & CONDF_INFIX) ? "C:" : "c:", - cdp->name); - cdp++; - } - while (mf_size--) - *featurep++ = dyncat("f:", (mfp++)->name); - while (pd_size--) - *featurep++ = dyncat("p:", (pdp++)->name); - - features[features_size] = NULL; - return features; -} - -/* - * Return the current set of enables for the features in a - * module using heap memory. Leave space for abstract - * features. The array is not zero terminated. - */ -/**/ -mod_export int * -getfeatureenables(UNUSED(Module m), Features f) -{ - int bn_size = f->bn_size, cd_size = f->cd_size; - 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; - MathFunc mfp = f->mf_list; - Paramdef pdp = f->pd_list; - int *enables = zhalloc(sizeof(int) * features_size); - int *enablep = enables; - - while (bn_size--) - *enablep++ = ((bnp++)->node.flags & BINF_ADDED) ? 1 : 0; - while (cd_size--) - *enablep++ = ((cdp++)->flags & CONDF_ADDED) ? 1 : 0; - while (mf_size--) - *enablep++ = ((mfp++)->flags & MFF_ADDED) ? 1 : 0; - while (pd_size--) - *enablep++ = (pdp++)->pm ? 1 : 0; - - return enables; -} - -/* - * Add or remove the concrete features passed in arguments, - * depending on the corresponding element of the array e. - * If e is NULL, disable everything. - * Return 0 for success, 1 for failure; does not attempt - * to imitate the return values of addbuiltins() etc. - * Any failure in adding a requested feature is an - * error. - */ - -/**/ -mod_export int -setfeatureenables(Module m, Features f, int *e) -{ - int ret = 0; - - if (f->bn_size) { - 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(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 (e) - e += f->mf_size; - } - if (f->pd_size) { - if (setparamdefs(m->node.nam, f->pd_list, f->pd_size, e)) - ret = 1; - if (e) - e += f->pd_size; - } - return ret; -} - -/* - * Convenient front-end to get or set features which - * can be used in a module enables_() function. - */ - -/**/ -mod_export int -handlefeatures(Module m, Features f, int **enables) -{ - if (!enables || *enables) - return setfeatureenables(m, f, enables ? *enables : NULL); - *enables = getfeatureenables(m, f); - return 0; -} - -/* - * Ensure module "modname" is providing feature with "prefix" - * 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. 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(const char *modname, const char *prefix, const char *feature) -{ - char *f; - struct feature_enables features[2]; - - if (!feature) - return require_module(modname, NULL, 0); - f = dyncat(prefix, feature); - - features[0].str = f; - features[0].pat = NULL; - features[1].str = NULL; - features[1].pat = NULL; - return require_module(modname, features, 0); -} - -/* - * Add autoloadable features for a given module. - */ - -/**/ -int -autofeatures(const char *cmdnam, const char *module, char **features, - int prefchar, int defflags) -{ - int ret = 0, subret; - Module defm, m; - char **modfeatures = NULL; - int *modenables = 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); - (void)enables_module(defm, &modenables); - } - } else - defm = NULL; - - for (; *features; features++) { - char *fnam, *typnam, *feature; - int add, fchar, flags = defflags; - autofeaturefn_t fn; - - if (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 { - feature = *features; - if (*feature == '-') { - add = 0; - feature++; - } else { - add = 1; - if (*feature == '+') - feature++; - } - - if (!*feature || feature[1] != ':') { - zwarnnam(cmdnam, "bad format for autoloadable feature: `%s'", - feature); - ret = 1; - continue; - } - fnam = feature + 2; - fchar = feature[0]; - } - if (flags & FEAT_REMOVE) - add = 0; - - switch (fchar) { - case 'b': - fn = add ? add_autobin : del_autobin; - typnam = "builtin"; - break; - - case 'C': - flags |= FEAT_INFIX; - /* FALLTHROUGH */ - case 'c': - fn = add ? add_autocond : del_autocond; - typnam = "condition"; - 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); - ret = 1; - continue; - } - - if (strchr(fnam, '/')) { - zwarnnam(cmdnam, "%s: `/' is illegal in a %s", fnam, typnam); - ret = 1; - continue; - } - - 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 the feature is already provided by the module, there's - * nothing more to do. - */ - if (modenables[ptr-modfeatures]) - continue; - /* - * Otherwise, marking it for autoload will do the - * right thing when the feature is eventually used. - */ - } - 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) { - /* -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); - break; - - case 2: - zwarnnam(cmdnam, "%s: no such %s", fnam, typnam); - break; - - case 3: - zwarnnam(cmdnam, "%s: %s is already defined", fnam, typnam); - break; - - default: - /* no (further) message needed */ - break; - } - } - } - - return ret; -} |
