summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2007-05-28 22:57:39 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2007-05-28 22:57:39 +0000
commitb0c5f09169ac31855ebf0e93772bb57b9635b380 (patch)
tree410c43a9843b2c88166c2cb9acd531eaa36d036d
parentbd7632079045b1b6d0dee498c40833b409cf757e (diff)
downloadzsh-b0c5f09169ac31855ebf0e93772bb57b9635b380.tar.gz
zsh-b0c5f09169ac31855ebf0e93772bb57b9635b380.zip
see 23479: add initial features support for modules
-rw-r--r--ChangeLog25
-rw-r--r--Completion/Unix/Command/_chmod10
-rw-r--r--Completion/Unix/Command/_chown12
-rw-r--r--Completion/Unix/Command/_cvs9
-rw-r--r--Completion/Unix/Type/_list_files15
-rw-r--r--Completion/Zsh/Command/_stat2
-rw-r--r--Completion/Zsh/Command/_zstyle1
-rw-r--r--Completion/Zsh/Type/_file_descriptors4
-rw-r--r--Doc/Zsh/builtins.yo64
-rw-r--r--Doc/Zsh/compsys.yo7
-rw-r--r--Doc/Zsh/mod_stat.yo17
-rw-r--r--Etc/zsh-development-guide274
-rw-r--r--Src/Builtins/rlimits.c27
-rw-r--r--Src/Builtins/sched.c28
-rw-r--r--Src/Modules/cap.c30
-rw-r--r--Src/Modules/clone.c30
-rw-r--r--Src/Modules/datetime.c41
-rw-r--r--Src/Modules/example.c35
-rw-r--r--Src/Modules/files.c28
-rw-r--r--Src/Modules/langinfo.c92
-rw-r--r--Src/Modules/langinfo.mdd2
-rw-r--r--Src/Modules/mapfile.c99
-rw-r--r--Src/Modules/mathfunc.c28
-rw-r--r--Src/Modules/parameter.c251
-rw-r--r--Src/Modules/pcre.c41
-rw-r--r--Src/Modules/regex.c30
-rw-r--r--Src/Modules/socket.c29
-rw-r--r--Src/Modules/stat.c29
-rw-r--r--Src/Modules/system.c138
-rw-r--r--Src/Modules/tcp.c28
-rw-r--r--Src/Modules/termcap.c110
-rw-r--r--Src/Modules/terminfo.c112
-rw-r--r--Src/Modules/zftp.c60
-rw-r--r--Src/Modules/zprof.c29
-rw-r--r--Src/Modules/zpty.c30
-rw-r--r--Src/Modules/zselect.c32
-rw-r--r--Src/Modules/zutil.c27
-rw-r--r--Src/Zle/compctl.c28
-rw-r--r--Src/Zle/complete.c33
-rw-r--r--Src/Zle/complist.c27
-rw-r--r--Src/Zle/computil.c28
-rw-r--r--Src/Zle/deltochar.c29
-rw-r--r--Src/Zle/zle_main.c27
-rw-r--r--Src/Zle/zle_thingy.c2
-rw-r--r--Src/Zle/zle_tricky.c2
-rw-r--r--Src/Zle/zleparameter.c118
-rw-r--r--Src/builtin.c31
-rw-r--r--Src/cond.c5
-rw-r--r--Src/exec.c4
-rw-r--r--Src/init.c10
-rw-r--r--Src/mkbltnmlst.sh7
-rw-r--r--Src/mkmakemod.sh2
-rw-r--r--Src/modentry.c10
-rw-r--r--Src/module.c1983
-rw-r--r--Src/params.c45
-rw-r--r--Src/zsh.h91
-rw-r--r--Test/B02typeset.ztst2
-rw-r--r--Test/V01zmodload.ztst6
-rw-r--r--Test/V04features.ztst162
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