summaryrefslogtreecommitdiffstats
path: root/Etc/zsh-development-guide
diff options
context:
space:
mode:
Diffstat (limited to 'Etc/zsh-development-guide')
-rw-r--r--Etc/zsh-development-guide270
1 files changed, 152 insertions, 118 deletions
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.
+in.
-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.
+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.
-In short, the `cleanup_'-function should undo what the `boot_'-function
-did, and the `finish_'-function should undo what the `setup_'-function
-did.
+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: