openenvutils/commandshell/shell/src/module.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // module.c - deal with dynamic modules
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1996-1997 Zoltán Hidvégi
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Zoltán Hidvégi or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Zoltán Hidvégi and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Zoltán Hidvégi and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Zoltán Hidvégi and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 #include "zsh.mdh"
       
    32 #include "module.pro"
       
    33 
       
    34 #ifdef __SYMBIAN32__
       
    35 #ifdef __WINSCW__
       
    36 #pragma warn_unusedarg off
       
    37 #pragma warn_possunwant off
       
    38 #endif//__WINSCW__
       
    39 #endif//__SYMBIAN32__
       
    40 
       
    41 /* List of linked-in modules. */
       
    42 
       
    43 /**/
       
    44 LinkList linkedmodules;
       
    45 
       
    46 
       
    47 /* The `zsh/main' module contains all the base code that can't actually be *
       
    48  * built as a separate module.  It is initialised by main(), so there's    *
       
    49  * nothing for the boot function to do.                                    */
       
    50 
       
    51 /**/
       
    52 int
       
    53 setup_(UNUSED(Module m))
       
    54 {
       
    55     return 0;
       
    56 }
       
    57 
       
    58 /**/
       
    59 int
       
    60 boot_(UNUSED(Module m))
       
    61 {
       
    62     return 0;
       
    63 }
       
    64 
       
    65 /**/
       
    66 int
       
    67 cleanup_(UNUSED(Module m))
       
    68 {
       
    69     return 0;
       
    70 }
       
    71 
       
    72 /**/
       
    73 int
       
    74 finish_(UNUSED(Module m))
       
    75 {
       
    76     return 0;
       
    77 }
       
    78 
       
    79 /* This registers a builtin module.                                   */
       
    80 
       
    81 /**/
       
    82 void
       
    83 register_module(char *n, Module_func setup, Module_func boot,
       
    84 		Module_func cleanup, Module_func finish)
       
    85 {
       
    86     Linkedmod m;
       
    87 
       
    88     m = (Linkedmod) zalloc(sizeof(*m));
       
    89 
       
    90     m->name = ztrdup(n);
       
    91     m->setup = setup;
       
    92     m->boot = boot;
       
    93     m->cleanup = cleanup;
       
    94     m->finish = finish;
       
    95 
       
    96     zaddlinknode(linkedmodules, m);
       
    97 }
       
    98 
       
    99 /* Print an alias. */
       
   100 
       
   101 /**/
       
   102 static void
       
   103 printmodalias(Module m, Options ops)
       
   104 {
       
   105     if (OPT_ISSET(ops,'L')) {
       
   106 	printf("zmodload -A ");
       
   107 	if (m->nam[0] == '-')
       
   108 	    fputs("-- ", stdout);
       
   109 	quotedzputs(m->nam, stdout);
       
   110 	putchar('=');
       
   111 	quotedzputs(m->u.alias, stdout);
       
   112     } else {
       
   113 	nicezputs(m->nam, stdout);
       
   114 	fputs(" -> ", stdout);
       
   115 	nicezputs(m->u.alias, stdout);
       
   116     }
       
   117     putchar('\n');
       
   118 }
       
   119 
       
   120 /* Check if a module is linked in. */
       
   121 
       
   122 /**/
       
   123 Linkedmod
       
   124 module_linked(char const *name)
       
   125 {
       
   126     LinkNode node;
       
   127 
       
   128     for (node = firstnode(linkedmodules); node; incnode(node))
       
   129 	if (!strcmp(((Linkedmod) getdata(node))->name, name))
       
   130 	    return (Linkedmod) getdata(node);
       
   131 
       
   132     return NULL;
       
   133 }
       
   134 
       
   135 /* addbuiltin() can be used to add a new builtin.  It returns zero on *
       
   136  * success, 1 on failure.  The only possible type of failure is that  *
       
   137  * a builtin with the specified name already exists.  An autoloaded   *
       
   138  * builtin can be replaced using this function.                       */
       
   139 
       
   140 /**/
       
   141 int
       
   142 addbuiltin(Builtin b)
       
   143 {
       
   144     Builtin bn = (Builtin) builtintab->getnode2(builtintab, b->nam);
       
   145     if (bn && (bn->flags & BINF_ADDED))
       
   146 	return 1;
       
   147     if (bn)
       
   148 	builtintab->freenode(builtintab->removenode(builtintab, b->nam));
       
   149     builtintab->addnode(builtintab, b->nam, b);
       
   150     return 0;
       
   151 }
       
   152 
       
   153 /* Add multiple builtins.  binl points to a table of `size' builtin      *
       
   154  * structures.  Those for which (.flags & BINF_ADDED) is false are to be *
       
   155  * added; that flag is set if they succeed.  If any fail, an error       *
       
   156  * message is printed, using nam as the leading name.  Returns 1 if all  *
       
   157  * additions succeed, 2 if some succeed and some fail, and 0 if all (and *
       
   158  * at least 1) fail.  The usual usage in a boot_*() function would be    *
       
   159  *  return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); */
       
   160 
       
   161 /**/
       
   162 mod_export int
       
   163 addbuiltins(char const *nam, Builtin binl, int size)
       
   164 {
       
   165     int hads = 0, hadf = 0, n;
       
   166 
       
   167     for(n = 0; n < size; n++) {
       
   168 	Builtin b = &binl[n];
       
   169 	if(b->flags & BINF_ADDED)
       
   170 	    continue;
       
   171 	if(addbuiltin(b)) {
       
   172 	    zwarnnam(nam, "name clash when adding builtin `%s'", b->nam, 0);
       
   173 	    hadf = 1;
       
   174 	} else {
       
   175 	    b->flags |= BINF_ADDED;
       
   176 	    hads = 2;
       
   177 	}
       
   178     }
       
   179     return hadf ? hads : 1;
       
   180 }
       
   181 
       
   182 /* The list of function wrappers defined. */
       
   183 
       
   184 /**/
       
   185 FuncWrap wrappers;
       
   186 
       
   187 /* This adds a definition for a wrapper. Return value is one in case of *
       
   188  * error and zero if all went fine. */
       
   189 
       
   190 /**/
       
   191 mod_export int
       
   192 addwrapper(Module m, FuncWrap w)
       
   193 {
       
   194     FuncWrap p, q;
       
   195 
       
   196     /*
       
   197      * We can't add a wrapper to an alias, since it's supposed
       
   198      * to behave identically to the resolved module.  This shouldn't
       
   199      * happen since we usually add wrappers when a real module is
       
   200      * loaded.
       
   201      */
       
   202     if (m->flags & MOD_ALIAS)
       
   203 	return 1;
       
   204 
       
   205     if (w->flags & WRAPF_ADDED)
       
   206 	return 1;
       
   207     for (p = wrappers, q = NULL; p; q = p, p = p->next);
       
   208     if (q)
       
   209 	q->next = w;
       
   210     else
       
   211 	wrappers = w;
       
   212     w->next = NULL;
       
   213     w->flags |= WRAPF_ADDED;
       
   214     w->module = m;
       
   215 
       
   216     return 0;
       
   217 }
       
   218 
       
   219 /* $module_path ($MODULE_PATH) */
       
   220 
       
   221 /**/
       
   222 char **module_path;
       
   223 
       
   224 /* List of modules */
       
   225 
       
   226 /**/
       
   227 mod_export LinkList modules;
       
   228 
       
   229 /* Define an autoloadable builtin.  It returns 0 on success, or 1 on *
       
   230  * failure.  The only possible cause of failure is that a builtin    *
       
   231  * with the specified name already exists.                           */
       
   232 
       
   233 /**/
       
   234 int
       
   235 add_autobin(char *nam, char *module)
       
   236 {
       
   237     Builtin bn = zshcalloc(sizeof(*bn));
       
   238     bn->nam = ztrdup(nam);
       
   239     bn->optstr = ztrdup(module);
       
   240     return addbuiltin(bn);
       
   241 }
       
   242 
       
   243 /* Remove the builtin added previously by addbuiltin().  Returns *
       
   244  * zero on succes and -1 if there is no builtin with that name.  */
       
   245 
       
   246 /**/
       
   247 int
       
   248 deletebuiltin(char *nam)
       
   249 {
       
   250     Builtin bn;
       
   251 
       
   252     bn = (Builtin) builtintab->removenode(builtintab, nam);
       
   253     if (!bn)
       
   254 	return -1;
       
   255     builtintab->freenode((HashNode)bn);
       
   256     return 0;
       
   257 }
       
   258 
       
   259 /* Delete multiple builtins.  binl points to a table of `size' builtin  *
       
   260  * structures.  Those for which (.flags & BINF_ADDED) is true are to be *
       
   261  * deleted; that flag is cleared.  If any fail, an error message is     *
       
   262  * printed, using nam as the leading name.  Returns 1 if all deletions  *
       
   263  * succeed, 2 if some succeed and some fail, and 0 if all (and at least *
       
   264  * 1) fail.  In normal use, from a cleanup_*() function, this return    *
       
   265  * value would be ignored -- the only cause of failure would be that a  *
       
   266  * wayward module had deleted our builtin without telling us.           */
       
   267 
       
   268 /**/
       
   269 mod_export int
       
   270 deletebuiltins(char const *nam, Builtin binl, int size)
       
   271 {
       
   272     int hads = 0, hadf = 0, n;
       
   273 
       
   274     for(n = 0; n < size; n++) {
       
   275 	Builtin b = &binl[n];
       
   276 	if(!(b->flags & BINF_ADDED))
       
   277 	    continue;
       
   278 	if(deletebuiltin(b->nam)) {
       
   279 	    zwarnnam(nam, "builtin `%s' already deleted", b->nam, 0);
       
   280 	    hadf = 1;
       
   281 	} else
       
   282 	    hads = 2;
       
   283 	b->flags &= ~BINF_ADDED;
       
   284     }
       
   285     return hadf ? hads : 1;
       
   286 }
       
   287 
       
   288 /* This removes the given wrapper definition from the list. Returned is *
       
   289  * one in case of error and zero otherwise. */
       
   290 
       
   291 /**/
       
   292 mod_export int
       
   293 deletewrapper(Module m, FuncWrap w)
       
   294 {
       
   295     FuncWrap p, q;
       
   296 
       
   297     if (m->flags & MOD_ALIAS)
       
   298 	return 1;
       
   299 
       
   300     if (w->flags & WRAPF_ADDED) {
       
   301 	for (p = wrappers, q = NULL; p && p != w; q = p, p = p->next);
       
   302 
       
   303 	if (p) {
       
   304 	    if (q)
       
   305 		q->next = p->next;
       
   306 	    else
       
   307 		wrappers = p->next;
       
   308 	    p->flags &= ~WRAPF_ADDED;
       
   309 
       
   310 	    return 0;
       
   311 	}
       
   312     }
       
   313     return 1;
       
   314 }
       
   315 
       
   316 /**/
       
   317 #ifdef DYNAMIC
       
   318 
       
   319 /**/
       
   320 #ifdef AIXDYNAMIC
       
   321 
       
   322 #include <sys/ldr.h>
       
   323 
       
   324 static char *dlerrstr[256];
       
   325 
       
   326 static void *
       
   327 load_and_bind(const char *fn)
       
   328 {
       
   329     void *ret = (void *) load((char *) fn, L_NOAUTODEFER, NULL);
       
   330 
       
   331     if (ret) {
       
   332 	LinkNode node;
       
   333 	int err = loadbind(0, (void *) addbuiltin, ret);
       
   334 	for (node = firstnode(modules); !err && node; incnode(node)) {
       
   335 	    Module m = (Module) getdata(node);
       
   336 	    if (!(m->flags & MOD_ALIAS) &&
       
   337 		m->u.handle && !(m->flags & MOD_LINKED))
       
   338 		err |= loadbind(0, m->u.handle, ret);
       
   339 	}
       
   340 
       
   341 	if (err) {
       
   342 	    loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr));
       
   343 	    unload(ret);
       
   344 	    ret = NULL;
       
   345 	}
       
   346     } else
       
   347 	loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr));
       
   348 
       
   349     return ret;
       
   350 }
       
   351 
       
   352 #define dlopen(X,Y) load_and_bind(X)
       
   353 #define dlclose(X)  unload(X)
       
   354 #define dlerror()   (dlerrstr[0])
       
   355 
       
   356 /**/
       
   357 #else
       
   358 
       
   359 #ifdef HAVE_DLFCN_H
       
   360 # if defined(HAVE_DL_H) && defined(HPUXDYNAMIC)
       
   361 #  include <dl.h>
       
   362 # else
       
   363 #  include <dlfcn.h>
       
   364 # endif
       
   365 #else
       
   366 # ifdef HAVE_DL_H
       
   367 #  include <dl.h>
       
   368 #  define RTLD_LAZY BIND_DEFERRED
       
   369 #  define RTLD_GLOBAL DYNAMIC_PATH
       
   370 # else
       
   371 #  include <sys/types.h>
       
   372 #  include <nlist.h>
       
   373 #  include <link.h>
       
   374 # endif
       
   375 #endif
       
   376 
       
   377 /**/
       
   378 #ifdef HPUXDYNAMIC
       
   379 # define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
       
   380 # define dlclose(handle) shl_unload((shl_t)(handle))
       
   381 
       
   382 static
       
   383 void *
       
   384 hpux_dlsym(void *handle, char *name)
       
   385 {
       
   386     void *sym_addr;
       
   387     if (!shl_findsym((shl_t *)&handle, name, TYPE_UNDEFINED, &sym_addr))
       
   388 	return sym_addr;
       
   389     return NULL;
       
   390 }
       
   391 
       
   392 # define dlsym(handle,name) hpux_dlsym(handle,name)
       
   393 # define dlerror() 0
       
   394 #else
       
   395 # ifndef HAVE_DLCLOSE
       
   396 #  define dlclose(X) ((X), 0)
       
   397 # endif
       
   398 /**/
       
   399 #endif
       
   400 
       
   401 #ifdef DLSYM_NEEDS_UNDERSCORE
       
   402 # define STR_SETUP     "_setup_"
       
   403 # define STR_BOOT      "_boot_"
       
   404 # define STR_CLEANUP   "_cleanup_"
       
   405 # define STR_FINISH    "_finish_"
       
   406 #else /* !DLSYM_NEEDS_UNDERSCORE */
       
   407 # define STR_SETUP     "setup_"
       
   408 # define STR_BOOT      "boot_"
       
   409 # define STR_CLEANUP   "cleanup_"
       
   410 # define STR_FINISH    "finish_"
       
   411 #endif /* !DLSYM_NEEDS_UNDERSCORE */
       
   412 
       
   413 /**/
       
   414 #endif /* !AIXDYNAMIC */
       
   415 
       
   416 #ifndef RTLD_LAZY
       
   417 # define RTLD_LAZY 1
       
   418 #endif
       
   419 #ifndef RTLD_GLOBAL
       
   420 # define RTLD_GLOBAL 0
       
   421 #endif
       
   422 
       
   423 /**/
       
   424 static void *
       
   425 try_load_module(char const *name)
       
   426 {
       
   427     char buf[PATH_MAX + 1];
       
   428     char **pp;
       
   429     void *ret = NULL;
       
   430     int l;
       
   431 
       
   432     l = 1 + strlen(name) + 1 + strlen(DL_EXT);
       
   433     for (pp = module_path; !ret && *pp; pp++) {
       
   434 	if (l + (**pp ? strlen(*pp) : 1) > PATH_MAX)
       
   435 	    continue;
       
   436 	sprintf(buf, "%s/%s.%s", **pp ? *pp : ".", name, DL_EXT);
       
   437 	ret = dlopen(unmeta(buf), RTLD_LAZY | RTLD_GLOBAL);
       
   438     }
       
   439 
       
   440     return ret;
       
   441 }
       
   442 
       
   443 /**/
       
   444 static void *
       
   445 do_load_module(char const *name)
       
   446 {
       
   447     void *ret;
       
   448 
       
   449     ret = try_load_module(name);
       
   450     if (!ret) {
       
   451 	int waserr = errflag;
       
   452 	zerr("failed to load module: %s", name, 0);
       
   453 	errflag = waserr;
       
   454     }
       
   455     return ret;
       
   456 }
       
   457 
       
   458 /**/
       
   459 #else /* !DYNAMIC */
       
   460 
       
   461 /**/
       
   462 static void *
       
   463 do_load_module(char const *name)
       
   464 {
       
   465     int waserr = errflag;
       
   466 
       
   467     zerr("failed to load module: %s", name, 0);
       
   468     errflag = waserr;
       
   469 
       
   470     return NULL;
       
   471 }
       
   472 
       
   473 /**/
       
   474 #endif /* !DYNAMIC */
       
   475 
       
   476 /*
       
   477  * Find a module in the list.
       
   478  * If aliasp is non-zero, resolve any aliases to the underlying module.
       
   479  * If namep is set, this is set to point to the last alias value resolved,
       
   480  *   even if that module was not loaded. or the module name if no aliases.
       
   481  *   Hence this is always the physical module to load in a chain of aliases.
       
   482  * Return NULL if the module named is not stored as a structure, or if we were
       
   483  * resolving aliases and the final module named is not stored as a
       
   484  * structure.
       
   485  *
       
   486  * TODO: now we have aliases, there may be some merit in using a hash
       
   487  * table instead of a linked list.
       
   488  */
       
   489 /**/
       
   490 static LinkNode
       
   491 find_module(const char *name, int aliasp, const char **namep)
       
   492 {
       
   493     Module m;
       
   494     LinkNode node;
       
   495 
       
   496     for (node = firstnode(modules); node; incnode(node)) {
       
   497 	m = (Module) getdata(node);
       
   498 	if (!strcmp(m->nam, name)) {
       
   499 	    if (aliasp && (m->flags & MOD_ALIAS)) {
       
   500 		if (namep)
       
   501 		    *namep = m->u.alias;
       
   502 		return find_module(m->u.alias, 1, namep);
       
   503 	    }
       
   504 	    if (namep)
       
   505 		*namep = m->nam;
       
   506 	    return node;
       
   507 	}
       
   508     }
       
   509     return NULL;
       
   510 }
       
   511 
       
   512 /*
       
   513  * Unlink and free a module node from the linked list.
       
   514  */
       
   515 
       
   516 /**/
       
   517 static void
       
   518 delete_module(LinkNode node)
       
   519 {
       
   520     Module m = (Module) remnode(modules, node);
       
   521 
       
   522     if (m->flags & MOD_ALIAS)
       
   523 	zsfree(m->u.alias);
       
   524     zsfree(m->nam);
       
   525     if (m->deps)
       
   526 	freelinklist(m->deps, freestr);
       
   527     zfree(m, sizeof(*m));
       
   528 }
       
   529 
       
   530 /**/
       
   531 mod_export int
       
   532 module_loaded(const char *name)
       
   533 {
       
   534     LinkNode node;
       
   535     Module m;
       
   536 
       
   537     return ((node = find_module(name, 1, NULL)) &&
       
   538 	    (m = ((Module) getdata(node)))->u.handle &&
       
   539 	    !(m->flags & MOD_UNLOAD));
       
   540 }
       
   541 
       
   542 /*
       
   543  * Setup and cleanup functions:  we don't search for aliases here,
       
   544  * since they should have been resolved before we try to load or unload
       
   545  * the module.
       
   546  */
       
   547 
       
   548 /**/
       
   549 #ifdef DYNAMIC
       
   550 
       
   551 /**/
       
   552 #ifdef AIXDYNAMIC
       
   553 
       
   554 /**/
       
   555 static int
       
   556 dyn_setup_module(Module m)
       
   557 {
       
   558     return ((int (*)_((int,Module))) m->u.handle)(0, m);
       
   559 }
       
   560 
       
   561 /**/
       
   562 static int
       
   563 dyn_boot_module(Module m)
       
   564 {
       
   565     return ((int (*)_((int,Module))) m->u.handle)(1, m);
       
   566 }
       
   567 
       
   568 /**/
       
   569 static int
       
   570 dyn_cleanup_module(Module m)
       
   571 {
       
   572     return ((int (*)_((int,Module))) m->u.handle)(2, m);
       
   573 }
       
   574 
       
   575 /**/
       
   576 static int
       
   577 dyn_finish_module(Module m)
       
   578 {
       
   579     return ((int (*)_((int,Module))) m->u.handle)(3, m);
       
   580 }
       
   581 
       
   582 /**/
       
   583 #else
       
   584 
       
   585 static Module_func
       
   586 module_func(Module m, char *name)
       
   587 {
       
   588 #ifdef DYNAMIC_NAME_CLASH_OK
       
   589     return (Module_func) dlsym(m->u.handle, name);
       
   590 #else /* !DYNAMIC_NAME_CLASH_OK */
       
   591     VARARR(char, buf, strlen(name) + strlen(m->nam)*2 + 1);
       
   592     char const *p;
       
   593     char *q;
       
   594     strcpy(buf, name);
       
   595     q = strchr(buf, 0);
       
   596     for(p = m->nam; *p; p++) {
       
   597 	if(*p == '/') {
       
   598 	    *q++ = 'Q';
       
   599 	    *q++ = 's';
       
   600 	} else if(*p == '_') {
       
   601 	    *q++ = 'Q';
       
   602 	    *q++ = 'u';
       
   603 	} else if(*p == 'Q') {
       
   604 	    *q++ = 'Q';
       
   605 	    *q++ = 'q';
       
   606 	} else
       
   607 	    *q++ = *p;
       
   608     }
       
   609     *q = 0;
       
   610     return (Module_func) dlsym(m->u.handle, buf);
       
   611 #endif /* !DYNAMIC_NAME_CLASH_OK */
       
   612 }
       
   613 
       
   614 /**/
       
   615 static int
       
   616 dyn_setup_module(Module m)
       
   617 {
       
   618     Module_func fn = module_func(m, STR_SETUP);
       
   619 
       
   620     if (fn)
       
   621 	return fn(m);
       
   622     zwarnnam(m->nam, "no setup function", NULL, 0);
       
   623     return 1;
       
   624 }
       
   625 
       
   626 /**/
       
   627 static int
       
   628 dyn_boot_module(Module m)
       
   629 {
       
   630     Module_func fn = module_func(m, STR_BOOT);
       
   631 
       
   632     if(fn)
       
   633 	return fn(m);
       
   634     zwarnnam(m->nam, "no boot function", NULL, 0);
       
   635     return 1;
       
   636 }
       
   637 
       
   638 /**/
       
   639 static int
       
   640 dyn_cleanup_module(Module m)
       
   641 {
       
   642     Module_func fn = module_func(m, STR_CLEANUP);
       
   643 
       
   644     if(fn)
       
   645 	return fn(m);
       
   646     zwarnnam(m->nam, "no cleanup function", NULL, 0);
       
   647     return 1;
       
   648 }
       
   649 
       
   650 /* Note that this function does more than just calling finish_foo(), *
       
   651  * it really unloads the module. */
       
   652 
       
   653 /**/
       
   654 static int
       
   655 dyn_finish_module(Module m)
       
   656 {
       
   657     Module_func fn = module_func(m, STR_FINISH);
       
   658     int r;
       
   659 
       
   660     if (fn)
       
   661 	r = fn(m);
       
   662     else {
       
   663 	zwarnnam(m->nam, "no finish function", NULL, 0);
       
   664 	r = 1;
       
   665     }
       
   666     dlclose(m->u.handle);
       
   667     return r;
       
   668 }
       
   669 
       
   670 /**/
       
   671 #endif /* !AIXDYNAMIC */
       
   672 
       
   673 /**/
       
   674 static int
       
   675 setup_module(Module m)
       
   676 {
       
   677     return ((m->flags & MOD_LINKED) ?
       
   678 	    (m->u.linked->setup)(m) : dyn_setup_module(m));
       
   679 }
       
   680 
       
   681 /**/
       
   682 static int
       
   683 boot_module(Module m)
       
   684 {
       
   685     return ((m->flags & MOD_LINKED) ?
       
   686 	    (m->u.linked->boot)(m) : dyn_boot_module(m));
       
   687 }
       
   688 
       
   689 /**/
       
   690 static int
       
   691 cleanup_module(Module m)
       
   692 {
       
   693     return ((m->flags & MOD_LINKED) ?
       
   694 	    (m->u.linked->cleanup)(m) : dyn_cleanup_module(m));
       
   695 }
       
   696 
       
   697 /**/
       
   698 static int
       
   699 finish_module(Module m)
       
   700 {
       
   701     return ((m->flags & MOD_LINKED) ?
       
   702 	    (m->u.linked->finish)(m) : dyn_finish_module(m));
       
   703 }
       
   704 
       
   705 /**/
       
   706 #else /* !DYNAMIC */
       
   707 
       
   708 /**/
       
   709 static int
       
   710 setup_module(Module m)
       
   711 {
       
   712     return ((m->flags & MOD_LINKED) ? (m->u.linked->setup)(m) : 1);
       
   713 }
       
   714 
       
   715 /**/
       
   716 static int
       
   717 boot_module(Module m)
       
   718 {
       
   719     return ((m->flags & MOD_LINKED) ? (m->u.linked->boot)(m) : 1);
       
   720 }
       
   721 
       
   722 /**/
       
   723 static int
       
   724 cleanup_module(Module m)
       
   725 {
       
   726     return ((m->flags & MOD_LINKED) ? (m->u.linked->cleanup)(m) : 1);
       
   727 }
       
   728 
       
   729 /**/
       
   730 static int
       
   731 finish_module(Module m)
       
   732 {
       
   733     return ((m->flags & MOD_LINKED) ? (m->u.linked->finish)(m) : 1);
       
   734 }
       
   735 
       
   736 /**/
       
   737 #endif /* !DYNAMIC */
       
   738 
       
   739 /**/
       
   740 static int
       
   741 modname_ok(char const *p)
       
   742 {
       
   743     do {
       
   744 	if(*p != '_' && !ialnum(*p))
       
   745 	    return 0;
       
   746 	do {
       
   747 	    p++;
       
   748 	} while(*p == '_' || ialnum(*p));
       
   749 	if(!*p)
       
   750 	    return 1;
       
   751     } while(*p++ == '/');
       
   752     return 0;
       
   753 }
       
   754 
       
   755 /**/
       
   756 mod_export int
       
   757 load_module(char const *name)
       
   758 {
       
   759     Module m;
       
   760     void *handle = NULL;
       
   761     Linkedmod linked;
       
   762     LinkNode node, n;
       
   763     int set;
       
   764 
       
   765     if (!modname_ok(name)) {
       
   766 	zerr("invalid module name `%s'", name, 0);
       
   767 	return 0;
       
   768     }
       
   769     /*
       
   770      * The following function call may alter name to the final name in a
       
   771      * chain of aliases.  This makes sure the actual module loaded
       
   772      * is the right one.
       
   773      */
       
   774     queue_signals();
       
   775     if (!(node = find_module(name, 1, &name))) {
       
   776 	if (!(linked = module_linked(name)) &&
       
   777 	    !(handle = do_load_module(name))) {
       
   778 	    unqueue_signals();
       
   779 	    return 0;
       
   780 	}
       
   781 	m = zshcalloc(sizeof(*m));
       
   782 	m->nam = ztrdup(name);
       
   783 	if (handle) {
       
   784 	    m->u.handle = handle;
       
   785 	    m->flags |= MOD_SETUP;
       
   786 	} else {
       
   787 	    m->u.linked = linked;
       
   788 	    m->flags |= MOD_SETUP | MOD_LINKED;
       
   789 	}
       
   790 	node = zaddlinknode(modules, m);
       
   791 
       
   792 	if ((set = setup_module(m)) || boot_module(m)) {
       
   793 	    if (!set)
       
   794 		finish_module(m);
       
   795 	    delete_module(node);
       
   796 	    unqueue_signals();
       
   797 	    return 0;
       
   798 	}
       
   799 	m->flags |= MOD_INIT_S | MOD_INIT_B;
       
   800 	m->flags &= ~MOD_SETUP;
       
   801 	unqueue_signals();
       
   802 	return 1;
       
   803     } 
       
   804     m = (Module) getdata(node);
       
   805     if (m->flags & MOD_SETUP) {
       
   806 	unqueue_signals();
       
   807 	return 1;
       
   808     }
       
   809     if (m->flags & MOD_UNLOAD)
       
   810 	m->flags &= ~MOD_UNLOAD;
       
   811     else if ((m->flags & MOD_LINKED) ? m->u.linked : m->u.handle) {
       
   812 	unqueue_signals();
       
   813 	return 1;
       
   814     }
       
   815     if (m->flags & MOD_BUSY) {
       
   816 	zerr("circular dependencies for module %s", name, 0);
       
   817 	return 0;
       
   818     }
       
   819     m->flags |= MOD_BUSY;
       
   820     if (m->deps)
       
   821 	for (n = firstnode(m->deps); n; incnode(n))
       
   822 	    if (!load_module((char *) getdata(n))) {
       
   823 		m->flags &= ~MOD_BUSY;
       
   824 		unqueue_signals();
       
   825 		return 0;
       
   826 	    }
       
   827     m->flags &= ~MOD_BUSY;
       
   828     if (!m->u.handle) {
       
   829 	handle = NULL;
       
   830 	if (!(linked = module_linked(name)) &&
       
   831 	    !(handle = do_load_module(name))) {
       
   832 	    unqueue_signals();
       
   833 	    return 0;
       
   834 	}
       
   835 	if (handle) {
       
   836 	    m->u.handle = handle;
       
   837 	    m->flags |= MOD_SETUP;
       
   838 	} else {
       
   839 	    m->u.linked = linked;
       
   840 	    m->flags |= MOD_SETUP | MOD_LINKED;
       
   841 	}
       
   842 	if (setup_module(m)) {
       
   843 	    if (handle)
       
   844 		m->u.handle = NULL;
       
   845 	    else
       
   846 		m->u.linked = NULL;
       
   847 	    m->flags &= ~MOD_SETUP;
       
   848 	    unqueue_signals();
       
   849 	    return 0;
       
   850 	}
       
   851 	m->flags |= MOD_INIT_S;
       
   852     }
       
   853     m->flags |= MOD_SETUP;
       
   854     if (boot_module(m)) {
       
   855 	finish_module(m);
       
   856 	if (m->flags & MOD_LINKED)
       
   857 	    m->u.linked = NULL;
       
   858 	else
       
   859 	    m->u.handle = NULL;
       
   860 	m->flags &= ~MOD_SETUP;
       
   861 	unqueue_signals();
       
   862 	return 0;
       
   863     }
       
   864     m->flags |= MOD_INIT_B;
       
   865     m->flags &= ~MOD_SETUP;
       
   866     unqueue_signals();
       
   867     return 1;
       
   868 }
       
   869 
       
   870 /* This ensures that the module with the name given as the second argument
       
   871  * is loaded.
       
   872  * The third argument should be non-zero if the function should complain
       
   873  * about trying to load a module with a full path name in restricted mode.
       
   874  * The last argument should be non-zero if this function should signal an
       
   875  * error if the module is already loaded.
       
   876  * The return value is non-zero if the module was found or loaded. */
       
   877 
       
   878 /**/
       
   879 mod_export int
       
   880 require_module(char *nam, const char *module, UNUSED(int res), int test)
       
   881 {
       
   882     Module m = NULL;
       
   883     LinkNode node;
       
   884     int ret = 1;
       
   885 
       
   886     /* Resolve aliases and actual loadable module as for load_module */
       
   887     queue_signals();
       
   888     node = find_module(module, 1, &module);
       
   889     if (node && (m = ((Module) getdata(node)))->u.handle &&
       
   890 	!(m->flags & MOD_UNLOAD)) {
       
   891 	if (test) {
       
   892 	    unqueue_signals();
       
   893 	    zwarnnam(nam, "module %s already loaded.", module, 0);
       
   894 	    return 0;
       
   895 	}
       
   896     } else
       
   897 	ret = load_module(module);
       
   898     unqueue_signals();
       
   899 
       
   900     return ret;
       
   901 }
       
   902 
       
   903 /**/
       
   904 void
       
   905 add_dep(const char *name, char *from)
       
   906 {
       
   907     LinkNode node;
       
   908     Module m;
       
   909 
       
   910     /*
       
   911      * If we were passed an alias, we must resolve it to a final
       
   912      * module name (and maybe add the corresponding struct), since otherwise
       
   913      * we would need to check all modules to see if they happen
       
   914      * to be aliased to the same thing to implement dependencies properly.
       
   915      *
       
   916      * This should mean that an attempt to add an alias which would
       
   917      * have the same name as a module which has dependencies is correctly
       
   918      * rejected, because then the module named already exists as a non-alias.
       
   919      * Better make sure.  (There's no problem making a an alias which
       
   920      * *points* to a module with dependencies, of course.)
       
   921      */
       
   922     if (!(node = find_module(name, 1, &name))) {
       
   923 	m = zshcalloc(sizeof(*m));
       
   924 	m->nam = ztrdup(name);
       
   925 	zaddlinknode(modules, m);
       
   926     } else
       
   927 	m = (Module) getdata(node);
       
   928     if (!m->deps)
       
   929 	m->deps = znewlinklist();
       
   930     for (node = firstnode(m->deps);
       
   931 	 node && strcmp((char *) getdata(node), from);
       
   932 	 incnode(node));
       
   933     if (!node)
       
   934 	zaddlinknode(m->deps, ztrdup(from));
       
   935 }
       
   936 
       
   937 /**/
       
   938 static void
       
   939 autoloadscan(HashNode hn, int printflags)
       
   940 {
       
   941     Builtin bn = (Builtin) hn;
       
   942 
       
   943     if(bn->flags & BINF_ADDED)
       
   944 	return;
       
   945     if(printflags & PRINT_LIST) {
       
   946 	fputs("zmodload -ab ", stdout);
       
   947 	if(bn->optstr[0] == '-')
       
   948 	    fputs("-- ", stdout);
       
   949 	quotedzputs(bn->optstr, stdout);
       
   950 	if(strcmp(bn->nam, bn->optstr)) {
       
   951 	    putchar(' ');
       
   952 	    quotedzputs(bn->nam, stdout);
       
   953 	}
       
   954     } else {
       
   955 	nicezputs(bn->nam, stdout);
       
   956 	if(strcmp(bn->nam, bn->optstr)) {
       
   957 	    fputs(" (", stdout);
       
   958 	    nicezputs(bn->optstr, stdout);
       
   959 	    putchar(')');
       
   960 	}
       
   961     }
       
   962     putchar('\n');
       
   963 }
       
   964 
       
   965 #ifndef __SYMBIAN32__
       
   966 /**/
       
   967 int
       
   968 bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func))
       
   969 {
       
   970     int ops_bcpf = OPT_ISSET(ops,'b') || OPT_ISSET(ops,'c') || 
       
   971 	OPT_ISSET(ops,'p') || OPT_ISSET(ops,'f');
       
   972     int ops_au = OPT_ISSET(ops,'a') || OPT_ISSET(ops,'u');
       
   973     int ret = 1;
       
   974 
       
   975     if (ops_bcpf && !ops_au) {
       
   976 	zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u",
       
   977 		 NULL, 0);
       
   978 	return 1;
       
   979     }
       
   980     if (OPT_ISSET(ops,'A') || OPT_ISSET(ops,'R')) {
       
   981 	if (ops_bcpf || ops_au || OPT_ISSET(ops,'d') || 
       
   982 	    (OPT_ISSET(ops,'R') && OPT_ISSET(ops,'e'))) {
       
   983 	    zwarnnam(nam, "illegal flags combined with -A or -R", NULL, 0);
       
   984 	    return 1;
       
   985 	}
       
   986 	if (!OPT_ISSET(ops,'e'))
       
   987 	    return bin_zmodload_alias(nam, args, ops);
       
   988     }
       
   989     if (OPT_ISSET(ops,'d') && OPT_ISSET(ops,'a')) {
       
   990 	zwarnnam(nam, "-d cannot be combined with -a", NULL, 0);
       
   991 	return 1;
       
   992     }
       
   993     if (OPT_ISSET(ops,'u') && !*args) {
       
   994 	zwarnnam(nam, "what do you want to unload?", NULL, 0);
       
   995 	return 1;
       
   996     }
       
   997     if (OPT_ISSET(ops,'e') && (OPT_ISSET(ops,'I') || OPT_ISSET(ops,'L') || 
       
   998 			       OPT_ISSET(ops,'a') || OPT_ISSET(ops,'d') ||
       
   999 			       OPT_ISSET(ops,'i') || OPT_ISSET(ops,'u'))) {
       
  1000 	zwarnnam(nam, "-e cannot be combined with other options", NULL, 0);
       
  1001 	return 1;
       
  1002     }
       
  1003     queue_signals();
       
  1004     if (OPT_ISSET(ops,'e'))
       
  1005 	ret = bin_zmodload_exist(nam, args, ops);
       
  1006     else if (OPT_ISSET(ops,'d'))
       
  1007 	ret = bin_zmodload_dep(nam, args, ops);
       
  1008     else if ((OPT_ISSET(ops,'a') || OPT_ISSET(ops,'b')) && 
       
  1009 	     !(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'p') || OPT_ISSET(ops,'f')))
       
  1010 	ret = bin_zmodload_auto(nam, args, ops);
       
  1011     else if (OPT_ISSET(ops,'c') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'p')))
       
  1012 	ret = bin_zmodload_cond(nam, args, ops);
       
  1013     else if (OPT_ISSET(ops,'f') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'p')))
       
  1014 	ret = bin_zmodload_math(nam, args, ops);
       
  1015     else if (OPT_ISSET(ops,'p') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'c')))
       
  1016 	ret = bin_zmodload_param(nam, args, ops);
       
  1017     else if (!(OPT_ISSET(ops,'a') || OPT_ISSET(ops,'b') || 
       
  1018 	       OPT_ISSET(ops,'c') || OPT_ISSET(ops,'p')))
       
  1019 	ret = bin_zmodload_load(nam, args, ops);
       
  1020     else
       
  1021 	zwarnnam(nam, "use only one of -b, -c, or -p", NULL, 0);
       
  1022     unqueue_signals();
       
  1023 
       
  1024     return ret;
       
  1025 }
       
  1026 #endif //#ifndef __SYMBIAN32__
       
  1027 
       
  1028 /**/
       
  1029 static int
       
  1030 bin_zmodload_alias(char *nam, char **args, Options ops)
       
  1031 {
       
  1032     /*
       
  1033      * TODO: while it would be too nasty to have aliases, as opposed
       
  1034      * to real loadable modules, with dependencies --- just what would
       
  1035      * we need to load when, exactly? --- there is in principle no objection
       
  1036      * to making it possible to force an alias onto an existing unloaded
       
  1037      * module which has dependencies.  This would simply transfer
       
  1038      * the dependencies down the line to the aliased-to module name.
       
  1039      * This is actually useful, since then you can alias zsh/zle=mytestzle
       
  1040      * to load another version of zle.  But then what happens when the
       
  1041      * alias is removed?  Do you transfer the dependencies back? And
       
  1042      * suppose other names are aliased to the same file?  It might be
       
  1043      * kettle of fish best left unwormed.
       
  1044      */
       
  1045     LinkNode node;
       
  1046     Module m;
       
  1047     int ret = 0;
       
  1048 
       
  1049     if (!*args) {
       
  1050 	if (OPT_ISSET(ops,'R')) {
       
  1051 	    zwarnnam(nam, "no module alias to remove", NULL, 0);
       
  1052 	    return 1;
       
  1053 	}
       
  1054 	for (node = firstnode(modules); node; incnode(node)) {
       
  1055 	    m = (Module) getdata(node);
       
  1056 	    if (m->flags & MOD_ALIAS)
       
  1057 		printmodalias(m, ops);
       
  1058 	}
       
  1059 	return 0;
       
  1060     }
       
  1061 
       
  1062     for (; !ret && *args; args++) {
       
  1063 	char *eqpos = strchr(*args, '=');
       
  1064 	char *aliasname = eqpos ? eqpos+1 : NULL;
       
  1065 	if (eqpos)
       
  1066 	    *eqpos = '\0';
       
  1067 	if (!modname_ok(*args)) {
       
  1068 	    zwarnnam(nam, "invalid module name `%s'", *args, 0);
       
  1069 	    return 1;
       
  1070 	}
       
  1071 	if (OPT_ISSET(ops,'R')) {
       
  1072 	    if (aliasname) {
       
  1073 		zwarnnam(nam, "bad syntax for removing module alias: %s",
       
  1074 			 *args, 0);
       
  1075 		return 1;
       
  1076 	    }
       
  1077 	    node = find_module(*args, 0, NULL);
       
  1078 	    if (node) {
       
  1079 		m = (Module) getdata(node);
       
  1080 		if (!(m->flags & MOD_ALIAS)) {
       
  1081 		    zwarnnam(nam, "module is not an alias: %s", *args, 0);
       
  1082 		    ret = 1;
       
  1083 		    break;
       
  1084 		}
       
  1085 		delete_module(node);
       
  1086 	    } else {
       
  1087 		zwarnnam(nam, "no such module alias: %s", *args, 0);
       
  1088 		return 1;
       
  1089 	    }
       
  1090 	} else {
       
  1091 	    if (aliasname) {
       
  1092 		const char *mname = aliasname;
       
  1093 		if (!modname_ok(aliasname)) {
       
  1094 		    zwarnnam(nam, "invalid module name `%s'", aliasname, 0);
       
  1095 		    return 1;
       
  1096 		}
       
  1097 		find_module(aliasname, 1, &mname);
       
  1098 		if (!strcmp(mname, *args)) {
       
  1099 		    zwarnnam(nam, "module alias would refer to itself: %s",
       
  1100 			     *args, 0);
       
  1101 		    return 1;
       
  1102 		}
       
  1103 		node = find_module(*args, 0, NULL);
       
  1104 		if (node) {
       
  1105 		    m = (Module) getdata(node);
       
  1106 		    if (!(m->flags & MOD_ALIAS)) {
       
  1107 			zwarnnam(nam, "module is not an alias: %s", *args, 0);
       
  1108 			return 1;
       
  1109 		    }
       
  1110 		    zsfree(m->u.alias);
       
  1111 		} else {
       
  1112 		    m = (Module) zshcalloc(sizeof(*m));
       
  1113 		    m->nam = ztrdup(*args);
       
  1114 		    m->flags = MOD_ALIAS;
       
  1115 		    zaddlinknode(modules, m);
       
  1116 		}
       
  1117 		m->u.alias = ztrdup(aliasname);
       
  1118 	    } else {
       
  1119 		if ((node = find_module(*args, 0, NULL))) {
       
  1120 		    m = (Module) getdata(node);
       
  1121 		    if (m->flags & MOD_ALIAS)
       
  1122 			printmodalias(m, ops);
       
  1123 		    else {
       
  1124 			zwarnnam(nam, "module is not an alias: %s",
       
  1125 				 *args, 0);
       
  1126 			return 1;
       
  1127 		    }
       
  1128 		} else {
       
  1129 		    zwarnnam(nam, "no such module alias: %s", *args, 0);
       
  1130 		    return 1;
       
  1131 		}
       
  1132 	    }
       
  1133 	}
       
  1134     }
       
  1135 
       
  1136     return 0;
       
  1137 }
       
  1138 
       
  1139 /**/
       
  1140 static int
       
  1141 bin_zmodload_exist(UNUSED(char *nam), char **args, Options ops)
       
  1142 {
       
  1143     LinkNode node;
       
  1144     Module m;
       
  1145     char *modname;
       
  1146 
       
  1147     if (!*args) {
       
  1148 	for (node = firstnode(modules); node; incnode(node)) {
       
  1149 	    m = (Module) getdata(node);
       
  1150 	    modname = m->nam;
       
  1151 	    if (m->flags & MOD_ALIAS) {
       
  1152 		LinkNode node2;
       
  1153 		if (OPT_ISSET(ops,'A') && 
       
  1154 		    (node2 = find_module(m->u.alias, 1, NULL)))
       
  1155 		    m = (Module) getdata(node2);
       
  1156 		else
       
  1157 		    continue;
       
  1158 	    } 
       
  1159 	    if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
       
  1160 		nicezputs(modname, stdout);
       
  1161 		putchar('\n');
       
  1162 	    }
       
  1163 	}
       
  1164 	return 0;
       
  1165     } else {
       
  1166 	int ret = 0;
       
  1167 
       
  1168 	for (; !ret && *args; args++) {
       
  1169 	    if (!(node = find_module(*args, 1, NULL))
       
  1170 		|| !(m = (Module) getdata(node))->u.handle
       
  1171 		|| (m->flags & MOD_UNLOAD))
       
  1172 		ret = 1;
       
  1173 	}
       
  1174 	return ret;
       
  1175     }
       
  1176 }
       
  1177 
       
  1178 /**/
       
  1179 static int
       
  1180 bin_zmodload_dep(UNUSED(char *nam), char **args, Options ops)
       
  1181 {
       
  1182     LinkNode node;
       
  1183     Module m;
       
  1184     if (OPT_ISSET(ops,'u')) {
       
  1185 	/* remove dependencies, which can't pertain to aliases */
       
  1186 	const char *tnam = *args++;
       
  1187 	node = find_module(tnam, 1, &tnam);
       
  1188 	if (!node)
       
  1189 	    return 0;
       
  1190 	m = (Module) getdata(node);
       
  1191 	if (*args && m->deps) {
       
  1192 	    do {
       
  1193 		LinkNode dnode;
       
  1194 		for (dnode = firstnode(m->deps); dnode; incnode(dnode))
       
  1195 		    if (!strcmp(*args, getdata(dnode))) {
       
  1196 			zsfree(getdata(dnode));
       
  1197 			remnode(m->deps, dnode);
       
  1198 			break;
       
  1199 		    }
       
  1200 	    } while(*++args);
       
  1201 	    if (empty(m->deps)) {
       
  1202 		freelinklist(m->deps, freestr);
       
  1203 		m->deps = NULL;
       
  1204 	    }
       
  1205 	} else {
       
  1206 	    if (m->deps) {
       
  1207 		freelinklist(m->deps, freestr);
       
  1208 		m->deps = NULL;
       
  1209 	    }
       
  1210 	}
       
  1211 	if (!m->deps && !m->u.handle)
       
  1212 	    delete_module(node);
       
  1213 	return 0;
       
  1214     } else if (!args[0] || !args[1]) {
       
  1215 	/* list dependencies */
       
  1216 	for (node = firstnode(modules); node; incnode(node)) {
       
  1217 	    m = (Module) getdata(node);
       
  1218 	    if (m->deps && (!args[0] || !strcmp(args[0], m->nam))) {
       
  1219 		LinkNode n;
       
  1220 		if (OPT_ISSET(ops,'L')) {
       
  1221 		    printf("zmodload -d ");
       
  1222 		    if(m->nam[0] == '-')
       
  1223 			fputs("-- ", stdout);
       
  1224 		    quotedzputs(m->nam, stdout);
       
  1225 		} else {
       
  1226 		    nicezputs(m->nam, stdout);
       
  1227 		    putchar(':');
       
  1228 		}
       
  1229 		for (n = firstnode(m->deps); n; incnode(n)) {
       
  1230 		    putchar(' ');
       
  1231 		    if(OPT_ISSET(ops,'L'))
       
  1232 			quotedzputs((char *) getdata(n), stdout);
       
  1233 		    else
       
  1234 			nicezputs((char *) getdata(n), stdout);
       
  1235 		}
       
  1236 		putchar('\n');
       
  1237 	    }
       
  1238 	}
       
  1239 	return 0;
       
  1240     } else {
       
  1241 	/* add dependencies */
       
  1242 	int ret = 0;
       
  1243 	char *tnam = *args++;
       
  1244 
       
  1245 	for (; *args; args++)
       
  1246 	    add_dep(tnam, *args);
       
  1247 	return ret;
       
  1248     }
       
  1249 }
       
  1250 
       
  1251 /**/
       
  1252 static int
       
  1253 bin_zmodload_auto(char *nam, char **args, Options ops)
       
  1254 {
       
  1255     int ret = 0;
       
  1256     if(OPT_ISSET(ops,'u')) {
       
  1257 	/* remove autoloaded builtins */
       
  1258 	for (; *args; args++) {
       
  1259 	    Builtin bn = (Builtin) builtintab->getnode2(builtintab, *args);
       
  1260 	    if (!bn) {
       
  1261 		if(!OPT_ISSET(ops,'i')) {
       
  1262 		    zwarnnam(nam, "%s: no such builtin", *args, 0);
       
  1263 		    ret = 1;
       
  1264 		}
       
  1265 	    } else if (bn->flags & BINF_ADDED) {
       
  1266 		zwarnnam(nam, "%s: builtin is already defined", *args, 0);
       
  1267 		ret = 1;
       
  1268 	    } else
       
  1269 		deletebuiltin(*args);
       
  1270 	}
       
  1271 	return ret;
       
  1272     } else if(!*args) {
       
  1273 	/* list autoloaded builtins */
       
  1274 	scanhashtable(builtintab, 0, 0, 0,
       
  1275 	    autoloadscan, OPT_ISSET(ops,'L') ? PRINT_LIST : 0);
       
  1276 	return 0;
       
  1277     } else {
       
  1278 	/* add autoloaded builtins */
       
  1279 	char *modnam;
       
  1280 	modnam = *args++;
       
  1281 	do {
       
  1282 	    char *bnam = *args ? *args++ : modnam;
       
  1283 	    if (strchr(bnam, '/')) {
       
  1284 		zwarnnam(nam, "%s: `/' is illegal in a builtin", bnam, 0);
       
  1285 		ret = 1;
       
  1286 	    } else if (add_autobin(bnam, modnam) && !OPT_ISSET(ops,'i')) {
       
  1287 		zwarnnam(nam, "failed to add builtin %s", bnam, 0);
       
  1288 		ret = 1;
       
  1289 	    }
       
  1290 	} while(*args);
       
  1291 	return ret;
       
  1292     }
       
  1293 }
       
  1294 
       
  1295 /**/
       
  1296 static int
       
  1297 bin_zmodload_cond(char *nam, char **args, Options ops)
       
  1298 {
       
  1299     int ret = 0;
       
  1300 
       
  1301     if (OPT_ISSET(ops,'u')) {
       
  1302 	/* remove autoloaded conditions */
       
  1303 	for (; *args; args++) {
       
  1304 	    Conddef cd = getconddef(OPT_ISSET(ops,'I'), *args, 0);
       
  1305 
       
  1306 	    if (!cd) {
       
  1307 		if (!OPT_ISSET(ops,'i')) {
       
  1308 		    zwarnnam(nam, "%s: no such condition", *args, 0);
       
  1309 		    ret = 1;
       
  1310 		}
       
  1311 	    } else if (cd->flags & CONDF_ADDED) {
       
  1312 		zwarnnam(nam, "%s: condition is already defined", *args, 0);
       
  1313 		ret = 1;
       
  1314 	    } else
       
  1315 		deleteconddef(cd);
       
  1316 	}
       
  1317 	return ret;
       
  1318     } else if (!*args) {
       
  1319 	/* list autoloaded conditions */
       
  1320 	Conddef p;
       
  1321 
       
  1322 	for (p = condtab; p; p = p->next) {
       
  1323 	    if (p->module) {
       
  1324 		if (OPT_ISSET(ops,'L')) {
       
  1325 		    fputs("zmodload -ac", stdout);
       
  1326 		    if (p->flags & CONDF_INFIX)
       
  1327 			putchar('I');
       
  1328 		    printf(" %s %s\n", p->module, p->name);
       
  1329 		} else {
       
  1330 		    if (p->flags & CONDF_INFIX)
       
  1331 			fputs("infix ", stdout);
       
  1332 		    else
       
  1333 			fputs("post ", stdout);
       
  1334 		    printf("%s (%s)\n",p->name, p->module);
       
  1335 		}
       
  1336 	    }
       
  1337 	}
       
  1338 	return 0;
       
  1339     } else {
       
  1340 	/* add autoloaded conditions */
       
  1341 	char *modnam;
       
  1342 
       
  1343 	modnam = *args++;
       
  1344 	do {
       
  1345 	    char *cnam = *args ? *args++ : modnam;
       
  1346 	    if (strchr(cnam, '/')) {
       
  1347 		zwarnnam(nam, "%s: `/' is illegal in a condition", cnam, 0);
       
  1348 		ret = 1;
       
  1349 	    } else if (add_autocond(cnam, OPT_ISSET(ops,'I'), modnam) &&
       
  1350 		       !OPT_ISSET(ops,'i')) {
       
  1351 		zwarnnam(nam, "failed to add condition `%s'", cnam, 0);
       
  1352 		ret = 1;
       
  1353 	    }
       
  1354 	} while(*args);
       
  1355 	return ret;
       
  1356     }
       
  1357 }
       
  1358 
       
  1359 /**/
       
  1360 static int
       
  1361 bin_zmodload_math(char *nam, char **args, Options ops)
       
  1362 {
       
  1363     int ret = 0;
       
  1364 
       
  1365     if (OPT_ISSET(ops,'u')) {
       
  1366 	/* remove autoloaded math functions */
       
  1367 	for (; *args; args++) {
       
  1368 	    MathFunc f = getmathfunc(*args, 0);
       
  1369 
       
  1370 	    if (!f) {
       
  1371 		if (!OPT_ISSET(ops,'i')) {
       
  1372 		    zwarnnam(nam, "%s: no such math function", *args, 0);
       
  1373 		    ret = 1;
       
  1374 		}
       
  1375 	    } else if (f->flags & MFF_ADDED) {
       
  1376 		zwarnnam(nam, "%s: math function is already defined", *args, 0);
       
  1377 		ret = 1;
       
  1378 	    } else
       
  1379 		deletemathfunc(f);
       
  1380 	}
       
  1381 	return ret;
       
  1382     } else if (!*args) {
       
  1383 	/* list autoloaded math functions */
       
  1384 	MathFunc p;
       
  1385 
       
  1386 	for (p = mathfuncs; p; p = p->next) {
       
  1387 	    if (p->module) {
       
  1388 		if (OPT_ISSET(ops,'L')) {
       
  1389 		    fputs("zmodload -af", stdout);
       
  1390 		    printf(" %s %s\n", p->module, p->name);
       
  1391 		} else
       
  1392 		    printf("%s (%s)\n",p->name, p->module);
       
  1393 	    }
       
  1394 	}
       
  1395 	return 0;
       
  1396     } else {
       
  1397 	/* add autoloaded math functions */
       
  1398 	char *modnam;
       
  1399 
       
  1400 	modnam = *args++;
       
  1401 	do {
       
  1402 	    char *fnam = *args ? *args++ : modnam;
       
  1403 	    if (strchr(fnam, '/')) {
       
  1404 		zwarnnam(nam, "%s: `/' is illegal in a math function",
       
  1405 			 fnam, 0);
       
  1406 		ret = 1;
       
  1407 	    } else if (add_automathfunc(fnam, modnam) && !OPT_ISSET(ops,'i')) {
       
  1408 		zwarnnam(nam, "failed to add math function `%s'", fnam, 0);
       
  1409 		ret = 1;
       
  1410 	    }
       
  1411 	} while(*args);
       
  1412 	return ret;
       
  1413     }
       
  1414 }
       
  1415 
       
  1416 static void
       
  1417 printautoparams(HashNode hn, int lon)
       
  1418 {
       
  1419     Param pm = (Param) hn;
       
  1420 
       
  1421     if (pm->flags & PM_AUTOLOAD) {
       
  1422 	if (lon)
       
  1423 	    printf("zmodload -ap %s %s\n", pm->u.str, pm->nam);
       
  1424 	else
       
  1425 	    printf("%s (%s)\n", pm->nam, pm->u.str);
       
  1426     }
       
  1427 }
       
  1428 
       
  1429 /**/
       
  1430 static int
       
  1431 bin_zmodload_param(char *nam, char **args, Options ops)
       
  1432 {
       
  1433     int ret = 0;
       
  1434 
       
  1435     if (OPT_ISSET(ops,'u')) {
       
  1436 	/* remove autoloaded parameters */
       
  1437 	for (; *args; args++) {
       
  1438 	    Param pm = (Param) gethashnode2(paramtab, *args);
       
  1439 
       
  1440 	    if (!pm) {
       
  1441 		if (!OPT_ISSET(ops,'i')) {
       
  1442 		    zwarnnam(nam, "%s: no such parameter", *args, 0);
       
  1443 		    ret = 1;
       
  1444 		}
       
  1445 	    } else if (!(pm->flags & PM_AUTOLOAD)) {
       
  1446 		zwarnnam(nam, "%s: parameter is already defined", *args, 0);
       
  1447 		ret = 1;
       
  1448 	    } else
       
  1449 		unsetparam_pm(pm, 0, 1);
       
  1450 	}
       
  1451 	return ret;
       
  1452     } else if (!*args) {
       
  1453 	scanhashtable(paramtab, 1, 0, 0, printautoparams, OPT_ISSET(ops,'L'));
       
  1454 	return 0;
       
  1455     } else {
       
  1456 	/* add autoloaded parameters */
       
  1457 	char *modnam;
       
  1458 
       
  1459 	modnam = *args++;
       
  1460 	do {
       
  1461 	    char *pnam = *args ? *args++ : modnam;
       
  1462 	    if (strchr(pnam, '/')) {
       
  1463 		zwarnnam(nam, "%s: `/' is illegal in a parameter", pnam, 0);
       
  1464 		ret = 1;
       
  1465 	    } else
       
  1466 		add_autoparam(pnam, modnam);
       
  1467 	} while(*args);
       
  1468 	return ret;
       
  1469     }
       
  1470 }
       
  1471 
       
  1472 /**/
       
  1473 int
       
  1474 unload_module(Module m, LinkNode node)
       
  1475 {
       
  1476     /*
       
  1477      * Only unload the real module, so resolve aliases.
       
  1478      */
       
  1479     if (m->flags & MOD_ALIAS) {
       
  1480 	LinkNode node = find_module(m->u.alias, 1, NULL);
       
  1481 	if (!node)
       
  1482 	    return 1;
       
  1483 	m = (Module) getdata(node);
       
  1484     }
       
  1485     if ((m->flags & MOD_INIT_S) &&
       
  1486 	!(m->flags & MOD_UNLOAD) &&
       
  1487 	((m->flags & MOD_LINKED) ?
       
  1488 	 (m->u.linked && m->u.linked->cleanup(m)) :
       
  1489 	 (m->u.handle && cleanup_module(m))))
       
  1490 	return 1;
       
  1491     else {
       
  1492 	int del = (m->flags & MOD_UNLOAD);
       
  1493 
       
  1494 	if (m->wrapper) {
       
  1495 	    m->flags |= MOD_UNLOAD;
       
  1496 	    return 0;
       
  1497 	}
       
  1498 	m->flags &= ~MOD_UNLOAD;
       
  1499 	if (m->flags & MOD_INIT_B) {
       
  1500 	    if (m->flags & MOD_LINKED) {
       
  1501 		if (m->u.linked) {
       
  1502 		    m->u.linked->finish(m);
       
  1503 		    m->u.linked = NULL;
       
  1504 		}
       
  1505 	    } else {
       
  1506 		if (m->u.handle) {
       
  1507 		    finish_module(m);
       
  1508 		    m->u.handle = NULL;
       
  1509 		}
       
  1510 	    }
       
  1511 	}
       
  1512 	if (del && m->deps) {
       
  1513 	    /* The module was unloaded delayed, unload all modules *
       
  1514 	     * on which it depended. */
       
  1515 	    LinkNode n;
       
  1516 
       
  1517 	    for (n = firstnode(m->deps); n; incnode(n)) {
       
  1518 		LinkNode dn = find_module((char *) getdata(n), 1, NULL);
       
  1519 		Module dm;
       
  1520 
       
  1521 		if (dn && (dm = (Module) getdata(dn)) &&
       
  1522 		    (dm->flags & MOD_UNLOAD)) {
       
  1523 		    /* See if this is the only module depending on it. */
       
  1524 
       
  1525 		    LinkNode an;
       
  1526 		    Module am;
       
  1527 		    int du = 1;
       
  1528 
       
  1529 		    for (an = firstnode(modules); du && an; incnode(an)) {
       
  1530 			am = (Module) getdata(an);
       
  1531 			if (am != m && am->deps &&
       
  1532 			    ((am->flags & MOD_LINKED) ?
       
  1533 			     am->u.linked : am->u.handle)) {
       
  1534 			    LinkNode sn;
       
  1535 
       
  1536 			    for (sn = firstnode(am->deps); du && sn;
       
  1537 				 incnode(sn)) {
       
  1538 				if (!strcmp((char *) getdata(sn), dm->nam))
       
  1539 				    du = 0;
       
  1540 			    }
       
  1541 			}
       
  1542 		    }
       
  1543 		    if (du)
       
  1544 			unload_module(dm, NULL);
       
  1545 		}
       
  1546 	    }
       
  1547 	}
       
  1548 	if(!m->deps) {
       
  1549 	    if (!node) {
       
  1550 		for (node = firstnode(modules); node; incnode(node))
       
  1551 		    if (m == (Module) getdata(node))
       
  1552 			break;
       
  1553 		if (!node)
       
  1554 		    return 1;
       
  1555 	    }
       
  1556 	    delete_module(node);
       
  1557 	}
       
  1558     }
       
  1559     return 0;
       
  1560 }
       
  1561 
       
  1562 /**/
       
  1563 static int
       
  1564 bin_zmodload_load(char *nam, char **args, Options ops)
       
  1565 {
       
  1566     LinkNode node;
       
  1567     Module m;
       
  1568     int ret = 0;
       
  1569     if(OPT_ISSET(ops,'u')) {
       
  1570 	/* unload modules */
       
  1571 	const char *mname = *args;
       
  1572 	for(; *args; args++) {
       
  1573 	    node = find_module(*args, 1, &mname);
       
  1574 	    if (node) {
       
  1575 		LinkNode mn, dn;
       
  1576 		int del = 0;
       
  1577 
       
  1578 		for (mn = firstnode(modules); mn; incnode(mn)) {
       
  1579 		    m = (Module) getdata(mn);
       
  1580 		    if (m->deps && m->u.handle)
       
  1581 			for (dn = firstnode(m->deps); dn; incnode(dn))
       
  1582 			    if (!strcmp((char *) getdata(dn), mname)) {
       
  1583 				if (m->flags & MOD_UNLOAD)
       
  1584 				    del = 1;
       
  1585 				else {
       
  1586 				    zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", mname, 0);
       
  1587 				    ret = 1;
       
  1588 				    goto cont;
       
  1589 				}
       
  1590 			    }
       
  1591 		}
       
  1592 		m = (Module) getdata(node);
       
  1593 		if (del)
       
  1594 		    m->wrapper++;
       
  1595 		if (unload_module(m, node))
       
  1596 		    ret = 1;
       
  1597 		if (del)
       
  1598 		    m->wrapper--;
       
  1599 	    } else if (!OPT_ISSET(ops,'i')) {
       
  1600 		zwarnnam(nam, "no such module %s", *args, 0);
       
  1601 		ret = 1;
       
  1602 	    }
       
  1603 	    cont: ;
       
  1604 	}
       
  1605 	return ret;
       
  1606     } else if(!*args) {
       
  1607 	/* list modules */
       
  1608 	for (node = firstnode(modules); node; incnode(node)) {
       
  1609 	    m = (Module) getdata(node);
       
  1610 	    if (m->u.handle && !(m->flags & (MOD_UNLOAD|MOD_ALIAS))) {
       
  1611 		if(OPT_ISSET(ops,'L')) {
       
  1612 		    printf("zmodload ");
       
  1613 		    if(m->nam[0] == '-')
       
  1614 			fputs("-- ", stdout);
       
  1615 		    quotedzputs(m->nam, stdout);
       
  1616 		} else
       
  1617 		    nicezputs(m->nam, stdout);
       
  1618 		putchar('\n');
       
  1619 	    }
       
  1620 	}
       
  1621 	return 0;
       
  1622     } else {
       
  1623 	/* load modules */
       
  1624 	for (; *args; args++)
       
  1625 	    if (!require_module(nam, *args, 1, (!OPT_ISSET(ops,'i'))))
       
  1626 		ret = 1;
       
  1627 
       
  1628 	return ret;
       
  1629     }
       
  1630 }
       
  1631 
       
  1632 /* The list of module-defined conditions. */
       
  1633 
       
  1634 /**/
       
  1635 mod_export Conddef condtab;
       
  1636 
       
  1637 /* This gets a condition definition with the given name. The first        *
       
  1638  * argument says if we have to look for an infix condition. The last      *
       
  1639  * argument is non-zero if we should autoload modules if needed. */
       
  1640 
       
  1641 /**/
       
  1642 Conddef
       
  1643 getconddef(int inf, char *name, int autol)
       
  1644 {
       
  1645     Conddef p;
       
  1646     int f = 1;
       
  1647 
       
  1648     do {
       
  1649 	for (p = condtab; p; p = p->next) {
       
  1650 	    if ((!!inf == !!(p->flags & CONDF_INFIX)) &&
       
  1651 		!strcmp(name, p->name))
       
  1652 		break;
       
  1653 	}
       
  1654 	if (autol && p && p->module) {
       
  1655 	    /* This is a definition for an autoloaded condition, load the *
       
  1656 	     * module if we haven't tried that already. */
       
  1657 	    if (f) {
       
  1658 		load_module(p->module);
       
  1659 		f = 0;
       
  1660 		p = NULL;
       
  1661 	    } else {
       
  1662 		deleteconddef(p);
       
  1663 		return NULL;
       
  1664 	    }
       
  1665 	} else
       
  1666 	    break;
       
  1667     } while (!p);
       
  1668     return p;
       
  1669 }
       
  1670 
       
  1671 /* This adds the given condition definition. The return value is zero on *
       
  1672  * success and 1 on failure. If there is a matching definition for an    *
       
  1673  * autoloaded condition, it is removed. */
       
  1674 
       
  1675 /**/
       
  1676 int
       
  1677 addconddef(Conddef c)
       
  1678 {
       
  1679     Conddef p = getconddef((c->flags & CONDF_INFIX), c->name, 0);
       
  1680 
       
  1681     if (p) {
       
  1682 	if (!p->module || (p->flags & CONDF_ADDED))
       
  1683 	    return 1;
       
  1684 	/* There is an autoload definition. */
       
  1685 
       
  1686 	deleteconddef(p);
       
  1687     }
       
  1688     c->next = condtab;
       
  1689     condtab = c;
       
  1690     return 0;
       
  1691 }
       
  1692 
       
  1693 /* This adds multiple condition definitions. This is like addbuiltins(). */
       
  1694 
       
  1695 /**/
       
  1696 mod_export int
       
  1697 addconddefs(char const *nam, Conddef c, int size)
       
  1698 {
       
  1699     int hads = 0, hadf = 0;
       
  1700 
       
  1701     while (size--) {
       
  1702 	if (c->flags & CONDF_ADDED) {
       
  1703 	    c++;
       
  1704 	    continue;
       
  1705 	}
       
  1706 	if (addconddef(c)) {
       
  1707 	    zwarnnam(nam, "name clash when adding condition `%s'", c->name, 0);
       
  1708 	    hadf = 1;
       
  1709 	} else {
       
  1710 	    c->flags |= CONDF_ADDED;
       
  1711 	    hads = 2;
       
  1712 	}
       
  1713 	c++;
       
  1714     }
       
  1715     return hadf ? hads : 1;
       
  1716 }
       
  1717 
       
  1718 /* This list of hook functions defined. */
       
  1719 
       
  1720 /**/
       
  1721 Hookdef hooktab;
       
  1722 
       
  1723 /* Find a hook definition given the name. */
       
  1724 
       
  1725 /**/
       
  1726 Hookdef
       
  1727 gethookdef(char *n)
       
  1728 {
       
  1729     Hookdef p;
       
  1730 
       
  1731     for (p = hooktab; p; p = p->next)
       
  1732 	if (!strcmp(n, p->name))
       
  1733 	    return p;
       
  1734     return NULL;
       
  1735 }
       
  1736 
       
  1737 /* This adds the given hook definition. The return value is zero on      *
       
  1738  * success and 1 on failure.                                             */
       
  1739 
       
  1740 /**/
       
  1741 int
       
  1742 addhookdef(Hookdef h)
       
  1743 {
       
  1744     if (gethookdef(h->name))
       
  1745 	return 1;
       
  1746 
       
  1747     h->next = hooktab;
       
  1748     hooktab = h;
       
  1749     h->funcs = znewlinklist();
       
  1750 
       
  1751     return 0;
       
  1752 }
       
  1753 
       
  1754 /* This adds multiple hook definitions. This is like addbuiltins(). */
       
  1755 
       
  1756 /**/
       
  1757 mod_export int
       
  1758 addhookdefs(char const *nam, Hookdef h, int size)
       
  1759 {
       
  1760     int hads = 0, hadf = 0;
       
  1761 
       
  1762     while (size--) {
       
  1763 	if (addhookdef(h)) {
       
  1764 	    zwarnnam(nam, "name clash when adding hook `%s'", h->name, 0);
       
  1765 	    hadf = 1;
       
  1766 	} else
       
  1767 	    hads = 2;
       
  1768 	h++;
       
  1769     }
       
  1770     return hadf ? hads : 1;
       
  1771 }
       
  1772 
       
  1773 /* Delete hook definitions. */
       
  1774 
       
  1775 /**/
       
  1776 int
       
  1777 deletehookdef(Hookdef h)
       
  1778 {
       
  1779     Hookdef p, q;
       
  1780 
       
  1781     for (p = hooktab, q = NULL; p && p != h; q = p, p = p->next);
       
  1782 
       
  1783     if (!p)
       
  1784 	return 1;
       
  1785 
       
  1786     if (q)
       
  1787 	q->next = p->next;
       
  1788     else
       
  1789 	hooktab = p->next;
       
  1790     freelinklist(p->funcs, NULL);
       
  1791     return 0;
       
  1792 }
       
  1793 
       
  1794 /**/
       
  1795 mod_export int
       
  1796 deletehookdefs(UNUSED(char const *nam), Hookdef h, int size)
       
  1797 {
       
  1798     while (size--) {
       
  1799 	deletehookdef(h);
       
  1800 	h++;
       
  1801     }
       
  1802     return 1;
       
  1803 }
       
  1804 
       
  1805 /* Add a function to a hook. */
       
  1806 
       
  1807 /**/
       
  1808 int
       
  1809 addhookdeffunc(Hookdef h, Hookfn f)
       
  1810 {
       
  1811     zaddlinknode(h->funcs, (void *) f);
       
  1812 
       
  1813     return 0;
       
  1814 }
       
  1815 
       
  1816 /**/
       
  1817 mod_export int
       
  1818 addhookfunc(char *n, Hookfn f)
       
  1819 {
       
  1820     Hookdef h = gethookdef(n);
       
  1821 
       
  1822     if (h)
       
  1823 	return addhookdeffunc(h, f);
       
  1824     return 1;
       
  1825 }
       
  1826 
       
  1827 /* Delete a function from a hook. */
       
  1828 
       
  1829 /**/
       
  1830 int
       
  1831 deletehookdeffunc(Hookdef h, Hookfn f)
       
  1832 {
       
  1833     LinkNode p;
       
  1834 
       
  1835     for (p = firstnode(h->funcs); p; incnode(p))
       
  1836 	if (f == (Hookfn) getdata(p)) {
       
  1837 	    remnode(h->funcs, p);
       
  1838 	    return 0;
       
  1839 	}
       
  1840     return 1;
       
  1841 }
       
  1842 
       
  1843 /**/
       
  1844 mod_export int
       
  1845 deletehookfunc(char *n, Hookfn f)
       
  1846 {
       
  1847     Hookdef h = gethookdef(n);
       
  1848 
       
  1849     if (h)
       
  1850 	return deletehookdeffunc(h, f);
       
  1851     return 1;
       
  1852 }
       
  1853 
       
  1854 /* Run the function(s) for a hook. */
       
  1855 
       
  1856 /**/
       
  1857 mod_export int
       
  1858 runhookdef(Hookdef h, void *d)
       
  1859 {
       
  1860     if (empty(h->funcs)) {
       
  1861 	if (h->def)
       
  1862 	    return h->def(h, d);
       
  1863 	return 0;
       
  1864     } else if (h->flags & HOOKF_ALL) {
       
  1865 	LinkNode p;
       
  1866 	int r;
       
  1867 
       
  1868 	for (p = firstnode(h->funcs); p; incnode(p))
       
  1869 	    if ((r = ((Hookfn) getdata(p))(h, d)))
       
  1870 		return r;
       
  1871 	if (h->def)
       
  1872 	    return h->def(h, d);
       
  1873 	return 0;
       
  1874     } else
       
  1875 	return ((Hookfn) getdata(lastnode(h->funcs)))(h, d);
       
  1876 }
       
  1877 
       
  1878 /**/
       
  1879 int
       
  1880 runhook(char *n, void *d)
       
  1881 {
       
  1882     Hookdef h = gethookdef(n);
       
  1883 
       
  1884     if (h)
       
  1885 	return runhookdef(h, d);
       
  1886     return 0;
       
  1887 }
       
  1888 
       
  1889 /* This adds the given parameter definition. The return value is zero on *
       
  1890  * success and 1 on failure. */
       
  1891 
       
  1892 /**/
       
  1893 int
       
  1894 addparamdef(Paramdef d)
       
  1895 {
       
  1896     Param pm;
       
  1897 
       
  1898     if ((pm = (Param) gethashnode2(paramtab, d->name)))
       
  1899 	unsetparam_pm(pm, 0, 1);
       
  1900 
       
  1901     if (!(pm = createparam(d->name, d->flags)) &&
       
  1902 	!(pm = (Param) paramtab->getnode(paramtab, d->name)))
       
  1903 	return 1;
       
  1904 
       
  1905     pm->level = 0;
       
  1906     pm->u.data = d->var;
       
  1907     if (d->gsu)
       
  1908 	pm->gsu.i = (GsuInteger) d->gsu;
       
  1909     else {
       
  1910 	/*
       
  1911 	 * If no get/set/unset class, use the appropriate
       
  1912 	 * variable type.
       
  1913 	 */
       
  1914 	switch (PM_TYPE(pm->flags)) {
       
  1915 	case PM_SCALAR:
       
  1916 	    pm->gsu.s = &varscalar_gsu;
       
  1917 	    break;
       
  1918 
       
  1919 	case PM_INTEGER:
       
  1920 	    pm->gsu.i = &varinteger_gsu;
       
  1921 	    break;
       
  1922 
       
  1923 	case PM_ARRAY:
       
  1924 	    pm->gsu.a = &vararray_gsu;
       
  1925 	    break;
       
  1926 
       
  1927 	default:
       
  1928 	    unsetparam_pm(pm, 0, 1);
       
  1929 	    return 1;
       
  1930 	}
       
  1931     }
       
  1932 
       
  1933     return 0;
       
  1934 }
       
  1935 
       
  1936 /* This adds multiple parameter definitions. This is like addbuiltins(). */
       
  1937 
       
  1938 /**/
       
  1939 mod_export int
       
  1940 addparamdefs(char const *nam, Paramdef d, int size)
       
  1941 {
       
  1942     int hads = 0, hadf = 0;
       
  1943 
       
  1944     while (size--) {
       
  1945 	if (addparamdef(d)) {
       
  1946 	    zwarnnam(nam, "error when adding parameter `%s'", d->name, 0);
       
  1947 	    hadf = 1;
       
  1948 	} else
       
  1949 	    hads = 2;
       
  1950 	d++;
       
  1951     }
       
  1952     return hadf ? hads : 1;
       
  1953 }
       
  1954 
       
  1955 /* Delete parameters defined. No error checking yet. */
       
  1956 
       
  1957 /**/
       
  1958 int
       
  1959 deleteparamdef(Paramdef d)
       
  1960 {
       
  1961     unsetparam(d->name);
       
  1962     return 0;
       
  1963 }
       
  1964 
       
  1965 /**/
       
  1966 mod_export int
       
  1967 deleteparamdefs(UNUSED(char const *nam), Paramdef d, int size)
       
  1968 {
       
  1969     while (size--) {
       
  1970 	deleteparamdef(d);
       
  1971 	d++;
       
  1972     }
       
  1973     return 1;
       
  1974 }
       
  1975 
       
  1976 /* This adds a definition for autoloading a module for a condition. */
       
  1977 
       
  1978 /**/
       
  1979 int
       
  1980 add_autocond(char *nam, int inf, char *module)
       
  1981 {
       
  1982     Conddef c = (Conddef) zalloc(sizeof(*c));
       
  1983 
       
  1984     c->name = ztrdup(nam);
       
  1985     c->flags = (inf  ? CONDF_INFIX : 0);
       
  1986     c->module = ztrdup(module);
       
  1987 
       
  1988     if (addconddef(c)) {
       
  1989 	zsfree(c->name);
       
  1990 	zsfree(c->module);
       
  1991 	zfree(c, sizeof(*c));
       
  1992 
       
  1993 	return 1;
       
  1994     }
       
  1995     return 0;
       
  1996 }
       
  1997 
       
  1998 /* This removes the given condition definition from the list(s). If this *
       
  1999  * is a definition for a autoloaded condition, the memory is freed. */
       
  2000 
       
  2001 /**/
       
  2002 int
       
  2003 deleteconddef(Conddef c)
       
  2004 {
       
  2005     Conddef p, q;
       
  2006 
       
  2007     for (p = condtab, q = NULL; p && p != c; q = p, p = p->next);
       
  2008 
       
  2009     if (p) {
       
  2010 	if (q)
       
  2011 	    q->next = p->next;
       
  2012 	else 
       
  2013 	    condtab = p->next;
       
  2014 		
       
  2015 	if (p->module) {
       
  2016 	    /* autoloaded, free it */
       
  2017 	    zsfree(p->name);
       
  2018 	    zsfree(p->module);
       
  2019 	    zfree(p, sizeof(*p));
       
  2020 	}
       
  2021 	return 0;
       
  2022     }
       
  2023     return -1;
       
  2024 }
       
  2025 
       
  2026 /* This removes multiple condition definitions (like deletebuiltins()). */
       
  2027 
       
  2028 /**/
       
  2029 mod_export int
       
  2030 deleteconddefs(char const *nam, Conddef c, int size)
       
  2031 {
       
  2032     int hads = 0, hadf = 0;
       
  2033 
       
  2034     while (size--) {
       
  2035 	if (!(c->flags & CONDF_ADDED)) {
       
  2036 	    c++;
       
  2037 	    continue;
       
  2038 	}
       
  2039 	if (deleteconddef(c)) {
       
  2040 	    zwarnnam(nam, "condition `%s' already deleted", c->name, 0);
       
  2041 	    hadf = 1;
       
  2042 	} else
       
  2043 	    hads = 2;
       
  2044 	c->flags &= ~CONDF_ADDED;
       
  2045 	c++;
       
  2046     }
       
  2047     return hadf ? hads : 1;
       
  2048 }
       
  2049 
       
  2050 /* This adds a definition for autoloading a module for a parameter. */
       
  2051 
       
  2052 /**/
       
  2053 void
       
  2054 add_autoparam(char *nam, char *module)
       
  2055 {
       
  2056     Param pm;
       
  2057 
       
  2058     queue_signals();
       
  2059     if ((pm = (Param) gethashnode2(paramtab, nam)))
       
  2060 	unsetparam_pm(pm, 0, 1);
       
  2061 
       
  2062     pm = setsparam(nam, ztrdup(module));
       
  2063 
       
  2064     pm->flags |= PM_AUTOLOAD;
       
  2065     unqueue_signals();
       
  2066 }
       
  2067 
       
  2068 /* List of math functions. */
       
  2069 
       
  2070 /**/
       
  2071 MathFunc mathfuncs;
       
  2072 
       
  2073 /**/
       
  2074 static void removemathfunc(MathFunc previous, MathFunc current)
       
  2075 {
       
  2076     if (previous)
       
  2077 	previous->next = current->next;
       
  2078     else
       
  2079 	mathfuncs = current->next;
       
  2080 
       
  2081     zsfree(current->name);
       
  2082     zsfree(current->module);
       
  2083     zfree(current, sizeof(*current));
       
  2084 }
       
  2085 
       
  2086 /**/
       
  2087 MathFunc
       
  2088 getmathfunc(char *name, int autol)
       
  2089 {
       
  2090     MathFunc p, q = NULL;
       
  2091 
       
  2092     for (p = mathfuncs; p; q = p, p = p->next)
       
  2093 	if (!strcmp(name, p->name)) {
       
  2094 	    if (autol && p->module) {
       
  2095 		char *n = dupstring(p->module);
       
  2096 
       
  2097 		removemathfunc(q, p);
       
  2098 
       
  2099 		load_module(n);
       
  2100 
       
  2101 		return getmathfunc(name, 0);
       
  2102 	    }
       
  2103 	    return p;
       
  2104 	}
       
  2105 
       
  2106     return NULL;
       
  2107 }
       
  2108 
       
  2109 /**/
       
  2110 mod_export int
       
  2111 addmathfunc(MathFunc f)
       
  2112 {
       
  2113     MathFunc p, q = NULL;
       
  2114 
       
  2115     if (f->flags & MFF_ADDED)
       
  2116 	return 1;
       
  2117 
       
  2118     for (p = mathfuncs; p; q = p, p = p->next)
       
  2119 	if (!strcmp(f->name, p->name)) {
       
  2120 	    if (p->module) {
       
  2121 		/*
       
  2122 		 * Autoloadable, replace.
       
  2123 		 */
       
  2124 		removemathfunc(q, p);
       
  2125 		break;
       
  2126 	    }
       
  2127 	    return 1;
       
  2128 	}
       
  2129 
       
  2130     f->flags |= MFF_ADDED;
       
  2131     f->next = mathfuncs;
       
  2132     mathfuncs = f;
       
  2133 
       
  2134     return 0;
       
  2135 }
       
  2136 
       
  2137 /**/
       
  2138 mod_export int
       
  2139 addmathfuncs(char const *nam, MathFunc f, int size)
       
  2140 {
       
  2141     int hads = 0, hadf = 0;
       
  2142 
       
  2143     while (size--) {
       
  2144 	if (f->flags & MFF_ADDED) {
       
  2145 	    f++;
       
  2146 	    continue;
       
  2147 	}
       
  2148 	if (addmathfunc(f)) {
       
  2149 	    zwarnnam(nam, "name clash when adding math function `%s'",
       
  2150 		     f->name, 0);
       
  2151 	    hadf = 1;
       
  2152 	} else
       
  2153 	    hads = 2;
       
  2154 	f++;
       
  2155     }
       
  2156     return hadf ? hads : 1;
       
  2157 }
       
  2158 
       
  2159 /**/
       
  2160 int
       
  2161 add_automathfunc(char *nam, char *module)
       
  2162 {
       
  2163     MathFunc f = (MathFunc) zalloc(sizeof(*f));
       
  2164 
       
  2165     f->name = ztrdup(nam);
       
  2166     f->module = ztrdup(module);
       
  2167     f->flags = 0;
       
  2168 
       
  2169     if (addmathfunc(f)) {
       
  2170 	zsfree(f->name);
       
  2171 	zsfree(f->module);
       
  2172 	zfree(f, sizeof(*f));
       
  2173 
       
  2174 	return 1;
       
  2175     }
       
  2176     f->flags &= ~MFF_ADDED; /* still to autoload, not added yet */
       
  2177 
       
  2178     return 0;
       
  2179 }
       
  2180 
       
  2181 /**/
       
  2182 mod_export int
       
  2183 deletemathfunc(MathFunc f)
       
  2184 {
       
  2185     MathFunc p, q;
       
  2186 
       
  2187     for (p = mathfuncs, q = NULL; p && p != f; q = p, p = p->next);
       
  2188 
       
  2189     if (p) {
       
  2190 	if (q)
       
  2191 	    q->next = f->next;
       
  2192 	else
       
  2193 	    mathfuncs = f->next;
       
  2194 
       
  2195 	if (f->module) {
       
  2196 	    zsfree(f->name);
       
  2197 	    zsfree(f->module);
       
  2198 	    zfree(f, sizeof(*f));
       
  2199 	} else
       
  2200 	    f->flags &= ~MFF_ADDED;
       
  2201 
       
  2202 	return 0;
       
  2203     }
       
  2204     return -1;
       
  2205 }
       
  2206 
       
  2207 /**/
       
  2208 mod_export int
       
  2209 deletemathfuncs(char const *nam, MathFunc f, int size)
       
  2210 {
       
  2211     int hads = 0, hadf = 0;
       
  2212 
       
  2213     while (size--) {
       
  2214 	if (!(f->flags & MFF_ADDED)) {
       
  2215 	    f++;
       
  2216 	    continue;
       
  2217 	}
       
  2218 	if (deletemathfunc(f)) {
       
  2219 	    zwarnnam(nam, "math function `%s' already deleted",
       
  2220 		     f->name, 0);
       
  2221 	    hadf = 1;
       
  2222 	} else
       
  2223 	    hads = 2;
       
  2224 	f++;
       
  2225     }
       
  2226     return hadf ? hads : 1;
       
  2227 }