From b0c5f09169ac31855ebf0e93772bb57b9635b380 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 28 May 2007 22:57:39 +0000 Subject: see 23479: add initial features support for modules --- Etc/zsh-development-guide | 274 ++++++++++++++++++++++++++-------------------- 1 file changed, 154 insertions(+), 120 deletions(-) (limited to 'Etc') 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: -- cgit 1.4.1