diff options
59 files changed, 2858 insertions, 1620 deletions
diff --git a/ChangeLog b/ChangeLog index 12a464445..427d8ab7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,30 @@ 2007-05-28 Peter Stephenson <p.w.stephenson@ntlworld.com> + * Not posted but see 23479:Completion/Unix/Command/_chmod, + Completion/Unix/Command/_chown, Completion/Unix/Command/_cvs, + Completion/Unix/Type/_list_files, Completion/Zsh/Command/_stat, + Completion/Zsh/Command/_zstyle, + Completion/Zsh/Type/_file_descriptors,Doc/Zsh/builtins.yo, + Doc/Zsh/compsys.yo, Doc/Zsh/mod_stat.yo, + Etc/zsh-development-guide, Src/builtin.c, Src/cond.c, Src/exec.c + Src/init.c, Src/mkbltnmlst.sh, Src/mkmakemod.sh, Src/modentry.c, + Src/module.c, Src/params.c, Src/zsh.h, Src/Builtins/rlimits.c, + Src/Builtins/sched.c, Src/Modules/cap.c, Src/Modules/clone.c, + Src/Modules/datetime.c, Src/Modules/example.c, + Src/Modules/files.c, Src/Modules/langinfo.c, + Src/Modules/langinfo.mdd, Src/Modules/mapfile.c, + Src/Modules/mathfunc.c, Src/Modules/parameter.c, + Src/Modules/pcre.c, Src/Modules/regex.c, Src/Modules/socket.c, + Src/Modules/stat.c, Src/Modules/system.c, Src/Modules/tcp.c, + Src/Modules/termcap.c, Src/Modules/terminfo.c, Src/Modules/zftp.c, + Src/Modules/zprof.c, Src/Modules/zpty.c, Src/Modules/zselect.c, + Src/Modules/zutil.c, Src/Zle/compctl.c, Src/Zle/complete.c, + Src/Zle/complist.c, Src/Zle/computil.c, Src/Zle/deltochar.c, + Src/Zle/zle_main.c, Src/Zle/zle_thingy.c, Src/Zle/zle_tricky.c, + Src/Zle/zleparameter.c, Test/B02typeset.ztst, + Test/V01zmodload.ztst, Test/V04features.ztst: add "zmodload -F" + and internal features support for modules. + * 23478: Src/Zle/compresult.c: don't run reverse-menu-complete if no completion yet. diff --git a/Completion/Unix/Command/_chmod b/Completion/Unix/Command/_chmod index 3df93fd64..84013d591 100644 --- a/Completion/Unix/Command/_chmod +++ b/Completion/Unix/Command/_chmod @@ -54,13 +54,9 @@ case "$state" in ;; files) if [[ -n $opt_args[--reference] ]]; then - if zstyle -t ":completion:${curcontext}:" disable-stat; then - _files && ret=0 - else - zmodload -i zsh/stat 2>/dev/null - typeset -i8 ref=$(stat +mode $opt_args[--reference]) - _wanted files expl file _files -g "*(-.^f${ref#??})" && ret=0 - fi + zmodload -F zsh/stat zstat 2>/dev/null + typeset -i8 ref=$(zstat +mode $opt_args[--reference]) + _wanted files expl file _files -g "*(-.^f${ref#??})" && ret=0 elif [[ $words[2] = [0-7]## ]]; then _wanted files expl file _files -g "*(-.^f$words[2])" && ret=0 else diff --git a/Completion/Unix/Command/_chown b/Completion/Unix/Command/_chown index 3371e8ea4..9246db42c 100644 --- a/Completion/Unix/Command/_chown +++ b/Completion/Unix/Command/_chown @@ -50,14 +50,10 @@ case $state in files) (( $+opt_args[-h] || $+opt_args[--no-dereference] )) || deref="-" if (( $+opt_args[--reference] )); then - if zstyle -t ":completion:${curcontext}:" disable-stat; then - _files && ret=0 - else - zmodload -i zsh/stat 2>/dev/null - usr=$(stat +uid $opt_args[--reference]) - grp=$(stat +gid $opt_args[--reference]) - _wanted files expl file _files -g "*($deref^u$usr,$deref^g$grp)" && ret=0 - fi + zmodload -F zsh/stat zstat 2>/dev/null + usr=$(zstat +uid $opt_args[--reference]) + grp=$(zstat +gid $opt_args[--reference]) + _wanted files expl file _files -g "*($deref^u$usr,$deref^g$grp)" && ret=0 return ret fi if [[ $service = chgrp ]]; then diff --git a/Completion/Unix/Command/_cvs b/Completion/Unix/Command/_cvs index 839075f64..c5fd75050 100644 --- a/Completion/Unix/Command/_cvs +++ b/Completion/Unix/Command/_cvs @@ -550,11 +550,10 @@ _cvs_watchers() { (( $+functions[_cvs_loadstat] )) || _cvs_loadstat() { - zstyle -t ":completion:${curcontext}:" disable-stat && return 1 (( $+_cvs_loadstat_status )) && return $_cvs_loadstat_status - zmodload -i zsh/stat 2>/dev/null - (( _cvs_loadstat_status = ! $+builtins[stat] )) + zmodload -F zsh/stat zstat 2>/dev/null + (( _cvs_loadstat_status = ! $+builtins[zstat] )) return $_cvs_loadstat_status } @@ -566,7 +565,7 @@ _cvs_root() { if [[ -f "${cvspassfile::=${CVS_PASSFILE:-$HOME/.cvspass}}" ]]; then if _cvs_loadstat; then - id="$(LC_ALL=C builtin stat -g +mtime -F '%Y/%m/%d-%T' "$cvspassfile")" + id="$(LC_ALL=C builtin zstat -g +mtime -F '%Y/%m/%d-%T' "$cvspassfile")" else id="$(LC_ALL=C ls -l "$cvspassfile")" fi @@ -865,7 +864,7 @@ _cvs_modified_entries() { realdir=${(e)~linedir} [[ -f "$realdir"CVS/Entries ]] && { local -a mtime - LC_ALL=C builtin stat -A mtime -gn +mtime -F $'%a %b %e %T %Y\n' ${realdir}*(D) 2>/dev/null + LC_ALL=C builtin zstat -A mtime -gn +mtime -F $'%a %b %e %T %Y\n' ${realdir}*(D) 2>/dev/null [[ -n ${pat::="${(@j:|:)${(@)${(@)${(@)${(@)${(@)${(@M)${(@f)"$(<"$realdir"CVS/Entries)"}:#/*}#/}/${slash}[^${slash}]#${slash}//}%/[^/]#/[^/]#}:#${(j:|:)~${(f)${(j:/:)${mtime##*/}}//(#m)[][*?()<|^~#\\]/\\$MATCH}#/}}%%/*}//(#m)[][*?()<|^~#\\]/\\$MATCH}"} ]] } && _wanted files expl 'modified file' _path_files -g "$pat" diff --git a/Completion/Unix/Type/_list_files b/Completion/Unix/Type/_list_files index 8475d2056..bcb42907d 100644 --- a/Completion/Unix/Type/_list_files +++ b/Completion/Unix/Type/_list_files @@ -46,15 +46,7 @@ done (( ok )) || return 1 -zmodload -i zsh/stat 2>/dev/null || return 1 - -{ -# Enable stat temporarily if disabled to avoid clashes. -integer disable_stat -if [[ ${builtins[stat]} != defined ]]; then - (( disable_stat = 1 )) - enable stat -fi +zmodload -F zsh/stat zstat 2>/dev/null || return 1 dir=${2:+$2/} dir=${(Q)dir} @@ -66,7 +58,7 @@ for f in ${(PQ)1}; do fi # Borrowed from Functions/Example/zls - stat -s -H stat -F "%b %e %H:%M" - "$dir$f" >/dev/null 2>&1 + zstat -s -H stat -F "%b %e %H:%M" - "$dir$f" >/dev/null 2>&1 listfiles+=("$stat[mode] ${(l:3:)stat[nlink]} ${(r:8:)stat[uid]} \ ${(r:8:)stat[gid]} ${(l:8:)stat[size]} $stat[mtime] $f") @@ -74,7 +66,4 @@ done (( ${#listfiles} )) && listopts=(-d listfiles -l -o) -} always { - (( disable_stat )) && disable stat -} return 0 diff --git a/Completion/Zsh/Command/_stat b/Completion/Zsh/Command/_stat index 5ba06388b..03e42e3af 100644 --- a/Completion/Zsh/Command/_stat +++ b/Completion/Zsh/Command/_stat @@ -1,4 +1,4 @@ -#compdef stat +#compdef stat zstat local expl ret=1 diff --git a/Completion/Zsh/Command/_zstyle b/Completion/Zsh/Command/_zstyle index 4090f0ac3..2bf2709ca 100644 --- a/Completion/Zsh/Command/_zstyle +++ b/Completion/Zsh/Command/_zstyle @@ -40,7 +40,6 @@ styles=( completer c:completer condition c:bool cursor c:cursor - disable-stat c:bool disabled c:bool domains c: expand c: diff --git a/Completion/Zsh/Type/_file_descriptors b/Completion/Zsh/Type/_file_descriptors index 6d21ed2b6..82d19d62a 100644 --- a/Completion/Zsh/Type/_file_descriptors +++ b/Completion/Zsh/Type/_file_descriptors @@ -7,9 +7,9 @@ for i in {0..9}; [[ -e /dev/fd/$i ]] && fds+=( $i ) if zstyle -T ":completion:${curcontext}:" verbose && [[ -e /proc/$$/fd ]]; then zstyle -s ":completion:${curcontext}:" list-separator sep || sep=-- - if zmodload -e zsh/stat; then + if zmodload -F zsh/stat zstat; then for i in "${fds[@]}"; do - stat +link -A link /proc/$$/fd/$i + zstat +link -A link /proc/$$/fd/$i list+=( "$i $sep ${link[1]}" ) done elif (( $+commands[readlink] )); then diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 0f90bca6d..cd655c146 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1845,6 +1845,7 @@ findex(zmodload) cindex(modules, loading) cindex(loading modules) xitem(tt(zmodload) [ tt(-dL) ] [ ... ]) +xitem(tt(zmodload -F) [ tt(-lLe) tt(-P) tt(param) ] var(module) [tt(PLUS()-)]var(feature...)) xitem(tt(zmodload -e) [ tt(-A) ] [ ... ]) xitem(tt(zmodload) [ tt(-a) [ tt(-bcpf) [ tt(-I) ] ] ] [ tt(-iL) ] ...) xitem(tt(zmodload) tt(-u) [ tt(-abcdpf) [ tt(-I) ] ] [ tt(-iL) ] ...) @@ -1867,21 +1868,24 @@ item(tt(zmodload) tt(-u) [ tt(-i) ] var(name) ...)( In the simplest case, tt(zmodload) loads a binary module. The module must be in a file with a name consisting of the specified var(name) followed by a standard suffix, usually `tt(.so)' (`tt(.sl)' on HPUX). -If the module to be loaded is -already loaded and the tt(-i) option is given, the duplicate module is -ignored. Otherwise tt(zmodload) prints an error message and returns -a non-zero status. If tt(zmodload) detects an inconsistency, such as an +If the module to be loaded is already loaded the duplicate module is +ignored. If tt(zmodload) detects an inconsistency, such as an invalid module name or circular dependency list, the current code block is -aborted. Hence `tt(zmodload -i) var(module) tt(2>/dev/null)' is sufficient +aborted. Hence `tt(zmodload) var(module) tt(2>/dev/null)' is sufficient to test whether a module is available. If it is available, the module is loaded if necessary, while if it -is not available, non-zero status is silently returned. +is not available, non-zero status is silently returned. The option +tt(-i) is accepted for compatibility but has no effect. The var(name)d module is searched for in the same way a command is, using tt($module_path) instead of tt($path). However, the path search is performed even when the module name contains a `tt(/)', which it usually does. There is no way to prevent the path search. +If the module supports features (see below), tt(zmodload) tries to +enable all features when loading a module. If the module was successfully +loaded but not all features could be enabled, tt(zmodload) returns status 2. + With tt(-u), tt(zmodload) unloads modules. The same var(name) must be given that was given when the module was loaded, but it is not necessary for the module to exist in the filesystem. @@ -1892,6 +1896,54 @@ Each module has a boot and a cleanup function. The module will not be loaded if its boot function fails. Similarly a module can only be unloaded if its cleanup function runs successfully. ) +item(tt(zmodload -F) [ tt(-lLe) tt(-P) tt(param) ] var(module) [tt(PLUS()-)]var(feature...))( +tt(zmodload -F) allows more selective control over the features provided +by modules. With no options apart from tt(-F), the module named +var(module) is loaded, if it was not already loaded, and the list of +var(feature)s is set to the required state. If no +var(feature)s are specified, the module is loaded, if it was not already +loaded, but the state of features is unchanged. Each feature +may be preceded by a tt(PLUS()) to turn the feature on, or tt(-) to turn it +off; the tt(PLUS()) is assumed if neither character is present. +Any feature not explicitly mentioned is left in its current state; +if the module was not previously loaded this means any such features will +remain disabled. The return status is zero if all features were +set, 1 if the module failed to load, and 2 if some features could +not be set (for example, a parameter couldn't be added because there +was a different parameter of the same name) but the module was loaded. + +The standard features are builtins, conditions, parameters and math +functions; these are indicated by the prefix `tt(b:)', `tt(c:)', `tt(p:)' +and `tt(f:)', respectively, followed by the name that the corresponding +feature would have in the shell. For example, `tt(b:strftime)' indicates +a builtin named tt(strftime) and tt(p:EPOCHSECONDS) indicates a parameter +named tt(EPOCHSECONDS). The module may provide other (`abstract') features +of its own as indicated by its documentation; these have no prefix. + +With tt(-l) or tt(-L), features provided by the module are listed. With +tt(-l) alone, a list of features together with their states is shown, one +feature per line. With tt(-L) alone, a tt(zmodload -F) command that would +cause enabled features of the module to be turned on is shown. With +tt(-lL), a tt(zmodload -F) command that would cause all the features to be +set to their current state is shown. If one of these combinations is given +the option tt(-P) var(param) then the parameter tt(param) is set to an +array of features, either features together with their state or (if +tt(-L) alone is given) enabled features. + +A set of features may be provided together with tt(-l) or tt(-L); in +that case only the state of features provided is considered. Each +feature may be preceded by tt(PLUS()) or tt(-) but the character +has no effect. If no set of features is provided, all features +are considered. + +With tt(-e), the command first tests that the module is loaded; +if it is not, status 1 is returned. If the module is loaded, +the list of features given as an argument is examined. Any feature +given with no prefix is simply tested to see if the module provides it; +any feature given with a prefix tt(PLUS()) or tt(-) is tested to +see if is provided and in the given state. If the tests on all features +in the list succeed, status 0 is returned, else status 1. +) xitem(tt(zmodload) tt(-d) [ tt(-L) ] [ var(name) ]) xitem(tt(zmodload) tt(-d) var(name) var(dep) ...) item(tt(zmodload) tt(-ud) var(name) [ var(dep) ... ])( diff --git a/Doc/Zsh/compsys.yo b/Doc/Zsh/compsys.yo index 48df05471..963e43c96 100644 --- a/Doc/Zsh/compsys.yo +++ b/Doc/Zsh/compsys.yo @@ -1268,13 +1268,6 @@ If this is set to `true', the tt(_expand_alias) completer and bindable command will try to expand disabled aliases, too. The default is `tt(false)'. ) -kindex(disable-stat, completion style) -item(tt(disable-stat))( -This is used with an empty tag by the tt(_cvs) function -to decide whether the tt(zsh/stat) module should be used to -generate names of modified files in the appropriate places (this is its -only use). If the style is set, completion will use the tt(ls) command. -) kindex(domains, completion style) item(tt(domains))( A list of names of network domains for completion. diff --git a/Doc/Zsh/mod_stat.yo b/Doc/Zsh/mod_stat.yo index 0354196ad..e0fc15abd 100644 --- a/Doc/Zsh/mod_stat.yo +++ b/Doc/Zsh/mod_stat.yo @@ -1,17 +1,24 @@ COMMENT(!MOD!zsh/stat A builtin command interface to the tt(stat) system call. !MOD!) -The tt(zsh/stat) module makes available one builtin command: +The tt(zsh/stat) module makes available one builtin command under +two possible names: startitem() findex(stat) cindex(files, listing) cindex(files, examining) -item(tt(stat) [ tt(-gnNolLtTrs) ] [ tt(-f) var(fd) ] \ +xitem(tt(zstat) [ tt(-gnNolLtTrs) ] [ tt(-f) var(fd) ] \ [ tt(-H) var(hash) ] [ tt(-A) var(array) ] \ - [ tt(-F) var(fmt) ] [ tt(PLUS())var(element) ] [ var(file) ... ])( + [ tt(-F) var(fmt) ] [ tt(PLUS())var(element) ] [ var(file) ... ]) +itme(tt(stat) var(...))( The command acts as a front end to the tt(stat) system call (see -manref(stat)(2)). +manref(stat)(2)). The same command is provided with two names; as +the name tt(stat) is often used by an external command it is recommended +that only the tt(zstat) form of the command is used. This can be +arranged by loading the module with the command `tt(zmodload -F zsh/stat +zstat)'. + If the tt(stat) call fails, the appropriate system error message printed and status 1 is returned. The fields of tt(struct stat) give information about @@ -69,7 +76,7 @@ The number of disk blocks used by the file. item(tt(link))( If the file is a link and the tt(-L) option is in effect, this contains the name of the file linked to, otherwise -it is empty. Note that if this element is selected (``tt(stat PLUS()link)'') +it is empty. Note that if this element is selected (``tt(zstat PLUS()link)'') then the tt(-L) option is automatically used. ) enditem() diff --git a/Etc/zsh-development-guide b/Etc/zsh-development-guide index 4797f0d02..6e29ed842 100644 --- a/Etc/zsh-development-guide +++ b/Etc/zsh-development-guide @@ -213,25 +213,146 @@ following shell variables: Be sure to put the values in quotes. For further enlightenment have a look at the `mkmakemod.sh' script in the Src directory of the distribution. -Modules have to define four functions which will be called automatically +Modules have to define six functions which will be called automatically by the zsh core. The first one, named `setup_', should set up any data needed in the module, at least any data other modules may be interested -in. The second one, named `boot_', should register all builtins, -conditional codes, and function wrappers (i.e. anything that will be -visible to the user) and will be called after the `setup_'-function. - -The third one, named `cleanup_', is called when the user tries to unload -a module and should de-register the builtins etc. The last function, -`finish_' is called when the module is actually unloaded and should -finalize all the data initialized in the `setup_'-function. - -In short, the `cleanup_'-function should undo what the `boot_'-function -did, and the `finish_'-function should undo what the `setup_'-function -did. +in. + +The next pair are features_ and enables_ and deal with enabling module +features. Ensure you are familiar with the description of features under +`zmodload -F'. The function features_ takes an argument `char +***featuresp'; *featuresp is to be set to a NULL-terminated array +containing a list of all the features. It should then return zero. +It may return one to indicate features are not supported, but this is +not recommended. The function featuresarray conveniently interrogates +the module's feature strctures for all standard features; space +is left for abstract features at the end of the array and the names +must be added by the module. Note that heap memory should +be used for this (zhalloc, etc.) as memory for the features array is not +freed. + +A structure "struct features" should +be used to contain all standard features as well as the number of +abstract features (those only understood by the module itself). +It contains pointers to all builtins, conditions, parameters and +conditions controlled by the module. + +enables_ takes an argument `int **enablesp'. If *enablesp is NULL, it +should be set to an array of the same length as *featuresp without the +NULL, containing a 1 for every feature that is enabled and a zero for other +feature. By default features are disabled. If *enablesp is not NULL, its +values should be used to decide whether features are to be turned off. It +should return status 0 for success, 1 on a failure to alter a feature. +The function handlefeatures() conveniently handles all standard features +present in the module's features structure; abstract features must +be handled by the module. As with features_, any handling of the +array by the module itself should take into account that the array +will not be freed and any allocation should therefore be from heap memory. + +The functions features_ and enables_ can be called at any point +after setup_ has been called and before cleanup_ is called. In +particular they can be called before or after boot_. + +The function named `boot_' should register function wrappers, hooks and +anything that will be visible to the user that is not handled by features_ +and enables_ (so features should not be turned on here). It will be called +after the `setup_'-function, and also after the intial set of features +have been set by calls to features_ and enables_. + +The function named `cleanup_', is called when the user tries to unload +a module and should de-register all features and hooks. A call +to setfeatures with the final argument NULL will remove all standard +features present in the module's features structure. + +The last function, `finish_' is called when the module is actually unloaded +and should finalize all the data initialized in the `setup_'-function. + +In short, the `cleanup_'-function should undo what the `boot_'-function did +(together with handling any residual effects of enables_), and the +`finish_'-function should undo what the `setup_'-function did. All of these functions should return zero if they succeeded and non-zero otherwise. +Features +======== + +Builtins, conditions, parameters (variables) and math functions +are described as "features". They should be made available to +the shell by declaring a `struct feature' for each module. +Below are descriptions of the individual features; first here +is generic information. + +`struct feature' contains a pointer to the array that declares each +feature, followed by the number of entries in the array. The pointer +can be NULL and the the size zero for any feature that is not present in +the module. For example, to register only builtins in zsh and thereby +make them visible to the user, the structure should contain +"bintab" where the array is declared as an array of struct builtin, +as discussed below: + + static struct feature module_features = { + bintab, sizeof(bintab)/sizeof(*bintab), + NULL, 0, /* declare any conditions here */ + NULL, 0, /* declare any parameters here */ + NULL, 0, /* declare any math functions here */ + 0, /* number of abstract features */ + } + +Abstract features are handled by the module; the number present +in `struct features' is there to ensure the main shell allocated +space in the features and enables array in the standard +featuresarray() and handlefeatures() calls. However, the inserting +of names in the features array and the getting and setting of +feature enables is left entirely to the module. Note that abstract +features should not contain a colon (to avoid clashes with the +prefixes used in standard features). It is recommended that +only alphanumerics, - and _ be used in the names of abstract +features, and - not be the first character (to avoid confusion +with disabling features) but this is not required by the main shell. + +The features_ and enables_ functions for such a module will look +like: + + /**/ + int + features_example(Module m, char ***features) + { + *features = featuresarray(m->nam, &module_features); + /* fill in any abstract features in (*features) here */ + return 0; + } + + /**/ + int + enables_example(Module m, int **enables) + { + int ret; + + ret = handlefeatures(m->nam, &module_features, enables); + /* handle any abstract features here */ + ... + return ret; + } + +The functions shown take the name of the module, the set of features, + + +To de-register builtins, pass the features structure to +setfeatureenables with a NULL final value: + + /**/ + int + cleanup_example(Module m) + { + setfeatureenables(m->nam, &module_features, NULL); + ... + } + + +Builtins +-------- + Builtins are described in a table, for example: static struct builtin bintab[] = { @@ -280,37 +401,8 @@ integer value from the table (the sixth argument to `BUILTIN(...)'). The integer return value by the function is the value returned by the builtin in shell level. -To register builtins in zsh and thereby making them visible to the -user the function `addbuiltins()' is used: - - /**/ - int - boot_example(Module m) - { - int ret; - - ret = addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - ... - } - -The arguments are the name of the module (taken from the argument in -the example), the table of definitions and the number of entries in -this table. -The return value is 1 if everything went fine, 2 if at least one -builtin couldn't be defined, and 0 if none of the builtin could be -defined. - -To de-register builtins use the function `deletebuiltins()': - - /**/ - int - cleanup_example(Module m) - { - deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); - ... - } - -The arguments and the return value are the same as for `addbuiltins()' +Conditions +---------- The definition of condition codes in modules is equally simple. First we need a table with the descriptions: @@ -374,30 +466,8 @@ tokenized. There are three helper functions available: function is non-zero if the the num'th string from the array taken as a glob pattern matches the given string. -Registering and de-registering condition codes with the shell is -almost exactly the same as for builtins, using the functions -`addconddefs()' and `deleteconddefs()' instead: - - /**/ - int - boot_example(Module m) - { - int ret; - - ret = addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); - ... - } - - /**/ - int - cleanup_example(Module m) - { - deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)); - ... - } - -Arguments and return values are the same as for the functions for -builtins. +Parameters +---------- For defining parameters, a module can call `createparam()' directly or use a table to describe them, e.g.: @@ -443,33 +513,12 @@ initialized to either `NULL' or to a a piece of memory created with finish-function of the module because that will be taken care of by the `deleteparamdefs()' function described below. -To register the parameters in the zsh core, the function -`addparamdefs()' is called as in: - - /**/ - int - boot_example(Module m) - { - int ret; - - ret = addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) - ... - } - -The arguments and the return value are as for the functions used to -add builtins and condition codes and like these, it should be called -in the boot-function of the module. To remove the parameters defined, -the function `deleteparamdefs()' should be called, again with the same -arguments and the same return value as for the functions to remove -builtins and condition codes: +It is also possible to declare special parameters using +the macro SPECIALPMDEF(). More care is required in this case. +See, for example, many of the definitios in Src/Modules/parameter.c. - /**/ - int - cleanup_example(Module m) - { - deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)); - ... - } +Math functions +-------------- Modules can also define math functions. Again, they are described using a table: @@ -531,33 +580,13 @@ union looking like: The `type' field should be set to `MN_INTEGER' or `MN_FLOAT' and depending on its value either `u.l' or `u.d' contains the value. -To register and de-register math functions, the functions -`addmathfuncs()' and `deletemathfuncs()' are used: - - /**/ - int - boot_example(Module m) - { - int ret; - - ret = addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); - ... - } - - /**/ - int - cleanup_example(Module m) - { - deletemathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); - ... - } - -The arguments and return values are as for the functions used to -register and de-register parameters, conditions, etc. +Hooks +----- Modules can also define function hooks. Other modules can then add functions to these hooks to make the first module call these functions -instead of the default. +instead of the default. These are not handled by the features +mechanism as they are not directly visible to the user. Again, an array is used to define hooks: @@ -629,8 +658,13 @@ that are changed or called very often. These functions, structure defining the hook instead of the name and otherwise behave like their counterparts. -Finally, modules can define wrapper functions. These functions are -called whenever a shell function is to be executed. +Wrappers +-------- + +Finally, modules can define wrapper functions. These functions are +called whenever a shell function is to be executed. Again, they +are not handled by the features mechanism as they are not visible +to the user. The definition is simple: 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)) @@ -898,16 +906,31 @@ setup_(UNUSED(Module m)) /**/ 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)) @@ -342,10 +350,23 @@ setup_(UNUSED(Module m)) /**/ 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,21 +139,35 @@ 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)) { return 0; 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,21 +126,35 @@ 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)) { return 0; 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,30 +175,35 @@ 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)) { return 0; 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)) @@ -195,6 +203,21 @@ setup_(UNUSED(Module m)) /**/ 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) { intparam = 42; @@ -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)) @@ -715,17 +723,31 @@ setup_(UNUSED(Module m)) /**/ 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 <langinfo.h> #endif -static Param langinfo_pm; - /**/ #ifdef HAVE_NL_LANGINFO @@ -396,46 +392,6 @@ liitem(char *name) } /**/ -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,35 +474,35 @@ 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)) { return 0; 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)) @@ -570,17 +578,31 @@ setup_(UNUSED(Module m)) /**/ 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,149 +1834,117 @@ 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)) { return 0; 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)) @@ -304,25 +317,31 @@ setup_(UNUSED(Module m)) /**/ 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)) @@ -140,17 +150,31 @@ setup_(UNUSED(Module m)) /**/ 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 }; /**/ @@ -632,17 +641,31 @@ setup_(UNUSED(Module m)) /**/ 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 */ /**/ @@ -686,10 +694,25 @@ setup_(UNUSED(Module m)) /**/ 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,62 +158,11 @@ 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)) @@ -376,36 +342,36 @@ setup_(UNUSED(Module m)) /**/ 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) { #ifdef HAVE_TGETENT # 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 <term.h> # endif -static Param terminfo_pm; - /* echoti: output a terminfo capability */ /**/ @@ -126,64 +123,11 @@ 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)) @@ -351,6 +316,21 @@ setup_(UNUSED(Module m)) /**/ 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) { #ifdef USE_TERMINFO_MODULE @@ -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) @@ -305,6 +313,21 @@ setup_(Module m) /**/ 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) { calls = NULL; @@ -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)) @@ -738,12 +748,27 @@ setup_(UNUSED(Module m)) /**/ 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) { 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 @@ -1752,17 +1759,31 @@ setup_(UNUSED(Module m)) /**/ 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)) @@ -3964,11 +3972,26 @@ setup_(UNUSED(Module m)) /**/ 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)) @@ -1492,6 +1500,21 @@ setup_(UNUSED(Module m)) /**/ 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("complete", (Hookfn) do_completion); @@ -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)) @@ -3228,6 +3236,21 @@ setup_(UNUSED(Module m)) /**/ 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) { mtab = NULL; @@ -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 @@ -4584,17 +4592,31 @@ setup_(UNUSED(Module m)) /**/ 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)) @@ -83,6 +93,21 @@ setup_(UNUSED(Module m)) /**/ 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) { w_deletetochar = addzlefunction("delete-to-char", deltochar, @@ -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)) @@ -1817,11 +1825,25 @@ setup_(UNUSED(Module m)) /**/ 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,48 +151,35 @@ 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)) { return 0; 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 * @@ -49,6 +63,24 @@ setup_(UNUSED(Module m)) /**/ int +features_(UNUSED(Module m), UNUSED(char ***features)) +{ + /* + * There are lots and lots of features, but they're not + * handled here. + */ + return 1; +} + +/**/ +int +enables_(UNUSED(Module m), UNUSED(int **enables)) +{ + return 1; +} + +/**/ +int boot_(UNUSED(Module m)) { return 0; @@ -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,104 +330,713 @@ addwrapper(Module m, FuncWrap w) return 0; } -/* $module_path ($MODULE_PATH) */ +/* This removes the given wrapper definition from the list. Returned is * + * one in case of error and zero otherwise. */ /**/ -char **module_path; +mod_export int +deletewrapper(Module m, FuncWrap w) +{ + FuncWrap p, q; -/* List of modules */ + if (m->flags & MOD_ALIAS) + return 1; + + if (w->flags & WRAPF_ADDED) { + for (p = wrappers, q = NULL; p && p != w; q = p, p = p->next); + + if (p) { + if (q) + q->next = p->next; + else + wrappers = p->next; + p->flags &= ~WRAPF_ADDED; + + return 0; + } + } + return 1; +} + + +/************************************************************************ + * Conditions. + ************************************************************************/ + +/* The list of module-defined conditions. */ /**/ -mod_export LinkList modules; +mod_export Conddef condtab; -/* 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. */ +/* This gets a condition definition with the given name. The first * + * argument says if we have to look for an infix condition. The last * + * argument is non-zero if we should autoload modules if needed. */ + +/**/ +Conddef +getconddef(int inf, char *name, int autol) +{ + Conddef p; + int f = 1; + + 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) { + (void)load_module_silence(p->module, NULL, 0); + f = 0; + p = NULL; + } else { + deleteconddef(p); + return NULL; + } + } else + break; + } while (!p); + return p; +} + +/* + * This adds the given condition definition. The return value is zero on * + * success and 1 on failure. If there is a matching definition for an * + * autoloaded condition, it is removed. + * + * This is used for adding both an autoload definition or + * a real condition. In the latter case the caller is responsible + * for setting the CONDF_ADDED flag. + */ + +/**/ +static int +addconddef(Conddef c) +{ + Conddef p = getconddef((c->flags & CONDF_INFIX), c->name, 0); + + if (p) { + if (!p->module || (p->flags & CONDF_ADDED)) + return 1; + /* There is an autoload definition. */ + + deleteconddef(p); + } + c->next = condtab; + condtab = c; + return 0; +} + +/* This removes the given condition definition from the list(s). If this * + * is a definition for a autoloaded condition, the memory is freed. */ /**/ int -add_autobin(char *nam, char *module) +deleteconddef(Conddef c) { - Builtin bn = zshcalloc(sizeof(*bn)); - bn->node.nam = ztrdup(nam); - bn->optstr = ztrdup(module); - return addbuiltin(bn); + Conddef p, q; + + for (p = condtab, q = NULL; p && p != c; q = p, p = p->next); + + if (p) { + if (q) + q->next = p->next; + else + condtab = p->next; + + if (p->module) { + /* autoloaded, free it */ + zsfree(p->name); + zsfree(p->module); + zfree(p, sizeof(*p)); + } + return 0; + } + return -1; } -/* Remove the builtin added previously by addbuiltin(). Returns * - * zero on succes and -1 if there is no builtin with that name. */ +/**/ +mod_export int +setconddefs(char const *nam, Conddef c, int size, int *e) +{ + int hads = 0, hadf = 0; + + while (size--) { + if (e && *e++) { + if (c->flags & CONDF_ADDED) { + c++; + continue; + } + if (addconddef(c)) { + zwarnnam(nam, "name clash when adding condition `%s'", + c->name); + 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 hadf ? hads : 1; +} + +/* This adds a definition for autoloading a module for a condition. */ /**/ int -deletebuiltin(char *nam) +add_autocond(char *nam, int inf, char *module) { - Builtin bn; + Conddef c = (Conddef) zalloc(sizeof(*c)); - bn = (Builtin) builtintab->removenode(builtintab, nam); - if (!bn) - return -1; - builtintab->freenode(&bn->node); + 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; } -/* 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. */ + +/************************************************************************ + * Hook functions. + ************************************************************************/ + +/* This list of hook functions defined. */ + +/**/ +Hookdef hooktab; + +/* Find a hook definition given the name. */ + +/**/ +Hookdef +gethookdef(char *n) +{ + Hookdef p; + + for (p = hooktab; p; p = p->next) + if (!strcmp(n, p->name)) + return p; + return NULL; +} + +/* This adds the given hook definition. The return value is zero on * + * success and 1 on failure. */ + +/**/ +int +addhookdef(Hookdef h) +{ + if (gethookdef(h->name)) + return 1; + + h->next = hooktab; + hooktab = h; + h->funcs = znewlinklist(); + + return 0; +} + +/* This adds multiple hook definitions. This is like addbuiltins(). */ /**/ mod_export int -deletebuiltins(char const *nam, Builtin binl, int size) +addhookdefs(char const *nam, Hookdef h, int size) { - int hads = 0, hadf = 0, n; + int hads = 0, hadf = 0; - 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); + while (size--) { + if (addhookdef(h)) { + zwarnnam(nam, "name clash when adding hook `%s'", h->name); hadf = 1; } else hads = 2; - b->node.flags &= ~BINF_ADDED; + h++; } return hadf ? hads : 1; } -/* This removes the given wrapper definition from the list. Returned is * - * one in case of error and zero otherwise. */ +/* Delete hook definitions. */ /**/ -mod_export int -deletewrapper(Module m, FuncWrap w) +int +deletehookdef(Hookdef h) { - FuncWrap p, q; + Hookdef p, q; - if (m->flags & MOD_ALIAS) + for (p = hooktab, q = NULL; p && p != h; q = p, p = p->next); + + if (!p) return 1; - if (w->flags & WRAPF_ADDED) { - for (p = wrappers, q = NULL; p && p != w; q = p, p = p->next); + if (q) + q->next = p->next; + else + hooktab = p->next; + freelinklist(p->funcs, NULL); + return 0; +} - if (p) { - if (q) - q->next = p->next; - else - wrappers = p->next; - p->flags &= ~WRAPF_ADDED; +/**/ +mod_export int +deletehookdefs(UNUSED(char const *nam), Hookdef h, int size) +{ + while (size--) { + deletehookdef(h); + h++; + } + 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) +{ + Hookdef h = gethookdef(n); + + if (h) + return addhookdeffunc(h, f); + return 1; +} + +/* Delete a function from a hook. */ + +/**/ +int +deletehookdeffunc(Hookdef h, Hookfn f) +{ + LinkNode p; + + for (p = firstnode(h->funcs); p; incnode(p)) + if (f == (Hookfn) getdata(p)) { + remnode(h->funcs, p); return 0; } - } return 1; } /**/ +mod_export int +deletehookfunc(char *n, Hookfn f) +{ + Hookdef h = gethookdef(n); + + if (h) + return deletehookdeffunc(h, f); + return 1; +} + +/* Run the function(s) for a hook. */ + +/**/ +mod_export int +runhookdef(Hookdef h, void *d) +{ + if (empty(h->funcs)) { + if (h->def) + return h->def(h, d); + return 0; + } else if (h->flags & HOOKF_ALL) { + LinkNode p; + int r; + + for (p = firstnode(h->funcs); p; incnode(p)) + if ((r = ((Hookfn) getdata(p))(h, d))) + return r; + if (h->def) + return h->def(h, d); + return 0; + } else + return ((Hookfn) getdata(lastnode(h->funcs)))(h, d); +} + +/**/ +int +runhook(char *n, void *d) +{ + Hookdef h = gethookdef(n); + + if (h) + return runhookdef(h, d); + return 0; +} + + +/************************************************************************ + * Shell parameters. + ************************************************************************/ + +static int +checkaddparam(char *nam) +{ + Param pm; + + 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; + } + + unsetparam_pm(pm, 0, 1); + return 0; +} + +/* This adds the given parameter definition. The return value is zero on * + * success and 1 on failure. */ + +/**/ +int +addparamdef(Paramdef d) +{ + Param pm; + + if (checkaddparam(d->name)) + 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. */ + +/**/ +int +deleteparamdef(Paramdef d) +{ + Param pm = (Param) paramtab->getnode(paramtab, d->name); + + if (!pm) + return 1; + if (pm != d->pm) { + /* + * See if the parameter has been hidden. If so, + * bring it to the front to unset it. + */ + Param prevpm, searchpm; + for (prevpm = pm, searchpm = pm->old; + searchpm; + prevpm = searchpm, searchpm = searchpm->old) + if (searchpm == d->pm) + break; + + if (!searchpm) + return 1; + + paramtab->removenode(paramtab, pm->node.nam); + prevpm->old = searchpm->old; + searchpm->old = pm; + paramtab->addnode(paramtab, searchpm->node.nam, searchpm); + + pm = searchpm; + } + pm->node.flags = (pm->node.flags & ~PM_READONLY) | PM_REMOVABLE; + unsetparam_pm(pm, 0, 1); + d->pm = NULL; + return 0; +} + +/**/ +mod_export int +setparamdefs(char const *nam, Paramdef d, int size, int *e) +{ + 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; +} + +/* This adds a definition for autoloading a module for a parameter. */ + +/**/ +void +add_autoparam(char *nam, char *module) +{ + 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. */ + +/**/ +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) +{ + 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); + + (void)load_module_silence(n, NULL, 0); + + return getmathfunc(name, 0); + } + return p; + } + + return NULL; +} + +/**/ +static int +addmathfunc(MathFunc f) +{ + MathFunc p, q = NULL; + + if (f->flags & MFF_ADDED) + return 1; + + for (p = mathfuncs; p; q = p, p = p->next) + if (!strcmp(f->name, p->name)) { + if (p->module && !(p->flags & MFF_USERFUNC)) { + /* + * Autoloadable, replace. + */ + removemathfunc(q, p); + break; + } + return 1; + } + + f->next = mathfuncs; + mathfuncs = f; + + return 0; +} + +/**/ +mod_export int +deletemathfunc(MathFunc f) +{ + MathFunc p, q; + + for (p = mathfuncs, q = NULL; p && p != f; q = p, p = p->next); + + if (p) { + if (q) + q->next = f->next; + else + mathfuncs = f->next; + + /* the following applies to both unloaded and user-defined functions */ + if (f->module) { + zsfree(f->name); + zsfree(f->module); + zfree(f, sizeof(*f)); + } else + f->flags &= ~MFF_ADDED; + + return 0; + } + return -1; +} + +/**/ +mod_export int +setmathfuncs(char const *nam, MathFunc f, int size, int *e) +{ + int hads = 0, hadf = 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; + } + } + f++; + } + return hadf ? hads : 1; +} + +/**/ +int +add_automathfunc(char *nam, char *module) +{ + 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)); + + return 1; + } + + return 0; +} + + +/************************************************************************ + * Now support for dynamical loading and the fallback functions + * we use for loading if dynamical loading is not available. + ************************************************************************/ + +/**/ #ifdef DYNAMIC /**/ @@ -392,11 +1123,15 @@ hpux_dlsym(void *handle, char *name) #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_" @@ -542,38 +1277,52 @@ module_loaded(const char *name) static int dyn_setup_module(Module m) { - return ((int (*)_((int,Module))) m->u.handle)(0, 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 +dyn_enables_module(Module m, int **enables) +{ + return ((int (*)_((int,Module))) m->u.handle)(5, m, enables); } /**/ static int dyn_boot_module(Module m) { - return ((int (*)_((int,Module))) m->u.handle)(1, m); + return ((int (*)_((int,Module))) m->u.handle)(1, m, NULL); } /**/ static int dyn_cleanup_module(Module m) { - return ((int (*)_((int,Module))) m->u.handle)(2, m); + return ((int (*)_((int,Module))) m->u.handle)(2, m, NULL); } /**/ static int dyn_finish_module(Module m) { - return ((int (*)_((int,Module))) m->u.handle)(3, m); + return ((int (*)_((int,Module))) m->u.handle)(3, m, NULL); } /**/ #else -static Module_func +static Module_generic_func module_func(Module m, char *name) { #ifdef DYNAMIC_NAME_CLASH_OK - return (Module_func) dlsym(m->u.handle, name); + 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; @@ -594,7 +1343,7 @@ module_func(Module m, char *name) *q++ = *p; } *q = 0; - return (Module_func) dlsym(m->u.handle, buf); + return (Module_generic_func) dlsym(m->u.handle, buf); #endif /* !DYNAMIC_NAME_CLASH_OK */ } @@ -602,7 +1351,7 @@ module_func(Module m, char *name) static int dyn_setup_module(Module m) { - Module_func fn = module_func(m, STR_SETUP); + Module_void_func fn = (Module_void_func)module_func(m, STR_SETUP); if (fn) return fn(m); @@ -612,9 +1361,34 @@ dyn_setup_module(Module m) /**/ static int +dyn_features_module(Module m, char ***features) +{ + Module_features_func fn = + (Module_features_func)module_func(m, STR_FEATURES); + + if (fn) + return fn(m, features); + /* not a user-visible error if no features function */ + return 1; +} + +/**/ +static int +dyn_enables_module(Module m, int **enables) +{ + Module_enables_func fn = (Module_enables_func)module_func(m, STR_ENABLES); + + if (fn) + return fn(m, enables); + /* not a user-visible error if no enables function */ + return 1; +} + +/**/ +static int dyn_boot_module(Module m) { - Module_func fn = module_func(m, STR_BOOT); + Module_void_func fn = (Module_void_func)module_func(m, STR_BOOT); if(fn) return fn(m); @@ -626,7 +1400,7 @@ dyn_boot_module(Module m) static int dyn_cleanup_module(Module m) { - Module_func fn = module_func(m, STR_CLEANUP); + Module_void_func fn = (Module_void_func)module_func(m, STR_CLEANUP); if(fn) return fn(m); @@ -641,7 +1415,7 @@ dyn_cleanup_module(Module m) static int dyn_finish_module(Module m) { - Module_func fn = module_func(m, STR_FINISH); + Module_void_func fn = (Module_void_func)module_func(m, STR_FINISH); int r; if (fn) @@ -667,6 +1441,24 @@ setup_module(Module m) /**/ static int +features_module(Module m, char ***features) +{ + return ((m->flags & MOD_LINKED) ? + (m->u.linked->features)(m, features) : + dyn_features_module(m, features)); +} + +/**/ +static int +enables_module(Module m, int **enables) +{ + return ((m->flags & MOD_LINKED) ? + (m->u.linked->enables)(m, enables) : + dyn_enables_module(m, enables)); +} + +/**/ +static int boot_module(Module m) { return ((m->flags & MOD_LINKED) ? @@ -701,6 +1493,22 @@ setup_module(Module m) /**/ static int +features_module(Module m, char ***features) +{ + return ((m->flags & MOD_LINKED) ? (m->u.linked->features)(m, features) + : 1); +} + +/**/ +static int +enables_module(Module m, int **enables) +{ + return ((m->flags & MOD_LINKED) ? (m->u.linked->enables)(m, enables) + : 1); +} + +/**/ +static int boot_module(Module m) { return ((m->flags & MOD_LINKED) ? (m->u.linked->boot)(m) : 1); @@ -723,6 +1531,125 @@ finish_module(Module m) /**/ #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 +do_module_features(Module m, char **enablesstr, int silent) +{ + 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; + } + + 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; + } + + 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; +} + +/* + * Boot the module, including setting up features. + * As we've only just loaded the module, we don't yet + * know what features it supports, so we get them passed + * as a string. + * + * Returns 0 if OK, 1 if completely failed, 2 if some features + * couldn't be set up. + */ + +/**/ +static int +do_boot_module(Module m, char **enablesstr, int silent) +{ + int ret = do_module_features(m, enablesstr, silent); + + if (ret == 1) + return 1; + + if (boot_module(m)) + return 1; + return ret; +} + +/* + * Cleanup the module. + */ + +/**/ +static int +do_cleanup_module(Module m) +{ + return (m->flags & MOD_LINKED) ? + (m->u.linked && m->u.linked->cleanup(m)) : + (m->u.handle && cleanup_module(m)); +} + /**/ static int modname_ok(char const *p) @@ -735,27 +1662,37 @@ modname_ok(char const *p) return 0; } +/* + * Now returns 0 for success (changed post-4.3.4), + * 1 for complete failure, 2 if some features couldn't be set. + */ + /**/ mod_export int -load_module(char const *name) +load_module(char const *name, char **enablesstr) { - return load_module_silence(name, 0); + return load_module_silence(name, enablesstr, 0); } +/* + * Returns 0 for success (changed post-4.3.4), 1 for complete + * failure, 2 if some features couldn't be set. + */ + /**/ mod_export int -load_module_silence(char const *name, int silent) +load_module_silence(char const *name, char **enablesstr, int silent) { Module m; void *handle = NULL; Linkedmod linked; LinkNode node, n; - int set; + int set, bootret; if (!modname_ok(name)) { if (!silent) zerr("invalid module name `%s'", name); - return 0; + return 1; } /* * The following function call may alter name to the final name in a @@ -767,7 +1704,7 @@ load_module_silence(char const *name, int silent) if (!(linked = module_linked(name)) && !(handle = do_load_module(name, silent))) { unqueue_signals(); - return 0; + return 1; } m = zshcalloc(sizeof(*m)); m->nam = ztrdup(name); @@ -780,40 +1717,47 @@ load_module_silence(char const *name, int silent) } node = zaddlinknode(modules, m); - if ((set = setup_module(m)) || boot_module(m)) { - if (!set) + 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 0; + return 1; } m->flags |= MOD_INIT_S | MOD_INIT_B; m->flags &= ~MOD_SETUP; unqueue_signals(); - return 1; - } + return bootret; + } m = (Module) getdata(node); if (m->flags & MOD_SETUP) { unqueue_signals(); - return 1; + 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 1; + return 0; } if (m->flags & MOD_BUSY) { zerr("circular dependencies for module %s", name); - return 0; + 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), silent)) { + if (load_module_silence((char *) getdata(n), NULL, silent) == 1) { m->flags &= ~MOD_BUSY; unqueue_signals(); - return 0; + return 1; } m->flags &= ~MOD_BUSY; if (!m->u.handle) { @@ -821,7 +1765,7 @@ load_module_silence(char const *name, int silent) if (!(linked = module_linked(name)) && !(handle = do_load_module(name, silent))) { unqueue_signals(); - return 0; + return 1; } if (handle) { m->u.handle = handle; @@ -837,12 +1781,13 @@ load_module_silence(char const *name, int silent) m->u.linked = NULL; m->flags &= ~MOD_SETUP; unqueue_signals(); - return 0; + return 1; } m->flags |= MOD_INIT_S; } m->flags |= MOD_SETUP; - if (boot_module(m)) { + 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; @@ -850,42 +1795,44 @@ load_module_silence(char const *name, int silent) m->u.handle = NULL; m->flags &= ~MOD_SETUP; unqueue_signals(); - return 0; + return 1; } m->flags |= MOD_INIT_B; m->flags &= ~MOD_SETUP; unqueue_signals(); - return 1; + return bootret; } /* 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. */ + * 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. + */ /**/ mod_export int -require_module(char *nam, const char *module, UNUSED(int res), int test) +require_module(char *nam, const char *module, char **features) { Module m = NULL; LinkNode node; - int ret = 1; + 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)) { - if (test) { - unqueue_signals(); - zwarnnam(nam, "module %s already loaded.", module); - return 0; - } - } else - ret = load_module_silence(module, 0); + 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(); return ret; @@ -953,6 +1900,11 @@ autoloadscan(HashNode hn, int printflags) putchar('\n'); } + +/************************************************************************ + * Handling for the zmodload builtin and its various options. + ************************************************************************/ + /**/ int bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func)) @@ -961,10 +1913,18 @@ bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func)) 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 (ops_bcpf && !ops_au) { - zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u"); - return 1; + 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') || @@ -987,10 +1947,19 @@ bin_zmodload(char *nam, char **args, Options ops, UNUSED(int func)) 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,'e')) + 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); @@ -1471,9 +2440,7 @@ unload_module(Module m, LinkNode 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)))) + do_cleanup_module(m)) return 1; else { int del = (m->flags & MOD_UNLOAD); @@ -1622,608 +2589,274 @@ bin_zmodload_load(char *nam, char **args, Options ops) return 0; } else { /* load modules */ - for (; *args; args++) - if (!require_module(nam, *args, 1, (!OPT_ISSET(ops,'i')))) - ret = 1; - - return ret; - } -} - -/* The list of module-defined conditions. */ - -/**/ -mod_export Conddef condtab; - -/* This gets a condition definition with the given name. The first * - * argument says if we have to look for an infix condition. The last * - * argument is non-zero if we should autoload modules if needed. */ - -/**/ -Conddef -getconddef(int inf, char *name, int autol) -{ - Conddef p; - int f = 1; - - 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; -} - -/* 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. */ - -/**/ -int -addconddef(Conddef c) -{ - Conddef p = getconddef((c->flags & CONDF_INFIX), c->name, 0); - - if (p) { - if (!p->module || (p->flags & CONDF_ADDED)) - return 1; - /* There is an autoload definition. */ - - deleteconddef(p); - } - c->next = condtab; - condtab = c; - return 0; -} - -/* This adds multiple condition definitions. This is like addbuiltins(). */ - -/**/ -mod_export int -addconddefs(char const *nam, Conddef c, int size) -{ - int hads = 0, hadf = 0; - - while (size--) { - 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; + for (; *args; args++) { + int tmpret = require_module(nam, *args, NULL); + if (tmpret && ret != 1) + ret = tmpret; } - c++; - } - return hadf ? hads : 1; -} - -/* This list of hook functions defined. */ -/**/ -Hookdef hooktab; - -/* Find a hook definition given the name. */ - -/**/ -Hookdef -gethookdef(char *n) -{ - Hookdef p; - - for (p = hooktab; p; p = p->next) - if (!strcmp(n, p->name)) - return p; - return NULL; -} - -/* This adds the given hook definition. The return value is zero on * - * success and 1 on failure. */ - -/**/ -int -addhookdef(Hookdef h) -{ - if (gethookdef(h->name)) - return 1; - - h->next = hooktab; - hooktab = h; - h->funcs = znewlinklist(); - - return 0; -} - -/* This adds multiple hook definitions. This is like addbuiltins(). */ - -/**/ -mod_export int -addhookdefs(char const *nam, Hookdef h, int size) -{ - int hads = 0, hadf = 0; - - while (size--) { - if (addhookdef(h)) { - zwarnnam(nam, "name clash when adding hook `%s'", h->name); - hadf = 1; - } else - hads = 2; - h++; + return ret; } - return hadf ? hads : 1; } -/* Delete hook definitions. */ - /**/ -int -deletehookdef(Hookdef h) +static int +bin_zmodload_features(char *nam, char **args, Options ops) { - Hookdef p, q; + char *modname = *args; - for (p = hooktab, q = NULL; p && p != h; q = p, p = p->next); - - if (!p) + if (!modname) { + zwarnnam(nam, "-F requires a module name"); return 1; - - if (q) - q->next = p->next; - else - hooktab = p->next; - freelinklist(p->funcs, NULL); - return 0; -} - -/**/ -mod_export int -deletehookdefs(UNUSED(char const *nam), Hookdef h, int size) -{ - while (size--) { - deletehookdef(h); - h++; } - 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) -{ - Hookdef h = gethookdef(n); - - if (h) - return addhookdeffunc(h, f); - return 1; -} - -/* Delete a function from a hook. */ - -/**/ -int -deletehookdeffunc(Hookdef h, Hookfn f) -{ - LinkNode p; - - for (p = firstnode(h->funcs); p; incnode(p)) - if (f == (Hookfn) getdata(p)) { - remnode(h->funcs, p); - return 0; - } - return 1; -} - -/**/ -mod_export int -deletehookfunc(char *n, Hookfn f) -{ - Hookdef h = gethookdef(n); - - if (h) - return deletehookdeffunc(h, f); - return 1; -} - -/* Run the function(s) for a hook. */ - -/**/ -mod_export int -runhookdef(Hookdef h, void *d) -{ - if (empty(h->funcs)) { - if (h->def) - return h->def(h, d); - return 0; - } else if (h->flags & HOOKF_ALL) { - LinkNode p; - int r; - - for (p = firstnode(h->funcs); p; incnode(p)) - if ((r = ((Hookfn) getdata(p))(h, d))) - return r; - if (h->def) - return h->def(h, d); - return 0; - } else - return ((Hookfn) getdata(lastnode(h->funcs)))(h, d); -} - -/**/ -int -runhook(char *n, void *d) -{ - Hookdef h = gethookdef(n); - - if (h) - return runhookdef(h, d); - return 0; -} - -/* This adds the given parameter definition. The return value is zero on * - * success and 1 on failure. */ - -/**/ -int -addparamdef(Paramdef d) -{ - Param pm; - - if ((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; + args++; - pm->level = 0; - pm->u.data = d->var; - if (d->gsu) - pm->gsu.i = (GsuInteger) d->gsu; - else { + if (OPT_ISSET(ops,'l') || OPT_ISSET(ops,'L') || OPT_ISSET(ops,'e')) { /* - * If no get/set/unset class, use the appropriate - * variable type. + * 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. */ - switch (PM_TYPE(pm->node.flags)) { - case PM_SCALAR: - pm->gsu.s = &varscalar_gsu; - break; - - case PM_INTEGER: - pm->gsu.i = &varinteger_gsu; - break; - - case PM_ARRAY: - pm->gsu.a = &vararray_gsu; - break; - - default: - unsetparam_pm(pm, 0, 1); + 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; } - } - - return 0; -} - -/* This adds multiple parameter definitions. This is like addbuiltins(). */ - -/**/ -mod_export int -addparamdefs(char const *nam, Paramdef d, int size) -{ - int hads = 0, hadf = 0; - - while (size--) { - if (addparamdef(d)) { - zwarnnam(nam, "error when adding parameter `%s'", d->name); - hadf = 1; - } else - hads = 2; - d++; - } - return hadf ? hads : 1; -} - -/* Delete parameters defined. No error checking yet. */ - -/**/ -int -deleteparamdef(Paramdef d) -{ - unsetparam(d->name); - return 0; -} - -/**/ -mod_export int -deleteparamdefs(UNUSED(char const *nam), Paramdef d, int size) -{ - while (size--) { - deleteparamdef(d); - d++; - } - return 1; -} - -/* This adds a definition for autoloading a module for a condition. */ - -/**/ -int -add_autocond(char *nam, int inf, char *module) -{ - Conddef c = (Conddef) zalloc(sizeof(*c)); - - 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; -} - -/* This removes the given condition definition from the list(s). If this * - * is a definition for a autoloaded condition, the memory is freed. */ - -/**/ -int -deleteconddef(Conddef c) -{ - Conddef p, q; - - for (p = condtab, q = NULL; p && p != c; q = p, p = p->next); - - if (p) { - if (q) - q->next = p->next; - else - condtab = p->next; - - if (p->module) { - /* autoloaded, free it */ - zsfree(p->name); - zsfree(p->module); - zfree(p, sizeof(*p)); + if (features_module(m, &features)) { + if (!OPT_ISSET(ops,'e')) + zwarnnam(nam, "module `%s' does not support features", m->nam); + return 1; } - return 0; - } - return -1; -} - -/* This removes multiple condition definitions (like deletebuiltins()). */ - -/**/ -mod_export int -deleteconddefs(char const *nam, Conddef c, int size) -{ - int hads = 0, hadf = 0; - - while (size--) { - if (!(c->flags & CONDF_ADDED)) { - c++; - continue; + 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; } - if (deleteconddef(c)) { - zwarnnam(nam, "condition `%s' already deleted", c->name); - hadf = 1; - } else - hads = 2; - c->flags &= ~CONDF_ADDED; - c++; + 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; } - return hadf ? hads : 1; -} - -/* This adds a definition for autoloading a module for a parameter. */ -/**/ -void -add_autoparam(char *nam, char *module) -{ - Param pm; - - queue_signals(); - if ((pm = (Param) gethashnode2(paramtab, nam))) - unsetparam_pm(pm, 0, 1); - - pm = setsparam(nam, ztrdup(module)); - - pm->node.flags |= PM_AUTOLOAD; - unqueue_signals(); + return require_module(nam, modname, args); } -/* List of math functions. */ -/**/ -MathFunc mathfuncs; +/************************************************************************ + * Generic feature support. + * These functions are designed to be called by modules. + ************************************************************************/ -/**/ -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)); -} +/* + * 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. + */ /**/ -MathFunc -getmathfunc(char *name, int autol) +mod_export char ** +featuresarray(char const *nam, Features f) { - 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); + 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; - return getmathfunc(name, 0); - } - return p; - } + 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); - return NULL; + features[features_size] = NULL; + return features; } +/* + * Return the current set of enables for the features in a + * module using heap memory. Leave space for abstract + * features. The array is not zero terminated. + */ /**/ -mod_export int -addmathfunc(MathFunc f) +mod_export int * +getfeatureenables(char const *nam, Features f) { - MathFunc p, q = NULL; - - if (f->flags & MFF_ADDED) - return 1; - - for (p = mathfuncs; p; q = p, p = p->next) - if (!strcmp(f->name, p->name)) { - if (p->module && !(p->flags & MFF_USERFUNC)) { - /* - * Autoloadable, replace. - */ - removemathfunc(q, p); - break; - } - return 1; - } + 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; - f->flags |= MFF_ADDED; - f->next = mathfuncs; - mathfuncs = f; + 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; } -/**/ -mod_export int -addmathfuncs(char const *nam, MathFunc f, int size) -{ - int hads = 0, hadf = 0; - - 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; -} - -/**/ -int -add_automathfunc(char *nam, char *module) -{ - 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)); - - return 1; - } - f->flags &= ~MFF_ADDED; /* still to autoload, not added yet */ - - return 0; -} +/* + * 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) diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst index bbc00a2ea..40669defd 100644 --- a/Test/B02typeset.ztst +++ b/Test/B02typeset.ztst @@ -356,8 +356,6 @@ local parentenv=preserved fn() { - # The first declare works around the "not an identifier" bug with -h - declare \! \# \$ \* - \? @ 0 typeset -h +g -m \* unset -m \* integer i=9 diff --git a/Test/V01zmodload.ztst b/Test/V01zmodload.ztst index d26ae1e42..daba3e0a1 100644 --- a/Test/V01zmodload.ztst +++ b/Test/V01zmodload.ztst @@ -49,9 +49,11 @@ >zmodload zsh/main >zmodload zsh/parameter +# You use to need zmodload -i to avoid an error. +# That has been deemed pointless, so now an attempt +# to load a loaded module should succeed. zmodload zsh/main -1:Test reloading an already-loaded module -?(eval):zmodload:1: module zsh/main already loaded. +0:Test reloading an already-loaded module # Loop over the modules found above and attempt to load each one. Use # the -i flag in case dependencies cause multiple modules to be loaded, diff --git a/Test/V04features.ztst b/Test/V04features.ztst new file mode 100644 index 000000000..f5f136b65 --- /dev/null +++ b/Test/V04features.ztst @@ -0,0 +1,162 @@ +%prep + +# Do some tests on handling of features. +# This also does some slightly more sophisticated loading and +# unloading tests than we did in V01zmodload.ztst. +# +# We use zsh/datetime because it has a list of features that is short +# but contains two types. + + if ! (zmodload zsh/datetime >/dev/null 2>/dev/null); then + ZTST_unimplemented="can't load the zsh/datetime module for testing" + fi + +%test + zmodload -F zsh/datetime + zmodload -lF zsh/datetime +0:Loading modules with no features +>-b:strftime +>-p:EPOCHSECONDS + + zmodload -F zsh/datetime b:strftime + zmodload -lF zsh/datetime +0:Enabling features +>+b:strftime +>-p:EPOCHSECONDS + + zmodload -F zsh/datetime +p:EPOCHSECONDS -b:strftime + zmodload -lF zsh/datetime +0:Disabling features +>-b:strftime +>+p:EPOCHSECONDS + + zmodload -Fe zsh/datetime p:EPOCHSECONDS b:strftime +0:Testing existing features + + zmodload -Fe zsh/datetime +p:EPOCHSECONDS +0:Testing features are in given state (on feature is on) + + zmodload -Fe zsh/datetime -p:EPOCHSECONDS +1:Testing features are in given state (on feature is not off + + zmodload -Fe zsh/datetime +p:strftime +1:Testing features are in given state (off feature is not on) + + zmodload -Fe zsh/datetime -b:strftime +0:Testing features are in given state (off feature is off + + zmodload -Fe zsh/datetime p:EPOCHSECONDS b:strftime b:mktimebetter +1:Testing non-existent features + + zmodload -FlP dtf zsh/datetime + for feature in b:strftime p:EPOCHSECONDS; do + if [[ ${${dtf[(R)?$feature]}[1]} = + ]]; then + print $feature is enabled + else + print $feature is disabled + fi + done +0:Testing features via array parameter +>b:strftime is disabled +>p:EPOCHSECONDS is enabled + + fn() { + local EPOCHSECONDS=scruts + print $EPOCHSECONDS + print ${(t)EPOCHSECONDS} + } + fn + if [[ $EPOCHSECONDS = <-> ]]; then + print EPOCHSECONDS is a number + else + print EPOCHSECONDS is some random piece of junk + fi + print ${(t)EPOCHSECONDS} +0:Module special parameter is hidden by a local parameter +>scruts +>scalar-local +>EPOCHSECONDS is a number +>integer-readonly-hide-hideval-special + + typeset +h EPOCHSECONDS + fn() { + local EPOCHSECONDS=scruts + print Didn\'t get here >&2 + } + fn +1:Unhidden readonly special can't be assigned to when made local +?fn:1: read-only variable: EPOCHSECONDS + + zmodload -u zsh/datetime +0:Module unloaded + + zmodload -e zsh/datetime +1:Module doesn't exist when unloaded + + zmodload -Fe zsh/datetime p:EPOCHSECONDS +1:Module doesn't have features when unloaded + + fn() { + local EPOCHSECONDS=scrimf + zmodload zsh/datetime + } + fn +# status is zero because load succeded although features not all enabled +2:Failed to add parameter if local parameter present +?fn:2: Can't add module parameter `EPOCHSECONDS': local parameter exists +?fn:zsh/datetime:2: error when adding parameter `EPOCHSECONDS' + + zmodload -lF zsh/datetime +0:Feature state with loading after error enabling +>+b:strftime +>-p:EPOCHSECONDS + + zmodload -F zsh/datetime p:EPOCHSECONDS + zmodload -Fe zsh/datetime +p:EPOCHSECONDS +0:Successfully added feature parameter that previously failed + + fn() { + local EPOCHSECONDS=scrooble + zmodload -u zsh/datetime + print $EPOCHSECONDS + } + fn + print ${+EPOCHSECONDS} +0:Successfully unloaded a module despite a parameter being hidden +>scrooble +>0 + + EPOCHSECONDS=(any old parameter) + print -l $EPOCHSECONDS +0:Using parameter as normal after unloading is OK +>any +>old +>parameter + + print strftime is ${builtins[strftime]:-undefined} + zmodload -F zsh/datetime b:strftime + print strftime is ${builtins[strftime]:-undefined} + zmodload -F zsh/datetime -b:strftime + print strftime is ${builtins[strftime]:-undefined} +0:Enabling and disabling of builtins as features +>strftime is undefined +>strftime is defined +>strftime is undefined + + zmodload -u zsh/datetime + zmodload zsh/datetime +2:Loading won't override global parameter +?(eval):2: Can't add module parameter `EPOCHSECONDS': parameter already exists +?(eval):zsh/datetime:2: error when adding parameter `EPOCHSECONDS' + + unset EPOCHSECONDS + zmodload -F zsh/datetime p:EPOCHSECONDS + zmodload -Fe zsh/datetime +p:EPOCHSECONDS +0:unsetting a global parameter allows feature parameter to be enabled + + zmodload -F zsh/datetime -b:strftime -p:EPOCHSECONDS + zmodload zsh/datetime + zmodload -lF zsh/datetime +0:zmodload with no -F enables all features +>+b:strftime +>+p:EPOCHSECONDS |