mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-12-29 16:25:35 +01:00
966 lines
39 KiB
Text
966 lines
39 KiB
Text
------------------------------
|
|
GUIDELINES FOR ZSH DEVELOPMENT
|
|
------------------------------
|
|
|
|
Zsh is currently developed and maintained by the Zsh Development Group.
|
|
This development takes place by mailing list. Check the META-FAQ for the
|
|
various zsh mailing lists and how to subscribe to them. The development
|
|
is very open and anyone is welcomed and encouraged to join and contribute.
|
|
Because zsh is a very large package whose development can sometimes
|
|
be very rapid, we kindly ask that people observe a few guidelines when
|
|
contributing patches and feedback to the mailing list. These guidelines
|
|
are very simple and hopefully should make for a more orderly development
|
|
of zsh.
|
|
|
|
Tools
|
|
-----
|
|
|
|
To develop (as opposed to just build) zsh, you'll need a few specialised
|
|
tools:
|
|
|
|
* GNU autoconf, version 2.50 or later. This version contained
|
|
significant enhancements and earlier versions will no
|
|
longer work.
|
|
|
|
* GNU m4. (Required by autoconf.)
|
|
|
|
* yodl.
|
|
|
|
* texi2html.
|
|
|
|
Patches
|
|
-------
|
|
|
|
* Send all patches to the mailing list rather than directly to me.
|
|
|
|
* Send only context diffs "diff -c oldfile newfile" or unified diffs
|
|
"diff -u oldfile newfile". They are much easier to read and
|
|
understand while also allowing the patch program to patch more
|
|
intelligently. Please make sure the filenames in the diff header
|
|
are relative to the top-level directory of the zsh distribution; for
|
|
example, it should say "Src/init.c" rather than "init.c" or
|
|
"zsh/Src/init.c". Git-style naming of diffs is also acceptable.
|
|
|
|
* Please put only one bug fix or feature enhancement in a single patch and
|
|
only one patch per mail message. This helps me to multiplex the many
|
|
(possibly conflicting) patches that I receive for zsh. You shouldn't
|
|
needlessly split patches, but send them in the smallest LOGICAL unit.
|
|
|
|
* If a patch depends on other patches, then please say so. Also please
|
|
mention what version of zsh this patch is for.
|
|
|
|
* Please test your patch and make sure it applies cleanly. It takes
|
|
considerably more time to manually merge a patch into the baseline code.
|
|
|
|
* By convention, patches should be sent with a Subject: line starting with
|
|
one of "PATCH:", "[PATCH]" or "[PATCH n/m]" (for a patch series).
|
|
|
|
Git Workflow
|
|
------------
|
|
|
|
* To allow changesets to be cross-referenced between the mailing list
|
|
archives and version control history, commit messages should start with
|
|
the mailing list sequence number. This number is generated by the list
|
|
server and inserted as an X-Seq: header field in the e-mail. To add
|
|
the number, you can use "git commit --amend" to change the commit.
|
|
|
|
* Do not merge your private feature branches onto the master branch: a
|
|
linear history without merge commits is simpler to follow (and to
|
|
bisect). Both "git cherry-pick" and "git merge --ff-only" can be used
|
|
bring changes over to another branch without a merge commit.
|
|
|
|
* It is often useful to regularly check in changes while prototyping a
|
|
solution on a private branch. When finished, it is better to deliver a
|
|
clean history. For small changes, use "git merge --squash" to get a
|
|
single changeset for the feature. Where a change can be logically
|
|
divided into separate changesets use "git rebase -i master" from the
|
|
feature branch and squash your many intermediate steps into
|
|
appropriate changesets that each do something meaningful. Post each
|
|
changeset separately to the mailing list.
|
|
|
|
* Before pushing your changes to the main zsh repository, you can use
|
|
"git pull --rebase" to fetch any new updates from the server and
|
|
rebase your changes on top of them. You can also use "git rebase
|
|
master" from your feature branches.
|
|
|
|
* Patches can be prepared for the mailing list with "git format-patch
|
|
origin/master". To apply patches from a mailing list message, you can
|
|
use "git am".
|
|
|
|
Testing
|
|
-------
|
|
|
|
* Because zsh has a huge number of different options and interacts with
|
|
a wide range of human and artificial life, it is very difficult to
|
|
test the shell thoroughly. For this purpose, the Test subdirectory
|
|
exists. It consists of a driver script (ztst.zsh) and various test
|
|
files (*.ztst) in a format which is described in B01cd.ztst, which acts
|
|
as a template. It is designed to make it easy to provide input to
|
|
chunks of shell code and to test the corresponding standard output,
|
|
error output and exit status.
|
|
|
|
* There is not much there yet, but please don't let that put you off adding
|
|
tests for basic syntactic features, builtins, options etc. which you
|
|
know to be flakey or to have had difficulties in the past. Better
|
|
support for testing job control and interactive features is expected
|
|
to follow eventually.
|
|
|
|
* The directory is not part of the usual process of building and
|
|
installation. To run the tests, go to Test and `make check'. Please
|
|
report any errors with all the usual information about the zsh version
|
|
and the system you are using.
|
|
|
|
C coding style
|
|
--------------
|
|
|
|
* The primary language is ANSI C as defined by the 1989 standard, but the
|
|
code should always be compatible with late K&R era compilers ("The C
|
|
Programming Language" 1st edition, plus "void" and "enum"). There are
|
|
many hacks to avoid the need to actually restrict the code to K&R C --
|
|
check out the configure tests -- but always bear the compatibility
|
|
requirements in mind. In particular, preprocessing directives must
|
|
have the "#" unindented, and string pasting is not available.
|
|
|
|
* Conversely, there are preprocessor macros to provide safe access to some
|
|
language features not present in pure ANSI C, such as variable-length
|
|
arrays. Always use the macros if you want to use these facilities.
|
|
|
|
* Avoid writing code that generates warnings under gcc with the default
|
|
options set by the configure script. For example, write
|
|
"if ((foo = bar))" rather than "if (foo = bar)".
|
|
|
|
* Please try not using lines longer than 79 characters.
|
|
|
|
* The indent/brace style is Kernighan and Ritchie with 4 characters
|
|
indentations (with leading tab characters replacing sequences of
|
|
8 spaces). This means that the opening brace is the last character
|
|
in the line of the if/while/for/do statement and the closing brace
|
|
has its own line:
|
|
|
|
if (foo) {
|
|
do that
|
|
}
|
|
|
|
* Put only one simple statement on a line. The body of an if/while/for/do
|
|
statement has its own line with 4 characters indentation even if there
|
|
are no braces.
|
|
|
|
* Do not use space between the function name and the opening parenthesis.
|
|
Use space after if/for/while. Use space after type casts.
|
|
|
|
* Do not use (unsigned char) casts since some compilers do not handle
|
|
them properly. Use the provided STOUC(X) macro instead.
|
|
|
|
* If you use emacs 19.30 or newer you can put the following line to your
|
|
~/.emacs file to make these formatting rules the default:
|
|
|
|
(add-hook 'c-mode-common-hook (function (lambda () (c-set-style "BSD"))))
|
|
|
|
* Function declarations must look like this:
|
|
|
|
/**/
|
|
int
|
|
foo(char *s, char **p)
|
|
{
|
|
function body
|
|
}
|
|
|
|
There must be an empty line, a line with "/**/", a line with the
|
|
type of the function, and finally the name of the function with typed
|
|
arguments. These lines must not be indented. The script generating
|
|
function prototypes and the ansi2knr program depend on this format.
|
|
|
|
* Variable declarations must similarly be preceded by a
|
|
line containing only "/**/", for the prototype generation script.
|
|
The declaration itself should be all on one line (except for multi-line
|
|
initialisers).
|
|
|
|
* Preprocessor directives that affect the function/variable declarations must
|
|
also be preceded by a "/**/" line, so that they get copied into the
|
|
prototype lists.
|
|
|
|
* There are three levels of visibility for a function or variable. It can
|
|
be file-local, for which it must be marked with the keyword "static" at
|
|
the front of the declaration. It can be visible to other object files in
|
|
the same module, for which it requires no extra keyword. Or it can be
|
|
made available to the entire program (including other dynamically loaded
|
|
modules), for which it must be marked with the pseudo-keyword "mod_export"
|
|
at the front of the declaration. Symbols should have the least visibility
|
|
possible.
|
|
|
|
* Leave a blank line between the declarations and statements in a compound
|
|
statement, if both are present. Use blank lines elsewhere to separate
|
|
groups of statements in the interests of clarity. There should never
|
|
be two consecutive blank lines.
|
|
|
|
* Each .c file *must* #include the .mdh header for the module it is a
|
|
part of and then its own .pro file (for local prototypes). It may
|
|
also #include other system headers. It *must not* #include any other
|
|
module's headers or any other .pro files.
|
|
|
|
* The repository includes a `.editorconfig' file with whitespace/indent
|
|
control settings. Information about text editor plugins and this file
|
|
can be found at <http://editorconfig.org/>.
|
|
|
|
|
|
Modules
|
|
-------
|
|
|
|
Modules have hierarchical names. Name segments are separated by `/', and
|
|
each segment consists of alphanumerics plus `_'. Relative names are never
|
|
used; the naming hierarchy is strictly for organisational convenience.
|
|
|
|
Each module is described by a file with a name ending in `.mdd' somewhere
|
|
under the Src directory. This file is actually a shell script that will
|
|
sourced when zsh is built. To describe the module it can/should set the
|
|
following shell variables:
|
|
|
|
- name name of the module
|
|
- link `static', `dynamic' or `no', as described in INSTALL.
|
|
In addition, the value `either' is allowed in the .mdd
|
|
file, which will be converted by configure to `dynamic'
|
|
if that is available, else `static'.
|
|
May also be a command string, which will be run within
|
|
configure and whose output is used to set the value
|
|
of `link' in config.modules. This allows a
|
|
system-specific choice of modules. For example,
|
|
link='case $host in *-hpux*) echo dynamic; ;;
|
|
*) echo no; ;; esac'
|
|
- load `yes' or `no': whether the shell should include hooks
|
|
for loading the module automatically as necessary.
|
|
(This corresponds to an `L' in xmods.conf in the
|
|
old mechanism.)
|
|
- moddeps modules on which this module depends (default none)
|
|
- nozshdep non-empty indicates no dependence on the `zsh/main'
|
|
pseudo-module
|
|
- alwayslink if non-empty, always link the module into the executable
|
|
- autofeatures features defined by the module for autoloading,
|
|
a space-separated list. The syntax for features is as
|
|
for zmodload -F, e.g. b:mybin refers to the builtin
|
|
mybin. This replaces the previous mechanism with
|
|
separate variables for builtins, conditions, math
|
|
functions and parameters. Note the features are only
|
|
available in zsh's native mode, not in emulation modes.
|
|
- autofeatures_emu As autofeatures, but the features so presented are
|
|
available in modes that are *not* zsh's native mode.
|
|
The variable autofeatures must also be present.
|
|
- objects .o files making up this module (*must* be defined)
|
|
- proto .syms files for this module (default generated from $objects)
|
|
- headers extra headers for this module (default none)
|
|
- hdrdeps extra headers on which the .mdh depends (default none)
|
|
- otherincs extra headers that are included indirectly (default none)
|
|
|
|
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 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 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 structures 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; note also the pointers for the abstract features are not
|
|
initialised so setting them is mandatory any time there are any present.
|
|
|
|
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).
|
|
See below.
|
|
|
|
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 the features array, the area of the enables
|
|
array for abstract features is not even initialised by the main shell). 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 initial 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. Note that
|
|
`cleanup_' is called whenever `setup_' succeeded, so that `cleanup_'
|
|
must be prepared to handle any state resulting from a failed `boot_'
|
|
or initial call to `features_'. Note also that a return code of 1
|
|
from `cleanup_' will result in the module not being unloaded, so
|
|
usually `cleanup_' will return 0 even if it has to handle an unclean
|
|
state; if it does return 1, it must be prepared to be called again
|
|
in a future attempt to unload.
|
|
|
|
The last function, `finish_' is called when the module is actually unloaded
|
|
and should finalize all the data initialized in the `setup_'-function.
|
|
However, `finish_' is called even if `setup_' failed, so it should
|
|
not rely on the module successfully being set up.
|
|
The state from `finish_' module is currently ignored; it is called
|
|
too late to prevent the module from being unloaded.
|
|
*Note* in addition to freeing memory, variables associated with allocated
|
|
memory should be set to NULL or to indicate arrays are empty, etc. It
|
|
should not be assumed that the variables will automatically be zeroed if
|
|
the module is reloaded (though some configurations may do this).
|
|
|
|
In short, the `cleanup_'-function should undo what the `boot_'-function did
|
|
(together with handling any residual effects of `enables_'), but should
|
|
not rely on `boot_' having been successful, and the
|
|
`finish_'-function should undo what the `setup_'-function did, but
|
|
should not rely on `setup_' having been successful.
|
|
|
|
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 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 */
|
|
}
|
|
|
|
Within each individual table ("bintab", etc.), features should be listed
|
|
in ASCII order as no further sorting is performed by the shell when
|
|
features are listed.
|
|
|
|
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[] = {
|
|
BUILTIN("example", 0, bin_example, 0, -1, 0, "flags", NULL),
|
|
};
|
|
|
|
Here `BUILTIN(...)' is a macro that simplifies the description. Its
|
|
arguments are:
|
|
- the name of the builtin as a string
|
|
- optional flags (see BINF_* in zsh.h)
|
|
- the C-function implementing the builtin
|
|
- the minimum number of arguments the builtin needs
|
|
- the maximum number of arguments the builtin can handle or -1 if
|
|
the builtin can get any number of arguments
|
|
- an integer that is passed to the handler function and can be used
|
|
to distinguish builtins if the same C-function is used to
|
|
implement multiple builtins
|
|
- the options the builtin accepts, given as a string containing the
|
|
option characters (the above example makes the builtin accept the
|
|
options `f', `l', `a', `g', and `s'). Passing NULL here disables
|
|
all flag handling, i.e. even "--".
|
|
- and finally a optional string containing option characters that
|
|
will always be reported as set when calling the C-function (this,
|
|
too, can be used when using one C-function to implement multiple
|
|
builtins)
|
|
|
|
The definition of the handler function looks like:
|
|
|
|
/**/
|
|
static int
|
|
bin_example(char *nam, char **args, char *ops, int func)
|
|
{
|
|
...
|
|
}
|
|
|
|
The special comment /**/ is used by the zsh Makefile to generate the
|
|
`*.pro' files. The arguments of the function are the number under
|
|
which this function was invoked (the name of the builtin, but for
|
|
functions that implement more than one builtin this information is
|
|
needed). The second argument is the array of arguments *excluding* the
|
|
options that were defined in the struct and which are handled by the
|
|
calling code. These options are given as the third argument. It is an
|
|
array of 256 characters in which the n'th element is non-zero if the
|
|
option with ASCII-value n was set (i.e. you can easily test if an
|
|
option was used by `if (ops['f'])' etc.). The last argument is the
|
|
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.
|
|
|
|
Conditions
|
|
----------
|
|
|
|
The definition of condition codes in modules is equally simple. First
|
|
we need a table with the descriptions:
|
|
|
|
static struct conddef cotab[] = {
|
|
CONDDEF("len", 0, cond_p_len, 1, 2, 0),
|
|
CONDDEF("ex", CONDF_INFIX, cond_i_ex, 0, 0, 0),
|
|
};
|
|
|
|
Again a macro is used, with the following arguments:
|
|
|
|
- the name of the condition code without the leading hyphen
|
|
(i.e. the example makes the condition codes `-len' and `-ex'
|
|
usable in `[[...]]' constructs)
|
|
- an optional flag which for now can only be CONDF_INFIX; if this is
|
|
given, an infix operator is created (i.e. the above makes
|
|
`[[ -len str ]]' and `[[ s1 -ex s2 ]]' available)
|
|
- the C-function implementing the conditional
|
|
- for non-infix condition codes the next two arguments give the
|
|
minimum and maximum number of string the conditional can handle
|
|
(i.e. `-len' can get one or two strings); as with builtins giving
|
|
-1 as the maximum number means that the conditional accepts any
|
|
number of strings
|
|
- finally as the last argument an integer that is passed to the
|
|
handler function that can be used to distinguish different
|
|
condition codes if the same C-function implements more than one of
|
|
them
|
|
|
|
The definition for the function looks like:
|
|
|
|
/**/
|
|
static int
|
|
cond_p_len(char **a, int id)
|
|
{
|
|
...
|
|
}
|
|
|
|
The first argument is an array containing the strings (NULL-terminated
|
|
like the array of arguments for builtins), the second argument is the
|
|
integer value stored in the table (the last argument to `CONDDEF(...)').
|
|
The value returned by the function should be non-zero if the condition
|
|
is true and zero otherwise.
|
|
|
|
Note that no preprocessing is done on the strings. This means that
|
|
no substitutions are performed on them and that they will be
|
|
tokenized. There are three helper functions available:
|
|
|
|
- char *cond_str(args, num, raw)
|
|
The first argument is the array of strings the handler function
|
|
got as an argument and the second one is an index into this array.
|
|
The return value is the num'th string from the array with
|
|
substitutions performed. If the last argument is zero, the string
|
|
will also be untokenized.
|
|
- long cond_val(args, num)
|
|
The arguments are the same as for cond_str(). The return value is
|
|
the result of the mathematical evaluation of the num'th string
|
|
form the array.
|
|
- int cond_match(args, num, str)
|
|
Again, the first two arguments are the same as for the other
|
|
functions. The third argument is any string. The result of the
|
|
function is non-zero if the num'th string from the array taken
|
|
as a glob pattern matches the given string.
|
|
|
|
Parameters
|
|
----------
|
|
|
|
For defining parameters, a module can call `createparam()' directly or
|
|
use a table to describe them, e.g.:
|
|
|
|
static struct paramdef patab[] = {
|
|
PARAMDEF("foo", PM_INTEGER, NULL, get_foo, set_foo, unset_foo),
|
|
INTPARAMDEF("exint", &intparam),
|
|
STRPARAMDEF("exstr", &strparam),
|
|
ARRPARAMDEF("exarr", &arrparam),
|
|
};
|
|
|
|
There are four macros used:
|
|
|
|
- PARAMDEF() gets as arguments:
|
|
- the name of the parameter
|
|
- the parameter flags to set for it (from the PM_* flags defined
|
|
in zsh.h)
|
|
- optionally a pointer to a variable holding the value of the
|
|
parameter
|
|
- three functions that will be used to get the value of the
|
|
parameter, store a value in the parameter, and unset the
|
|
parameter
|
|
- the other macros provide simple ways to define the most common
|
|
types of parameters; they get the name of the parameter and a
|
|
pointer to a variable holding the value as arguments; they are
|
|
used to define integer-, scalar-, and array-parameters, so the
|
|
variables whose addresses are given should be of type `long',
|
|
`char *', and `char **', respectively
|
|
|
|
For a description of how to write functions for getting or setting the
|
|
value of parameters, or how to write a function to unset a parameter,
|
|
see the description of the following functions in the `params.c' file:
|
|
|
|
- `intvargetfn()' and `intvarsetfn()' for integer parameters
|
|
- `strvargetfn()' and `strvarsetfn()' for scalar parameters
|
|
- `arrvargetfn()' and `arrvarsetfn()' for array parameters
|
|
- `stdunsetfn()' for unsetting parameters
|
|
|
|
Note that if one defines parameters using the last two macros (for
|
|
scalars and arrays), the variable holding the value should be
|
|
initialized to either `NULL' or to a piece of memory created with
|
|
`zalloc()'. But this memory should *not* be freed in the
|
|
finish-function of the module because that will be taken care of by
|
|
the `deleteparamdefs()' function described below.
|
|
|
|
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 definitions in Src/Modules/parameter.c.
|
|
|
|
Math functions
|
|
--------------
|
|
|
|
Modules can also define math functions. Again, they are described
|
|
using a table:
|
|
|
|
static struct mathfunc mftab[] = {
|
|
NUMMATHFUNC("sum", math_sum, 1, -1, 0),
|
|
STRMATHFUNC("length", math_length, 0),
|
|
};
|
|
|
|
The `NUMMATHFUNC()' macro defines a math function that gets an array
|
|
of mnumbers (the zsh type for representing values in arithmetic
|
|
expressions) taken from the string in parentheses at the function
|
|
call. Its arguments are the name of the function, the C-function
|
|
implementing it, the minimum and maximum number of arguments (as
|
|
usual, the later may be `-1' to specify that the function accepts any
|
|
number of arguments), and finally an integer that is given unchanged
|
|
to the C-function (to be able to implement multiple math functions in
|
|
one C-function).
|
|
|
|
The `STRMATHFUNC()' macro defines a math function that gets the string
|
|
in parentheses at the call as one string argument (without the
|
|
parentheses). The arguments are the name of the function, the
|
|
C-function, and an integer used like the last argument of
|
|
`NUMMATHFUNC()'.
|
|
|
|
The C-functions implementing the math functions look like this:
|
|
|
|
/**/
|
|
static mnumber
|
|
math_sum(char *name, int argc, mnumber *argv, int id)
|
|
{
|
|
...
|
|
}
|
|
|
|
/**/
|
|
static mnumber
|
|
math_length(char *name, char *arg, int id)
|
|
{
|
|
...
|
|
}
|
|
|
|
Functions defined with `NUMMATHFUNC' get the name of the function, the
|
|
number of numeric arguments, an array with these arguments, and the
|
|
last argument from the macro-call. Functions defined with
|
|
`STRMATHFUNC' get the name of the function, the string between the
|
|
parentheses at the call, and the last argument from the macro-call.
|
|
|
|
Both types of functions return an mnumber which is a discriminated
|
|
union looking like:
|
|
|
|
typedef struct {
|
|
union {
|
|
zlong l;
|
|
double d;
|
|
} u;
|
|
int type;
|
|
} mnumber;
|
|
|
|
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.
|
|
|
|
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. 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:
|
|
|
|
static struct hookdef foohooks[] = {
|
|
HOOKDEF("foo", foofunc, 0),
|
|
};
|
|
|
|
The first argument of the macro is the name of the hook. This name
|
|
is used whenever the hook is used. The second argument is the default
|
|
function for the hook or NULL if no default function exists. The
|
|
last argument is used to define flags for the hook. Currently only one
|
|
such flag is defined: `HOOKF_ALL'. If this flag is given and more than
|
|
one function was added to the hook, all functions will be called
|
|
(including the default function). Otherwise only the last function
|
|
added will be called.
|
|
|
|
The functions that can be used as default functions or that can be
|
|
added to a hook have to be defined like:
|
|
|
|
/**/
|
|
static int
|
|
foofunc(Hookdef h, void *data)
|
|
{
|
|
...
|
|
}
|
|
|
|
The first argument is a pointer to the struct defining the hook. The
|
|
second argument is an arbitrary pointer that is given to the function
|
|
used to invoke hooks (see below).
|
|
|
|
The functions to register and de-register hooks look like those for
|
|
the other things that can be defined by modules:
|
|
|
|
/**/
|
|
int
|
|
boot_foo(Module m)
|
|
{
|
|
int ret;
|
|
|
|
ret = addhookdefs(m->nam, foohooks, sizeof(foohooks)/sizeof(*foohooks))
|
|
...
|
|
}
|
|
...
|
|
/**/
|
|
int
|
|
cleanup_foo(Module m)
|
|
{
|
|
deletehookdefs(m->nam, foohooks, sizeof(foohooks)/sizeof(*foohooks));
|
|
...
|
|
}
|
|
|
|
Modules that define hooks can invoke the function(s) registered for
|
|
them by calling the function `runhook(name, data)'. The first argument
|
|
is the name of the hook and the second one is the pointer given to the
|
|
hook functions as their second argument. Hooks that have the `HOOKF_ALL'
|
|
flag call all function defined for them until one returns non-zero.
|
|
The return value of `runhook()' is the return value of the last hook
|
|
function called or zero if none was called.
|
|
|
|
To add a function to a hook, the function `addhookfunc(name, func)' is
|
|
called with the name of the hook and a hook function as arguments.
|
|
Deleting them is done by calling `deletehookfunc(name, func)' with the
|
|
same arguments as for the corresponding call to `addhookfunc()'.
|
|
|
|
Alternative forms of the last three function are provided for hooks
|
|
that are changed or called very often. These functions,
|
|
`runhookdef(def, data)', `addhookdeffunc(def, func)', and
|
|
`deletehookdeffunc(def, func)' get a pointer to the `hookdef'
|
|
structure defining the hook instead of the name and otherwise behave
|
|
like their counterparts.
|
|
|
|
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:
|
|
|
|
static struct funcwrap wrapper[] = {
|
|
WRAPDEF(ex_wrapper),
|
|
};
|
|
|
|
The macro `WRAPDEF(...)' gets the C-function as its only argument.
|
|
This function should be defined like:
|
|
|
|
/**/
|
|
static int
|
|
ex_wrapper(List list, FuncWrap w, char *name)
|
|
{
|
|
...
|
|
runshfunc(list, w, name);
|
|
...
|
|
return 0;
|
|
}
|
|
|
|
The first two arguments should only be used to pass them to
|
|
`runshfunc()' which will execute the shell function. The last argument
|
|
is the name of the function to be executed. The arguments passed to
|
|
the function can be accessed vie the global variable `pparams' (a
|
|
NULL-terminated array of strings).
|
|
|
|
The return value of the wrapper function should be zero if it calls
|
|
`runshfunc()' itself and non-zero otherwise. This can be used for
|
|
wrapper functions that only need to run under certain conditions or
|
|
that don't need to clean anything up after the shell function has
|
|
finished:
|
|
|
|
/**/
|
|
static int
|
|
ex_wrapper(List list, FuncWrap w, char *name)
|
|
{
|
|
if (wrapper_need_to_run) {
|
|
...
|
|
runshfunc(list, w, name);
|
|
...
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
Inside these wrapper functions the global variable `sfcontext' will be
|
|
set to a clue indicating the circumstances under which the shell
|
|
function was called. It can have any of the following values:
|
|
|
|
- SFC_DIRECT: the function was invoked directly by the user
|
|
- SFC_SIGNAL: the function was invoked as a signal handler
|
|
- SFC_HOOK: the function was automatically invoked as one of the
|
|
special functions known by the shell (like `chpwd')
|
|
- SFC_WIDGET: the function was called from the zsh line editor as a
|
|
user-defined widget
|
|
- SFC_COMPLETE: the function was called from the completion code
|
|
(e.g. with `compctl -K func')
|
|
|
|
If a module invokes a shell function (e.g. as a hook function), the
|
|
value of this variable should only be changed temporarily and restored
|
|
to its previous value after the shell function has finished.
|
|
|
|
There is a problem when the user tries to unload a module that has
|
|
defined wrappers from a shell function. In this case the module can't
|
|
be unloaded immediately since the wrapper function is still on the
|
|
call stack. The zsh code delays unloading modules until all wrappers
|
|
from them have finished. To hide this from the user, the module's
|
|
cleanup function is run immediately so that all builtins, condition
|
|
codes, and wrapper function defined by the module are
|
|
de-registered. But if there is some module-global state that has to be
|
|
finalized (e.g. some memory that has to be freed) and that is used by
|
|
the wrapper functions finalizing this data in the cleanup function
|
|
won't work.
|
|
|
|
This is why there are two functions each for the initialization and
|
|
finalization of modules. The `boot'- and `cleanup'-functions are run
|
|
whenever the user calls `zmodload' or `zmodload -u' and should only
|
|
register or de-register the module's interface that is visible to the
|
|
user. Anything else should be done in the `setup'- and
|
|
`finish'-functions. Otherwise modules that other modules depend upon
|
|
may destroy their state too early and wrapper functions in the latter
|
|
modules may stop working since the state they use is already destroyed.
|
|
|
|
Documentation
|
|
-------------
|
|
|
|
* Edit only the .yo files. All other formats (man pages, TeXinfo, HTML,
|
|
etc.) are automatically generated from the yodl source.
|
|
|
|
* Always use the correct markup. em() is used for emphasis, and bf()
|
|
for citations. tt() marks text that is literal input to or output
|
|
from the shell. var() marks metasyntactic variables.
|
|
|
|
* In addition to appropriate markup, always use quotes (`') where
|
|
appropriate. Specifically, use quotes to mark text that is not a part
|
|
of the actual text of the documentation (i.e., that it is being quoted).
|
|
In principle, all combinations of quotes and markup are possible,
|
|
because the purposes of the two devices are completely orthogonal.
|
|
For example,
|
|
|
|
Type `tt(xyzzy)' to let zsh know you have played tt(advent).
|
|
Saying `plugh' aloud doesn't have much effect, however.
|
|
|
|
In this case, "zsh" is normal text (a name), "advent" is a command name
|
|
occurring in the main text, "plugh" is a normal word that is being quoted
|
|
(it's the user that says `plugh', not the documentation), and "xyzzy"
|
|
is some text to be typed literally that is being quoted.
|
|
|
|
* For multiple-line pieces of text that should not be filled, there are
|
|
various models.
|
|
- If the text is pure example, i.e. with no metasyntactic variables etc.,
|
|
it should be included within `example(...)'. The text will be
|
|
indented, will not be filled and will be put into a fixed width font.
|
|
- If the text includes mixed fonts, it should be included within
|
|
`indent(...)'. The text is now filled unless `nofill(...)' is also
|
|
used, and explicit font-changing commands are required inside.
|
|
- If the text appears inside some other format, such as for example the
|
|
`item()' list structure, then the instruction `nofill(...)', which
|
|
simply turns off filling should be used; as with `indent(...)',
|
|
explicit font changing commands are required. This can be used
|
|
without `indent()' when no indentation is required, e.g. if the
|
|
accumulated indentation would otherwise be too long.
|
|
All the above should appear on their own, separated by newlines from the
|
|
surrounding text. No extra newlines after the opening or before the
|
|
closing parenthesis are required.
|
|
|
|
Module names
|
|
------------
|
|
|
|
Modules have hierarchical names. Name segments are separated by `/', and
|
|
each segment consists of alphanumerics plus `_'. Relative names are never
|
|
used; the naming hierarchy is strictly for organisational convenience.
|
|
|
|
Top-level name segments should be organisational identifiers, assigned
|
|
by the Zsh Development Group and recorded here:
|
|
|
|
top-level identifier organisation
|
|
-------------------- ------------
|
|
x_* reserved for private experimental use
|
|
zsh The Zsh Development Group (contact: <coordinator@zsh.org>)
|
|
|
|
Below the top level, naming authority is delegated.
|
|
|
|
|
|
Distribution of files
|
|
---------------------
|
|
|
|
zsh is distributed in two parts: a "src" distribution containing all
|
|
the source files (roughly, but not exactly, corresponding to the git
|
|
tree), and a "doc" distribution containing some pre-built files from
|
|
the documentation directory. All the files in the "doc" distribution
|
|
may be generated from files in the "src" distribution with appropriate
|
|
freely available tools.
|
|
|
|
To indicate which files should be distributed, each directory in the git
|
|
tree includes a file .distfiles that sets any number of a set of Bourne
|
|
shell (scalar) parameters. The value of the parameter is expanded as a
|
|
set of standard command line arguments. Basic globbing is allowed in the
|
|
values.
|
|
|
|
The following parameters are currently used:
|
|
|
|
- DISTFILES_SRC is a list of files from the directory for the "src"
|
|
distribution.
|
|
|
|
- DISTFILES_DOC is a list of files from the directory for the "doc"
|
|
distribution.
|
|
|
|
- DISTFILES_NOT is a list of files that will not be included in a
|
|
distribution, but that need to be present in the git tree. This
|
|
variable is not used by the zsh build process and is present for
|
|
the convenience of external checks.
|
|
|
|
|
|
Use of Git
|
|
----------
|
|
|
|
zsh has migrated from CVS to git for version control. We have so far
|
|
kept our workflow unchanged; to wit:
|
|
|
|
1. change is developed and posted to the zsh-workers mailing list
|
|
2. the zsh-workers list management software adds an X-Seq: header
|
|
3. an entry is added to ChangeLog with details, including the X-Seq:
|
|
header.
|
|
[Open Question: should the first 6 or so characters of the commit
|
|
fingerprint be included, so: "* 12345/deadbeef: frobbed the baz" ?]
|
|
4. this is committed to git as a second commit
|
|
5. this is pushed to the master server
|
|
|
|
Micro Git Tutorial:
|
|
|
|
% $VISUAL file1.c file2.c new-file3.c
|
|
% git add new-file3.c
|
|
% git commit -a
|
|
% git push
|
|
|
|
"git commit -a" automatically finds files which are tracked and have
|
|
been modified, but doesn't pick up new files; "git add" adds a file to
|
|
the index to be part of the next commit, and can be used for new files
|
|
or for existing files (commit -a is a shortcut for the latter)
|
|
|
|
"git push" assumes that you're on the master branch and the repository
|
|
was created by cloning it from some place, with default options.
|
|
|
|
Feature branch work:
|
|
|
|
% git checkout -b feature_foo
|
|
% $VISUAL path/to/files ...
|
|
% git commit -a
|
|
[lather, rinse, repeat]
|
|
% git push origin feature_foo
|
|
[ do mailing-list stuff here ]
|
|
[ Switch back to master: ]
|
|
% git checkout master
|
|
[ and get the most recent changes: ]
|
|
% git pull
|
|
[ make the branch content now be relative to *new* master tip ]
|
|
% git checkout feature_foo
|
|
% git rebase master
|
|
[ then bring in your changes: ]
|
|
% git checkout master
|
|
% git merge --ff-only feature_foo
|
|
% $VISUAL ChangeLog
|
|
% git commit -i ChangeLog
|
|
% git push
|
|
[ Cleanup: ]
|
|
% git branch -d feature_foo
|
|
% git push origin :feature_foo
|
|
|
|
Git further reading:
|
|
* git help tutorial
|
|
* git help tutorial-2
|
|
* git help gitcore-tutorial
|
|
* http://www-cs-students.stanford.edu/~blynn/gitmagic/
|
|
|