From b0c5f09169ac31855ebf0e93772bb57b9635b380 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 28 May 2007 22:57:39 +0000 Subject: see 23479: add initial features support for modules --- Src/Builtins/rlimits.c | 27 +- Src/Builtins/sched.c | 28 +- Src/Modules/cap.c | 30 +- Src/Modules/clone.c | 30 +- Src/Modules/datetime.c | 41 +- Src/Modules/example.c | 35 +- Src/Modules/files.c | 28 +- Src/Modules/langinfo.c | 92 +- Src/Modules/langinfo.mdd | 2 +- Src/Modules/mapfile.c | 99 +- Src/Modules/mathfunc.c | 28 +- Src/Modules/parameter.c | 251 ++- Src/Modules/pcre.c | 41 +- Src/Modules/regex.c | 30 +- Src/Modules/socket.c | 29 +- Src/Modules/stat.c | 29 +- Src/Modules/system.c | 138 +- Src/Modules/tcp.c | 28 +- Src/Modules/termcap.c | 110 +- Src/Modules/terminfo.c | 112 +- Src/Modules/zftp.c | 60 +- Src/Modules/zprof.c | 29 +- Src/Modules/zpty.c | 30 +- Src/Modules/zselect.c | 32 +- Src/Modules/zutil.c | 27 +- Src/Zle/compctl.c | 28 +- Src/Zle/complete.c | 33 +- Src/Zle/complist.c | 27 +- Src/Zle/computil.c | 28 +- Src/Zle/deltochar.c | 29 +- Src/Zle/zle_main.c | 27 +- Src/Zle/zle_thingy.c | 2 +- Src/Zle/zle_tricky.c | 2 +- Src/Zle/zleparameter.c | 118 +- Src/builtin.c | 31 +- Src/cond.c | 5 +- Src/exec.c | 4 +- Src/init.c | 10 +- Src/mkbltnmlst.sh | 7 +- Src/mkmakemod.sh | 2 + Src/modentry.c | 10 +- Src/module.c | 3805 +++++++++++++++++++++++++++------------------- Src/params.c | 45 +- Src/zsh.h | 91 +- 44 files changed, 3338 insertions(+), 2352 deletions(-) (limited to 'Src') diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c index 88c7602af..8d55d022d 100644 --- a/Src/Builtins/rlimits.c +++ b/Src/Builtins/rlimits.c @@ -889,6 +889,14 @@ static struct builtin bintab[] = { BUILTIN("unlimit", 0, bin_unlimit, 0, -1, 0, "hs", NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -896,18 +904,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return setfeatureenables(m->nam, &module_features, NULL); return 0; } diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c index 1d9feab7d..b6b00dff3 100644 --- a/Src/Builtins/sched.c +++ b/Src/Builtins/sched.c @@ -333,6 +333,14 @@ static struct builtin bintab[] = { BUILTIN("sched", 0, bin_sched, 0, -1, 0, NULL, NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -340,12 +348,25 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab))) - return 1; addprepromptfn(&checksched); return 0; } @@ -364,8 +385,7 @@ cleanup_(Module m) zfree(sch, sizeof(*sch)); } delprepromptfn(&checksched); - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/cap.c b/Src/Modules/cap.c index 875b8c4e5..2886c42b4 100644 --- a/Src/Modules/cap.c +++ b/Src/Modules/cap.c @@ -122,6 +122,14 @@ static struct builtin bintab[] = { BUILTIN("setcap", 0, bin_setcap, 2, -1, 0, NULL, NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -131,19 +139,33 @@ setup_(UNUSED(Module m)) /**/ int -boot_(Module m) +features_(Module m, char ***features) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + *features = featuresarray(m->nam, &module_features); + return 0; } /**/ int -cleanup_(Module m) +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + +/**/ +int +boot_(UNUSED(Module m)) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); return 0; } +/**/ +int +cleanup_(Module m) +{ + return setfeatureenables(m->nam, &module_features, NULL); +} + /**/ int finish_(UNUSED(Module m)) diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c index cc303d063..adab4cb59 100644 --- a/Src/Modules/clone.c +++ b/Src/Modules/clone.c @@ -109,6 +109,14 @@ static struct builtin bintab[] = { BUILTIN("clone", 0, bin_clone, 1, 1, 0, NULL, NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -118,19 +126,33 @@ setup_(UNUSED(Module m)) /**/ int -boot_(Module m) +features_(Module m, char ***features) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + *features = featuresarray(m->nam, &module_features); + return 0; } /**/ int -cleanup_(Module m) +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + +/**/ +int +boot_(UNUSED(Module m)) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); return 0; } +/**/ +int +cleanup_(Module m) +{ + return setfeatureenables(m->nam, &module_features, NULL); +} + /**/ int finish_(UNUSED(Module m)) diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c index add4b303b..06bf52046 100644 --- a/Src/Modules/datetime.c +++ b/Src/Modules/datetime.c @@ -154,8 +154,16 @@ static const struct gsu_integer epochseconds_gsu = { getcurrentsecs, NULL, stdunsetfn }; static struct paramdef patab[] = { - PARAMDEF("EPOCHSECONDS", PM_INTEGER|PM_SPECIAL|PM_READONLY, - NULL, &epochseconds_gsu), + SPECIALPMDEF("EPOCHSECONDS", PM_INTEGER|PM_READONLY, + &epochseconds_gsu, NULL, NULL), +}; + +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + patab, sizeof(patab)/sizeof(*patab), + NULL, 0, + 0 }; /**/ @@ -167,28 +175,33 @@ setup_(UNUSED(Module m)) /**/ int -boot_(Module m) +features_(Module m, char ***features) { - return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | - addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) - ); + *features = featuresarray(m->nam, &module_features); + return 0; } /**/ int -cleanup_(Module m) +enables_(Module m, int **enables) { - Param pm; + return handlefeatures(m->nam, &module_features, enables); +} - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - pm = (Param) paramtab->getnode(paramtab, "EPOCHSECONDS"); - if (pm && (pm->node.flags & PM_SPECIAL)) { - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); - } +/**/ +int +boot_(Module m) +{ return 0; } +/**/ +int +cleanup_(Module m) +{ + return setfeatureenables(m->nam, &module_features, NULL); +} + /**/ int finish_(UNUSED(Module m)) diff --git a/Src/Modules/example.c b/Src/Modules/example.c index ab3a70592..88e910814 100644 --- a/Src/Modules/example.c +++ b/Src/Modules/example.c @@ -184,6 +184,14 @@ static struct funcwrap wrapper[] = { WRAPDEF(ex_wrapper), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + cotab, sizeof(cotab)/sizeof(*cotab), + patab, sizeof(patab)/sizeof(*patab), + mftab, sizeof(mftab)/sizeof(*mftab), + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -193,6 +201,21 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -203,23 +226,15 @@ boot_(Module m) arrparam[0] = ztrdup("example"); arrparam[1] = ztrdup("array"); arrparam[2] = NULL; - return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | - addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) | - addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) | - addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)) | - !addwrapper(m, wrapper)); + return addwrapper(m, wrapper); } /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); - deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)); - deletemathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); deletewrapper(m, wrapper); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/files.c b/Src/Modules/files.c index 079aeac4d..ba742cc50 100644 --- a/Src/Modules/files.c +++ b/Src/Modules/files.c @@ -706,6 +706,14 @@ static struct builtin bintab[] = { BUILTIN("sync", 0, bin_sync, 0, 0, 0, NULL, NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -713,19 +721,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/langinfo.c b/Src/Modules/langinfo.c index a09c1a0bb..cfbdeed44 100644 --- a/Src/Modules/langinfo.c +++ b/Src/Modules/langinfo.c @@ -30,14 +30,10 @@ #include "langinfo.mdh" #include "langinfo.pro" -static char langinfo_nam[] = "langinfo"; - #ifdef HAVE_LANGINFO_H # include #endif -static Param langinfo_pm; - /**/ #ifdef HAVE_NL_LANGINFO @@ -395,46 +391,6 @@ liitem(char *name) return NULL; } -/**/ -static void -shempty(void) -{ -} - -/* Create a simple special hash parameter. */ - -/**/ -static Param -createlihash() -{ - Param pm; - HashTable ht; - - unsetparam(langinfo_nam); - - if (!(pm = createparam(langinfo_nam, PM_SPECIAL|PM_HIDE|PM_HIDEVAL| - PM_REMOVABLE|PM_HASHED))) - return NULL; - - pm->level = pm->old ? locallevel : 0; - pm->gsu.h = &stdhash_gsu; - pm->u.hash = ht = newhashtable(7, langinfo_nam, NULL); - - ht->hash = hasher; - ht->emptytable = (TableFunc) shempty; - ht->filltable = NULL; - ht->addnode = (AddNodeFunc) shempty; - ht->getnode = ht->getnode2 = getlanginfo; - ht->removenode = (RemoveNodeFunc) shempty; - ht->disablenode = NULL; - ht->enablenode = NULL; - ht->freenode = (FreeNodeFunc) shempty; - ht->printnode = printparamnode; - ht->scantab = scanlanginfo; - - return (langinfo_pm = pm); -} - /**/ static HashNode getlanginfo(UNUSED(HashTable ht), char *name) @@ -490,9 +446,25 @@ scanlanginfo(UNUSED(HashTable ht), ScanFunc func, int flags) } +static struct paramdef partab[] = { + SPECIALPMDEF("langinfo", 0, NULL, getlanginfo, scanlanginfo) +}; + /**/ #endif /* HAVE_NL_LANGINFO */ +static struct features module_features = { + NULL, 0, + NULL, 0, +#ifdef HAVE_NL_LANGINFO + partab, sizeof(partab)/sizeof(*partab), +#else + NULL, 0, +#endif + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -502,33 +474,33 @@ setup_(UNUSED(Module m)) /**/ int -boot_(UNUSED(Module m)) +features_(Module m, char ***features) { -#ifdef HAVE_NL_LANGINFO - if (!createlihash()) - return 1; -#else - unsetparam(langinfo_nam); -#endif + *features = featuresarray(m->nam, &module_features); return 0; } /**/ int -cleanup_(UNUSED(Module m)) +enables_(Module m, int **enables) { -#ifdef HAVE_NL_LANGINFO - Param pm; + return handlefeatures(m->nam, &module_features, enables); +} - if ((pm = (Param) paramtab->getnode(paramtab, langinfo_nam)) && - pm == langinfo_pm) { - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); - } -#endif +/**/ +int +boot_(UNUSED(Module m)) +{ return 0; } +/**/ +int +cleanup_(UNUSED(Module m)) +{ + return setfeatureenables(m->nam, &module_features, NULL); +} + /**/ int finish_(UNUSED(Module m)) diff --git a/Src/Modules/langinfo.mdd b/Src/Modules/langinfo.mdd index a3a615113..66c4cd452 100644 --- a/Src/Modules/langinfo.mdd +++ b/Src/Modules/langinfo.mdd @@ -1,6 +1,6 @@ name=zsh/langinfo -link=either +link=`if test x$ac_cv_func_nl_langinfo; then echo either; else echo no; fi` load=no autoparams="langinfo" diff --git a/Src/Modules/mapfile.c b/Src/Modules/mapfile.c index 9f3ca2612..25b506f03 100644 --- a/Src/Modules/mapfile.c +++ b/Src/Modules/mapfile.c @@ -58,60 +58,9 @@ #endif /* HAVE_MMAP && HAVE_MUNMAP && HAVE_MSYNC */ #endif /* HAVE_SYS_MMAN_H && HAVE_FTRUNCATE */ -/* - * Name of the special parameter. If zmodload took arguments, - * we could make this selectable. - */ -static char mapfile_nam[] = "mapfile"; - -static Param mapfile_pm; - -/* Empty dummy function for special hash parameters. */ - -/**/ -static void -shempty(void) -{ -} - static const struct gsu_hash mapfiles_gsu = { hashgetfn, setpmmapfiles, stdunsetfn }; -/* Create the special hash parameter. */ - -/**/ -static Param -createmapfilehash() -{ - Param pm; - HashTable ht; - - unsetparam(mapfile_nam); - mapfile_pm = NULL; - - if (!(pm = createparam(mapfile_nam, PM_SPECIAL|PM_HIDE|PM_HIDEVAL| - PM_REMOVABLE|PM_HASHED))) - return NULL; - - pm->level = pm->old ? locallevel : 0; - pm->gsu.h = &mapfiles_gsu; - pm->u.hash = ht = newhashtable(7, mapfile_nam, NULL); - - ht->hash = hasher; - ht->emptytable = (TableFunc) shempty; - ht->filltable = NULL; - ht->addnode = (AddNodeFunc) shempty; - ht->getnode = ht->getnode2 = getpmmapfile; - ht->removenode = (RemoveNodeFunc) shempty; - ht->disablenode = NULL; - ht->enablenode = NULL; - ht->freenode = (FreeNodeFunc) shempty; - ht->printnode = printparamnode; - ht->scantab = scanpmmapfile; - - return (mapfile_pm = pm); -} - /* Functions for the options special parameter. */ /**/ @@ -192,9 +141,6 @@ setpmmapfiles(Param pm, HashTable ht) int i; HashNode hn; - /* just to see if I've understood what's happening */ - DPUTS(pm != mapfile_pm, "BUG: setpmmapfiles called for wrong param"); - if (!ht) return; @@ -261,6 +207,10 @@ get_contents(char *fname) static const struct gsu_scalar mapfile_gsu = { strgetfn, setpmmapfile, unsetpmmapfile }; +static struct paramdef partab[] = { + SPECIALPMDEF("mapfile", 0, &mapfiles_gsu, getpmmapfile, scanpmmapfile) +}; + /**/ static HashNode getpmmapfile(UNUSED(HashTable ht), char *name) @@ -272,7 +222,7 @@ getpmmapfile(UNUSED(HashTable ht), char *name) pm->node.nam = dupstring(name); pm->node.flags = PM_SCALAR; pm->gsu.s = &mapfile_gsu; - pm->node.flags |= (mapfile_pm->node.flags & PM_READONLY); + pm->node.flags |= (partab[0].pm->node.flags & PM_READONLY); /* Set u.str to contents of file given by name */ if ((contents = get_contents(pm->node.nam))) @@ -298,7 +248,7 @@ scanpmmapfile(UNUSED(HashTable ht), ScanFunc func, int flags) memset((void *)&pm, 0, sizeof(struct param)); pm.node.flags = PM_SCALAR; pm.gsu.s = &mapfile_gsu; - pm.node.flags |= (mapfile_pm->node.flags & PM_READONLY); + pm.node.flags |= (partab[0].pm->node.flags & PM_READONLY); /* Here we scan the current directory, calling func() for each file */ while ((pm.node.nam = zreaddir(dir, 1))) { @@ -315,6 +265,14 @@ scanpmmapfile(UNUSED(HashTable ht), ScanFunc func, int flags) closedir(dir); } +static struct features module_features = { + NULL, 0, + NULL, 0, + partab, sizeof(partab)/sizeof(*partab), + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -324,13 +282,23 @@ setup_(UNUSED(Module m)) /**/ int -boot_(UNUSED(Module m)) +features_(Module m, char ***features) { - /* Create the special associative array. */ + *features = featuresarray(m->nam, &module_features); + return 0; +} - if (!createmapfilehash()) - return 1; +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} +/**/ +int +boot_(UNUSED(Module m)) +{ return 0; } @@ -338,16 +306,7 @@ boot_(UNUSED(Module m)) int cleanup_(UNUSED(Module m)) { - Param pm; - - /* Remove the special parameter if it is still the same. */ - - if ((pm = (Param) paramtab->getnode(paramtab, mapfile_nam)) && - pm == mapfile_pm) { - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); - } - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c index f6d437ff9..a473476e3 100644 --- a/Src/Modules/mathfunc.c +++ b/Src/Modules/mathfunc.c @@ -561,6 +561,14 @@ math_string(UNUSED(char *name), char *arg, int id) } +static struct features module_features = { + NULL, 0, + NULL, 0, + NULL, 0, + mftab, sizeof(mftab)/sizeof(*mftab), + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -568,19 +576,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - return !addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); + return 0; } /**/ int cleanup_(Module m) { - deletemathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 7b790acc6..9d52bcd3f 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -34,46 +34,6 @@ static int incleanup; -/* Empty dummy function for special hash parameters. */ - -/**/ -static void -shempty(void) -{ -} - -/* Create a simple special hash parameter. */ - -/**/ -static Param -createspecialhash(char *name, GetNodeFunc get, ScanTabFunc scan) -{ - Param pm; - HashTable ht; - - if (!(pm = createparam(name, PM_SPECIAL|PM_HIDE|PM_HIDEVAL| - PM_REMOVABLE|PM_HASHED))) - return NULL; - - pm->level = pm->old ? locallevel : 0; - pm->gsu.h = &stdhash_gsu; - pm->u.hash = ht = newhashtable(0, name, NULL); - - ht->hash = hasher; - ht->emptytable = (TableFunc) shempty; - ht->filltable = NULL; - ht->addnode = (AddNodeFunc) shempty; - ht->getnode = ht->getnode2 = get; - ht->removenode = (RemoveNodeFunc) shempty; - ht->disablenode = NULL; - ht->enablenode = NULL; - ht->freenode = (FreeNodeFunc) shempty; - ht->printnode = printparamnode; - ht->scantab = scan; - - return pm; -} - /* Functions for the parameters special parameter. */ /* Return a string describing the type of a parameter. */ @@ -1838,13 +1798,6 @@ struct pardef { Param pm; }; -/* - * This is a duplicate of nullsethash_gsu. On some systems - * (such as Cygwin) we can't put a pointer to an imported variable - * in a compile-time initialiser, so we use this instead. - */ -static const struct gsu_hash pmnullsethash_gsu = -{ hashgetfn, nullsethashfn, nullunsetfn }; static const struct gsu_hash pmcommands_gsu = { hashgetfn, setpmcommands, stdunsetfn }; static const struct gsu_hash pmfunctions_gsu = @@ -1881,147 +1834,115 @@ static const struct gsu_array dirs_gsu = static const struct gsu_array historywords_gsu = { histwgetfn, arrsetfn, stdunsetfn }; -static struct pardef partab[] = { - { "parameters", PM_READONLY, - getpmparameter, scanpmparameters, &pmnullsethash_gsu, - NULL, NULL }, - { "commands", 0, - getpmcommand, scanpmcommands, &pmcommands_gsu, - NULL, NULL }, - { "functions", 0, - getpmfunction, scanpmfunctions, &pmfunctions_gsu, - NULL, NULL }, - { "dis_functions", 0, - getpmdisfunction, scanpmdisfunctions, &pmdisfunctions_gsu, - NULL, NULL }, - { "funcstack", PM_ARRAY|PM_SPECIAL|PM_READONLY, - NULL, NULL, NULL, - &funcstack_gsu, NULL }, - { "functrace", PM_ARRAY|PM_SPECIAL|PM_READONLY, - NULL, NULL, NULL, - &functrace_gsu, NULL }, - { "builtins", PM_READONLY, - getpmbuiltin, scanpmbuiltins, NULL, - NULL, NULL }, - { "dis_builtins", PM_READONLY, - getpmdisbuiltin, scanpmdisbuiltins, NULL, - NULL, NULL }, - { "reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY, - NULL, NULL, NULL, - &reswords_gsu, NULL }, - { "dis_reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY, - NULL, NULL, NULL, - &disreswords_gsu, NULL }, - { "options", 0, - getpmoption, scanpmoptions, &pmoptions_gsu, - NULL, NULL }, - { "modules", PM_READONLY, - getpmmodule, scanpmmodules, NULL, - NULL, NULL }, - { "dirstack", PM_ARRAY|PM_SPECIAL|PM_REMOVABLE, - NULL, NULL, NULL, - &dirs_gsu, NULL }, - { "history", PM_READONLY, - getpmhistory, scanpmhistory, NULL, - NULL, NULL, }, - { "historywords", PM_ARRAY|PM_SPECIAL|PM_READONLY, - NULL, NULL, NULL, - &historywords_gsu, NULL }, - { "jobtexts", PM_READONLY, - getpmjobtext, scanpmjobtexts, NULL, - NULL, NULL }, - { "jobstates", PM_READONLY, - getpmjobstate, scanpmjobstates, NULL, - NULL, NULL }, - { "jobdirs", PM_READONLY, - getpmjobdir, scanpmjobdirs, NULL, - NULL, NULL }, - { "nameddirs", 0, - getpmnameddir, scanpmnameddirs, &pmnameddirs_gsu, - NULL, NULL }, - { "userdirs", PM_READONLY, - getpmuserdir, scanpmuserdirs, NULL, - NULL, NULL }, - { "aliases", 0, - getpmralias, scanpmraliases, &pmraliases_gsu, - NULL, NULL }, - { "galiases", 0, - getpmgalias, scanpmgaliases, &pmgaliases_gsu, - NULL, NULL }, - { "saliases", 0, - getpmsalias, scanpmsaliases, &pmsaliases_gsu, - NULL, NULL }, - { "dis_aliases", 0, - getpmdisralias, scanpmdisraliases, &pmdisraliases_gsu, - NULL, NULL }, - { "dis_galiases", 0, - getpmdisgalias, scanpmdisgaliases, &pmdisgaliases_gsu, - NULL, NULL }, - { "dis_saliases", 0, - getpmdissalias, scanpmdissaliases, &pmdissaliases_gsu, - NULL, NULL }, - { NULL, 0, NULL, NULL, NULL, NULL, NULL } +static struct paramdef partab[] = { + SPECIALPMDEF("parameters", PM_READONLY, + NULL, getpmparameter, scanpmparameters), + SPECIALPMDEF("commands", 0, &pmcommands_gsu, getpmcommand, scanpmcommands), + SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction, + scanpmfunctions), + SPECIALPMDEF("dis_functions", 0, + &pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions), + SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY, + &funcstack_gsu, NULL, NULL), + SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY, + &functrace_gsu, NULL, NULL), + SPECIALPMDEF("builtins", PM_READONLY, NULL, getpmbuiltin, scanpmbuiltins), + SPECIALPMDEF("dis_builtins", PM_READONLY, + NULL, getpmdisbuiltin, scanpmdisbuiltins), + SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY, + &reswords_gsu, NULL, NULL), + SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY, + &disreswords_gsu, NULL, NULL), + SPECIALPMDEF("options", 0, + &pmoptions_gsu, getpmoption, scanpmoptions), + SPECIALPMDEF("modules", PM_READONLY, + NULL, getpmmodule, scanpmmodules), + SPECIALPMDEF("dirstack", PM_ARRAY, + &dirs_gsu, NULL, NULL), + SPECIALPMDEF("history", PM_READONLY, + NULL, getpmhistory, scanpmhistory), + SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY, + &historywords_gsu, NULL, NULL), + SPECIALPMDEF("jobtexts", PM_READONLY, + NULL, getpmjobtext, scanpmjobtexts), + SPECIALPMDEF("jobstates", PM_READONLY, + NULL, getpmjobstate, scanpmjobstates), + SPECIALPMDEF("jobdirs", PM_READONLY, + NULL, getpmjobdir, scanpmjobdirs), + SPECIALPMDEF("nameddirs", 0, + &pmnameddirs_gsu, getpmnameddir, scanpmnameddirs), + SPECIALPMDEF("userdirs", PM_READONLY, + NULL, getpmuserdir, scanpmuserdirs), + SPECIALPMDEF("aliases", 0, + &pmraliases_gsu, getpmralias, scanpmraliases), + SPECIALPMDEF("galiases", 0, + &pmgaliases_gsu, getpmgalias, scanpmgaliases), + SPECIALPMDEF("saliases", 0, + &pmsaliases_gsu, getpmsalias, scanpmsaliases), + SPECIALPMDEF("dis_aliases", 0, + &pmdisraliases_gsu, getpmdisralias, scanpmdisraliases), + SPECIALPMDEF("dis_galiases", 0, + &pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases), + SPECIALPMDEF("dis_saliases", 0, + &pmdissaliases_gsu, getpmdissalias, scanpmdissaliases) +}; + +static struct features module_features = { + NULL, 0, + NULL, 0, + partab, sizeof(partab)/sizeof(*partab), + NULL, 0, + 0 }; /**/ int setup_(UNUSED(Module m)) { - incleanup = 0; - return 0; } /**/ int -boot_(UNUSED(Module m)) +features_(Module m, char ***features) { - /* Create the special associative arrays. - * As an example for autoloaded parameters, this is probably a bad - * example, because the zsh core doesn't support creation of - * special hashes, yet. */ - - struct pardef *def; - - for (def = partab; def->name; def++) { - unsetparam(def->name); - - if (def->getnfn) { - if (!(def->pm = createspecialhash(def->name, def->getnfn, - def->scantfn))) - return 1; - def->pm->node.flags |= def->flags; - if (def->hash_gsu) - def->pm->gsu.h = def->hash_gsu; - } else { - if (!(def->pm = createparam(def->name, def->flags | PM_HIDE| - PM_HIDEVAL | PM_REMOVABLE))) - return 1; - def->pm->gsu.a = def->array_gsu; - } - } + *features = featuresarray(m->nam, &module_features); return 0; } /**/ int -cleanup_(UNUSED(Module m)) +enables_(Module m, int **enables) { - Param pm; - struct pardef *def; - + int ret; + /* + * If we remove features, we shouldn't have an effect + * on the main shell, so set the flag to indicate. + */ incleanup = 1; + ret = handlefeatures(m->nam, &module_features, enables); + incleanup = 0; + return ret; +} - for (def = partab; def->name; def++) { - if ((pm = (Param) paramtab->getnode(paramtab, def->name)) && - pm == def->pm) { - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); - } - } +/**/ +int +boot_(Module m) +{ return 0; } +/**/ +int +cleanup_(Module m) +{ + int ret; + incleanup = 1; + ret = setfeatureenables(m->nam, &module_features, NULL); + incleanup = 0; + return ret; +} + /**/ int finish_(UNUSED(Module m)) diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c index d067d8949..45c38eba0 100644 --- a/Src/Modules/pcre.c +++ b/Src/Modules/pcre.c @@ -295,6 +295,19 @@ static struct builtin bintab[] = { }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), +#if defined(HAVE_PCRE_COMPILE) && defined(HAVE_PCRE_EXEC) + cotab, sizeof(cotab)/sizeof(*cotab), +#else /* !(HAVE_PCRE_COMPILE && HAVE_PCRE_EXEC) */ + NULL, 0, +#endif /* !(HAVE_PCRE_COMPILE && HAVE_PCRE_EXEC) */ + NULL, 0, + NULL, 0, + 0 +}; + + /**/ int setup_(UNUSED(Module m)) @@ -302,27 +315,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { -#if defined(HAVE_PCRE_COMPILE) && defined(HAVE_PCRE_EXEC) - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) || - !addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); -#else /* !(HAVE_PCRE_COMPILE && HAVE_PCRE_EXEC) */ - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); -#endif /* !(HAVE_PCRE_COMPILE && HAVE_PCRE_EXEC) */ + return 0; } /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); -#if defined(HAVE_PCRE_COMPILE) && defined(HAVE_PCRE_EXEC) - deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); -#endif /* !(HAVE_PCRE_COMPILE && HAVE_PCRE_EXEC) */ - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/regex.c b/Src/Modules/regex.c index 44019a1b9..a3d956055 100644 --- a/Src/Modules/regex.c +++ b/Src/Modules/regex.c @@ -131,6 +131,16 @@ static struct conddef cotab[] = { CONDDEF("regex-match", CONDF_INFIX, zcond_regex_match, 0, 0, ZREGEX_EXTENDED) }; + +static struct features module_features = { + NULL, 0, + cotab, sizeof(cotab)/sizeof(*cotab), + NULL, 0, + NULL, 0, + 0 +}; + + /**/ int setup_(UNUSED(Module m)) @@ -138,19 +148,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - return !addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); + return 0; } /**/ int cleanup_(Module m) { - deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/socket.c b/Src/Modules/socket.c index 7ca56b4e7..413625dcf 100644 --- a/Src/Modules/socket.c +++ b/Src/Modules/socket.c @@ -255,6 +255,14 @@ static struct builtin bintab[] = { BUILTIN("zsocket", 0, bin_zsocket, 0, 3, 0, "ad:ltv", NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /* The load/unload routines required by the zsh library interface */ /**/ @@ -266,18 +274,31 @@ setup_(UNUSED(Module m)) /**/ int -boot_(Module m) +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return handlefeatures(m->nam, &module_features, enables); } +/**/ +int +boot_(Module m) +{ + return 0; +} /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c index 3ffaf9d4d..1d55317ea 100644 --- a/Src/Modules/stat.c +++ b/Src/Modules/stat.c @@ -621,6 +621,15 @@ bin_stat(char *name, char **args, Options ops, UNUSED(int func)) static struct builtin bintab[] = { BUILTIN("stat", 0, bin_stat, 0, -1, 0, NULL, NULL), + BUILTIN("zstat", 0, bin_stat, 0, -1, 0, NULL, NULL), +}; + +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 }; /**/ @@ -630,19 +639,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/system.c b/Src/Modules/system.c index 1eaa2fabd..f8a188d42 100644 --- a/Src/Modules/system.c +++ b/Src/Modules/system.c @@ -364,47 +364,70 @@ static const struct gsu_array errnos_gsu = /* Functions for the sysparams special parameter. */ /**/ -static char * -sysparamgetfn(Param pm) +static void +fillpmsysparams(Param pm, char *name) { char buf[DIGBUFSIZE]; int num; - if (!strcmp(pm->node.nam, "pid")) { + pm->node.nam = dupstring(name); + pm->node.flags = PM_SCALAR | PM_READONLY; + pm->gsu.s = &nullsetscalar_gsu; + if (!strcmp(name, "pid")) { num = (int)getpid(); - } else if (!strcmp(pm->node.nam, "ppid")) { + } else if (!strcmp(name, "ppid")) { num = (int)getppid(); - } - else { -#ifdef DEBUG - dputs("Bad sysparam parameter"); -#endif - return ""; + } else { + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return; } sprintf(buf, "%d", num); - return dupstring(buf); + pm->u.str = dupstring(buf); } -static const struct gsu_scalar sysparam_gsu = -{ sysparamgetfn, strsetfn, stdunsetfn }; +/**/ +static HashNode +getpmsysparams(UNUSED(HashTable ht), char *name) +{ + Param pm; + + pm = (Param) hcalloc(sizeof(struct param)); + fillpmsysparams(pm, name); + return &pm->node; +} + + +/**/ static void -fixsysparams(HashNode hn, int flags) +scanpmsysparams(UNUSED(HashTable ht), ScanFunc func, int flags) { - Param pm = (Param)hn; + struct param spm; - if (flags) { - /* prepare to free */ - pm->node.flags &= ~PM_READONLY; - } else { - /* assign */ - pm->gsu.s = &sysparam_gsu; - pm->node.flags |= PM_READONLY; - } + fillpmsysparams(&spm, "pid"); + func(&spm.node, flags); + fillpmsysparams(&spm, "ppid"); + func(&spm.node, flags); } +static struct paramdef partab[] = { + SPECIALPMDEF("errnos", PM_ARRAY|PM_READONLY, + &errnos_gsu, NULL, NULL), + SPECIALPMDEF("sysparams", PM_READONLY, + NULL, getpmsysparams, scanpmsysparams) +}; + +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + partab, sizeof(partab)/sizeof(*partab), + NULL, 0, + 0 +}; + /* The load/unload routines required by the zsh library interface */ /**/ @@ -415,61 +438,24 @@ setup_(UNUSED(Module m)) } /**/ -static void -tidyparam(Param pm) +int +features_(Module m, char ***features) { - if (!pm) - return; - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); + *features = featuresarray(m->nam, &module_features); + return 0; } +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} /**/ int boot_(Module m) { - Param pm_nos, pm_params; - HashTable ht; - const char *sysparams_args[] = { - "pid", "ppid", NULL - }, **srcptr; - char **arglist, **dstptr; - - /* this takes care of an autoload on errnos */ - unsetparam("errnos"); - if (!(pm_nos = createparam("errnos", PM_ARRAY|PM_SPECIAL|PM_READONLY| - PM_HIDE|PM_HIDEVAL|PM_REMOVABLE))) - return 1; - pm_nos->gsu.a = &errnos_gsu; - - if (!(pm_params = createparam("sysparams", PM_HASHED|PM_SPECIAL| - PM_HIDE|PM_HIDEVAL|PM_REMOVABLE))) { - tidyparam(pm_nos); - return 1; - } - pm_params->level = pm_params->old ? locallevel : 0; - pm_params->gsu.h = &stdhash_gsu; - pm_params->u.hash = ht = newparamtable(0, "sysparams"); - - arglist = (char **)zshcalloc((2*arrlen((char **)sysparams_args) + 1) * - sizeof(char *)); - for (srcptr = sysparams_args, dstptr = arglist; *srcptr; ) { - *dstptr++ = ztrdup(*srcptr++); - *dstptr++ = ztrdup(""); - } - *dstptr = NULL; - /* make sure we don't overwrite the hash table: use the "augment" arg */ - arrhashsetfn(pm_params, arglist, 1); - scanhashtable(ht, 0, 0, 0, fixsysparams, 0); - - pm_params->node.flags |= PM_READONLY; - - if (!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab))) { - tidyparam(pm_nos); - tidyparam(pm_params); - return 1; - } return 0; } @@ -478,17 +464,7 @@ boot_(Module m) int cleanup_(Module m) { - Param pm; - if ((pm = (Param)paramtab->getnode(paramtab, "errnos"))) - tidyparam(pm); - if ((pm = (Param)paramtab->getnode(paramtab, "sysparams"))) - { - scanhashtable(pm->u.hash, 0, 0, 0, fixsysparams, 1); - tidyparam(pm); - } - - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/tcp.c b/Src/Modules/tcp.c index 2484edfe3..86803e952 100644 --- a/Src/Modules/tcp.c +++ b/Src/Modules/tcp.c @@ -675,6 +675,14 @@ static struct builtin bintab[] = { BUILTIN("ztcp", 0, bin_ztcp, 0, 3, 0, "acd:flLtv", NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /* The load/unload routines required by the zsh library interface */ /**/ @@ -684,12 +692,27 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { ztcp_sessions = znewlinklist(); - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } @@ -698,9 +721,8 @@ int cleanup_(Module m) { tcp_cleanup(); - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); freelinklist(ztcp_sessions, (FreeFunc) ztcp_free_session); - return 0; + return setfeatureeanbles(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/termcap.c b/Src/Modules/termcap.c index e29b2bf74..c19db4892 100644 --- a/Src/Modules/termcap.c +++ b/Src/Modules/termcap.c @@ -48,8 +48,7 @@ #include "termcap.mdh" #include "termcap.pro" -static char termcap_nam[] = "termcap"; - +/**/ #ifdef HAVE_TGETENT # ifdef USES_TERM_H # ifdef HAVE_TERMIO_H @@ -65,8 +64,6 @@ static char termcap_nam[] = "termcap"; # endif # endif -static Param termcap_pm; - #ifndef HAVE_BOOLCODES static char *boolcodes[] = { "bw", "am", "ut", "cc", "xs", "YA", "YF", "YB", "xt", "xn", "eo", @@ -161,61 +158,10 @@ bin_echotc(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) return 0; } -#else /* ! HAVE_TGETENT */ - -#define bin_echotc bin_notavail - -#endif /* HAVE_TGETENT */ - static struct builtin bintab[] = { BUILTIN("echotc", 0, bin_echotc, 1, -1, 0, NULL, NULL), }; -/**/ -#ifdef HAVE_TGETENT - -/* Empty dummy function for special hash parameters. */ - -/**/ -static void -shempty(void) -{ -} - -/* Create a simple special hash parameter. */ - -/**/ -static Param -createtchash() -{ - Param pm; - HashTable ht; - - unsetparam(termcap_nam); - - if (!(pm = createparam(termcap_nam, PM_SPECIAL|PM_HIDE|PM_HIDEVAL| - PM_REMOVABLE|PM_HASHED))) - return NULL; - - pm->level = pm->old ? locallevel : 0; - pm->gsu.h = &stdhash_gsu; - pm->u.hash = ht = newhashtable(7, termcap_nam, NULL); - - ht->hash = hasher; - ht->emptytable = (TableFunc) shempty; - ht->filltable = NULL; - ht->addnode = (AddNodeFunc) shempty; - ht->getnode = ht->getnode2 = gettermcap; - ht->removenode = (RemoveNodeFunc) shempty; - ht->disablenode = NULL; - ht->enablenode = NULL; - ht->freenode = (FreeNodeFunc) shempty; - ht->printnode = printparamnode; - ht->scantab = scantermcap; - - return (termcap_pm = pm); -} - /**/ static HashNode gettermcap(UNUSED(HashTable ht), char *name) @@ -364,9 +310,29 @@ scantermcap(UNUSED(HashTable ht), ScanFunc func, int flags) } } +struct paramdef partab[] = { + SPECIALPMDEF("termcap", PM_READONLY, NULL, gettermcap, scantermcap) +}; + /**/ #endif /* HAVE_TGETENT */ +static struct features module_features = { +#ifdef HAVE_TGETENT + bintab, sizeof(bintab)/sizeof(*bintab), +#else + NULL, 0, +#endif + NULL, 0, +#ifdef HAVE_TGETENT + partab, sizeof(partab)/sizeof(*partab), +#else + NULL, 0, +#endif + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -374,6 +340,21 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -382,30 +363,15 @@ boot_(Module m) # ifdef HAVE_SETUPTERM setupterm((char *)0, 1, (int *)0); # endif - - if (!createtchash()) - return 1; -#else - unsetparam(termcap_nam); #endif - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } /**/ int cleanup_(Module m) { -#ifdef HAVE_TGETENT - Param pm; - - if ((pm = (Param) paramtab->getnode(paramtab, termcap_nam)) && - pm == termcap_pm) { - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); - } -#endif - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/terminfo.c b/Src/Modules/terminfo.c index b4a1c599b..d324c3a6c 100644 --- a/Src/Modules/terminfo.c +++ b/Src/Modules/terminfo.c @@ -37,7 +37,6 @@ #endif #include "terminfo.pro" -static char terminfo_nam[] = "terminfo"; /**/ #ifdef USE_TERMINFO_MODULE @@ -55,8 +54,6 @@ static char terminfo_nam[] = "terminfo"; # include # endif -static Param terminfo_pm; - /* echoti: output a terminfo capability */ /**/ @@ -126,63 +123,10 @@ bin_echoti(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) return 0; } -/**/ -#else /* !USE_TERMINFO_MODULE */ - -#define bin_echoti bin_notavail - -/**/ -#endif /* !USE_TERMINFO_MODULE */ - static struct builtin bintab[] = { BUILTIN("echoti", 0, bin_echoti, 1, -1, 0, NULL, NULL), }; -/**/ -#ifdef USE_TERMINFO_MODULE - -/* Empty dummy function for special hash parameters. */ - -/**/ -static void -shempty(void) -{ -} - -/* Create a simple special hash parameter. */ - -/**/ -static Param -createtihash() -{ - Param pm; - HashTable ht; - - unsetparam(terminfo_nam); - - if (!(pm = createparam(terminfo_nam, PM_SPECIAL|PM_HIDE|PM_HIDEVAL| - PM_REMOVABLE|PM_HASHED))) - return NULL; - - pm->level = pm->old ? locallevel : 0; - pm->gsu.h = &stdhash_gsu; - pm->u.hash = ht = newhashtable(7, terminfo_nam, NULL); - - ht->hash = hasher; - ht->emptytable = (TableFunc) shempty; - ht->filltable = NULL; - ht->addnode = (AddNodeFunc) shempty; - ht->getnode = ht->getnode2 = getterminfo; - ht->removenode = (RemoveNodeFunc) shempty; - ht->disablenode = NULL; - ht->enablenode = NULL; - ht->freenode = (FreeNodeFunc) shempty; - ht->printnode = printparamnode; - ht->scantab = scanterminfo; - - return (terminfo_pm = pm); -} - /**/ static HashNode getterminfo(UNUSED(HashTable ht), char *name) @@ -339,9 +283,30 @@ scanterminfo(UNUSED(HashTable ht), ScanFunc func, int flags) } } +static struct paramdef partab[] = { + SPECIALPMDEF("terminfo", PM_READONLY, NULL, + getterminfo, scanterminfo) +}; + /**/ #endif /* USE_TERMINFO_MODULE */ +static struct features module_features = { +#ifdef USE_TERMINFO_MODULE + bintab, sizeof(bintab)/sizeof(*bintab), +#else + NULL, 0, +#endif + NULL, 0, +#ifdef USE_TERMINFO_MODULE + partab, sizeof(partab)/sizeof(*partab), +#else + NULL, 0, +#endif + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -349,6 +314,21 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -360,30 +340,16 @@ boot_(Module m) if (setupterm((char *)0, 1, &errret) == ERR) return 1; # endif - - if (!createtihash()) - return 1; -#else - unsetparam(terminfo_nam); #endif - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + + return 0; } /**/ int cleanup_(Module m) { -#ifdef USE_TERMINFO_MODULE - Param pm; - - if ((pm = (Param) paramtab->getnode(paramtab, terminfo_nam)) && - pm == terminfo_pm) { - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); - } -#endif - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c index 8c9cdf735..89b869592 100644 --- a/Src/Modules/zftp.c +++ b/Src/Modules/zftp.c @@ -3151,7 +3151,6 @@ zftp_cleanup(void) zfunsetparam("ZFTP_SESSION"); freelinklist(zfsessions, (FreeFunc) freesession); zfree(zfstatusp, sizeof(int)*zfsesscnt); - deletebuiltins("zftp", bintab, sizeof(bintab)/sizeof(*bintab)); } static int @@ -3161,47 +3160,68 @@ zftpexithook(UNUSED(Hookdef d), UNUSED(void *dummy)) return 0; } +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /* The load/unload routines required by the zsh library interface */ /**/ int setup_(UNUSED(Module m)) { - /* setup_ returns 0 for success. require_module returns 1 for success. */ - return !require_module("", "zsh/net/tcp", 0, 0); + return (require_module("", "zsh/net/tcp", NULL) == 1); +} + +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); } /**/ int boot_(UNUSED(Module m)) { - int ret; - if ((ret = addbuiltins("zftp", bintab, - sizeof(bintab)/sizeof(*bintab))) == 1) { - /* if successful, set some default parameters */ - off_t tmout_def = 60; - zfsetparam("ZFTP_VERBOSE", ztrdup("450"), ZFPM_IFUNSET); - zfsetparam("ZFTP_TMOUT", &tmout_def, ZFPM_IFUNSET|ZFPM_INTEGER); - zfsetparam("ZFTP_PREFS", ztrdup("PS"), ZFPM_IFUNSET); - /* default preferences if user deletes variable */ - zfprefs = ZFPF_SNDP|ZFPF_PASV; + /* + * Set some default parameters. + * These aren't special, so aren't associated with features. + */ + off_t tmout_def = 60; + zfsetparam("ZFTP_VERBOSE", ztrdup("450"), ZFPM_IFUNSET); + zfsetparam("ZFTP_TMOUT", &tmout_def, ZFPM_IFUNSET|ZFPM_INTEGER); + zfsetparam("ZFTP_PREFS", ztrdup("PS"), ZFPM_IFUNSET); + /* default preferences if user deletes variable */ + zfprefs = ZFPF_SNDP|ZFPF_PASV; - zfsessions = znewlinklist(); - newsession("default"); + zfsessions = znewlinklist(); + newsession("default"); - addhookfunc("exit", zftpexithook); - } + addhookfunc("exit", zftpexithook); - return !ret; + return 0; } /**/ int -cleanup_(UNUSED(Module m)) +cleanup_(Module m) { deletehookfunc("exit", zftpexithook); zftp_cleanup(); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/zprof.c b/Src/Modules/zprof.c index ca053a9e9..b30e44432 100644 --- a/Src/Modules/zprof.c +++ b/Src/Modules/zprof.c @@ -295,6 +295,14 @@ static struct funcwrap wrapper[] = { WRAPDEF(zprof_wrapper), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(Module m) @@ -303,6 +311,21 @@ setup_(Module m) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -312,8 +335,7 @@ boot_(Module m) arcs = NULL; narcs = 0; stack = NULL; - return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | - !addwrapper(m, wrapper)); + return addwrapper(m, wrapper); } /**/ @@ -322,9 +344,8 @@ cleanup_(Module m) { freepfuncs(calls); freeparcs(arcs); - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); deletewrapper(m, wrapper); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 744548f50..3280b8175 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -725,10 +725,20 @@ ptyhook(UNUSED(Hookdef d), UNUSED(void *dummy)) return 0; } + static struct builtin bintab[] = { BUILTIN("zpty", 0, bin_zpty, 0, -1, 0, "ebdrwLnt", NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + + /**/ int setup_(UNUSED(Module m)) @@ -736,6 +746,21 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -743,7 +768,7 @@ boot_(Module m) ptycmds = NULL; addhookfunc("exit", ptyhook); - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } /**/ @@ -752,8 +777,7 @@ cleanup_(Module m) { deletehookfunc("exit", ptyhook); deleteallptycmds(); - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Modules/zselect.c b/Src/Modules/zselect.c index 4e547a47e..3e71fa3bd 100644 --- a/Src/Modules/zselect.c +++ b/Src/Modules/zselect.c @@ -267,10 +267,20 @@ bin_zselect(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) #endif } + static struct builtin bintab[] = { BUILTIN("zselect", 0, bin_zselect, 0, -1, 0, NULL, NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + + /* The load/unload routines required by the zsh library interface */ /**/ @@ -282,20 +292,34 @@ setup_(UNUSED(Module m)) /**/ int -boot_(Module m) +features_(Module m, char ***features) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + *features = featuresarray(m->nam, &module_features); + return 0; } +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} /**/ int -cleanup_(UNUSED(Module m)) +boot_(Module m) { - deletebuiltins("zselect", bintab, sizeof(bintab)/sizeof(*bintab)); return 0; } + +/**/ +int +cleanup_(Module m) +{ + return setfeatureenables(m->nam, &module_features, NULL); +} + /**/ int finish_(UNUSED(Module m)) diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 1e4bf975a..a4172c581 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1740,6 +1740,13 @@ static struct builtin bintab[] = { BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; /**/ int @@ -1750,19 +1757,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 81f11b423..bafbb2f68 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -3942,6 +3942,14 @@ static struct builtin bintab[] = { BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -3962,13 +3970,28 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { addhookfunc("compctl_make", (Hookfn) ccmakehookfn); addhookfunc("compctl_cleanup", (Hookfn) cccleanuphookfn); - return (addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) != 1); + return 0; } /**/ @@ -3977,8 +4000,7 @@ cleanup_(Module m) { deletehookfunc("compctl_make", (Hookfn) ccmakehookfn); deletehookfunc("compctl_cleanup", (Hookfn) cccleanuphookfn); - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c index a73d3cf14..aac760a92 100644 --- a/Src/Zle/complete.c +++ b/Src/Zle/complete.c @@ -1467,6 +1467,14 @@ struct hookdef comphooks[] = { HOOKDEF("comp_list_matches", ilistmatches, 0), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + cotab, sizeof(cotab)/sizeof(*cotab), + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -1490,6 +1498,21 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -1502,11 +1525,7 @@ boot_(Module m) addhookfunc("list_matches", (Hookfn) list_matches); addhookfunc("invalidate_list", (Hookfn) invalidate_list); addhookdefs(m->nam, comphooks, sizeof(comphooks)/sizeof(*comphooks)); - if (!(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) | - addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) | - !addwrapper(m, wrapper))) - return 1; - return 0; + return addwrapper(m, wrapper); } /**/ @@ -1521,10 +1540,8 @@ cleanup_(Module m) deletehookfunc("list_matches", (Hookfn) list_matches); deletehookfunc("invalidate_list", (Hookfn) invalidate_list); deletehookdefs(m->nam, comphooks, sizeof(comphooks)/sizeof(*comphooks)); - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); deletewrapper(m, wrapper); - return 0; + return seteatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index cedccc254..787b7b25c 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -3219,6 +3219,14 @@ menuselect(char **args) return 0; } +static struct features module_features = { + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -3226,6 +3234,21 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -3269,7 +3292,7 @@ boot_(Module m) /**/ int -cleanup_(UNUSED(Module m)) +cleanup_(Module m) { free(mtab); free(mgtab); @@ -3279,7 +3302,7 @@ cleanup_(UNUSED(Module m)) deletehookfunc("menu_start", (Hookfn) domenuselect); unlinkkeymap("menuselect", 1); unlinkkeymap("listscroll", 1); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c index dbbaa61e2..0d8cf5364 100644 --- a/Src/Zle/computil.c +++ b/Src/Zle/computil.c @@ -4567,6 +4567,14 @@ static struct builtin bintab[] = { BUILTIN("compgroups", 0, bin_compgroups, 1, -1, 0, NULL, NULL), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int @@ -4582,19 +4590,33 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { - return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); + return 0; } /**/ int cleanup_(Module m) { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Zle/deltochar.c b/Src/Zle/deltochar.c index e7bfabfd3..0c64cf18d 100644 --- a/Src/Zle/deltochar.c +++ b/Src/Zle/deltochar.c @@ -74,6 +74,16 @@ deltochar(UNUSED(char **args)) return !ok; } + +static struct features module_features = { + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + + /**/ int setup_(UNUSED(Module m)) @@ -81,6 +91,21 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) @@ -100,11 +125,11 @@ boot_(Module m) /**/ int -cleanup_(UNUSED(Module m)) +cleanup_(Module m) { deletezlefunction(w_deletetochar); deletezlefunction(w_zaptochar); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index 9f71f692b..8ab10e5de 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -1777,6 +1777,14 @@ mod_export struct hookdef zlehooks[] = { HOOKDEF("invalidate_list", NULL, 0), }; +static struct features module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, + NULL, 0, + NULL, 0, + 0 +}; + /**/ int setup_(UNUSED(Module m)) @@ -1815,13 +1823,27 @@ setup_(UNUSED(Module m)) return 0; } +/**/ +int +features_(Module m, char ***features) +{ + *features = featuresarray(m->nam, &module_features); + return 0; +} + +/**/ +int +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + /**/ int boot_(Module m) { addhookfunc("before_trap", (Hookfn) zlebeforetrap); addhookfunc("after_trap", (Hookfn) zleaftertrap); - addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); addhookdefs(m->nam, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks)); return 0; } @@ -1836,9 +1858,8 @@ cleanup_(Module m) } deletehookfunc("before_trap", (Hookfn) zlebeforetrap); deletehookfunc("after_trap", (Hookfn) zleaftertrap); - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); deletehookdefs(m->nam, zlehooks, sizeof(zlehooks)/sizeof(*zlehooks)); - return 0; + return setfeatureenables(m->nam, &module_features, NULL); } /**/ diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c index debd31a28..42e32f142 100644 --- a/Src/Zle/zle_thingy.c +++ b/Src/Zle/zle_thingy.c @@ -590,7 +590,7 @@ bin_zle_complete(char *name, char **args, UNUSED(Options ops), UNUSED(char func) Thingy t; Widget w, cw; - if (!require_module(name, "zsh/complete", 0, 0)) { + if (require_module(name, "zsh/complete", NULL) == 1) { zwarnnam(name, "can't load complete module"); return 1; } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 6aaf53e80..2b8e17c22 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -612,7 +612,7 @@ docomplete(int lst) * no completion widgets are defined. */ if (!module_loaded("zsh/compctl") && !hascompwidgets) - load_module("zsh/compctl"); + (void)load_module("zsh/compctl", NULL); if (runhookdef(BEFORECOMPLETEHOOK, (void *) &lst)) { active = 0; diff --git a/Src/Zle/zleparameter.c b/Src/Zle/zleparameter.c index 3c7f1474f..1b84fdff7 100644 --- a/Src/Zle/zleparameter.c +++ b/Src/Zle/zleparameter.c @@ -30,45 +30,6 @@ #include "zleparameter.mdh" #include "zleparameter.pro" -/* Empty dummy function for special hash parameters. */ - -/**/ -static void -shempty(void) -{ -} - -/* Create a simple special hash parameter. */ - -/**/ -static Param -createspecialhash(char *name, GetNodeFunc get, ScanTabFunc scan) -{ - Param pm; - HashTable ht; - - if (!(pm = createparam(name, PM_SPECIAL|PM_HIDE|PM_REMOVABLE|PM_HASHED))) - return NULL; - - pm->level = pm->old ? locallevel : 0; - pm->gsu.h = &stdhash_gsu; - pm->u.hash = ht = newhashtable(0, name, NULL); - - ht->hash = hasher; - ht->emptytable = (TableFunc) shempty; - ht->filltable = NULL; - ht->addnode = (AddNodeFunc) shempty; - ht->getnode = ht->getnode2 = get; - ht->removenode = (RemoveNodeFunc) shempty; - ht->disablenode = NULL; - ht->enablenode = NULL; - ht->freenode = (FreeNodeFunc) shempty; - ht->printnode = printparamnode; - ht->scantab = scan; - - return pm; -} - /* Functions for the zlewidgets special parameter. */ /**/ @@ -157,18 +118,6 @@ keymapsgetfn(UNUSED(Param pm)) return ret; } -/* Table for defined parameters. */ - -struct pardef { - char *name; - int flags; - GetNodeFunc getnfn; - ScanTabFunc scantfn; - GsuHash hash_gsu; - GsuArray array_gsu; - Param pm; -}; - /* * This is a duplicate of stdhash_gsu. On some systems * (such as Cygwin) we can't put a pointer to an imported variable @@ -179,14 +128,18 @@ static const struct gsu_hash zlestdhash_gsu = static const struct gsu_array keymaps_gsu = { keymapsgetfn, arrsetfn, stdunsetfn }; -static struct pardef partab[] = { - { "widgets", PM_READONLY, - getpmwidgets, scanpmwidgets, &zlestdhash_gsu, - NULL, NULL }, - { "keymaps", PM_ARRAY|PM_SPECIAL|PM_READONLY, - NULL, NULL, NULL, - &keymaps_gsu, NULL }, - { NULL, 0, NULL, NULL, NULL, NULL, NULL } +static struct paramdef partab[] = { + SPECIALPMDEF("widgets", PM_READONLY, + &zlestdhash_gsu, getpmwidgets, scanpmwidgets), + SPECIALPMDEF("keymaps", PM_ARRAY|PM_READONLY, &keymaps_gsu, NULL, NULL), +}; + +static struct features module_features = { + NULL, 0, + NULL, 0, + partab, sizeof(partab)/sizeof(*partab), + NULL, 0, + 0 }; /**/ @@ -198,46 +151,33 @@ setup_(UNUSED(Module m)) /**/ int -boot_(UNUSED(Module m)) +features_(Module m, char ***features) { - struct pardef *def; - - for (def = partab; def->name; def++) { - unsetparam(def->name); - - if (def->getnfn) { - if (!(def->pm = createspecialhash(def->name, def->getnfn, - def->scantfn))) - return 1; - def->pm->node.flags |= def->flags; - if (def->hash_gsu) - def->pm->gsu.h = def->hash_gsu; - } else { - if (!(def->pm = createparam(def->name, def->flags | PM_HIDE))) - return 1; - def->pm->gsu.a = def->array_gsu; - } - } + *features = featuresarray(m->nam, &module_features); return 0; } /**/ int -cleanup_(UNUSED(Module m)) +enables_(Module m, int **enables) +{ + return handlefeatures(m->nam, &module_features, enables); +} + +/**/ +int +boot_(UNUSED(Module m)) { - Param pm; - struct pardef *def; - - for (def = partab; def->name; def++) { - if ((pm = (Param) paramtab->getnode(paramtab, def->name)) && - pm == def->pm) { - pm->node.flags &= ~PM_READONLY; - unsetparam_pm(pm, 0, 1); - } - } return 0; } +/**/ +int +cleanup_(Module m) +{ + return setfeatureenables(m->nam, &module_features, NULL); +} + /**/ int finish_(UNUSED(Module m)) diff --git a/Src/builtin.c b/Src/builtin.c index d8732af45..17af59398 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -131,7 +131,7 @@ static struct builtin builtins[] = BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL), BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"), BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"), - BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ARILabcfdipue", NULL), + BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilpue", NULL), BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL), }; @@ -2033,6 +2033,10 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * because we've checked for unpleasant surprises above. */ pm->node.flags = (PM_TYPE(pm->node.flags) | on | PM_SPECIAL) & ~off; + /* + * Readonlyness of special parameters must be preserved. + */ + pm->node.flags |= tpm->node.flags & PM_READONLY; if (newspecial == NS_SECONDS) { /* We save off the raw internal value of the SECONDS var */ tpm->u.dval = getrawseconds(); @@ -2085,7 +2089,21 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), "%s: array elements must be scalar", pname); return NULL; } - } else if (isident(pname) && !idigit(*pname)) { + } + /* + * As we can hide existing parameters, we allow a name if + * it's not a normal identifier but is one of the special + * set found in the parameter table. The second test is + * because we can set individual positional parameters; + * however "0" is not a positional parameter and is OK. + * + * It would be neater to extend isident() and be clearer + * about where we allow various parameter types. It's + * not entirely clear to me isident() should reject + * specially named parameters given that it accepts digits. + */ + else if ((isident(pname) || paramtab->getnode(paramtab, pname)) + && (!idigit(*pname) || !strcmp(pname, "0"))) { /* * Create a new node for a parameter with the flags in `on' minus the * readonly flag @@ -2101,10 +2119,10 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), return NULL; } } else { - if (isident(pname)) - zerrnam(cname, "not valid in this context: %s", pname); - else + if (idigit(*pname)) zerrnam(cname, "not an identifier: %s", pname); + else + zerrnam(cname, "not valid in this context: %s", pname); return NULL; } @@ -2138,7 +2156,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), "BUG: parameter recreated with wrong flags"); unsetparam_pm(ipm, 0, 1); } - } else if (newspecial != NS_NONE && !(pm->old->node.flags & PM_NORESTORE)) { + } else if (newspecial != NS_NONE && + !(pm->old->node.flags & (PM_NORESTORE|PM_READONLY))) { /* * We need to use the special setting function to re-initialise * the special parameter to empty. diff --git a/Src/cond.c b/Src/cond.c index 8950d845c..a597587b6 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -95,7 +95,10 @@ evalcond(Estate state, char *fromtest) case COND_REGEX: { char *modname = isset(REMATCHPCRE) ? "zsh/pcre" : "zsh/regex"; - if (!load_module_silence(modname, 1)) { + /* + * TODO: we just need to load the appropriate condition. + */ + if (load_module_silence(modname, NULL, 1) == 1) { zwarnnam(fromtest, "%s not available for regex", modname); return 2; diff --git a/Src/exec.c b/Src/exec.c index f711f3d30..751282127 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2012,7 +2012,7 @@ execcmd(Estate state, int input, int output, int how, int last1) /* autoload the builtin if necessary */ if (!((Builtin) hn)->handlerfunc) { - load_module(((Builtin) hn)->optstr); + (void)load_module(((Builtin) hn)->optstr, NULL); hn = builtintab->getnode(builtintab, cmdarg); } assign = (hn && (hn->flags & BINF_MAGICEQUALS)); @@ -2229,7 +2229,7 @@ execcmd(Estate state, int input, int output, int how, int last1) /* autoload the builtin if necessary */ if (!((Builtin) hn)->handlerfunc) { - load_module(((Builtin) hn)->optstr); + (void)load_module(((Builtin) hn)->optstr, NULL); hn = builtintab->getnode(builtintab, cmdarg); } break; diff --git a/Src/init.c b/Src/init.c index 6c5421e6f..fce8adcd5 100644 --- a/Src/init.c +++ b/Src/init.c @@ -979,7 +979,7 @@ run_init_scripts(void) * Always attempt to load the newuser module to perform * checks for new zsh users. Don't care if we can't load it. */ - if (load_module_silence("zsh/newuser", 1)) { + if (!load_module_silence("zsh/newuser", NULL, 1)) { /* Unload it immediately. */ unload_named_module("zsh/newuser", "zsh", 1); } @@ -1152,7 +1152,7 @@ init_bltinmods(void) #include "bltinmods.list" - load_module("zsh/main"); + (void)load_module("zsh/main", NULL); } /**/ @@ -1213,8 +1213,8 @@ char * autoload_zleread(char **lp, char **rp, int ha, int con) { zlereadptr = fallback_zleread; - if (load_module("zsh/zle")) - load_module("zsh/compctl"); + if (load_module("zsh/zle", NULL) != 1) + (void)load_module("zsh/compctl", NULL); return zlereadptr(lp, rp, ha, con); } @@ -1240,7 +1240,7 @@ static void autoload_zlesetkeymap(int mode) { zlesetkeymapptr = noop_function_int; - load_module("zsh/zle"); + (void)load_module("zsh/zle", NULL); (*zlesetkeymapptr)(mode); } diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh index 3af496f07..a3785cb8c 100644 --- a/Src/mkbltnmlst.sh +++ b/Src/mkbltnmlst.sh @@ -87,11 +87,16 @@ for bin_mod in $bin_mods; do echo " {" echo " extern int setup_${q_bin_mod} _((Module));" echo " extern int boot_${q_bin_mod} _((Module));" + echo " extern int features_${q_bin_mod} _((Module,char***));" + echo " extern int enables_${q_bin_mod} _((Module,int**));" echo " extern int cleanup_${q_bin_mod} _((Module));" echo " extern int finish_${q_bin_mod} _((Module));" echo echo " register_module(\"$bin_mod\"," - echo " setup_${q_bin_mod}, boot_${q_bin_mod}," + echo " setup_${q_bin_mod}," + echo " features_${q_bin_mod}," + echo " enables_${q_bin_mod}," + echo " boot_${q_bin_mod}," echo " cleanup_${q_bin_mod}, finish_${q_bin_mod});" echo " }" done_mods="$done_mods$bin_mod " diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh index da01c953b..d275038d9 100644 --- a/Src/mkmakemod.sh +++ b/Src/mkmakemod.sh @@ -364,6 +364,8 @@ if $first_stage; then echo " fi; \\" echo " echo '# define boot_ boot_${q_name}'; \\" echo " echo '# define cleanup_ cleanup_${q_name}'; \\" + echo " echo '# define features_ features_${q_name}'; \\" + echo " echo '# define enables_ enables_${q_name}'; \\" echo " echo '# define setup_ setup_${q_name}'; \\" echo " echo '# define finish_ finish_${q_name}'; \\" echo " if test @SHORTBOOTNAMES@ = yes; then \\" diff --git a/Src/modentry.c b/Src/modentry.c index 87c89e0d7..ea2ca6656 100644 --- a/Src/modentry.c +++ b/Src/modentry.c @@ -8,7 +8,7 @@ int modentry _((int boot, Module m)); /**/ int -modentry(int boot, Module m) +modentry(int boot, Module m, void *ptr) { switch (boot) { case 0: @@ -27,6 +27,14 @@ modentry(int boot, Module m) return finish_(m); break; + case 4: + return features_(m, (char ***)ptr); + break; + + case 5: + return enables_(m, (int **)ptr); + break; + default: zerr("bad call to modentry"); return 1; diff --git a/Src/module.c b/Src/module.c index ffa659efc..8f5afca83 100644 --- a/Src/module.c +++ b/Src/module.c @@ -35,6 +35,20 @@ /**/ LinkList linkedmodules; +/* $module_path ($MODULE_PATH) */ + +/**/ +char **module_path; + +/* List of modules */ + +/**/ +mod_export LinkList modules; + + +/************************************************************************ + * 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 * @@ -47,6 +61,24 @@ 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)) @@ -68,12 +100,21 @@ finish_(UNUSED(Module m)) return 0; } + +/************************************************************************ + * Module utility functions + ************************************************************************/ + /* This registers a builtin module. */ /**/ void -register_module(char *n, Module_func setup, Module_func boot, - Module_func cleanup, Module_func finish) +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; @@ -81,6 +122,8 @@ register_module(char *n, Module_func setup, Module_func boot, m->name = ztrdup(n); m->setup = setup; + m->features = features; + m->enables = enables; m->boot = boot; m->cleanup = cleanup; m->finish = finish; @@ -124,6 +167,12 @@ module_linked(char const *name) 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 * @@ -142,13 +191,81 @@ addbuiltin(Builtin b) return 0; } -/* 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 1 if all * - * additions succeed, 2 if some succeed and some fail, and 0 if all (and * - * at least 1) fail. The usual usage in a boot_*() function would be * - * return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); */ +/* 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. */ + +/**/ +int +add_autobin(char *nam, char *module) +{ + Builtin bn = zshcalloc(sizeof(*bn)); + bn->node.nam = ztrdup(nam); + bn->optstr = ztrdup(module); + return addbuiltin(bn); +} + +/* Remove the builtin added previously by addbuiltin(). Returns * + * zero on succes and -1 if there is no builtin with that name. */ + +/**/ +int +deletebuiltin(char *nam) +{ + Builtin bn; + + bn = (Builtin) builtintab->removenode(builtintab, nam); + if (!bn) + return -1; + builtintab->freenode(&bn->node); + return 0; +} + +/**/ +mod_export int +setbuiltins(char const *nam, Builtin binl, int size, int *e) +{ + int hads = 0, hadf = 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); + hadf = 1; + } else { + b->node.flags |= BINF_ADDED; + hads = 2; + } + } else { + if (!(b->node.flags & BINF_ADDED)) + continue; + if (deletebuiltin(b->node.nam)) { + zwarnnam(nam, "builtin `%s' already deleted", b->node.nam); + hadf = 1; + } else { + hads = 2; + b->node.flags &= ~BINF_ADDED; + } + } + } + return hadf ? hads : 1; +} + +/* + * 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 1 if all additions succeed, 2 if some succeed and some fail, and 0 + * if all (and at least 1) fail. + * + * This should not be used from a module; instead, use handlefeatures(). + */ /**/ mod_export int @@ -171,6 +288,11 @@ addbuiltins(char const *nam, Builtin binl, int size) return hadf ? hads : 1; } + +/************************************************************************ + * Function wrappers. + ************************************************************************/ + /* The list of function wrappers defined. */ /**/ @@ -208,75 +330,6 @@ addwrapper(Module m, FuncWrap w) return 0; } -/* $module_path ($MODULE_PATH) */ - -/**/ -char **module_path; - -/* List of modules */ - -/**/ -mod_export LinkList modules; - -/* 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. */ - -/**/ -int -add_autobin(char *nam, char *module) -{ - Builtin bn = zshcalloc(sizeof(*bn)); - bn->node.nam = ztrdup(nam); - bn->optstr = ztrdup(module); - return addbuiltin(bn); -} - -/* Remove the builtin added previously by addbuiltin(). Returns * - * zero on succes and -1 if there is no builtin with that name. */ - -/**/ -int -deletebuiltin(char *nam) -{ - Builtin bn; - - bn = (Builtin) builtintab->removenode(builtintab, nam); - if (!bn) - return -1; - builtintab->freenode(&bn->node); - return 0; -} - -/* Delete multiple builtins. binl points to a table of `size' builtin * - * structures. Those for which (.flags & BINF_ADDED) is true are to be * - * deleted; that flag is cleared. If any fail, an error message is * - * printed, using nam as the leading name. Returns 1 if all deletions * - * succeed, 2 if some succeed and some fail, and 0 if all (and at least * - * 1) fail. In normal use, from a cleanup_*() function, this return * - * value would be ignored -- the only cause of failure would be that a * - * wayward module had deleted our builtin without telling us. */ - -/**/ -mod_export int -deletebuiltins(char const *nam, Builtin binl, int size) -{ - int hads = 0, hadf = 0, n; - - for(n = 0; n < size; n++) { - Builtin b = &binl[n]; - if(!(b->node.flags & BINF_ADDED)) - continue; - if(deletebuiltin(b->node.nam)) { - zwarnnam(nam, "builtin `%s' already deleted", b->node.nam); - hadf = 1; - } else - hads = 2; - b->node.flags &= ~BINF_ADDED; - } - return hadf ? hads : 1; -} - /* This removes the given wrapper definition from the list. Returned is * * one in case of error and zero otherwise. */ @@ -305,1925 +358,2505 @@ deletewrapper(Module m, FuncWrap w) return 1; } -/**/ -#ifdef DYNAMIC -/**/ -#ifdef AIXDYNAMIC +/************************************************************************ + * Conditions. + ************************************************************************/ -#include +/* The list of module-defined conditions. */ -static char *dlerrstr[256]; +/**/ +mod_export Conddef condtab; -static void * -load_and_bind(const char *fn) -{ - void *ret = (void *) load((char *) fn, L_NOAUTODEFER, NULL); +/* 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. */ - if (ret) { - LinkNode node; - int err = loadbind(0, (void *) addbuiltin, ret); - for (node = firstnode(modules); !err && node; incnode(node)) { - Module m = (Module) getdata(node); - if (!(m->flags & MOD_ALIAS) && - m->u.handle && !(m->flags & MOD_LINKED)) - err |= loadbind(0, m->u.handle, ret); - } +/**/ +Conddef +getconddef(int inf, char *name, int autol) +{ + Conddef p; + int f = 1; - if (err) { - loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr)); - unload(ret); - ret = NULL; + do { + for (p = condtab; p; p = p->next) { + if ((!!inf == !!(p->flags & CONDF_INFIX)) && + !strcmp(name, p->name)) + break; } - } else - loadquery(L_GETMESSAGES, dlerrstr, sizeof(dlerrstr)); - - return ret; + 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)load_module_silence(p->module, NULL, 0); + f = 0; + p = NULL; + } else { + deleteconddef(p); + return NULL; + } + } else + break; + } while (!p); + return p; } -#define dlopen(X,Y) load_and_bind(X) -#define dlclose(X) unload(X) -#define dlerror() (dlerrstr[0]) +/* + * 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. + */ /**/ -#else - -#ifdef HAVE_DLFCN_H -# if defined(HAVE_DL_H) && defined(HPUXDYNAMIC) -# include -# else -# include -# endif -#else -# ifdef HAVE_DL_H -# include -# define RTLD_LAZY BIND_DEFERRED -# define RTLD_GLOBAL DYNAMIC_PATH -# else -# include -# include -# include -# endif -#endif +static int +addconddef(Conddef c) +{ + Conddef p = getconddef((c->flags & CONDF_INFIX), c->name, 0); -/**/ -#ifdef HPUXDYNAMIC -# define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0) -# define dlclose(handle) shl_unload((shl_t)(handle)) + if (p) { + if (!p->module || (p->flags & CONDF_ADDED)) + return 1; + /* There is an autoload definition. */ -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; + deleteconddef(p); + } + c->next = condtab; + condtab = c; + return 0; } -# define dlsym(handle,name) hpux_dlsym(handle,name) -# define dlerror() 0 -#else -# ifndef HAVE_DLCLOSE -# define dlclose(X) ((X), 0) -# endif +/* This removes the given condition definition from the list(s). If this * + * is a definition for a autoloaded condition, the memory is freed. */ + /**/ -#endif - -#ifdef DLSYM_NEEDS_UNDERSCORE -# define STR_SETUP "_setup_" -# define STR_BOOT "_boot_" -# define STR_CLEANUP "_cleanup_" -# define STR_FINISH "_finish_" -#else /* !DLSYM_NEEDS_UNDERSCORE */ -# define STR_SETUP "setup_" -# define STR_BOOT "boot_" -# define STR_CLEANUP "cleanup_" -# define STR_FINISH "finish_" -#endif /* !DLSYM_NEEDS_UNDERSCORE */ +int +deleteconddef(Conddef c) +{ + Conddef p, q; -/**/ -#endif /* !AIXDYNAMIC */ + for (p = condtab, q = NULL; p && p != c; q = p, p = p->next); -#ifndef RTLD_LAZY -# define RTLD_LAZY 1 -#endif -#ifndef RTLD_GLOBAL -# define RTLD_GLOBAL 0 -#endif + 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; +} /**/ -static void * -try_load_module(char const *name) +mod_export int +setconddefs(char const *nam, Conddef c, int size, int *e) { - char buf[PATH_MAX + 1]; - char **pp; - void *ret = NULL; - int l; + int hads = 0, hadf = 0; - 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); - ret = dlopen(unmeta(buf), RTLD_LAZY | RTLD_GLOBAL); + 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); + hadf = 1; + } else { + c->flags |= CONDF_ADDED; + hads = 2; + } + } else { + if (!(c->flags & CONDF_ADDED)) { + c++; + continue; + } + if (deleteconddef(c)) { + zwarnnam(nam, "condition `%s' already deleted", c->name); + hadf = 1; + } else { + c->flags &= ~CONDF_ADDED; + hads = 2; + } + } + c++; } - - return ret; + return hadf ? hads : 1; } +/* This adds a definition for autoloading a module for a condition. */ + /**/ -static void * -do_load_module(char const *name, int silent) +int +add_autocond(char *nam, int inf, char *module) { - void *ret; + Conddef c = (Conddef) zalloc(sizeof(*c)); - ret = try_load_module(name); - if (!ret && !silent) - zwarn("failed to load module: %s", name); - return ret; + c->name = ztrdup(nam); + c->flags = (inf ? CONDF_INFIX : 0); + c->module = ztrdup(module); + + if (addconddef(c)) { + zsfree(c->name); + zsfree(c->module); + zfree(c, sizeof(*c)); + + return 1; + } + return 0; } -/**/ -#else /* !DYNAMIC */ -/**/ -static void * -do_load_module(char const *name, int silent) -{ - if (!silent) - zwarn("failed to load module: %s", name); +/************************************************************************ + * Hook functions. + ************************************************************************/ - return NULL; -} +/* This list of hook functions defined. */ /**/ -#endif /* !DYNAMIC */ +Hookdef hooktab; + +/* Find a hook definition given the name. */ -/* - * Find a module in the list. - * If aliasp is non-zero, resolve any aliases to the underlying module. - * If namep is set, this is set to point to the last alias value resolved, - * even if that module was not loaded. or the module name if no aliases. - * Hence this is always the physical module to load in a chain of aliases. - * Return NULL if the module named is not stored as a structure, or if we were - * resolving aliases and the final module named is not stored as a - * structure. - * - * TODO: now we have aliases, there may be some merit in using a hash - * table instead of a linked list. - */ /**/ -static LinkNode -find_module(const char *name, int aliasp, const char **namep) +Hookdef +gethookdef(char *n) { - Module m; - LinkNode node; + Hookdef p; - for (node = firstnode(modules); node; incnode(node)) { - m = (Module) getdata(node); - if (!strcmp(m->nam, name)) { - if (aliasp && (m->flags & MOD_ALIAS)) { - if (namep) - *namep = m->u.alias; - return find_module(m->u.alias, 1, namep); - } - if (namep) - *namep = m->nam; - return node; - } - } + for (p = hooktab; p; p = p->next) + if (!strcmp(n, p->name)) + return p; return NULL; } -/* - * Unlink and free a module node from the linked list. - */ +/* This adds the given hook definition. The return value is zero on * + * success and 1 on failure. */ /**/ -static void -delete_module(LinkNode node) +int +addhookdef(Hookdef h) { - Module m = (Module) remnode(modules, node); + if (gethookdef(h->name)) + return 1; - if (m->flags & MOD_ALIAS) - zsfree(m->u.alias); - zsfree(m->nam); - if (m->deps) - freelinklist(m->deps, freestr); - zfree(m, sizeof(*m)); + h->next = hooktab; + hooktab = h; + h->funcs = znewlinklist(); + + return 0; } +/* This adds multiple hook definitions. This is like addbuiltins(). */ + /**/ mod_export int -module_loaded(const char *name) +addhookdefs(char const *nam, Hookdef h, int size) { - LinkNode node; - Module m; + int hads = 0, hadf = 0; - return ((node = find_module(name, 1, NULL)) && - (m = ((Module) getdata(node)))->u.handle && - !(m->flags & MOD_UNLOAD)); + while (size--) { + if (addhookdef(h)) { + zwarnnam(nam, "name clash when adding hook `%s'", h->name); + hadf = 1; + } else + hads = 2; + h++; + } + return hadf ? hads : 1; } -/* - * 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. - */ +/* Delete hook definitions. */ /**/ -#ifdef DYNAMIC +int +deletehookdef(Hookdef h) +{ + Hookdef p, q; -/**/ -#ifdef AIXDYNAMIC + 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; +} /**/ -static int -dyn_setup_module(Module m) +mod_export int +deletehookdefs(UNUSED(char const *nam), Hookdef h, int size) { - return ((int (*)_((int,Module))) m->u.handle)(0, m); + while (size--) { + deletehookdef(h); + h++; + } + return 1; } +/* Add a function to a hook. */ + /**/ -static int -dyn_boot_module(Module m) +int +addhookdeffunc(Hookdef h, Hookfn f) { - return ((int (*)_((int,Module))) m->u.handle)(1, m); + zaddlinknode(h->funcs, (void *) f); + + return 0; } /**/ -static int -dyn_cleanup_module(Module m) +mod_export int +addhookfunc(char *n, Hookfn f) { - return ((int (*)_((int,Module))) m->u.handle)(2, m); + Hookdef h = gethookdef(n); + + if (h) + return addhookdeffunc(h, f); + return 1; } +/* Delete a function from a hook. */ + /**/ -static int -dyn_finish_module(Module m) +int +deletehookdeffunc(Hookdef h, Hookfn f) { - return ((int (*)_((int,Module))) m->u.handle)(3, m); + LinkNode p; + + for (p = firstnode(h->funcs); p; incnode(p)) + if (f == (Hookfn) getdata(p)) { + remnode(h->funcs, p); + return 0; + } + return 1; } /**/ -#else - -static Module_func -module_func(Module m, char *name) -{ -#ifdef DYNAMIC_NAME_CLASH_OK - return (Module_func) dlsym(m->u.handle, name); -#else /* !DYNAMIC_NAME_CLASH_OK */ - VARARR(char, buf, strlen(name) + strlen(m->nam)*2 + 1); - char const *p; - char *q; - strcpy(buf, name); - q = strchr(buf, 0); - for(p = m->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_func) dlsym(m->u.handle, buf); -#endif /* !DYNAMIC_NAME_CLASH_OK */ -} - -/**/ -static int -dyn_setup_module(Module m) +mod_export int +deletehookfunc(char *n, Hookfn f) { - Module_func fn = module_func(m, STR_SETUP); + Hookdef h = gethookdef(n); - if (fn) - return fn(m); - zwarnnam(m->nam, "no setup function"); + if (h) + return deletehookdeffunc(h, f); return 1; } +/* Run the function(s) for a hook. */ + /**/ -static int -dyn_boot_module(Module m) +mod_export int +runhookdef(Hookdef h, void *d) { - Module_func fn = module_func(m, STR_BOOT); + if (empty(h->funcs)) { + if (h->def) + return h->def(h, d); + return 0; + } else if (h->flags & HOOKF_ALL) { + LinkNode p; + int r; - if(fn) - return fn(m); - zwarnnam(m->nam, "no boot function"); - return 1; + 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); } /**/ -static int -dyn_cleanup_module(Module m) +int +runhook(char *n, void *d) { - Module_func fn = module_func(m, STR_CLEANUP); + Hookdef h = gethookdef(n); - if(fn) - return fn(m); - zwarnnam(m->nam, "no cleanup function"); - return 1; + if (h) + return runhookdef(h, d); + return 0; } -/* Note that this function does more than just calling finish_foo(), * - * it really unloads the module. */ -/**/ +/************************************************************************ + * Shell parameters. + ************************************************************************/ + static int -dyn_finish_module(Module m) +checkaddparam(char *nam) { - Module_func fn = module_func(m, STR_FINISH); - int r; + Param pm; - if (fn) - r = fn(m); - else { - zwarnnam(m->nam, "no finish function"); - r = 1; + if (!(pm = (Param) gethashnode2(paramtab, nam))) + return 0; + + if (pm->level || !(pm->node.flags & PM_AUTOLOAD)) { + zwarn("Can't add module parameter `%s': %s", + nam, pm->level ? + "local parameter exists" : + "parameter already exists"); + return 1; } - dlclose(m->u.handle); - return r; + + unsetparam_pm(pm, 0, 1); + return 0; } -/**/ -#endif /* !AIXDYNAMIC */ +/* This adds the given parameter definition. The return value is zero on * + * success and 1 on failure. */ /**/ -static int -setup_module(Module m) +int +addparamdef(Paramdef d) { - return ((m->flags & MOD_LINKED) ? - (m->u.linked->setup)(m) : dyn_setup_module(m)); -} + Param pm; -/**/ -static int -boot_module(Module m) -{ - return ((m->flags & MOD_LINKED) ? - (m->u.linked->boot)(m) : dyn_boot_module(m)); + if (checkaddparam(d->name)) + 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_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. */ + /**/ -static int -cleanup_module(Module m) +int +deleteparamdef(Paramdef d) { - return ((m->flags & MOD_LINKED) ? - (m->u.linked->cleanup)(m) : dyn_cleanup_module(m)); + 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; } /**/ -static int -finish_module(Module m) +mod_export int +setparamdefs(char const *nam, Paramdef d, int size, int *e) { - return ((m->flags & MOD_LINKED) ? - (m->u.linked->finish)(m) : dyn_finish_module(m)); + int hads = 0, hadf = 0; + + while (size--) { + if (e && *e++) { + if (d->pm) { + d++; + continue; + } + if (addparamdef(d)) { + zwarnnam(nam, "error when adding parameter `%s'", d->name); + hadf = 1; + } else { + hads = 2; + } + } else { + if (!d->pm) { + d++; + continue; + } + if (deleteparamdef(d)) { + zwarnnam(nam, "parameter `%s' already deleted", d->name); + hadf = 1; + } else { + hads = 2; + } + } + d++; + } + return hadf ? hads : 1; } -/**/ -#else /* !DYNAMIC */ +/* This adds a definition for autoloading a module for a parameter. */ /**/ -static int -setup_module(Module m) +void +add_autoparam(char *nam, char *module) { - return ((m->flags & MOD_LINKED) ? (m->u.linked->setup)(m) : 1); + Param pm; + + queue_signals(); + if (checkaddparam(nam)) { + unqueue_signals(); + return; + } + + pm = setsparam(nam, ztrdup(module)); + + pm->node.flags |= PM_AUTOLOAD; + unqueue_signals(); } + +/************************************************************************ + * Math functions. + ************************************************************************/ + +/* List of math functions. */ + /**/ -static int -boot_module(Module m) -{ - return ((m->flags & MOD_LINKED) ? (m->u.linked->boot)(m) : 1); -} +MathFunc mathfuncs; /**/ -static int -cleanup_module(Module m) +void +removemathfunc(MathFunc previous, MathFunc current) { - return ((m->flags & MOD_LINKED) ? (m->u.linked->cleanup)(m) : 1); + if (previous) + previous->next = current->next; + else + mathfuncs = current->next; + + zsfree(current->name); + zsfree(current->module); + zfree(current, sizeof(*current)); } /**/ -static int -finish_module(Module m) +MathFunc +getmathfunc(char *name, int autol) { - return ((m->flags & MOD_LINKED) ? (m->u.linked->finish)(m) : 1); -} + MathFunc p, q = NULL; -/**/ -#endif /* !DYNAMIC */ + 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); -/**/ -static int -modname_ok(char const *p) -{ - do { - p = itype_end(p, IIDENT, 0); - if (!*p) - return 1; - } while(*p++ == '/'); - return 0; + removemathfunc(q, p); + + (void)load_module_silence(n, NULL, 0); + + return getmathfunc(name, 0); + } + return p; + } + + return NULL; } /**/ -mod_export int -load_module(char const *name) +static int +addmathfunc(MathFunc f) { - return load_module_silence(name, 0); -} + 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; +} /**/ mod_export int -load_module_silence(char const *name, int silent) +deletemathfunc(MathFunc f) { - Module m; - void *handle = NULL; - Linkedmod linked; - LinkNode node, n; - int set; + MathFunc p, q; - if (!modname_ok(name)) { - if (!silent) - zerr("invalid module name `%s'", name); - return 0; - } - /* - * The following function call may alter name to the final name in a - * chain of aliases. This makes sure the actual module loaded - * is the right one. - */ - queue_signals(); - if (!(node = find_module(name, 1, &name))) { - if (!(linked = module_linked(name)) && - !(handle = do_load_module(name, silent))) { - unqueue_signals(); - return 0; - } - m = zshcalloc(sizeof(*m)); - m->nam = ztrdup(name); - if (handle) { - m->u.handle = handle; - m->flags |= MOD_SETUP; - } else { - m->u.linked = linked; - m->flags |= MOD_SETUP | MOD_LINKED; - } - node = zaddlinknode(modules, m); + for (p = mathfuncs, q = NULL; p && p != f; q = p, p = p->next); - if ((set = setup_module(m)) || boot_module(m)) { - if (!set) - finish_module(m); - delete_module(node); - unqueue_signals(); - return 0; - } - m->flags |= MOD_INIT_S | MOD_INIT_B; - m->flags &= ~MOD_SETUP; - unqueue_signals(); - return 1; - } - m = (Module) getdata(node); - if (m->flags & MOD_SETUP) { - unqueue_signals(); - return 1; - } - if (m->flags & MOD_UNLOAD) - m->flags &= ~MOD_UNLOAD; - else if ((m->flags & MOD_LINKED) ? m->u.linked : m->u.handle) { - unqueue_signals(); - return 1; - } - if (m->flags & MOD_BUSY) { - zerr("circular dependencies for module %s", name); - return 0; - } - m->flags |= MOD_BUSY; - if (m->deps) - for (n = firstnode(m->deps); n; incnode(n)) - if (!load_module_silence((char *) getdata(n), silent)) { - m->flags &= ~MOD_BUSY; - unqueue_signals(); - return 0; - } - m->flags &= ~MOD_BUSY; - if (!m->u.handle) { - handle = NULL; - if (!(linked = module_linked(name)) && - !(handle = do_load_module(name, silent))) { - unqueue_signals(); - return 0; - } - if (handle) { - m->u.handle = handle; - m->flags |= MOD_SETUP; - } else { - m->u.linked = linked; - m->flags |= MOD_SETUP | MOD_LINKED; - } - if (setup_module(m)) { - if (handle) - m->u.handle = NULL; - else - m->u.linked = NULL; - m->flags &= ~MOD_SETUP; - unqueue_signals(); - return 0; - } - m->flags |= MOD_INIT_S; - } - m->flags |= MOD_SETUP; - if (boot_module(m)) { - finish_module(m); - if (m->flags & MOD_LINKED) - m->u.linked = NULL; + if (p) { + if (q) + q->next = f->next; else - m->u.handle = NULL; - m->flags &= ~MOD_SETUP; - unqueue_signals(); + 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; } - m->flags |= MOD_INIT_B; - m->flags &= ~MOD_SETUP; - unqueue_signals(); - return 1; + return -1; } -/* This ensures that the module with the name given as the second argument - * is loaded. - * The third argument should be non-zero if the function should complain - * about trying to load a module with a full path name in restricted mode. - * The last argument should be non-zero if this function should signal an - * error if the module is already loaded. - * The return value is non-zero if the module was found or loaded. */ - /**/ mod_export int -require_module(char *nam, const char *module, UNUSED(int res), int test) +setmathfuncs(char const *nam, MathFunc f, int size, int *e) { - Module m = NULL; - LinkNode node; - int ret = 1; + int hads = 0, hadf = 0; - /* Resolve aliases and actual loadable module as for load_module */ - queue_signals(); - node = find_module(module, 1, &module); - if (node && (m = ((Module) getdata(node)))->u.handle && - !(m->flags & MOD_UNLOAD)) { - if (test) { - unqueue_signals(); - zwarnnam(nam, "module %s already loaded.", module); - return 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); + hadf = 1; + } else { + f->flags |= MFF_ADDED; + hads = 2; + } + } else { + if (!(f->flags & MFF_ADDED)) { + f++; + continue; + } + if (deletemathfunc(f)) { + zwarnnam(nam, "math function `%s' already deleted", f->name); + hadf = 1; + } else { + f->flags &= ~MFF_ADDED; + hads = 2; + } } - } else - ret = load_module_silence(module, 0); - unqueue_signals(); - - return ret; + f++; + } + return hadf ? hads : 1; } /**/ -void -add_dep(const char *name, char *from) +int +add_automathfunc(char *nam, char *module) { - LinkNode node; - Module m; + MathFunc f = (MathFunc) zalloc(sizeof(*f)); - /* - * 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.) - */ - if (!(node = find_module(name, 1, &name))) { - m = zshcalloc(sizeof(*m)); - m->nam = ztrdup(name); - zaddlinknode(modules, m); - } else - m = (Module) getdata(node); - 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)); -} + f->name = ztrdup(nam); + f->module = ztrdup(module); + f->flags = 0; -/**/ -static void -autoloadscan(HashNode hn, int printflags) -{ - Builtin bn = (Builtin) hn; + if (addmathfunc(f)) { + zsfree(f->name); + zsfree(f->module); + zfree(f, sizeof(*f)); - 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(')'); - } + return 1; } - putchar('\n'); + + return 0; } + +/************************************************************************ + * Now support for dynamical loading and the fallback functions + * we use for loading if dynamical loading is not available. + ************************************************************************/ + /**/ -int -bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func)) +#ifdef DYNAMIC + +/**/ +#ifdef AIXDYNAMIC + +#include + +static char *dlerrstr[256]; + +static void * +load_and_bind(const char *fn) { - 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; + void *ret = (void *) load((char *) fn, L_NOAUTODEFER, NULL); - 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,'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 (ret) { + LinkNode node; + int err = loadbind(0, (void *) addbuiltin, ret); + for (node = firstnode(modules); !err && node; incnode(node)) { + Module m = (Module) getdata(node); + if (!(m->flags & MOD_ALIAS) && + m->u.handle && !(m->flags & MOD_LINKED)) + err |= loadbind(0, m->u.handle, ret); } - 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,'d') || - OPT_ISSET(ops,'i') || OPT_ISSET(ops,'u'))) { - zwarnnam(nam, "-e cannot be combined with other options"); - return 1; - } - queue_signals(); - 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 ((OPT_ISSET(ops,'a') || OPT_ISSET(ops,'b')) && - !(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'p') || OPT_ISSET(ops,'f'))) - ret = bin_zmodload_auto(nam, args, ops); - else if (OPT_ISSET(ops,'c') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'p'))) - ret = bin_zmodload_cond(nam, args, ops); - else if (OPT_ISSET(ops,'f') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'p'))) - ret = bin_zmodload_math(nam, args, ops); - else if (OPT_ISSET(ops,'p') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'c'))) - ret = bin_zmodload_param(nam, args, ops); - else if (!(OPT_ISSET(ops,'a') || OPT_ISSET(ops,'b') || - OPT_ISSET(ops,'c') || OPT_ISSET(ops,'p'))) - ret = bin_zmodload_load(nam, args, ops); - else - zwarnnam(nam, "use only one of -b, -c, or -p"); - unqueue_signals(); + + 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]) + /**/ -static int -bin_zmodload_alias(char *nam, char **args, Options ops) +#else + +#ifdef HAVE_DLFCN_H +# if defined(HAVE_DL_H) && defined(HPUXDYNAMIC) +# include +# else +# include +# endif +#else +# ifdef HAVE_DL_H +# include +# define RTLD_LAZY BIND_DEFERRED +# define RTLD_GLOBAL DYNAMIC_PATH +# else +# include +# include +# include +# endif +#endif + +/**/ +#ifdef HPUXDYNAMIC +# 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) { - /* - * TODO: while it would be too nasty to have aliases, as opposed - * to real loadable modules, with dependencies --- just what would - * we need to load when, exactly? --- there is in principle no objection - * to making it possible to force an alias onto an existing unloaded - * module which has dependencies. This would simply transfer - * the dependencies down the line to the aliased-to module name. - * This is actually useful, since then you can alias zsh/zle=mytestzle - * to load another version of zle. But then what happens when the - * alias is removed? Do you transfer the dependencies back? And - * suppose other names are aliased to the same file? It might be - * kettle of fish best left unwormed. - */ - LinkNode node; - Module m; + void *sym_addr; + if (!shl_findsym((shl_t *)&handle, name, TYPE_UNDEFINED, &sym_addr)) + return sym_addr; + return NULL; +} - if (!*args) { - if (OPT_ISSET(ops,'R')) { - zwarnnam(nam, "no module alias to remove"); - return 1; - } - for (node = firstnode(modules); node; incnode(node)) { - m = (Module) getdata(node); - if (m->flags & MOD_ALIAS) - printmodalias(m, ops); - } - return 0; +# define dlsym(handle,name) hpux_dlsym(handle,name) +# define dlerror() 0 +#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 + +/**/ +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); + ret = dlopen(unmeta(buf), RTLD_LAZY | RTLD_GLOBAL); } - 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; - } - node = find_module(*args, 0, NULL); - if (node) { - m = (Module) getdata(node); - if (!(m->flags & MOD_ALIAS)) { - zwarnnam(nam, "module is not an alias: %s", *args); - return 1; - } - delete_module(node); - } 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 ((node = find_module(mname, 0, NULL)) - && ((m = (Module) getdata(node))->flags & MOD_ALIAS) - && (mname = m->u.alias)); - node = find_module(*args, 0, NULL); - if (node) { - m = (Module) getdata(node); - if (!(m->flags & MOD_ALIAS)) { - zwarnnam(nam, "module is not an alias: %s", *args); - return 1; - } - zsfree(m->u.alias); - } else { - m = (Module) zshcalloc(sizeof(*m)); - m->nam = ztrdup(*args); - m->flags = MOD_ALIAS; - zaddlinknode(modules, m); - } - m->u.alias = ztrdup(aliasname); - } else { - if ((node = find_module(*args, 0, NULL))) { - m = (Module) getdata(node); - if (m->flags & MOD_ALIAS) - printmodalias(m, ops); - else { - zwarnnam(nam, "module is not an alias: %s", *args); - return 1; - } - } else { - zwarnnam(nam, "no such module alias: %s", *args); - return 1; - } + return ret; +} + +/**/ +static void * +do_load_module(char const *name, int silent) +{ + void *ret; + + ret = try_load_module(name); + if (!ret && !silent) + zwarn("failed to load module: %s", name); + return ret; +} + +/**/ +#else /* !DYNAMIC */ + +/**/ +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. + * If aliasp is non-zero, resolve any aliases to the underlying module. + * If namep is set, this is set to point to the last alias value resolved, + * even if that module was not loaded. or the module name if no aliases. + * Hence this is always the physical module to load in a chain of aliases. + * Return NULL if the module named is not stored as a structure, or if we were + * resolving aliases and the final module named is not stored as a + * structure. + * + * TODO: now we have aliases, there may be some merit in using a hash + * table instead of a linked list. + */ +/**/ +static LinkNode +find_module(const char *name, int aliasp, const char **namep) +{ + Module m; + LinkNode node; + + for (node = firstnode(modules); node; incnode(node)) { + m = (Module) getdata(node); + if (!strcmp(m->nam, name)) { + if (aliasp && (m->flags & MOD_ALIAS)) { + if (namep) + *namep = m->u.alias; + return find_module(m->u.alias, 1, namep); } + if (namep) + *namep = m->nam; + return node; } } + return NULL; +} - return 0; +/* + * Unlink and free a module node from the linked list. + */ + +/**/ +static void +delete_module(LinkNode node) +{ + Module m = (Module) remnode(modules, node); + + if (m->flags & MOD_ALIAS) + zsfree(m->u.alias); + zsfree(m->nam); + if (m->deps) + freelinklist(m->deps, freestr); + zfree(m, sizeof(*m)); } /**/ -static int -bin_zmodload_exist(UNUSED(char *nam), char **args, Options ops) +mod_export int +module_loaded(const char *name) { LinkNode node; Module m; - char *modname; - if (!*args) { - for (node = firstnode(modules); node; incnode(node)) { - m = (Module) getdata(node); - modname = m->nam; - if (m->flags & MOD_ALIAS) { - LinkNode node2; - if (OPT_ISSET(ops,'A') && - (node2 = find_module(m->u.alias, 1, NULL))) - m = (Module) getdata(node2); - else - continue; - } - if (m->u.handle && !(m->flags & MOD_UNLOAD)) { - nicezputs(modname, stdout); - putchar('\n'); - } - } - return 0; - } else { - int ret = 0; + return ((node = find_module(name, 1, NULL)) && + (m = ((Module) getdata(node)))->u.handle && + !(m->flags & MOD_UNLOAD)); +} - for (; !ret && *args; args++) { - if (!(node = find_module(*args, 1, NULL)) - || !(m = (Module) getdata(node))->u.handle - || (m->flags & MOD_UNLOAD)) - ret = 1; - } - return ret; - } +/* + * 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))) m->u.handle)(0, m, NULL); +} + +/**/ +static int +dyn_features_module(Module m, char ***features) +{ + return ((int (*)_((int,Module))) m->u.handle)(4, m, features); } /**/ static int -bin_zmodload_dep(UNUSED(char *nam), char **args, Options ops) +dyn_enables_module(Module m, int **enables) { - LinkNode node; - Module m; - if (OPT_ISSET(ops,'u')) { - /* remove dependencies, which can't pertain to aliases */ - const char *tnam = *args++; - node = find_module(tnam, 1, &tnam); - if (!node) - return 0; - m = (Module) getdata(node); - if (*args && m->deps) { - 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(node); - return 0; - } else if (!args[0] || !args[1]) { - /* list dependencies */ - for (node = firstnode(modules); node; incnode(node)) { - m = (Module) getdata(node); - if (m->deps && (!args[0] || !strcmp(args[0], m->nam))) { - LinkNode n; - if (OPT_ISSET(ops,'L')) { - printf("zmodload -d "); - if(m->nam[0] == '-') - fputs("-- ", stdout); - quotedzputs(m->nam, stdout); - } else { - nicezputs(m->nam, stdout); - putchar(':'); - } - for (n = firstnode(m->deps); n; incnode(n)) { - putchar(' '); - if(OPT_ISSET(ops,'L')) - quotedzputs((char *) getdata(n), stdout); - else - nicezputs((char *) getdata(n), stdout); - } - putchar('\n'); - } - } - return 0; - } else { - /* add dependencies */ - int ret = 0; - char *tnam = *args++; - - for (; *args; args++) - add_dep(tnam, *args); - return ret; - } + return ((int (*)_((int,Module))) m->u.handle)(5, m, enables); } /**/ static int -bin_zmodload_auto(char *nam, char **args, Options ops) +dyn_boot_module(Module m) { - int ret = 0; - if(OPT_ISSET(ops,'u')) { - /* remove autoloaded builtins */ - for (; *args; args++) { - Builtin bn = (Builtin) builtintab->getnode2(builtintab, *args); - if (!bn) { - if(!OPT_ISSET(ops,'i')) { - zwarnnam(nam, "%s: no such builtin", *args); - ret = 1; - } - } else if (bn->node.flags & BINF_ADDED) { - zwarnnam(nam, "%s: builtin is already defined", *args); - ret = 1; - } else - deletebuiltin(*args); - } - return ret; - } else if(!*args) { - /* list autoloaded builtins */ - scanhashtable(builtintab, 1, 0, 0, - autoloadscan, OPT_ISSET(ops,'L') ? PRINT_LIST : 0); - return 0; - } else { - /* add autoloaded builtins */ - char *modnam; - modnam = *args++; - do { - char *bnam = *args ? *args++ : modnam; - if (strchr(bnam, '/')) { - zwarnnam(nam, "%s: `/' is illegal in a builtin", bnam); - ret = 1; - } else if (add_autobin(bnam, modnam) && !OPT_ISSET(ops,'i')) { - zwarnnam(nam, "failed to add builtin %s", bnam); - ret = 1; - } - } while(*args); - return ret; - } + return ((int (*)_((int,Module))) m->u.handle)(1, m, NULL); } /**/ static int -bin_zmodload_cond(char *nam, char **args, Options ops) +dyn_cleanup_module(Module m) { - int ret = 0; - - if (OPT_ISSET(ops,'u')) { - /* remove autoloaded conditions */ - for (; *args; args++) { - Conddef cd = getconddef(OPT_ISSET(ops,'I'), *args, 0); + return ((int (*)_((int,Module))) m->u.handle)(2, m, NULL); +} - if (!cd) { - if (!OPT_ISSET(ops,'i')) { - zwarnnam(nam, "%s: no such condition", *args); - ret = 1; - } - } else if (cd->flags & CONDF_ADDED) { - zwarnnam(nam, "%s: condition is already defined", *args); - ret = 1; - } else - deleteconddef(cd); - } - return ret; - } else if (!*args) { - /* list autoloaded conditions */ - Conddef p; +/**/ +static int +dyn_finish_module(Module m) +{ + return ((int (*)_((int,Module))) m->u.handle)(3, m, NULL); +} - 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; - } else { - /* add autoloaded conditions */ - char *modnam; +/**/ +#else - modnam = *args++; - do { - char *cnam = *args ? *args++ : modnam; - if (strchr(cnam, '/')) { - zwarnnam(nam, "%s: `/' is illegal in a condition", cnam); - ret = 1; - } else if (add_autocond(cnam, OPT_ISSET(ops,'I'), modnam) && - !OPT_ISSET(ops,'i')) { - zwarnnam(nam, "failed to add condition `%s'", cnam); - ret = 1; - } - } while(*args); - return ret; +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->nam)*2 + 1); + char const *p; + char *q; + strcpy(buf, name); + q = strchr(buf, 0); + for(p = m->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 -bin_zmodload_math(char *nam, char **args, Options ops) +dyn_setup_module(Module m) { - int ret = 0; + Module_void_func fn = (Module_void_func)module_func(m, STR_SETUP); - if (OPT_ISSET(ops,'u')) { - /* remove autoloaded math functions */ - for (; *args; args++) { - MathFunc f = getmathfunc(*args, 0); + if (fn) + return fn(m); + zwarnnam(m->nam, "no setup function"); + return 1; +} - if (!f) { - if (!OPT_ISSET(ops,'i')) { - zwarnnam(nam, "%s: no such math function", *args); - ret = 1; - } - } else if (f->flags & MFF_ADDED) { - zwarnnam(nam, "%s: math function is already defined", *args); - ret = 1; - } else - deletemathfunc(f); - } - return ret; - } else if (!*args) { - /* list autoloaded math functions */ - MathFunc p; +/**/ +static int +dyn_features_module(Module m, char ***features) +{ + Module_features_func fn = + (Module_features_func)module_func(m, STR_FEATURES); - 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; - } else { - /* add autoloaded math functions */ - char *modnam; + if (fn) + return fn(m, features); + /* not a user-visible error if no features function */ + return 1; +} - modnam = *args++; - do { - char *fnam = *args ? *args++ : modnam; - if (strchr(fnam, '/')) { - zwarnnam(nam, "%s: `/' is illegal in a math function", fnam); - ret = 1; - } else if (add_automathfunc(fnam, modnam) && !OPT_ISSET(ops,'i')) { - zwarnnam(nam, "failed to add math function `%s'", fnam); - ret = 1; - } - } while(*args); - return ret; - } +/**/ +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 void -printautoparams(HashNode hn, int lon) +/**/ +static int +dyn_boot_module(Module m) { - Param pm = (Param) hn; + Module_void_func fn = (Module_void_func)module_func(m, STR_BOOT); - 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); - } + if(fn) + return fn(m); + zwarnnam(m->nam, "no boot function"); + return 1; } /**/ static int -bin_zmodload_param(char *nam, char **args, Options ops) +dyn_cleanup_module(Module m) { - int ret = 0; + Module_void_func fn = (Module_void_func)module_func(m, STR_CLEANUP); - if (OPT_ISSET(ops,'u')) { - /* remove autoloaded parameters */ - for (; *args; args++) { - Param pm = (Param) gethashnode2(paramtab, *args); + if(fn) + return fn(m); + zwarnnam(m->nam, "no cleanup function"); + return 1; +} - if (!pm) { - if (!OPT_ISSET(ops,'i')) { - zwarnnam(nam, "%s: no such parameter", *args); - ret = 1; - } - } else if (!(pm->node.flags & PM_AUTOLOAD)) { - zwarnnam(nam, "%s: parameter is already defined", *args); - ret = 1; - } else - unsetparam_pm(pm, 0, 1); - } - return ret; - } else if (!*args) { - scanhashtable(paramtab, 1, 0, 0, printautoparams, OPT_ISSET(ops,'L')); - return 0; - } else { - /* add autoloaded parameters */ - char *modnam; +/* Note that this function does more than just calling finish_foo(), * + * it really unloads the module. */ - modnam = *args++; - do { - char *pnam = *args ? *args++ : modnam; - if (strchr(pnam, '/')) { - zwarnnam(nam, "%s: `/' is illegal in a parameter", pnam); - ret = 1; - } else - add_autoparam(pnam, modnam); - } while(*args); - return ret; +/**/ +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->nam, "no finish function"); + r = 1; } + dlclose(m->u.handle); + return r; } /**/ -int -unload_module(Module m, LinkNode node) +#endif /* !AIXDYNAMIC */ + +/**/ +static int +setup_module(Module m) { - /* - * Only unload the real module, so resolve aliases. - */ - if (m->flags & MOD_ALIAS) { - LinkNode node = find_module(m->u.alias, 1, NULL); - if (!node) - return 1; - m = (Module) getdata(node); - } - if ((m->flags & MOD_INIT_S) && - !(m->flags & MOD_UNLOAD) && - ((m->flags & MOD_LINKED) ? - (m->u.linked && m->u.linked->cleanup(m)) : - (m->u.handle && cleanup_module(m)))) - return 1; - else { - int del = (m->flags & MOD_UNLOAD); + return ((m->flags & MOD_LINKED) ? + (m->u.linked->setup)(m) : dyn_setup_module(m)); +} - if (m->wrapper) { - m->flags |= MOD_UNLOAD; - return 0; - } - m->flags &= ~MOD_UNLOAD; - if (m->flags & MOD_INIT_B) { - if (m->flags & MOD_LINKED) { - if (m->u.linked) { - m->u.linked->finish(m); - m->u.linked = NULL; - } - } else { - if (m->u.handle) { - finish_module(m); - m->u.handle = NULL; - } - } - } - if (del && m->deps) { - /* The module was unloaded delayed, unload all modules * - * on which it depended. */ - LinkNode n; +/**/ +static int +features_module(Module m, char ***features) +{ + return ((m->flags & MOD_LINKED) ? + (m->u.linked->features)(m, features) : + dyn_features_module(m, features)); +} - for (n = firstnode(m->deps); n; incnode(n)) { - LinkNode dn = find_module((char *) getdata(n), 1, NULL); - Module dm; +/**/ +static int +enables_module(Module m, int **enables) +{ + return ((m->flags & MOD_LINKED) ? + (m->u.linked->enables)(m, enables) : + dyn_enables_module(m, enables)); +} - if (dn && (dm = (Module) getdata(dn)) && - (dm->flags & MOD_UNLOAD)) { - /* See if this is the only module depending on it. */ +/**/ +static int +boot_module(Module m) +{ + return ((m->flags & MOD_LINKED) ? + (m->u.linked->boot)(m) : dyn_boot_module(m)); +} - LinkNode an; - Module am; - int du = 1; +/**/ +static int +cleanup_module(Module m) +{ + return ((m->flags & MOD_LINKED) ? + (m->u.linked->cleanup)(m) : dyn_cleanup_module(m)); +} - for (an = firstnode(modules); du && an; incnode(an)) { - am = (Module) getdata(an); - if (am != m && am->deps && - ((am->flags & MOD_LINKED) ? - am->u.linked : am->u.handle)) { - LinkNode sn; +/**/ +static int +finish_module(Module m) +{ + return ((m->flags & MOD_LINKED) ? + (m->u.linked->finish)(m) : dyn_finish_module(m)); +} - for (sn = firstnode(am->deps); du && sn; - incnode(sn)) { - if (!strcmp((char *) getdata(sn), dm->nam)) - du = 0; - } - } - } - if (du) - unload_module(dm, NULL); - } - } - } - if(!m->deps) { - if (!node) { - for (node = firstnode(modules); node; incnode(node)) - if (m == (Module) getdata(node)) - break; - if (!node) - return 1; - } - delete_module(node); - } - } - return 0; +/**/ +#else /* !DYNAMIC */ + +/**/ +static int +setup_module(Module m) +{ + return ((m->flags & MOD_LINKED) ? (m->u.linked->setup)(m) : 1); } +/**/ +static int +features_module(Module m, char ***features) +{ + return ((m->flags & MOD_LINKED) ? (m->u.linked->features)(m, features) + : 1); +} /**/ -int -unload_named_module(char *modname, char *nam, int silent) +static int +enables_module(Module m, int **enables) { - const char *mname; - LinkNode node; - Module m; - int ret = 0; + return ((m->flags & MOD_LINKED) ? (m->u.linked->enables)(m, enables) + : 1); +} - node = find_module(modname, 1, &mname); - if (node) { - LinkNode mn, dn; - int del = 0; +/**/ +static int +boot_module(Module m) +{ + return ((m->flags & MOD_LINKED) ? (m->u.linked->boot)(m) : 1); +} - for (mn = firstnode(modules); mn; incnode(mn)) { - m = (Module) getdata(mn); - if (m->deps && m->u.handle) - for (dn = firstnode(m->deps); dn; incnode(dn)) - if (!strcmp((char *) getdata(dn), mname)) { - if (m->flags & MOD_UNLOAD) - del = 1; - else { - zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", mname); - return 1; - } - } - } - m = (Module) getdata(node); - if (del) - m->wrapper++; - if (unload_module(m, node)) - ret = 1; - if (del) - m->wrapper--; - } else if (!silent) { - zwarnnam(nam, "no such module %s", modname); - ret = 1; - } +/**/ +static int +cleanup_module(Module m) +{ + return ((m->flags & MOD_LINKED) ? (m->u.linked->cleanup)(m) : 1); +} - return ret; +/**/ +static int +finish_module(Module m) +{ + return ((m->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. + */ /**/ static int -bin_zmodload_load(char *nam, char **args, Options ops) +do_module_features(Module m, char **enablesstr, int silent) { - LinkNode node; - Module m; - 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; + char **features; + + 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 (!silent) + zwarn("error getting enabled features for module `%s'", + m->nam); + return 1; } - return ret; - } else if(!*args) { - /* list modules */ - for (node = firstnode(modules); node; incnode(node)) { - m = (Module) getdata(node); - if (m->u.handle && !(m->flags & (MOD_UNLOAD|MOD_ALIAS))) { - if(OPT_ISSET(ops,'L')) { - printf("zmodload "); - if(m->nam[0] == '-') - fputs("-- ", stdout); - quotedzputs(m->nam, stdout); - } else - nicezputs(m->nam, stdout); - putchar('\n'); + + if (enablesstr) { + char **ep; + for (ep = enablesstr; *ep; ep++) { + char **fp, *esp = *ep; + int on = 1; + if (*esp == '+') + esp++; + else if (*esp == '-') { + on = 0; + esp++; + } + for (fp = features; *fp; fp++) + if (!strcmp(*fp, esp)) { + enables[fp - features] = on; + break; + } + if (!*fp) { + if (!silent) + zwarn("module `%s' has no such feature: %s", + m->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; } - return 0; - } else { - /* load modules */ - for (; *args; args++) - if (!require_module(nam, *args, 1, (!OPT_ISSET(ops,'i')))) - ret = 1; - return ret; + if (enables_module(m, &enables)) + return 2; + } else if (enablesstr) { + if (!silent) + zwarn("module `%s' does not support features", m->nam); + return 1; } + /* Else it doesn't support features but we don't care. */ + + return 0; } -/* The list of module-defined conditions. */ +/* + * 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. + */ /**/ -mod_export Conddef condtab; +static int +do_boot_module(Module m, char **enablesstr, int silent) +{ + int ret = do_module_features(m, enablesstr, silent); -/* 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. */ + if (ret == 1) + return 1; + + if (boot_module(m)) + return 1; + return ret; +} + +/* + * Cleanup the module. + */ /**/ -Conddef -getconddef(int inf, char *name, int autol) +static int +do_cleanup_module(Module m) { - Conddef p; - int f = 1; + return (m->flags & MOD_LINKED) ? + (m->u.linked && m->u.linked->cleanup(m)) : + (m->u.handle && cleanup_module(m)); +} +/**/ +static int +modname_ok(char const *p) +{ do { - for (p = condtab; p; p = p->next) { - if ((!!inf == !!(p->flags & CONDF_INFIX)) && - !strcmp(name, 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) { - load_module_silence(p->module, 0); - f = 0; - p = NULL; - } else { - deleteconddef(p); - return NULL; - } - } else - break; - } while (!p); - return p; + p = itype_end(p, IIDENT, 0); + if (!*p) + return 1; + } while(*p++ == '/'); + return 0; } -/* 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. */ +/* + * Now returns 0 for success (changed post-4.3.4), + * 1 for complete failure, 2 if some features couldn't be set. + */ /**/ -int -addconddef(Conddef c) +mod_export int +load_module(char const *name, char **enablesstr) { - 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; + return load_module_silence(name, enablesstr, 0); } -/* This adds multiple condition definitions. This is like addbuiltins(). */ +/* + * Returns 0 for success (changed post-4.3.4), 1 for complete + * failure, 2 if some features couldn't be set. + */ /**/ mod_export int -addconddefs(char const *nam, Conddef c, int size) +load_module_silence(char const *name, char **enablesstr, int silent) { - int hads = 0, hadf = 0; + Module m; + void *handle = NULL; + Linkedmod linked; + LinkNode node, n; + int set, bootret; - while (size--) { - if (c->flags & CONDF_ADDED) { - c++; - continue; + 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 (!(node = find_module(name, 1, &name))) { + if (!(linked = module_linked(name)) && + !(handle = do_load_module(name, silent))) { + unqueue_signals(); + return 1; } - if (addconddef(c)) { - zwarnnam(nam, "name clash when adding condition `%s'", c->name); - hadf = 1; + m = zshcalloc(sizeof(*m)); + m->nam = ztrdup(name); + if (handle) { + m->u.handle = handle; + m->flags |= MOD_SETUP; } else { - c->flags |= CONDF_ADDED; - hads = 2; + m->u.linked = linked; + m->flags |= MOD_SETUP | MOD_LINKED; } - c++; + node = zaddlinknode(modules, m); + + if ((set = setup_module(m)) || + (bootret = do_boot_module(m, enablesstr, silent)) == 1) { + if (!set) { + do_cleanup_module(m); + finish_module(m); + } + delete_module(node); + unqueue_signals(); + return 1; + } + m->flags |= MOD_INIT_S | MOD_INIT_B; + m->flags &= ~MOD_SETUP; + unqueue_signals(); + return bootret; } - return hadf ? hads : 1; + m = (Module) getdata(node); + if (m->flags & MOD_SETUP) { + unqueue_signals(); + return 0; + } + if (m->flags & MOD_UNLOAD) + m->flags &= ~MOD_UNLOAD; + else if ((m->flags & MOD_LINKED) ? m->u.linked : m->u.handle) { + unqueue_signals(); + return 0; + } + if (m->flags & MOD_BUSY) { + zerr("circular dependencies for module %s", name); + return 1; + } + m->flags |= MOD_BUSY; + /* + * TODO: shouldn't we unload the module if one of + * its dependencies fails? + */ + if (m->deps) + for (n = firstnode(m->deps); n; incnode(n)) + if (load_module_silence((char *) getdata(n), NULL, silent) == 1) { + m->flags &= ~MOD_BUSY; + unqueue_signals(); + return 1; + } + m->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->flags |= MOD_SETUP; + } else { + m->u.linked = linked; + m->flags |= MOD_SETUP | MOD_LINKED; + } + if (setup_module(m)) { + if (handle) + m->u.handle = NULL; + else + m->u.linked = NULL; + m->flags &= ~MOD_SETUP; + unqueue_signals(); + return 1; + } + m->flags |= MOD_INIT_S; + } + m->flags |= MOD_SETUP; + if ((bootret = do_boot_module(m, enablesstr, silent)) == 1) { + do_cleanup_module(m); + finish_module(m); + if (m->flags & MOD_LINKED) + m->u.linked = NULL; + else + m->u.handle = NULL; + m->flags &= ~MOD_SETUP; + unqueue_signals(); + return 1; + } + m->flags |= MOD_INIT_B; + m->flags &= ~MOD_SETUP; + unqueue_signals(); + return bootret; } -/* This list of hook functions defined. */ - -/**/ -Hookdef hooktab; - -/* Find a hook definition given the name. */ +/* This ensures that the module with the name given as the second argument + * is loaded. + * The last argument is the array of features to set. If this is NULL + * and the module needs to be loaded, all features are enabled. + * 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. + */ /**/ -Hookdef -gethookdef(char *n) +mod_export int +require_module(char *nam, const char *module, char **features) { - Hookdef p; + Module m = NULL; + LinkNode node; + int ret = 0; + + /* Resolve aliases and actual loadable module as for load_module */ + queue_signals(); + node = find_module(module, 1, &module); + if (!node || !(m = ((Module) getdata(node)))->u.handle || + (m->flags & MOD_UNLOAD)) + ret = load_module_silence(module, features, 0); + else + ret = do_module_features(m, features, 0); + unqueue_signals(); - for (p = hooktab; p; p = p->next) - if (!strcmp(n, p->name)) - return p; - return NULL; + return ret; } -/* This adds the given hook definition. The return value is zero on * - * success and 1 on failure. */ - /**/ -int -addhookdef(Hookdef h) +void +add_dep(const char *name, char *from) { - if (gethookdef(h->name)) - return 1; - - h->next = hooktab; - hooktab = h; - h->funcs = znewlinklist(); + LinkNode node; + Module m; - return 0; + /* + * 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.) + */ + if (!(node = find_module(name, 1, &name))) { + m = zshcalloc(sizeof(*m)); + m->nam = ztrdup(name); + zaddlinknode(modules, m); + } else + m = (Module) getdata(node); + 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)); } -/* This adds multiple hook definitions. This is like addbuiltins(). */ - /**/ -mod_export int -addhookdefs(char const *nam, Hookdef h, int size) +static void +autoloadscan(HashNode hn, int printflags) { - int hads = 0, hadf = 0; + Builtin bn = (Builtin) hn; - while (size--) { - if (addhookdef(h)) { - zwarnnam(nam, "name clash when adding hook `%s'", h->name); - hadf = 1; - } else - hads = 2; - h++; + 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(')'); + } } - return hadf ? hads : 1; + putchar('\n'); } -/* Delete hook definitions. */ + +/************************************************************************ + * Handling for the zmodload builtin and its various options. + ************************************************************************/ /**/ int -deletehookdef(Hookdef h) +bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func)) { - Hookdef p, q; - - for (p = hooktab, q = NULL; p && p != h; q = p, p = p->next); + 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; + /* options only allowed with -F */ + char *fonly = "lP", *fp; - if (!p) + if (ops_bcpf) { + if (!ops_au) { + zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u"); + return 1; + } + if (OPT_ISSET(ops,'F')) { + zwarnnam(nam, "-b, -c, -f, and -p 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 (q) - q->next = p->next; + } + 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,'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 ((OPT_ISSET(ops,'a') || OPT_ISSET(ops,'b')) && + !(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'p') || OPT_ISSET(ops,'f'))) + ret = bin_zmodload_auto(nam, args, ops); + else if (OPT_ISSET(ops,'c') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'p'))) + ret = bin_zmodload_cond(nam, args, ops); + else if (OPT_ISSET(ops,'f') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'p'))) + ret = bin_zmodload_math(nam, args, ops); + else if (OPT_ISSET(ops,'p') && !(OPT_ISSET(ops,'b') || OPT_ISSET(ops,'c'))) + ret = bin_zmodload_param(nam, args, ops); + else if (!(OPT_ISSET(ops,'a') || OPT_ISSET(ops,'b') || + OPT_ISSET(ops,'c') || OPT_ISSET(ops,'p'))) + ret = bin_zmodload_load(nam, args, ops); else - hooktab = p->next; - freelinklist(p->funcs, NULL); - return 0; + zwarnnam(nam, "use only one of -b, -c, or -p"); + unqueue_signals(); + + return ret; } /**/ -mod_export int -deletehookdefs(UNUSED(char const *nam), Hookdef h, int size) +static int +bin_zmodload_alias(char *nam, char **args, Options ops) { - while (size--) { - deletehookdef(h); - h++; + /* + * TODO: while it would be too nasty to have aliases, as opposed + * to real loadable modules, with dependencies --- just what would + * we need to load when, exactly? --- there is in principle no objection + * to making it possible to force an alias onto an existing unloaded + * module which has dependencies. This would simply transfer + * the dependencies down the line to the aliased-to module name. + * This is actually useful, since then you can alias zsh/zle=mytestzle + * to load another version of zle. But then what happens when the + * alias is removed? Do you transfer the dependencies back? And + * suppose other names are aliased to the same file? It might be + * kettle of fish best left unwormed. + */ + LinkNode node; + Module m; + + if (!*args) { + if (OPT_ISSET(ops,'R')) { + zwarnnam(nam, "no module alias to remove"); + return 1; + } + for (node = firstnode(modules); node; incnode(node)) { + m = (Module) getdata(node); + if (m->flags & MOD_ALIAS) + printmodalias(m, ops); + } + 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; + } + node = find_module(*args, 0, NULL); + if (node) { + m = (Module) getdata(node); + if (!(m->flags & MOD_ALIAS)) { + zwarnnam(nam, "module is not an alias: %s", *args); + return 1; + } + delete_module(node); + } 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 ((node = find_module(mname, 0, NULL)) + && ((m = (Module) getdata(node))->flags & MOD_ALIAS) + && (mname = m->u.alias)); + node = find_module(*args, 0, NULL); + if (node) { + m = (Module) getdata(node); + if (!(m->flags & MOD_ALIAS)) { + zwarnnam(nam, "module is not an alias: %s", *args); + return 1; + } + zsfree(m->u.alias); + } else { + m = (Module) zshcalloc(sizeof(*m)); + m->nam = ztrdup(*args); + m->flags = MOD_ALIAS; + zaddlinknode(modules, m); + } + m->u.alias = ztrdup(aliasname); + } else { + if ((node = find_module(*args, 0, NULL))) { + m = (Module) getdata(node); + if (m->flags & MOD_ALIAS) + printmodalias(m, ops); + else { + zwarnnam(nam, "module is not an alias: %s", *args); + return 1; + } + } else { + zwarnnam(nam, "no such module alias: %s", *args); + return 1; + } + } + } } - return 1; -} - -/* 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) +static int +bin_zmodload_exist(UNUSED(char *nam), char **args, Options ops) { - Hookdef h = gethookdef(n); - - if (h) - return addhookdeffunc(h, f); - return 1; -} - -/* Delete a function from a hook. */ + LinkNode node; + Module m; + char *modname; -/**/ -int -deletehookdeffunc(Hookdef h, Hookfn f) -{ - LinkNode p; + if (!*args) { + for (node = firstnode(modules); node; incnode(node)) { + m = (Module) getdata(node); + modname = m->nam; + if (m->flags & MOD_ALIAS) { + LinkNode node2; + if (OPT_ISSET(ops,'A') && + (node2 = find_module(m->u.alias, 1, NULL))) + m = (Module) getdata(node2); + else + continue; + } + if (m->u.handle && !(m->flags & MOD_UNLOAD)) { + nicezputs(modname, stdout); + putchar('\n'); + } + } + return 0; + } else { + int ret = 0; - for (p = firstnode(h->funcs); p; incnode(p)) - if (f == (Hookfn) getdata(p)) { - remnode(h->funcs, p); - return 0; + for (; !ret && *args; args++) { + if (!(node = find_module(*args, 1, NULL)) + || !(m = (Module) getdata(node))->u.handle + || (m->flags & MOD_UNLOAD)) + ret = 1; } - return 1; + return ret; + } } /**/ -mod_export int -deletehookfunc(char *n, Hookfn f) +static int +bin_zmodload_dep(UNUSED(char *nam), char **args, Options ops) { - Hookdef h = gethookdef(n); + LinkNode node; + Module m; + if (OPT_ISSET(ops,'u')) { + /* remove dependencies, which can't pertain to aliases */ + const char *tnam = *args++; + node = find_module(tnam, 1, &tnam); + if (!node) + return 0; + m = (Module) getdata(node); + if (*args && m->deps) { + 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(node); + return 0; + } else if (!args[0] || !args[1]) { + /* list dependencies */ + for (node = firstnode(modules); node; incnode(node)) { + m = (Module) getdata(node); + if (m->deps && (!args[0] || !strcmp(args[0], m->nam))) { + LinkNode n; + if (OPT_ISSET(ops,'L')) { + printf("zmodload -d "); + if(m->nam[0] == '-') + fputs("-- ", stdout); + quotedzputs(m->nam, stdout); + } else { + nicezputs(m->nam, stdout); + putchar(':'); + } + for (n = firstnode(m->deps); n; incnode(n)) { + putchar(' '); + if(OPT_ISSET(ops,'L')) + quotedzputs((char *) getdata(n), stdout); + else + nicezputs((char *) getdata(n), stdout); + } + putchar('\n'); + } + } + return 0; + } else { + /* add dependencies */ + int ret = 0; + char *tnam = *args++; - if (h) - return deletehookdeffunc(h, f); - return 1; + for (; *args; args++) + add_dep(tnam, *args); + return ret; + } } -/* Run the function(s) for a hook. */ - /**/ -mod_export int -runhookdef(Hookdef h, void *d) +static int +bin_zmodload_auto(char *nam, char **args, Options ops) { - 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); + int ret = 0; + if(OPT_ISSET(ops,'u')) { + /* remove autoloaded builtins */ + for (; *args; args++) { + Builtin bn = (Builtin) builtintab->getnode2(builtintab, *args); + if (!bn) { + if(!OPT_ISSET(ops,'i')) { + zwarnnam(nam, "%s: no such builtin", *args); + ret = 1; + } + } else if (bn->node.flags & BINF_ADDED) { + zwarnnam(nam, "%s: builtin is already defined", *args); + ret = 1; + } else + deletebuiltin(*args); + } + return ret; + } else if(!*args) { + /* list autoloaded builtins */ + scanhashtable(builtintab, 1, 0, 0, + autoloadscan, OPT_ISSET(ops,'L') ? PRINT_LIST : 0); return 0; - } else - return ((Hookfn) getdata(lastnode(h->funcs)))(h, d); + } else { + /* add autoloaded builtins */ + char *modnam; + modnam = *args++; + do { + char *bnam = *args ? *args++ : modnam; + if (strchr(bnam, '/')) { + zwarnnam(nam, "%s: `/' is illegal in a builtin", bnam); + ret = 1; + } else if (add_autobin(bnam, modnam) && !OPT_ISSET(ops,'i')) { + zwarnnam(nam, "failed to add builtin %s", bnam); + ret = 1; + } + } while(*args); + return ret; + } } /**/ -int -runhook(char *n, void *d) +static int +bin_zmodload_cond(char *nam, char **args, Options ops) { - Hookdef h = gethookdef(n); + int ret = 0; - if (h) - return runhookdef(h, d); - return 0; + if (OPT_ISSET(ops,'u')) { + /* remove autoloaded conditions */ + for (; *args; args++) { + Conddef cd = getconddef(OPT_ISSET(ops,'I'), *args, 0); + + if (!cd) { + if (!OPT_ISSET(ops,'i')) { + zwarnnam(nam, "%s: no such condition", *args); + ret = 1; + } + } else if (cd->flags & CONDF_ADDED) { + zwarnnam(nam, "%s: condition is already defined", *args); + ret = 1; + } else + deleteconddef(cd); + } + return ret; + } else 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; + } else { + /* add autoloaded conditions */ + char *modnam; + + modnam = *args++; + do { + char *cnam = *args ? *args++ : modnam; + if (strchr(cnam, '/')) { + zwarnnam(nam, "%s: `/' is illegal in a condition", cnam); + ret = 1; + } else if (add_autocond(cnam, OPT_ISSET(ops,'I'), modnam) && + !OPT_ISSET(ops,'i')) { + zwarnnam(nam, "failed to add condition `%s'", cnam); + ret = 1; + } + } while(*args); + return ret; + } } -/* This adds the given parameter definition. The return value is zero on * - * success and 1 on failure. */ - /**/ -int -addparamdef(Paramdef d) +static int +bin_zmodload_math(char *nam, char **args, Options ops) { - Param pm; - - if ((pm = (Param) gethashnode2(paramtab, d->name))) - unsetparam_pm(pm, 0, 1); - - if (!(pm = createparam(d->name, d->flags)) && - !(pm = (Param) paramtab->getnode(paramtab, d->name))) - return 1; - - pm->level = 0; - pm->u.data = d->var; - if (d->gsu) - pm->gsu.i = (GsuInteger) d->gsu; - else { - /* - * If no get/set/unset class, use the appropriate - * variable type. - */ - switch (PM_TYPE(pm->node.flags)) { - case PM_SCALAR: - pm->gsu.s = &varscalar_gsu; - break; - - case PM_INTEGER: - pm->gsu.i = &varinteger_gsu; - break; + int ret = 0; - case PM_ARRAY: - pm->gsu.a = &vararray_gsu; - break; + if (OPT_ISSET(ops,'u')) { + /* remove autoloaded math functions */ + for (; *args; args++) { + MathFunc f = getmathfunc(*args, 0); - default: - unsetparam_pm(pm, 0, 1); - return 1; + if (!f) { + if (!OPT_ISSET(ops,'i')) { + zwarnnam(nam, "%s: no such math function", *args); + ret = 1; + } + } else if (f->flags & MFF_ADDED) { + zwarnnam(nam, "%s: math function is already defined", *args); + ret = 1; + } else + deletemathfunc(f); } - } - - return 0; -} - -/* This adds multiple parameter definitions. This is like addbuiltins(). */ + return ret; + } else if (!*args) { + /* list autoloaded math functions */ + MathFunc p; -/**/ -mod_export int -addparamdefs(char const *nam, Paramdef d, int size) -{ - int hads = 0, hadf = 0; + 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; + } else { + /* add autoloaded math functions */ + char *modnam; - while (size--) { - if (addparamdef(d)) { - zwarnnam(nam, "error when adding parameter `%s'", d->name); - hadf = 1; - } else - hads = 2; - d++; + modnam = *args++; + do { + char *fnam = *args ? *args++ : modnam; + if (strchr(fnam, '/')) { + zwarnnam(nam, "%s: `/' is illegal in a math function", fnam); + ret = 1; + } else if (add_automathfunc(fnam, modnam) && !OPT_ISSET(ops,'i')) { + zwarnnam(nam, "failed to add math function `%s'", fnam); + ret = 1; + } + } while(*args); + return ret; } - return hadf ? hads : 1; } -/* Delete parameters defined. No error checking yet. */ - -/**/ -int -deleteparamdef(Paramdef d) +static void +printautoparams(HashNode hn, int lon) { - unsetparam(d->name); - return 0; -} + Param pm = (Param) hn; -/**/ -mod_export int -deleteparamdefs(UNUSED(char const *nam), Paramdef d, int size) -{ - while (size--) { - deleteparamdef(d); - d++; + 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); } - return 1; } -/* This adds a definition for autoloading a module for a condition. */ - /**/ -int -add_autocond(char *nam, int inf, char *module) +static int +bin_zmodload_param(char *nam, char **args, Options ops) { - Conddef c = (Conddef) zalloc(sizeof(*c)); + int ret = 0; - c->name = ztrdup(nam); - c->flags = (inf ? CONDF_INFIX : 0); - c->module = ztrdup(module); + if (OPT_ISSET(ops,'u')) { + /* remove autoloaded parameters */ + for (; *args; args++) { + Param pm = (Param) gethashnode2(paramtab, *args); - if (addconddef(c)) { - zsfree(c->name); - zsfree(c->module); - zfree(c, sizeof(*c)); + if (!pm) { + if (!OPT_ISSET(ops,'i')) { + zwarnnam(nam, "%s: no such parameter", *args); + ret = 1; + } + } else if (!(pm->node.flags & PM_AUTOLOAD)) { + zwarnnam(nam, "%s: parameter is already defined", *args); + ret = 1; + } else + unsetparam_pm(pm, 0, 1); + } + return ret; + } else if (!*args) { + scanhashtable(paramtab, 1, 0, 0, printautoparams, OPT_ISSET(ops,'L')); + return 0; + } else { + /* add autoloaded parameters */ + char *modnam; - return 1; + modnam = *args++; + do { + char *pnam = *args ? *args++ : modnam; + if (strchr(pnam, '/')) { + zwarnnam(nam, "%s: `/' is illegal in a parameter", pnam); + ret = 1; + } else + add_autoparam(pnam, modnam); + } while(*args); + return ret; } - 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) +unload_module(Module m, LinkNode node) { - Conddef p, q; - - for (p = condtab, q = NULL; p && p != c; q = p, p = p->next); + /* + * Only unload the real module, so resolve aliases. + */ + if (m->flags & MOD_ALIAS) { + LinkNode node = find_module(m->u.alias, 1, NULL); + if (!node) + return 1; + m = (Module) getdata(node); + } + if ((m->flags & MOD_INIT_S) && + !(m->flags & MOD_UNLOAD) && + do_cleanup_module(m)) + return 1; + else { + int del = (m->flags & MOD_UNLOAD); - 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)); + if (m->wrapper) { + m->flags |= MOD_UNLOAD; + return 0; } - return 0; - } - return -1; -} + m->flags &= ~MOD_UNLOAD; + if (m->flags & MOD_INIT_B) { + if (m->flags & MOD_LINKED) { + if (m->u.linked) { + m->u.linked->finish(m); + m->u.linked = NULL; + } + } else { + if (m->u.handle) { + finish_module(m); + m->u.handle = NULL; + } + } + } + if (del && m->deps) { + /* The module was unloaded delayed, unload all modules * + * on which it depended. */ + LinkNode n; + + for (n = firstnode(m->deps); n; incnode(n)) { + LinkNode dn = find_module((char *) getdata(n), 1, NULL); + Module dm; -/* This removes multiple condition definitions (like deletebuiltins()). */ + if (dn && (dm = (Module) getdata(dn)) && + (dm->flags & MOD_UNLOAD)) { + /* See if this is the only module depending on it. */ -/**/ -mod_export int -deleteconddefs(char const *nam, Conddef c, int size) -{ - int hads = 0, hadf = 0; + LinkNode an; + Module am; + int du = 1; - while (size--) { - if (!(c->flags & CONDF_ADDED)) { - c++; - continue; + for (an = firstnode(modules); du && an; incnode(an)) { + am = (Module) getdata(an); + if (am != m && am->deps && + ((am->flags & MOD_LINKED) ? + am->u.linked : am->u.handle)) { + LinkNode sn; + + for (sn = firstnode(am->deps); du && sn; + incnode(sn)) { + if (!strcmp((char *) getdata(sn), dm->nam)) + du = 0; + } + } + } + if (du) + unload_module(dm, NULL); + } + } + } + if(!m->deps) { + if (!node) { + for (node = firstnode(modules); node; incnode(node)) + if (m == (Module) getdata(node)) + break; + if (!node) + return 1; + } + delete_module(node); } - if (deleteconddef(c)) { - zwarnnam(nam, "condition `%s' already deleted", c->name); - hadf = 1; - } else - hads = 2; - c->flags &= ~CONDF_ADDED; - c++; } - return hadf ? hads : 1; + return 0; } -/* This adds a definition for autoloading a module for a parameter. */ /**/ -void -add_autoparam(char *nam, char *module) +int +unload_named_module(char *modname, char *nam, int silent) { - Param pm; + const char *mname; + LinkNode node; + Module m; + int ret = 0; - queue_signals(); - if ((pm = (Param) gethashnode2(paramtab, nam))) - unsetparam_pm(pm, 0, 1); + node = find_module(modname, 1, &mname); + if (node) { + LinkNode mn, dn; + int del = 0; - pm = setsparam(nam, ztrdup(module)); + for (mn = firstnode(modules); mn; incnode(mn)) { + m = (Module) getdata(mn); + if (m->deps && m->u.handle) + for (dn = firstnode(m->deps); dn; incnode(dn)) + if (!strcmp((char *) getdata(dn), mname)) { + if (m->flags & MOD_UNLOAD) + del = 1; + else { + zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", mname); + return 1; + } + } + } + m = (Module) getdata(node); + if (del) + m->wrapper++; + if (unload_module(m, node)) + ret = 1; + if (del) + m->wrapper--; + } else if (!silent) { + zwarnnam(nam, "no such module %s", modname); + ret = 1; + } - pm->node.flags |= PM_AUTOLOAD; - unqueue_signals(); + return ret; } -/* List of math functions. */ - -/**/ -MathFunc mathfuncs; - -/**/ -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)); -} /**/ -MathFunc -getmathfunc(char *name, int autol) +static int +bin_zmodload_load(char *nam, char **args, Options ops) { - 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); - - removemathfunc(q, p); - - load_module_silence(n, 0); - - return getmathfunc(name, 0); + LinkNode node; + Module m; + 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 */ + for (node = firstnode(modules); node; incnode(node)) { + m = (Module) getdata(node); + if (m->u.handle && !(m->flags & (MOD_UNLOAD|MOD_ALIAS))) { + if(OPT_ISSET(ops,'L')) { + printf("zmodload "); + if(m->nam[0] == '-') + fputs("-- ", stdout); + quotedzputs(m->nam, stdout); + } else + nicezputs(m->nam, stdout); + putchar('\n'); } - return p; + } + return 0; + } else { + /* load modules */ + for (; *args; args++) { + int tmpret = require_module(nam, *args, NULL); + if (tmpret && ret != 1) + ret = tmpret; } - return NULL; + return ret; + } } /**/ -mod_export int -addmathfunc(MathFunc f) +static int +bin_zmodload_features(char *nam, char **args, Options ops) { - MathFunc p, q = NULL; + char *modname = *args; - if (f->flags & MFF_ADDED) + if (!modname) { + zwarnnam(nam, "-F requires a module name"); return 1; + } + args++; - 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; - } + 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. + */ + LinkNode node; + Module m = NULL; + char **features, **fp, **arrset = NULL, **arrp = NULL; + int *enables = NULL, *ep; + char *param = OPT_ARG_SAFE(ops,'P'); + + node = find_module(modname, 1, NULL); + if (node) + m = ((Module) getdata(node)); + if (!m || !m->u.handle || (m->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->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->nam); + return 1; + } + for (arrp = args; *arrp; arrp++) { + char *arg = *arrp; + int on; + if (*arg == '-') { + on = 0; + arg++; + } else if (*arg == '+') { + on = 1; + arg++; + } else + on = -1; + for (fp = features, ep = enables; *fp; fp++, ep++) { + if (!strcmp(arg, *fp)) { + /* for -e, check given state, if any */ + if (OPT_ISSET(ops,'e') && on != -1 && + on != (*ep & 1)) + return 1; + break; + } + } + if (!*fp) { + if (!OPT_ISSET(ops,'e')) + zwarnnam(nam, "module `%s' has no such feature: %s", + *arrp); + return 1; + } + } + if (OPT_ISSET(ops,'e')) /* yep, everything we want exists */ + return 0; + if (OPT_ISSET(ops,'P')) { + 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; *argp; argp++) { + char *arg = *argp; + /* ignore +/- for consistency */ + if (*arg == '+' || *arg == '-') + arg++; + if (!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->nam); + for (fp = features, ep = enables; *fp; fp++, ep++) { + char *onoff; + int term; + if (*args) { + char **argp; + for (argp = args; *argp; argp++) { + char *arg = *argp; + if (*arg == '+' || *arg == '-') + arg++; + if (!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; + } - f->flags |= MFF_ADDED; - f->next = mathfuncs; - mathfuncs = f; - - return 0; + return require_module(nam, modname, args); } + +/************************************************************************ + * 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 int -addmathfuncs(char const *nam, MathFunc f, int size) +mod_export char ** +featuresarray(char const *nam, Features f) { - int hads = 0, hadf = 0; + int bn_size = f->bn_size, cd_size = f->cd_size; + int pd_size = f->pd_size, mf_size = f->mf_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; + Paramdef pdp = f->pd_list; + MathFunc mfp = f->mf_list; + char **features = (char **)zhalloc((features_size + 1) * sizeof(char *)); + char **featurep = features; - while (size--) { - if (f->flags & MFF_ADDED) { - f++; - continue; - } - if (addmathfunc(f)) { - zwarnnam(nam, "name clash when adding math function `%s'", - f->name); - hadf = 1; - } else - hads = 2; - f++; - } - return hadf ? hads : 1; + while (bn_size--) + *featurep++ = dyncat("b:", (bnp++)->node.nam); + while (cd_size--) + *featurep++ = dyncat("c:", (cdp++)->name); + while (pd_size--) + *featurep++ = dyncat("p:", (pdp++)->name); + while (mf_size--) + *featurep++ = dyncat("f:", (mfp++)->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. + */ /**/ -int -add_automathfunc(char *nam, char *module) +mod_export int * +getfeatureenables(char const *nam, Features f) { - MathFunc f = (MathFunc) zalloc(sizeof(*f)); - - f->name = ztrdup(nam); - f->module = ztrdup(module); - f->flags = 0; - - if (addmathfunc(f)) { - zsfree(f->name); - zsfree(f->module); - zfree(f, sizeof(*f)); + int bn_size = f->bn_size, cd_size = f->cd_size; + int pd_size = f->pd_size, mf_size = f->mf_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; + Paramdef pdp = f->pd_list; + MathFunc mfp = f->mf_list; + int *enables = zhalloc(sizeof(int) * features_size); + int *enablep = enables; - return 1; - } - f->flags &= ~MFF_ADDED; /* still to autoload, not added yet */ + while (bn_size--) + *enablep++ = ((bnp++)->node.flags & BINF_ADDED) ? 1 : 0; + while (cd_size--) + *enablep++ = ((cdp++)->flags & CONDF_ADDED) ? 1 : 0; + while (pd_size--) + *enablep++ = (pdp++)->pm ? 1 : 0; + while (mf_size--) + *enablep++ = ((mfp++)->flags & MFF_ADDED) ? 1 : 0; - return 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 -deletemathfunc(MathFunc f) +setfeatureenables(char const *nam, Features f, int *e) { - 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; + int ret = 0; - return 0; - } - return -1; + if (f->bn_size && setbuiltins(nam, f->bn_list, f->bn_size, e) != 1) + ret = 1; + if (e) + e += f->bn_size; + if (f->cd_size && setconddefs(nam, f->cd_list, f->cd_size, e) != 1) + ret = 1; + if (e) + e += f->cd_size; + if (f->pd_size && setparamdefs(nam, f->pd_list, f->pd_size, e) != 1) + ret = 1; + if (e) + e += f->pd_size; + if (f->mf_size && setmathfuncs(nam, f->mf_list, f->mf_size, e) != 1) + ret = 1; + return ret; } - + /**/ mod_export int -deletemathfuncs(char const *nam, MathFunc f, int size) +handlefeatures(char *nam, Features f, int **enables) { - int hads = 0, hadf = 0; - - while (size--) { - if (!(f->flags & MFF_ADDED)) { - f++; - continue; - } - if (deletemathfunc(f)) { - zwarnnam(nam, "math function `%s' already deleted", f->name); - hadf = 1; - } else - hads = 2; - f++; - } - return hadf ? hads : 1; + if (!enables || *enables) + return setfeatureenables(nam, f, *enables); + *enables = getfeatureenables(nam, f); + return 0; } diff --git a/Src/params.c b/Src/params.c index 14ff4f6ca..31a65811f 100644 --- a/Src/params.c +++ b/Src/params.c @@ -419,7 +419,7 @@ getparamnode(HashTable ht, char *nam) if (pm && pm->u.str && (pm->node.flags & PM_AUTOLOAD)) { char *mn = dupstring(pm->u.str); - if (!load_module(mn)) + if (load_module(mn, NULL) == 1) return NULL; hn = gethashnode2(ht, nam); if (((Param) hn) == pm && (pm->node.flags & PM_AUTOLOAD)) { @@ -840,6 +840,47 @@ createparam(char *name, int flags) return pm; } +/* Empty dummy function for special hash parameters. */ + +/**/ +static void +shempty(void) +{ +} + +/* Create a simple special hash parameter. */ + +/**/ +mod_export Param +createspecialhash(char *name, GetNodeFunc get, ScanTabFunc scan, int flags) +{ + Param pm; + HashTable ht; + + if (!(pm = createparam(name, PM_SPECIAL|PM_HASHED|flags))) + return NULL; + + pm->level = pm->old ? locallevel : 0; + pm->gsu.h = (flags & PM_READONLY) ? &stdhash_gsu : + &nullsethash_gsu; + pm->u.hash = ht = newhashtable(0, name, NULL); + + ht->hash = hasher; + ht->emptytable = (TableFunc) shempty; + ht->filltable = NULL; + ht->addnode = (AddNodeFunc) shempty; + ht->getnode = ht->getnode2 = get; + ht->removenode = (RemoveNodeFunc) shempty; + ht->disablenode = NULL; + ht->enablenode = NULL; + ht->freenode = (FreeNodeFunc) shempty; + ht->printnode = printparamnode; + ht->scantab = scan; + + return pm; +} + + /* Copy a parameter */ /**/ @@ -4117,7 +4158,7 @@ scanendscope(HashNode hn, UNUSED(int flags)) if (pm->env) delenv(pm); - if (!(tpm->node.flags & PM_NORESTORE)) + if (!(tpm->node.flags & (PM_NORESTORE|PM_READONLY))) switch (PM_TYPE(pm->node.flags)) { case PM_SCALAR: pm->gsu.s->setfn(pm, tpm->u.str); diff --git a/Src/zsh.h b/Src/zsh.h index a80a6fd99..f7255c6e7 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -77,7 +77,7 @@ typedef mnumber (*StrMathFunc)(char *, char *, int); struct mathfunc { MathFunc next; char *name; - int flags; + int flags; /* MFF_* flags defined below */ NumMathFunc nfunc; StrMathFunc sfunc; char *module; @@ -93,6 +93,7 @@ struct mathfunc { /* Math function is implemented by a shell function */ #define MFF_USERFUNC 4 + #define NUMMATHFUNC(name, func, min, max, id) \ { NULL, name, 0, func, NULL, NULL, min, max, id } #define STRMATHFUNC(name, func, id) \ @@ -375,6 +376,7 @@ typedef struct builtin *Builtin; typedef struct cmdnam *Cmdnam; typedef struct complist *Complist; typedef struct conddef *Conddef; +typedef struct features *Features; typedef struct funcstack *Funcstack; typedef struct funcwrap *FuncWrap; typedef struct hashnode *HashNode; @@ -1166,14 +1168,40 @@ struct module { #define MOD_INIT_B (1<<5) #define MOD_ALIAS (1<<6) -typedef int (*Module_func) _((Module)); +typedef int (*Module_generic_func) _((void)); +typedef int (*Module_void_func) _((Module)); +typedef int (*Module_features_func) _((Module, char ***)); +typedef int (*Module_enables_func) _((Module, int **)); struct linkedmod { char *name; - Module_func setup; - Module_func boot; - Module_func cleanup; - Module_func finish; + Module_void_func setup; + Module_features_func features; + Module_enables_func enables; + Module_void_func boot; + Module_void_func cleanup; + Module_void_func finish; +}; + +/* + * Structure combining all the concrete features available in + * a module and with space for information about abstract features. + */ +struct features { + /* List of builtins provided by the module and the size thereof */ + Builtin bn_list; + int bn_size; + /* List of conditions provided by the module and the size thereof */ + Conddef cd_list; + int cd_size; + /* List of parameters provided by the module and the size thereof */ + Paramdef pd_list; + int pd_size; + /* List of math functions provided by the module and the size thereof */ + MathFunc mf_list; + int mf_size; + /* Number of abstract features */ + int n_abstract; }; /* C-function hooks */ @@ -1422,26 +1450,65 @@ struct tieddata { #define PF_ASSIGN 0x02 /* argument handled like the RHS of foo=bar */ #define PF_SINGLE 0x04 /* single word substitution */ +/* + * Structure for adding parameters in a module. + * The flags should declare the type; note PM_SCALAR is zero. + * + * Special hashes are recognized by getnfn so the PM_HASHED + * is optional. These get slightly non-standard attention: + * the function createspecialhash is used to create them. + * + * The get/set/unset attribute may be NULL; in that case the + * parameter is assigned methods suitable for handling the + * tie variable var, if that is not NULL, else standard methods. + * + * pm is set when the parameter is added to the parameter table + * and serves as a flag that the parameter has been added. + */ struct paramdef { char *name; int flags; - void *var; - void *gsu; /* get/set/unset structure */ + void *var; /* tied internal variable, if any */ + const void *gsu; /* get/set/unset structure, if special */ + GetNodeFunc getnfn; /* function to get node, if special hash */ + ScanTabFunc scantfn; /* function to scan table, if special hash */ + Param pm; /* structure inserted into param table */ }; +/* + * Shorthand for common uses of adding parameters, with no special + * hash properties. + */ #define PARAMDEF(name, flags, var, gsu) \ - { name, flags, (void *) var, (void *) gsu, } + { name, flags, (void *) var, (void *) gsu, \ + NULL, NULL, NULL \ + } /* * Note that the following definitions are appropriate for defining * parameters that reference a variable (var). Hence the get/set/unset * methods used will assume var needs dereferencing to get the value. */ #define INTPARAMDEF(name, var) \ - { name, PM_INTEGER, (void *) var, NULL } + { name, PM_INTEGER, (void *) var, NULL, NULL, NULL, NULL } #define STRPARAMDEF(name, var) \ - { name, PM_SCALAR, (void *) var, NULL } + { name, PM_SCALAR, (void *) var, NULL, NULL, NULL, NULL } #define ARRPARAMDEF(name, var) \ - { name, PM_ARRAY, (void *) var, NULL } + { name, PM_ARRAY, (void *) var, NULL, NULL, NULL, NULL } +/* + * The following is appropriate for a module function that behaves + * in a special fashion. Parameters used in a module that don't + * have special behaviour shouldn't be declared in a table but + * should just be added with the standard parameter functions. + * + * These parameters are not marked as removable, since they + * shouldn't be loaded as local parameters, unlike the special + * Zle parameters that are added and removed on each call to Zle. + * We add the PM_REMOVABLE flag when removing the feature corresponding + * to the parameter. + */ +#define SPECIALPMDEF(name, flags, gsufn, getfn, scanfn) \ + { name, flags | PM_SPECIAL | PM_HIDE | PM_HIDEVAL, \ + NULL, gsufn, getfn, scanfn, NULL } #define setsparam(S,V) assignsparam(S,V,0) #define setaparam(S,V) assignaparam(S,V,0) -- cgit 1.4.1