From 4da38599c2b3c2397582838a9ac715897af7b1a8 Mon Sep 17 00:00:00 2001
From: Hans Hagen <pragma@wxs.nl>
Date: Tue, 28 Oct 1997 00:00:00 +0100
Subject: stable 1997.10.28

---
 tex/context/base/syst-gen.tex | 2682 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2682 insertions(+)
 create mode 100644 tex/context/base/syst-gen.tex

(limited to 'tex/context/base/syst-gen.tex')

diff --git a/tex/context/base/syst-gen.tex b/tex/context/base/syst-gen.tex
new file mode 100644
index 000000000..b9b3da9d9
--- /dev/null
+++ b/tex/context/base/syst-gen.tex
@@ -0,0 +1,2682 @@
+%D \module 
+%D   [       file=syst-gen,
+%D        version=1996.3.20,
+%D          title=\CONTEXT\ System Macros,
+%D       subtitle=General,
+%D         author=Hans Hagen,
+%D           date=\currentdate,
+%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. Non||commercial use is 
+%C granted. 
+
+%D The following macros are responsible for the interaction
+%D with \CONTEXT. These macros have proven their use. These
+%D macros are optimized as far as possible within of course,
+%D the know how of the author. 
+%D 
+%D In this module we also show some of the optimizations, 
+%D mainly because we don't want to forget them and start doing 
+%D things over and over again. If showing them has a learing 
+%D effect for others too, we've surved another purpose too.  
+
+%D \macros
+%D   {abortinputifdefined}
+%D   {}
+%D
+%D Because this module can be used in a different context, we
+%D want to prevent it being loaded more than once. This can be
+%D done using:
+%D
+%D \starttypen
+%D \abortinputifdefined\command
+%D \stoptypen
+%D
+%D where \type{\command} is a command defined in the module
+%D to be loaded only once.
+%D 
+%D \starttypen
+%D \def\abortinputifdefined#1%
+%D   {\ifx#1\undefined
+%D      \let\next=\relax
+%D    \else
+%D      \let\next=\endinput
+%D    \fi
+%D    \next}
+%D \stoptypen
+%D
+%D This macro can be speed up in terms of speed as well as 
+%D memory. Because this is a nice example of a bit strange 
+%D command (\type{\endinput}), we spend some more lines on this.
+%D
+%D If we perform such actions directly, we can say: 
+%D 
+%D \starttypen 
+%D \ifx\somecommand\undefined
+%D   \let\next=\relax
+%D \else
+%D   \let\next=\endinput
+%D \fi
+%D \next
+%D \stoptypen
+%D 
+%D We need the \type{\next} because we need to end the 
+%D \type{\fi}. The efficient one is: 
+%D 
+%D \starttypen 
+%D \ifx\somecommand\undefined
+%D \else
+%D   \expandafter\endinput 
+%D \fi
+%D \stoptypen
+%D
+%D Because \type{\endinput} comes into action after the current 
+%D line, we can also say:
+%D 
+%D \starttypen 
+%D \ifx\somecommand\undefined \else \endinput \fi
+%D \stoptypen
+%D
+%D When we define a macro, we tend to use a format which 
+%D shows as besat as can how things are done. \TEX\ however 
+%D stores the definitions as a sequence of tokens, so in fact
+%D we can use a formatted definition: 
+
+\def\abortinputifdefined#1%
+  {\ifx#1\undefined \else 
+     \endinput 
+   \fi}
+
+%D which also works. Keep in mind that this is entirely due to 
+%D the fact that \type{\endinput} after the line, i.e. at the 
+%D end of the macro. We therefore can burry this primitive quite
+%D deep in code. 
+
+%D And because this module implements \type{\writestatus}, we
+%D just say:
+
+\abortinputifdefined\writestatus
+
+%D Normally we tell the users what module is being loaded.
+%D However, the command that is needed for this is not yet
+%D defined.
+%D
+%D \starttypen
+%D \writestatus{laden}{Context Systeem Macro's (a)}
+%D \stoptypen
+
+%D \macros
+%D   [beschermen]
+%D   {protect,unprotect}
+%D   {}
+%D
+%D We can shield macros from users by using some special
+%D characters in their names. Some characters that are normally
+%D no letters and therefore often used are: \type{@}, \type{!}
+%D and \type{?}. Before and after the definition of protected
+%D macros, we have to change the \CATCODE\ of these characters.
+%D This is done by \type{\unprotect} and \type{\protect}, for
+%D instance:
+%D
+%D \starttypen
+%D \unprotect
+%D \def\!test{test}
+%D \protect
+%D \stoptypen
+%D
+%D The defined command \type{\!test} can of course only be
+%D called upon when we are in the \type{\unprotect}'ed state,
+%D otherwise \TEX\ reads \type{\!} and probably complains
+%D loudly about not being in math mode.
+%D
+%D Both commands can be used nested, but only the \CATCODE\
+%D of the outermost level is saved. We make use of
+%D an auxilary macro \type{\doprotect} to prevent us from
+%D conflicts with existing macro's \type{\protect}. When
+%D nesting deeper than one level, the system shows the
+%D protection level.
+
+\newcount\protectionlevel
+
+\ifx\protect\undefined
+  \def\protect{\message{<too much protection>}}
+\fi
+
+\let\normalprotect=\protect
+
+%D Although we don't need the \type{%} after commands that
+%D don't take arguments, unless lines are obeyed, I decided 
+%D to put it there as a reminder. I only mention this once. 
+
+\def\unprotect%
+  {\ifnum\protectionlevel=0
+     \edef\doprotectcharacters%
+       {\catcode`@=\the\catcode`@\relax
+        \catcode`!=\the\catcode`!\relax
+        \catcode`?=\the\catcode`?\relax}%
+     \catcode`@=11
+     \catcode`!=11
+     \catcode`?=11
+     \let\protect=\doprotect
+   \fi
+   \advance\protectionlevel by 1
+   \ifnum\protectionlevel>1
+     \message{<unprotect \the\protectionlevel>}%
+   \fi}
+
+\def\doprotect%
+  {\ifnum\protectionlevel=1
+     \doprotectcharacters
+     \let\protect=\normalprotect
+   \fi
+   \ifnum\protectionlevel>1
+     \message{<protect \the\protectionlevel>}%
+   \fi
+   \advance\protectionlevel by -1\relax}
+
+%D Now it is defined, we can make use of this very useful
+%D macro.
+
+\unprotect
+
+%D \macros
+%D   {@@escape,@@begingroup,@@endgroup,@@mathshift,@@alignment,
+%D    @@endofline,@@parameter,@@superscript,@@subscript,
+%D    @@ignore,@@space,@@letter,@@other,@@active,@@comment}
+%D   {}
+%D
+%D In \CONTEXT\ we sometimes manipulate the \CATCODES\ of
+%D certain characters. Because we are not that good at numbers,
+%D we introduce some symbolic names.
+
+\chardef\@@escape      =  0
+\chardef\@@begingroup  =  1
+\chardef\@@endgroup    =  2
+\chardef\@@mathshift   =  3
+\chardef\@@alignment   =  4
+\chardef\@@endofline   =  5
+\chardef\@@parameter   =  6
+\chardef\@@superscript =  7
+\chardef\@@subscript   =  8
+\chardef\@@ignore      =  9
+\chardef\@@space       = 10
+\chardef\@@letter      = 11
+\chardef\@@other       = 12   \chardef\other  = 12
+\chardef\@@active      = 13   \chardef\active = 13
+\chardef\@@comment     = 14
+
+%D \macros
+%D   {normalspace}
+%D   {}
+%D
+%D We often need a space as defined in \PLAIN\ \TEX. Because 
+%D we cannot be sure of \type{\space} is redefined, we define: 
+
+\def\normalspace{ }
+
+%D \macros
+%D   {scratchcounter,
+%D    scratchdimen,scratchskip,scratchmuskip,
+%D    scratchbox,
+%D    scratchtoks
+%D    ifdone}
+%D   {}
+%D
+%D Because we often need counters on a temporary basis, we
+%D define the \COUNTER\ \type{\scratchcounter}. This is a
+%D real \COUNTER, and not a pseudo one, as we will meet
+%D further on. We also define some other scratch registers.
+
+\newcount  \scratchcounter
+\newdimen  \scratchdimen
+\newskip   \scratchskip
+\newmuskip \scratchmuskip
+\newbox    \scratchbox
+\newtoks   \scratchtoks
+\newif     \ifdone
+
+%D \macros
+%D   {ifCONTEXT}
+%D   {}
+%D 
+%D In the system and support modules we sometimes show examples
+%D that make use of core commands. We can skip those parts of
+%D the documentation when we use another macropackage. Of 
+%D course we default to false. 
+
+\newif \ifCONTEXT
+
+%D \macros
+%D   {!!count, !!toks, !!dimen, !!box, 
+%D    !!width, !!height, !!depth, !!string, !!done} 
+%D   {}
+%D
+%D We define some more \COUNTERS\ and \DIMENSIONS. We also 
+%D define some shortcuts to the local scatchregisters~0, 2, 4,
+%D 6 and~8.
+
+\newcount\!!counta \toksdef\!!toksa=0 \dimendef\!!dimena=0 \chardef\!!boxa=0
+\newcount\!!countb \toksdef\!!toksb=2 \dimendef\!!dimenb=2 \chardef\!!boxb=2
+\newcount\!!countc \toksdef\!!toksc=4 \dimendef\!!dimenc=4 \chardef\!!boxc=4
+\newcount\!!countd \toksdef\!!toksd=6 \dimendef\!!dimend=6 \chardef\!!boxd=6
+\newcount\!!counte \toksdef\!!tokse=8 \dimendef\!!dimene=8 \chardef\!!boxe=8
+\newcount\!!countf
+
+\def\!!stringa{} \def\!!stringb{} \def\!!stringc{}
+\def\!!stringd{} \def\!!stringe{} \def\!!stringf{}
+
+\newdimen\!!widtha \newdimen\!!heighta \newdimen\!!deptha \newif\if!!donea
+\newdimen\!!widthb \newdimen\!!heightb \newdimen\!!depthb \newif\if!!doneb
+
+%D \macros
+%D   {s!,c!,e!,p!,v!,@@,??}
+%D   {}
+%D
+%D To save memory, we use constants (sometimes called
+%D variables). Redefining these constants can have desastrous
+%D results.
+
+\def\v!prefix! {v!}           \def\c!prefix! {c!}
+\def\s!prefix! {s!}           \def\p!prefix! {p!} 
+
+\def\s!next    {next}         \def\s!default {default}
+\def\s!dummy   {dummy}        \def\s!unknown {unknown}
+
+\def\s!do      {do}           \def\s!dodo    {dodo}
+
+\def\s!complex {complex}      \def\s!start   {start}
+\def\s!simple  {simple}       \def\s!stop    {stop}
+
+%D \macros
+%D   {@EA,expanded}
+%D   {}
+%D
+%D When in unprotected mode, to be entered with 
+%D \type{\unprotect}, one can use \type{\@EA} as equivalent 
+%D of \type{\expandafter}.
+
+\let\@EA=\expandafter
+
+%D Sometimes we pass macros as arguments to commands that 
+%D don't expand them before interpretation. Such commands can
+%D be enclosed with \type{\expanded}, like: 
+%D
+%D \starttypen
+%D \expanded{\setupsomething[\alfa]} 
+%D \stoptypen
+%D  
+%D Such situations occur for instance when \type{\alfa} is a 
+%D commalist or when data stored in macros is fed to index of
+%D list commands. If needed, one should use \type{\noexpand} 
+%D inside the argument. Later on we will meet some more clever 
+%D alternatives to this command. 
+
+\def\expanded#1%
+  {\edef\@@expanded{\noexpand#1}\@@expanded}
+
+%D \macros
+%D   {gobbleoneargument,gobble...arguments}
+%D   {}
+%D
+%D The next set of macros just do nothing, except that they
+%D get rid of a number of arguments.
+
+\long\def\gobbleoneargument    #1{}
+\long\def\gobbletwoarguments   #1#2{}
+\long\def\gobblethreearguments #1#2#3{}
+\long\def\gobblefourarguments  #1#2#3#4{}
+\long\def\gobblefivearguments  #1#2#3#4#5{}
+\long\def\gobblesixarguments   #1#2#3#4#5#6{}
+\long\def\gobblesevenarguments #1#2#3#4#5#6#7{}
+\long\def\gobbleeightarguments #1#2#3#4#5#6#7#8{}
+\long\def\gobbleninearguments  #1#2#3#4#5#6#7#8#9{}
+
+%D \macros
+%D   {doifnextcharelse}
+%D   {}
+%D
+%D When we started using \TEX\ in the late eighties, our
+%D first experiences with programming concerned a simple shell
+%D around \LATEX. The commands probably use most at \PRAGMA,
+%D are the itemizing ones. One of those few shell commands took
+%D care of an optional argument, that enabled us to specify
+%D what kind of item symbol we wanted. Without understanding
+%D anything we were able to locate a \LATEX\ macro that could
+%D be used to inspect the next character.
+%D
+%D It's this macro that the ancester of the next one presented
+%D here. It executes one of two actions, dependant of the next
+%D character. Disturbing spaces and line endings, which are
+%D normally interpreted as spaces too, are skipped.
+%D
+%D \starttypen
+%D \doifnextcharelse {karakter} {then ...} {else ...}
+%D \stoptypen
+%D
+%D This macro differs from the original in testing on
+%D \type{\endoflinetoken}, which of course we have to define
+%D first. We also use \type{\localnext} because we don't want
+%D clashes with \type{\next}.
+
+\let\endoflinetoken=^^M
+
+\long\def\doifnextcharelse#1#2#3%
+   {\let\charactertoken=#1%
+    \def\!!stringa{#2}%
+    \def\!!stringb{#3}%
+    \futurelet\nexttoken\inspectnextcharacter}
+
+\def\inspectnextcharacter%
+  {\ifx\nexttoken\blankspace
+     \let\localnext\reinspectnextcharacter
+   \else\ifx\!!stringc\endoflinetoken
+     \let\localnext\reinspectnextcharacter
+   \else\ifx\nexttoken\charactertoken
+     \let\localnext\!!stringa
+   \else
+     \let\localnext\!!stringb
+   \fi\fi\fi
+   \localnext}
+
+%D This macro uses some auxiliary macros. Although we were able
+%D to program quite complicated things, I only understood these
+%D after rereading the \TEX book. The trick is in using a
+%D command with a one character name. Such commands differ from
+%D the longer ones in the fact that trailing spaces are {\em
+%D not} skipped. This enables us to indirectly define a long
+%D named macro that gobbles a space.
+%D
+%D In the first line we define \type{\blankspace}. Next we
+%D make \type{\:} equivalent to \type{\reinspect...}. This
+%D one||character command is expanded before the next
+%D \type{\def} comes into action. This way the space after
+%D \type{\:} becomes a delimiter of the longer named
+%D \type{\reinspectnextcharacter}. The chain reaction is
+%D visually compatible with the next sequence:
+%D
+%D \starttypen
+%D \expandafter\def\reinspectnextcharacter %
+%D   {\futurelet\nexttoken\inspectnextcharacter}
+%D \stoptypen
+%D
+%D However complicated it may look, I'm still glad I stumbled
+%D into this construction.
+
+\def\:{\let\blankspace= }  \:
+
+\def\:{\reinspectnextcharacter}
+
+\expandafter\def\: {\futurelet\nexttoken\inspectnextcharacter}
+
+%D \macros
+%D   {setvalue,setgvalue,setevalue,setxvalue,
+%D    letvalue,
+%D    getvalue,
+%D    resetvalue}
+%D   {}
+%D
+%D \TEX's primitive \type{\csname} can be used to construct
+%D all kind of commands that cannot be defined with
+%D \type{\def} and \type{\let}. Every macro programmer sooner
+%D or later wants macros like these.
+%D
+%D \starttypen
+%D \setvalue   {naam}{...} = \def\naam{...}
+%D \setgvalue  {naam}{...} = \gdef\naam{...}
+%D \setevalue  {naam}{...} = \edef\naam{...}
+%D \setxvalue  {naam}{...} = \xdef\naam{...}
+%D \letvalue   {naam}=\... = \let\naam=\...
+%D \getvalue   {naam}      = \naam
+%D \resetvalue {naam}      = \def\naam{}
+%D \stoptypen
+%D
+%D As we will see, \CONTEXT\ uses these commands many times,
+%D which is mainly due to its object oriented and parameter
+%D driven character.
+
+\def\setvalue#1%
+  {\expandafter\def\csname#1\endcsname}
+
+\def\setgvalue#1%
+  {\expandafter\gdef\csname#1\endcsname}
+
+\def\setevalue#1%
+  {\expandafter\edef\csname#1\endcsname}
+
+\def\setxvalue#1%
+  {\expandafter\xdef\csname#1\endcsname}
+
+\def\getvalue#1%
+  {\csname#1\endcsname}
+
+\def\letvalue#1%
+  {\expandafter\let\csname#1\endcsname}
+
+\def\resetvalue#1%
+  {\setvalue{#1}{}}
+
+%D \macros
+%D   {donottest,unexpanded}
+%D   {}
+%D
+%D When expansion of a macro gives problems, we can precede it
+%D by \type{\donottest}. It seems that protection is one of the
+%D burdens of developers of packages, so maybe that's why in
+%D e-\TeX\ protection will be solved in a more robust way.
+%D
+%D Sometimes prefixing the macro with \type{\donottest} leads
+%D to defining an auxiliary macro, like
+%D
+%D \starttypen
+%D \def\dosomecommand {... ... ...}
+%D \def\somecommand   {\donottest\dosomecommand}
+%D \stoptypen
+%D
+%D This double definition can be made transparant by using 
+%D \type{\protecte}, as in:
+%D 
+%D \starttypen
+%D \unexpanded\def\somecommand{... ... ...}
+%D \stoptypen
+%D 
+%D The protection mechanism uses:
+
+\def\dontprocesstest#1% 
+  {==}
+
+\def\doprocesstest#1%
+  {#1}
+
+\let\donottest=\doprocesstest
+
+%D By the way, we use a placeholder because we don't want 
+%D interference when testing on empty strings. Using a 
+%D placeholder of 8~characters increases the processing time 
+%D of simple \type{\doifelse} tests by about 10 \%. When we 
+%D process the test, we have to remove the braces and 
+%D therefore explictly gobble \type{#1}. 
+
+%D The fact that many macros have the same prefix, could have
+%D a negative impact on searching in the hash table. Because
+%D some simple testing does not show differences, we just use:
+%D 
+%D \starttypen
+%D \def\unexpanded#1#2%
+%D   {\@EA#1\@EA#2\@EA{\@EA\donottest\csname\s!do\string#2\endcsname}%
+%D    \@EA#1\csname\s!do\string#2\endcsname}
+%D \stoptypen
+%D 
+%D Well, in fact we use the bit more versaatile alternative: 
+
+\def\dosetunexpanded#1#2%
+  {\@EA#1\@EA{\@EA#2\@EA}%
+     \@EA{\@EA\donottest\csname\s!do\@EA\string\csname#2\endcsname\endcsname}%
+   \@EA#1{\s!do\@EA\string\csname#2\endcsname}}
+
+\def\docomunexpanded#1#2%
+  {\@EA#1\@EA#2\@EA{\@EA\donottest\csname\s!do\string#2\endcsname}%
+   \@EA#1\csname\s!do\string#2\endcsname}
+
+\def\unexpanded#1%
+  {\def\dounexpanded%
+     {\ifx\next\bgroup
+        \@EA\dosetunexpanded
+      \else
+        \@EA\docomunexpanded
+      \fi#1}%
+   \futurelet\next\dounexpanded}
+
+%D This one accepts the more direct \type{\def} and cousins 
+%D as well as the \CONTEXT\ specific \type{\setvalue} ones. 
+%D
+%D And so the definition in our example turns out to be:
+%D
+%D \starttypen
+%D \def\csname do\somecommand\endcsname{... ... ...}
+%D \def\somecommand{\donottest\csname do\somecommand\endcsname}
+%D \stoptypen
+%D
+%D In which \type{do\somecommand} is hidden from the user and 
+%D cannot lead to confusion. It's still permitted to define 
+%D auxiliary macros like \type{\dosomecommand}.  
+%D
+%D When we are going to use e-\TEX, we'll probably end up 
+%D redefining some commands, but we can probably keep the 
+%D \type{\unexpanded} ones unchanged. 
+
+%D \macros
+%D   {doifundefined,doifdefined,
+%D    doifundefinedelse,doifdefinedelse,
+%D    doifalldefinedelse}
+%D   {}
+%D
+%D The standard way of testing if a macro is defined is
+%D comparing its meaning with another undefined one, usually
+%D \type{\undefined}. To garantee correct working of the next
+%D set of macros, \type{\undefined} may never be defined!
+%D
+%D \starttypen
+%D \doifundefined      {string}    {...}
+%D \doifdefined        {string}    {...}
+%D \doifundefinedelse  {string}    {then ...} {else ...}
+%D \doifdefinedelse    {string}    {then ...} {else ...}
+%D \doifalldefinedelse {commalist} {then ...} {else ...}
+%D \stoptypen
+%D
+%D Every macroname that \TEX\ builds gets an entry in the hash
+%D table, which is of limited size. It is expected that e-\TeX\
+%D will offer a less memory||consuming alternative.
+
+%D Although it will probably never be a big problem, it is good
+%D to be aware of the difference between testing on a macro
+%D name to be build by using \type{\csname} and
+%D \type{\endcsname} and testing the \type{\name} directly. 
+%D 
+%D \starttypen
+%D \expandafter\ifx\csname NameA\endcsname\relax ... \else ... \fi
+%D 
+%D \ifx\NameB\undefined ... \else ... \fi
+%D \stoptypen
+%D 
+%D I became aware of this when I mistakenly testen the first
+%D one against \type{\undefined}. When \TEX\ build a name using
+%D \type{\csname} it automatically sets it to \type{\relax},
+%D which is definitely not the same as \type{\undefined}. The
+%D quickest way to check these things is asking \TEX\ to show
+%D the meaning of the names: 
+%D 
+%D \starttypen
+%D \expandafter\show\csname NameA\endcsname
+%D 
+%D \show\NameB
+%D \stoptypen
+%D
+%D The main reason why this never will be a big problem is that
+%D when one uses the \type{\csname} way, one probably has to do
+%D with some macroname that always is dealt with that way.
+%D Confusion can however arise when one applies both testing
+%D methods to the same macroname. By the way, the assignment
+%D of \type{\relax} obeys grouping. 
+
+%D The first one gets rid of \type{#1}, but still expands to
+%D something and the second one expands to \type{#1}. Because
+%D we accept arguments between \type{{}}, we have to get rid
+%D of one level of braces.
+%D
+%D Our first implementation of \type{\ifundefined} was
+%D straightforward and readable:
+%D
+%D \starttypen
+%D \def\ifundefined#1%
+%D   {\expandafter\ifx\csname#1\endcsname\relax}%
+%D
+%D \def\doifundefinedelse#1#2#3%
+%D   {\let\donottest=\dontprocesstest
+%D    \ifundefined{#1}%
+%D      \let\donottest=\doprocesstest#2%
+%D    \else
+%D      \let\donottest=\doprocesstest#3%
+%D    \fi}
+%D
+%D \def\doifdefinedelse#1#2#3%
+%D   {\doifundefinedelse{#1}{#3}{#2}}
+%D
+%D \def\doifundefined#1#2%
+%D   {\doifundefinedelse{#1}{#2}{}}
+%D
+%D \def\doifdefined#1#2%
+%D   {\doifundefinedelse{#1}{}{#2}}
+%D
+%D \def\doifalldefinedelse#1#2#3%
+%D   {\bgroup
+%D    \donetrue
+%D    \def\checkcommand##1%
+%D      {\doifundefined{##1}{\donefalse}}%
+%D    \processcommalist[#1]\checkcommand
+%D    \ifdone
+%D      \egroup#2%
+%D    \else
+%D      \egroup#3%
+%D    \fi}
+%D \stoptypen
+%D
+%D When this module was optimized, timing showed that the
+%D next alternative can be upto twice as fast, especially when
+%D longer arguments are used.
+
+\def\ifundefined#1%
+  {\expandafter\ifx\csname#1\endcsname\relax}
+
+\def\p!doifundefined#1%
+  {\let\donottest=\dontprocesstest
+   \expandafter\ifx\csname#1\endcsname\relax}
+
+\def\doifundefinedelse#1#2#3%
+  {\p!doifundefined{#1}%
+     \let\donottest=\doprocesstest#2%
+   \else
+     \let\donottest=\doprocesstest#3%
+   \fi}
+
+\def\doifdefinedelse#1#2#3%
+  {\p!doifundefined{#1}%
+     \let\donottest=\doprocesstest#3%
+   \else
+     \let\donottest=\doprocesstest#2%
+   \fi}
+
+\def\doifundefined#1#2%
+  {\p!doifundefined{#1}%
+     \let\donottest=\doprocesstest#2%
+   \else
+     \let\donottest=\doprocesstest
+   \fi}
+
+\def\doifdefined#1#2%
+  {\p!doifundefined{#1}%
+     \let\donottest=\doprocesstest
+   \else
+     \let\donottest=\doprocesstest#2%
+   \fi}
+
+%D Before we start using this variant, we used another one, 
+%D which is even a bit faster. This one looked like: 
+%D 
+%D \starttypen
+%D \def\p!doifundefined%
+%D   {\begingroup
+%D    \let\donottest=\dontprocesstest
+%D    \ifundefined}
+%D 
+%D \def\doifundefinedelse#1#2#3%
+%D   {\p!doifundefined{#1}%
+%D      \endgroup#2%
+%D    \else
+%D      \endgroup#3%
+%D    \fi}
+%D \stoptypen
+%D 
+%D A even more previous version used \type{\bgroup} and 
+%D \type{\egroup}. In math mode however, \type{$1{x}2$} differs
+%D from \type{$1x2$}. This can been seen when one compares the 
+%D output of: 
+%D 
+%D \starttypen 
+%D $\kern10pt\showthe\lastkern$
+%D $\kern10pt{\showthe\lastkern}$
+%D $\kern10pt\begingroup\showthe\lastkern\endgroup$
+%D \stoptypen
+%D 
+%D When we were developing the scientific units module, we 
+%D encountered different behavior in text and math mode, which 
+%D was due to this grouping subtilities. We therefore decided 
+%D to use \type{\begingroup} instead of \type{\bgroup}. 
+%D Later, when we had optimized some macro's the grouped 
+%D solution turned out to be unsafe when typesetting this 
+%D documentation, especially when using \type{\globaldefs}. 
+%D
+%D We still have to define \type{\doifalldefinedelse}. Watch 
+%D the use of grouping, which garantees local use of the 
+%D boolean \type{\ifdone}.
+
+\def\docheckonedefined#1%
+  {\ifundefined{#1}%
+     \donefalse
+   \fi}
+
+\def\doifalldefinedelse#1#2#3%
+  {\begingroup
+   \let\donottest=\dontprocesstest
+   \donetrue
+   \processcommalist[#1]\docheckonedefined
+   \ifdone
+     \endgroup\let\donottest=\doprocesstest#2%
+   \else
+     \endgroup\let\donottest=\doprocesstest#3%
+   \fi}
+
+%D \macros
+%D   {doif,doifelse,doifnot,
+%D    donottest}
+%D   {}
+%D
+%D Programming in \TEX\ differs from programming in procedural
+%D languages like \MODULA. This means that one --- well, let me
+%D speek for myself --- tries to do the things in the well
+%D known way. Therefore the next set of \type{\ifthenelse}
+%D commands were between the first ones we needed. A few years
+%D later, the opposite became true: when programming in
+%D \MODULA, I sometimes miss handy things like grouping,
+%D runtime redefinition, expansion etc. While \MODULA\ taught
+%D me to structure, \TEX\ taught me to think recursive.
+%D
+%D \starttypen
+%D \doif     {string1} {string2} {...}
+%D \doifnot  {string1} {string2} {...}
+%D \doifelse {string1} {string2} {then ...}{else ...}
+%D \stoptypen
+%D
+%D When expansion gives problems, we can precede the
+%D troublemaker with \type{\donottest}.
+%D
+%D This implementatie does not use the construction which is
+%D more robust for nested conditionals.
+%D
+%D \starttypen
+%D \ifx\!!stringa\!!stringb
+%D   \def\next{#3}%
+%D \else
+%D   \def\next{#4}%
+%D \fi
+%D \next
+%D \stoptypen
+%D
+%D In practice, this alternative is at least 20\% slower than
+%D the alternative used here. The few cases in which we
+%D really need the \type{\next} construction, often need some
+%D other precautions and or adaptions too.
+
+\long\def\doif#1#2#3%
+  {\let\donottest=\dontprocesstest
+   \edef\!!stringa{#1}%
+   \edef\!!stringb{#2}%
+   \let\donottest=\doprocesstest
+   \ifx\!!stringa\!!stringb
+     #3%
+   \fi}
+
+\long\def\doifnot#1#2#3%
+  {\let\donottest=\dontprocesstest
+   \edef\!!stringa{#1}%
+   \edef\!!stringb{#2}%
+   \let\donottest=\doprocesstest
+   \ifx\!!stringa\!!stringb
+   \else
+     #3%
+   \fi}
+
+\long\def\doifelse#1#2#3#4%
+  {\let\donottest=\dontprocesstest
+   \edef\!!stringa{#1}%
+   \edef\!!stringb{#2}%
+   \let\donottest=\doprocesstest
+   \ifx\!!stringa\!!stringb
+     #3%
+   \else
+     #4%
+   \fi}
+
+%D One could wonder why we don't follow the the same approach
+%D as in \type{\doifdefined} c.s.\ and use \type{\begingroup} 
+%D and \type{\endgroup}. In this case, this alternative is 
+%D slower, which is probably due to the fact that more meanings
+%D need to be restored.
+%D
+%D The in terms of memory more efficient alternative using a
+%D auxiliary macro also proved to be slower, so we definitely
+%D did not choose for:
+%D
+%D \starttypen
+%D \def\p!doifelse#1#2%
+%D   {\let\donottest=\dontprocesstest
+%D    \edef\!!stringa{#1}%
+%D    \edef\!!stringb{#2}%
+%D    \let\donottest=\doprocesstest
+%D    \ifx\!!stringa\!!stringb}
+%D
+%D \long\def\doif#1#2#3%
+%D   {\p!doifelse{#1}{#2}#3\fi}
+%D
+%D \long\def\doifnot#1#2#3%
+%D   {\p!doifelse{#1}{#2}\else#3\fi}
+%D
+%D \long\def\doifelse#1#2#3#4%
+%D   {\p!doifelse{#1}{#2}#3\else#4\fi}
+%D \stoptypen
+%D
+%D Optimizations like this are related of course to the
+%D bottlenecks in \TEX. It seems that restoring saved meanings
+%D and passing arguments takes some time.
+
+%D \macros
+%D   {doifempty,doifemptyelse,doifnotempty}
+%D   {}
+%D
+%D We complete our set of conditionals with:
+%D
+%D \starttypen
+%D \doifempty     {string} {...}
+%D \doifnot       {string} {...}
+%D \doifemptyelse {string} {then ...} {else ...}
+%D \stoptypen
+%D
+%D This time, the string is not expanded.
+
+\long\def\doifemptyelse#1#2#3%
+  {\def\!!stringa{#1}%
+   \ifx\!!stringa\empty
+     #2%
+   \else
+     #3%
+   \fi}
+
+\long\def\doifempty#1#2%
+  {\def\!!stringa{#1}%
+   \ifx\!!stringa\empty
+     #2%
+   \fi}
+
+\long\def\doifnotempty#1#2%
+  {\def\!!stringa{#1}%
+   \ifx\!!stringa\empty
+   \else
+     #2%
+   \fi}
+
+%D \macros
+%D   {doifinset,doifnotinset,doifinsetelse}
+%D   {}
+%D
+%D We can check if a string is present in a comma separated
+%D set of strings. Depending on the result, some action is
+%D taken.
+%D
+%D \starttypen
+%D \doifinset     {string} {string,...} {...}
+%D \doifnotinset  {string} {string,...} {...}
+%D \doifinsetelse {string} {string,...} {then ...} {else ...}
+%D \stoptypen
+%D
+%D The second argument is the comma separated set of strings.
+%D
+%D \starttypen
+%D \long\def\doifinsetelse#1#2#3#4%
+%D   {\doifelse{#1}{}
+%D      {#4}
+%D      {\donefalse
+%D       \def\v!checkiteminset##1%
+%D         {\doif{#1}{##1}
+%D            {\donetrue
+%D             \let\v!checkiteminset=\gobbleoneargument}}%
+%D       \processcommalist[#2]\v!checkiteminset
+%D       \ifdone
+%D         #3%
+%D       \else
+%D         #4%
+%D       \fi}}
+%D
+%D \long\def\doifinset#1#2#3%
+%D   {\doifinsetelse{#1}{#2}{#3}{}}
+%D
+%D \long\def\doifnotinset#1#2#3%
+%D   {\doifinsetelse{#1}{#2}{}{#3}}
+%D \stoptypen
+%D
+%D Because this macro is called quite often we've spent some
+%D time optimizing it. This time, the gain in speed is due to
+%D (1)~defining an external auxiliary macro, (2)~not calling
+%D any other macros and (3)~minimizing the passing of
+%D arguments. The gain in speed is impressive.
+
+\def\p!dodocheckiteminset#1%
+  {\edef\!!stringb{#1}%
+   \ifx\!!stringa\!!stringb
+     \donetrue
+     \let\p!docheckiteminset=\gobbleoneargument
+   \fi}
+
+\def\p!doifinsetelse#1#2%
+  {\let\donottest=\dontprocesstest
+   \donefalse
+   \edef\!!stringa{#1}%
+   \ifx\!!stringa\empty
+   \else
+     \let\p!docheckiteminset=\p!dodocheckiteminset
+     \processcommalist[#2]\p!docheckiteminset
+   \fi
+   \let\donottest=\doprocesstest
+   \ifdone}
+
+\long\def\doifinsetelse#1#2#3#4%
+  {\p!doifinsetelse{#1}{#2}%
+     #3%
+   \else
+     #4%
+   \fi}
+
+\long\def\doifinset#1#2#3%
+  {\p!doifinsetelse{#1}{#2}%
+     #3%
+   \fi}
+
+\long\def\doifnotinset#1#2#3%
+  {\p!doifinsetelse{#1}{#2}%
+   \else
+     #3%
+   \fi}
+
+%D \macros
+%D   {doifcommon,doifnotcommon,doifcommonelse}
+%D   {}
+%D
+%D Probably the most time consuming tests are those that test
+%D for overlap in sets of strings.
+%D
+%D \starttypen
+%D \doifcommon     {string,...} {string,...} {...}
+%D \doifnotcommon  {string,...} {string,...} {...}
+%D \doifcommonelse {string,...} {string,...} {then ...} {else ...}
+%D \stoptypen
+%D
+%D We show the slower alternative first, because it shows us
+%D how things are done.
+%D
+%D \starttypen
+%D \long\def\doifcommonelse#1#2#3#4%
+%D   {\donefalse
+%D    \def\p!docommoncheck##1%
+%D      {\def\p!dodocommoncheck####1%
+%D         {\doif{####1}{##1}
+%D            {\donetrue
+%D             \def\commalistelement{##1}%
+%D             \let\p!docommoncheck=\gobbleoneargument
+%D             \let\p!dodocommoncheck=\gobbleoneargument}}%
+%D       \processcommalist[#2]\p!dodocommoncheck}%
+%D    \processcommalist[#1]\p!docommoncheck
+%D    \ifdone
+%D      #3%
+%D    \else
+%D      #4%
+%D    \fi}
+%D
+%D \long\def\doifcommon#1#2#3%
+%D   {\doifcommonelse{#1}{#2}{#3}{}}
+%D
+%D \long\def\doifnotcommon#1#2#3%
+%D   {\doifcommonelse{#1}{#2}{}{#3}}
+%D \stoptypen
+%D
+%D The processing time is shortened by getting the auxiliary
+%D macro to the outermost level and using less \type{\edef}'s.
+%D Sometimes it makes more sence to define local macro's not
+%D only because this way we can be sure that they are not
+%D redefined, but also because it shows the dependance. In
+%D compiled languages, this is no problem at all. It can even
+%D save us bytes and processing time. In interpreted languages
+%D like \TEX\ it nearly always slows down processing.
+
+\def\p!dododocommoncheck#1%
+  {\edef\!!stringb{#1}%
+   \ifx\!!stringa\!!stringb
+     \donetrue
+     \let\p!docommoncheck\gobbleoneargument
+     \let\p!dodocommoncheck\gobbleoneargument
+   \fi}
+
+\def\p!doifcommonelse#1#2%
+  {\donefalse
+   \let\donottest\dontprocesstest
+   \let\p!dodocommoncheck\p!dododocommoncheck
+   \def\p!docommoncheck##1%
+     {\edef\!!stringa{##1}%
+      \def\commalistelement{##1}%
+      \processcommalist[#2]\p!dodocommoncheck}%
+   \processcommalist[#1]\p!docommoncheck
+   \let\donottest\doprocesstest
+   \ifdone}
+
+\long\def\doifcommonelse#1#2#3#4%
+  {\p!doifcommonelse{#1}{#2}%
+     #3%
+   \else
+     #4%
+   \fi}
+
+\long\def\doifcommon#1#2#3%
+  {\p!doifcommonelse{#1}{#2}%
+     #3%
+   \fi}
+
+\long\def\doifnotcommon#1#2#3%
+  {\p!doifcommonelse{#1}{#2}%
+   \else
+     #3%
+   \fi}
+
+%D \macros
+%D   {processcommalist,processcommacommand,
+%D    processcommalistwithparameters}
+%D   {}
+%D
+%D We've already seen some macros that take care of comma
+%D separated lists. Such list can be processed with
+%D
+%D \starttypen
+%D \processcommalist[string,string,...]\commando
+%D \stoptypen
+%D
+%D The user supplied command \type{\commando} receives one
+%D argument: the string. This command permits nesting and 
+%D spaces after commas are skipped. Empty sets are no problem.
+%D 
+%D \startbuffer
+%D \def\dosomething#1{(#1)}
+%D
+%D \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par
+%D \processcommalist [{a,b,c,d,e,f}]        \dosomething \par
+%D \processcommalist [{a,b,c},d,e,f]        \dosomething \par
+%D \processcommalist [a,b,{c,d,e},f]        \dosomething \par
+%D \processcommalist [a{b,c},d,e,f]         \dosomething \par
+%D \processcommalist [{a,b}c,d,e,f]         \dosomething \par
+%D \processcommalist []                     \dosomething \par
+%D \processcommalist [{[}]                  \dosomething \par
+%D \stopbuffer
+%D 
+%D \typebuffer
+%D
+%D Before we show the result, we present the macro's: 
+
+\newcount\commalevel
+
+\def\dododoprocesscommaitem%
+  {\csname\s!next\the\commalevel\endcsname}
+
+\def\dodoprocesscommaitem%
+  {\ifx\nexttoken\blankspace
+     \let\nextcommaitem\redoprocesscommaitem
+  %\else\ifx\nexttoken\endoflinetoken
+    %\let\nextcommaitem\redoprocesscommaitem
+   \else\ifx\nexttoken]%
+     \let\nextcommaitem=\gobbleoneargument
+   \else
+     \let\nextcommaitem=\dododoprocesscommaitem
+   \fi\fi%\fi
+   \nextcommaitem}
+
+\def\doprocesscommaitem%
+  {\futurelet\nexttoken\dodoprocesscommaitem}
+
+\def\doprocesscommalist#1]#2%
+  {\advance\commalevel by 1\relax
+   \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,%
+     {#2{##1}\doprocesscommaitem}%
+   \doprocesscommaitem#1,]\relax
+   \advance\commalevel by -1\relax}
+
+%D Empty arguments are not processed. Empty items (\type{,,})
+%D however are treated. 
+
+\def\docheckcommaitem%
+  {\ifx\nexttoken]%
+     \let\nextcommaitem=\gobbletwoarguments
+   \else
+     \let\nextcommaitem=\doprocesscommalist
+   \fi
+   \nextcommaitem}
+
+\def\processcommalist[%
+  {\futurelet\nexttoken\docheckcommaitem}
+
+%D We use the same hack for checking the next character, that
+%D we use in \type{\doifnextcharelse}. 
+
+\def\:{\redoprocesscommaitem}
+
+\expandafter\def\: {\futurelet\nexttoken\dodoprocesscommaitem}
+
+%D The previous examples lead to:
+%D
+%D \haalbuffer
+
+%D When a list is saved in a macro, we can use a construction
+%D like:
+%D
+%D \starttypen
+%D \expandafter\processcommalist\expandafter[\list]\command
+%D \stoptypen
+%D
+%D Such solutions suit most situations, but we wanted a bit
+%D more.
+%D
+%D \starttypen
+%D \processcommacommand[string,\stringset,string]\commando
+%D \stoptypen
+%D
+%D where \type{\stringset} is a predefined set, like:
+%D
+%D \starttypen
+%D \def\first{aap,noot,mies}
+%D \def\second{laatste}
+%D
+%D \processcommacommand[\first]\message
+%D \processcommacommand[\first,second,third]\message
+%D \processcommacommand[\first,between,\second]\message
+%D \stoptypen
+%D
+%D Commands that are part of the list are expanded, so the
+%D use of this macro has it slimits.
+
+\def\processcommacommand[#1]%
+  {\edef\commacommand{#1}%
+   \toks0=\expandafter{\expandafter[\commacommand]}%
+   \expandafter\processcommalist\the\toks0 }
+
+%D The argument to \type{\command} is not delimited. Because
+%D we often use \type{[]} as delimiters, we also have:
+%D
+%D \starttypen
+%D \processcommalistwithparameters[string,string,...]\command
+%D \stoptypen
+%D
+%D where \type{\command} looks like:
+%D
+%D \starttypen
+%D \def\command[#1]{... #1 ...}
+%D \stoptypen
+
+\def\processcommalistwithparameters[#1]#2%
+  {\def\docommand##1{#2[##1]}%
+   \processcommalist[#1]\docommand}
+
+%D \macros
+%D   {processaction,
+%D    processfirstactioninset,
+%D    processallactionsinset}
+%D   {}
+%D
+%D \CONTEXT\ makes extensive use of a sort of case or switch
+%D command. Depending of the presence of one or more provided
+%D items, some actions is taken. These macros can be nested
+%D without problems.
+%D
+%D \starttypen
+%D \processaction           [x]     [a=>\a,b=>\b,c=>\c]
+%D \processfirstactioninset [x,y,z] [a=>\a,b=>\b,c=>\c]
+%D \processallactionsinset  [x,y,z] [a=>\a,b=>\b,c=>\c]
+%D \stoptypen
+%D
+%D We can supply both a \type{default} action and an action
+%D to be undertaken when an \type{unknown} value is met:
+%D
+%D \starttypen
+%D \processallactionsinset
+%D   [x,y,z]
+%D   [      a=>\a,
+%D          b=>\b,
+%D          c=>\c,
+%D    default=>\default,
+%D    unknown=>\unknown{... \commalistelement ...}]
+%D \stoptypen
+%D 
+%D When \type{#1} is empty, this macro scans list \type{#2} for
+%D the keyword \type{default} and executed the related action
+%D if present. When \type{#1} is non empty and not in the list,
+%D the action related to \type{unknown} is executed. Both
+%D keywords must be at the end of list \type{#2}. Afterwards,
+%D the actually found keyword is available in
+%D \type{\commalistelement}. An advanced example of the use of
+%D this macro can be found in \PPCHTEX, where we completely
+%D rely on \TEX\ for interpreting user supplied keywords like
+%D \type{SB}, \type{SB1..6}, \type{SB125} etc. 
+%D 
+%D Even a quick glance at the macros below show some overlap,
+%D which means that more efficient alternatives are possible.
+%D Because these macro's are very sensitive to subtle changes,
+%D we've decided to present the readable originals first
+%D Maybe these these macros look complicated, but this is a
+%D direct result of the support of nesting. Protection is only
+%D applied in \type{\processaction}.
+%D
+%D \starttypen
+%D \newcount\processlevel
+%D
+%D \def\processaction[#1]#2[#3]%
+%D   {\doifelse{#1}{}
+%D      {\def\c!compareprocessaction[##1=>##2]%
+%D         {\edef\!!stringa{##1}%
+%D          \ifx\!!stringa\s!default
+%D            \def\commalistelement{#1}%
+%D            ##2%
+%D          \fi}}
+%D      {\let\donottest=\dontprocesstest
+%D       \edef\!!stringb{#1}%
+%D       \let\donottest=\doprocesstest
+%D       \def\c!compareprocessaction[##1=>##2]%
+%D         {\edef\!!stringa{##1}%
+%D          \ifx\!!stringa\!!stringb
+%D            \def\commalistelement{#1}%
+%D            ##2%
+%D            \let\c!doprocessaction=\gobbleoneargument
+%D          \else\ifx\!!stringa\s!unknown
+%D            \def\commalistelement{#1}%
+%D            ##2%
+%D          \fi\fi}}%
+%D    \def\c!doprocessaction##1%
+%D      {\c!compareprocessaction[##1]}%
+%D    \processcommalist[#3]\c!doprocessaction}
+%D
+%D \def\processfirstactioninset[#1]#2[#3]%
+%D   {\doifelse{#1}{}
+%D      {\processaction[][#3]}
+%D      {\def\c!compareprocessaction[##1=>##2][##3]%
+%D         {\edef\!!stringa{##1}%
+%D          \edef\!!stringb{##3}%
+%D          \ifx\!!stringa\!!stringb
+%D            \def\commalistelement{##3}%
+%D            ##2%
+%D            \let\c!doprocessaction=\gobbleoneargument
+%D            \let\c!dodoprocessaction=\gobbleoneargument
+%D          \else\ifx\!!stringa\s!unknown
+%D            \def\commalistelement{##3}%
+%D            ##2%
+%D          \fi\fi}%
+%D       \def\c!doprocessaction##1%
+%D         {\def\c!dodoprocessaction####1%
+%D            {\c!compareprocessaction[####1][##1]}%
+%D          \processcommalist[#3]\c!dodoprocessaction}%
+%D       \processcommalist[#1]\c!doprocessaction}}
+%D
+%D \def\processallactionsinset[#1]#2[#3]%
+%D   {\doifelse{#1}{}
+%D      {\processaction[][#3]}
+%D      {\advance\processlevel by 1\relax
+%D       \def\c!compareprocessaction[##1=>##2][##3]%
+%D         {\edef\!!stringa{##1}%
+%D          \edef\!!stringb{##3}%
+%D          \ifx\!!stringa\!!stringb
+%D            \def\commalistelement{##3}%
+%D            ##2%
+%D            \let\c!dodoprocessaction=\gobbleoneargument
+%D          \else\ifx\!!stringa\s!unknown
+%D            \def\commalistelement{##3}%
+%D            ##2%
+%D          \fi\fi}%
+%D       \setvalue{\s!do\the\processlevel}##1%
+%D         {\def\c!dodoprocessaction####1%
+%D            {\c!compareprocessaction[####1][##1]}%
+%D          \processcommalist[#3]\c!dodoprocessaction}%
+%D       \processcommalist[#1]{\getvalue{\s!do\the\processlevel}}%
+%D       \advance\processlevel by -1\relax}}
+%D \stoptypen
+%D
+%D The gain of speed in the final implementation is around
+%D 20\%, depending on the application.
+
+\newcount\processlevel
+
+\def\v!compareprocessactionA[#1=>#2]%
+  {\edef\!!stringb{#1}%
+   \ifx\!!stringb\s!default
+     #2%
+   \fi}
+
+\def\v!compareprocessactionB[#1=>#2]%
+  {\expandedaction\!!stringb{#1}%
+   \ifx\!!stringa\!!stringb
+     \def\commalistelement{#1}%
+     #2%
+     \let\p!doprocessaction=\gobbleoneargument
+   \else
+     \edef\!!stringb{#1}%
+     \ifx\!!stringb\s!unknown
+       \def\commalistelement{#1}%
+       #2%
+     \fi
+   \fi}
+
+\def\processaction[#1]#2[#3]%
+  {\let\donottest=\dontprocesstest
+   \expandedaction\!!stringa{#1}%
+   \let\donottest=\doprocesstest
+   \ifx\!!stringa\empty
+     \let\v!compareprocessaction=\v!compareprocessactionA
+   \else
+     \let\v!compareprocessaction=\v!compareprocessactionB
+   \fi
+   \def\p!doprocessaction##1%
+     {\v!compareprocessaction[##1]}%
+   \processcommalist[#3]\p!doprocessaction
+   \expandactions}
+
+\def\v!compareprocessactionC[#1=>#2][#3]%
+  {\expandedaction\!!stringa{#1}%
+   \expandedaction\!!stringb{#3}%
+   \ifx\!!stringa\!!stringb
+     \def\commalistelement{#3}%
+     #2%
+     \let\p!doprocessaction=\gobbleoneargument
+     \let\p!dodoprocessaction=\gobbleoneargument
+   \else
+     \edef\!!stringa{#1}%
+     \ifx\!!stringa\s!unknown
+       \def\commalistelement{#3}%
+       #2%
+     \fi
+   \fi}
+
+\def\processfirstactioninset[#1]#2[#3]%
+  {\expandedaction\!!stringa{#1}%
+   \ifx\!!stringa\empty
+     \processaction[][#3]%
+   \else
+     \def\p!doprocessaction##1%
+       {\def\p!dodoprocessaction####1%
+          {\v!compareprocessactionC[####1][##1]}%
+        \processcommalist[#3]\p!dodoprocessaction}%
+     \processcommalist[#1]\p!doprocessaction
+   \fi
+   \expandactions}
+
+\def\v!compareprocessactionD[#1=>#2][#3]%
+  {\expandedaction\!!stringa{#1}%
+   \expandedaction\!!stringb{#3}%
+   \ifx\!!stringa\!!stringb
+     \def\commalistelement{#3}%
+     #2%
+     \let\p!dodoprocessaction=\gobbleoneargument
+   \else
+     \edef\!!stringa{#1}%
+     \ifx\!!stringa\s!unknown
+       \def\commalistelement{#3}%
+       #2%
+     \fi
+   \fi}
+
+\def\processallactionsinset[#1]#2[#3]%
+  {\expandedaction\!!stringa{#1}%
+   \ifx\!!stringa\empty
+     \processaction[][#3]%
+   \else
+     \advance\processlevel by 1\relax
+     \setvalue{\s!do\the\processlevel}##1%
+       {\def\p!dodoprocessaction####1%
+          {\v!compareprocessactionD[####1][##1]}%
+        \processcommalist[#3]\p!dodoprocessaction}%
+     \processcommalist[#1]{\getvalue{\s!do\the\processlevel}}%
+     \advance\processlevel by -1\relax
+   \fi 
+   \expandactions}
+
+%D \macros
+%D   {unexpandedprocessaction,
+%D    unexpandedprocessfirstactioninset,
+%D    unexpandedprocessallactionsinset}
+%D   {}
+%D
+%D Now what are those expansion commands doing there. Well, 
+%D sometimes we want to compare actions that may consist off
+%D commands (i.e. are no constants). In such occasions we can 
+%D use the a bit slower alternatives: 
+
+\def\unexpandedprocessfirstactioninset{\dontexpandactions\processfirstactioninset}
+\def\unexpandedprocessaction          {\dontexpandactions\processaction}
+\def\unexpandedprocessallactionsinset {\dontexpandactions\processallactionsinset}
+
+%D By default we expand actions: 
+
+\def\expandactions%
+  {\let\expandedaction=\edef}
+
+\expandactions
+
+%D But when needed we convert the strings to meaningful 
+%D sequences of characters.  
+
+\def\unexpandedaction#1>{}
+
+\def\noexpandedaction#1#2%
+  {\def\convertedargument{#2}%
+   \@EA\edef\@EA#1\@EA{\@EA\unexpandedaction\meaning\convertedargument}}
+
+\def\dontexpandactions%
+  {\let\expandedaction=\noexpandedaction}
+
+%D \macros
+%D   {getfirstcharacter,firstcharacter}
+%D   {}
+%D
+%D Sometimes the action to be undertaken depends on the
+%D next character. This macro get this character and puts it in
+%D \type{\firstcharacter}.
+%D
+%D \starttypen
+%D \getfirstcharacter {string}
+%D \stoptypen
+%D
+%D A two step expansion is used to prevent problems with
+%D complicated arguments, for instance arguments that
+%D consist of two or more expandable tokens.
+
+\def\dogetfirstcharacter#1#2\\%
+  {\def\firstcharacter{#1}}
+
+\def\getfirstcharacter#1%
+  {\edef\!!stringa{#1}%
+   \expandafter\dogetfirstcharacter\!!stringa\\}
+
+%D \macros
+%D   {doifinstringelse}
+%D   {}
+%D
+%D We can check for the presence of a substring in a given
+%D sequence of characters.
+%D
+%D \starttypen
+%D \doifinsetelse {substring} {string} {then ...} {else ...}
+%D \stoptypen
+%D
+%D An application of this command can be found further on.
+%D Like before, we first show some alternatives, like the one
+%D we started with:
+%D
+%D \starttypen
+%D \long\def\p!doifinstringelse#1#2#3#4%
+%D   {\def\c!doifinstringelse##1#1##2##3\war%
+%D      {\if##2@%
+%D         #4%
+%D       \else
+%D         #3%
+%D       \fi}%
+%D    \c!doifinstringelse#2#1@@\war}
+%D
+%D \def\doifinstringelse%
+%D   {\ExpandBothAfter\p!doifinstringelse}
+%D \stoptypen
+%D
+%D After this we came to:
+%D
+%D \starttypen
+%D \def\p!doifinstringelse#1#2%
+%D   {\def\c!doifinstringelse##1#1##2##3\war%
+%D      {\if##2@}%
+%D    \c!doifinstringelse#2#1@@\war}
+%D
+%D \def\doifinstringelse#1#2#3#4%
+%D   {\ExpandBothAfter\p!doifinstringelse{#1}{#2}%
+%D      #4%
+%D    \else
+%D      #3%
+%D    \fi}
+%D \stoptypen
+%D
+%D And finaly it became:
+
+\def\v!ifinstringelse#1#2%
+  {\def\c!ifinstringelse##1#1##2##3\war%
+     {\csname\if##2@iffalse\else iftrue\fi\endcsname}%
+   \c!ifinstringelse#2#1@@\war}
+
+\def\ifinstringelse#1#2%
+  {\expanded{\v!ifinstringelse{#1}{#2}}}
+
+\long\def\doifinstringelse#1#2#3#4%
+  {\ifinstringelse{#1}{#2}%
+     #3%
+   \else
+     #4%
+   \fi}
+
+%D \macros
+%D   {doifnumberelse}
+%D   {}
+%D
+%D The next macro executes a command depending of the outcome
+%D of a test on numerals. This is probably one of the fastest
+%D test possible, exept from a less robust 10||step
+%D \type{\if}||ladder or some tricky \type{\lcode} checking.  
+%D
+%D \starttypen
+%D \doifnumberelse {string} {then ...} {else ...}
+%D \stoptypen
+%D
+%D The macro accepts \type{123}, \type{abc}, \type{{}},
+%D \type{\getal} and \type{\the\count...}.
+
+\long\def\doifnumberelse#1#2#3%
+  {\getfirstcharacter{#1}%
+   \@EA\ifinstringelse\firstcharacter{1234567890}%
+     #2%
+   \else
+     #3%
+   \fi}
+
+%D Before we had \type{\ifinstringelse} available, we used:
+%D
+%D \starttypen
+%D \def\doifnumberelse#1%
+%D   {\getfirstcharacter{#1}%
+%D    \rawdoifinsetelse{\firstcharacter}{1,2,3,4,5,6,7,8,9,0}}
+%D \stoptypen
+
+%D A faster but less fail safe alternative is: 
+%D
+%D \starttypen
+%D \dostepwiserecurse{0}{9}{1}
+%D   {\@EA\uccode\@EA`\recurselevel=1}
+%D 
+%D \long\def\doifnumberelse#1#2#3%
+%D   {\getfirstcharacter{#1}%
+%D    \@EA\ifnum\@EA\uccode\@EA`\firstcharacter=1
+%D      #2%
+%D    \else
+%D      #3%
+%D    \fi}
+%D \stoptypen 
+%D
+%D This one only works when the \type{\firstcharacter} is 
+%D indeed a character. Numbers and strings of characters go 
+%D all right, but arguments like \type{\relax} let things 
+%D go wrong. 
+
+%D \macros
+%D   {makerawcommalist,
+%D    rawdoinsetelse,
+%D    rawprocesscommalist,
+%D    rawprocessaction}
+%D   {}
+%D
+%D Some of the commands mentioned earlier are effective but
+%D slow. When one is desperately in need of faster alternatives
+%D and when the conditions are predictable safe, the \type{\raw}
+%D alternatives come into focus. A major drawback is that
+%D they do not take \type{\c!constants} into account, simply
+%D because no expansion is done. This is no problem with
+%D \type{\rawprocesscommalist}, because this macro does not 
+%D compare anything. Expandable macros are permitted as search
+%D string.
+%D
+%D \starttypen
+%D \makerawcommalist[string,string,...]\stringlist
+%D \rawdoifinsetelse{string}{string,...}{...}{...}
+%D \rawprocesscommalist[string,string,...]\commando
+%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c]
+%D \stoptypen
+%D
+%D Spaces embedded in the list, for instance after commas,
+%D spoil the search process. The gain in speed depends on the 
+%D length of the argument (the longer the argument, the less 
+%D we gain). 
+
+\def\makerawcommalist[#1]#2%
+  {\def\appendtocommalist##1%
+     {\doifelse{#2}{}
+        {\edef#2{##1}}
+        {\edef#2{#2,##1}}}%
+   \def#2{}%
+   \processcommalist[#1]\appendtocommalist}
+
+\def\rawprocesscommaitem#1,%
+  {\if]#1\else
+     \csname\s!next\the\commalevel\endcsname{#1}%
+     \expandafter\rawprocesscommaitem
+   \fi}
+
+\def\rawprocesscommalist[#1]#2%
+  {\advance\commalevel by 1\relax
+   \expandafter\let\csname\s!next\the\commalevel\endcsname=#2%
+   \expandafter\rawprocesscommaitem#1,],\relax
+   \advance\commalevel by -1\relax}
+
+\def\rawdoifinsetelse#1#2%
+  {\doifinstringelse{,#1,}{,#2,}}
+
+\def\v!rawprocessaction[#1][#2]%
+  {\def\c!rawprocessaction##1,#1=>##2,##3\war%
+     {\if##3@\else
+        \def\v!processaction{##2}%
+      \fi}%
+   \c!rawprocessaction,#2,#1=>,@\war}
+
+\def\rawprocessaction[#1]#2[#3]%
+  {\edef\!!stringa{#1}%
+   \edef\!!stringb{undefined}%
+   \let\v!processaction=\!!stringb
+   \ifx\!!stringa\empty
+     \@EA\v!rawprocessaction\@EA[\s!default][#3]%
+   \else
+      \expandafter\v!rawprocessaction\expandafter[\!!stringa][#3]%
+      \ifx\v!processaction\!!stringb
+        \@EA\v!rawprocessaction\@EA[\s!unknown][#3]%
+      \fi
+   \fi
+   \ifx\v!processaction\!!stringb
+   \else
+     \v!processaction
+   \fi}
+
+%D When we process the list \type{a,b,c,d,e}, the raw routine 
+%D takes over 30\% less time, when we feed $20+$ character 
+%D strings we gain about 20\%. Alternatives which use 
+%D \type{\futurelet} perform worse. Part of the speedup is 
+%D due to the \type{\let} and \type{\expandafter} in the test. 
+
+%D \macros
+%D   {processunexpandedcommalist}
+%D   {}
+%D
+%D When processing commalists, the arguments are expanded. The
+%D main reason for doing so lays in the fact that these 
+%D macros are used for interfacing. The next alternative can be used 
+%D for 
+%D
+%D \starttypen
+%D \processunexpandedcommalist
+%D   [\alfa\beta,\gamma,\delta\epsilon]
+%D   \handleitem
+%D \stoptypen
+%D
+%D This time nesting is not supported. 
+
+\def\processunexpandedcommaitem#1,%
+  {\if]\noexpand#1%
+     \let\nextcommaitem=\relax
+   \else
+     \handleunexpandedcommaitem{#1}%
+     \let\nextcommaitem=\processunexpandedcommaitem
+   \fi
+   \nextcommaitem}
+
+\def\processunexpandedcommalist[#1]#2%
+  {\def\handleunexpandedcommaitem{#2}%
+   \processunexpandedcommaitem#1,],\relax}
+
+%D Or faster: 
+
+\def\processunexpandedcommaitem#1,%
+  {\if]\noexpand#1\else
+     \handleunexpandedcommaitem{#1}%
+     \expandafter\processunexpandedcommaitem
+   \fi}
+
+%D \macros
+%D   {dosetvalue,dosetevalue,docopyvalue,doresetvalue,
+%D    dogetvalue}
+%D   {}
+%D
+%D When we are going to do assignments, we have to take
+%D multi||linguality into account. For the moment we keep
+%D things simple and single||lingual.
+%D
+%D \starttypen
+%D \dosetvalue   {label}    {variable}   {value}
+%D \dosetevalue  {label}    {variable}   {value}
+%D \docopyvalue  {to label} {from label} {variable}
+%D \doresetvalue {label}    {variable}
+%D \stoptypen
+%D
+%D These macros are in fact auxiliary ones and are not meant
+%D for use outside the assignment macros.
+
+\def\dosetvalue#1#2% #3
+  {\@EA\def\csname#1#2\endcsname} % {#3}}
+
+\def\dosetevalue#1#2% #3
+  {\@EA\edef\csname#1#2\endcsname} % {#3}}
+
+\def\doresetvalue#1#2%
+  {\@EA\def\csname#1#2\endcsname{}}
+
+\def\docopyvalue#1#2#3%
+  {\@EA\def\csname#1#3\endcsname{\csname#2#3\endcsname}}
+
+%D \macros
+%D   {doassign,undoassign,doassignempty}
+%D   {}
+%D
+%D Assignments are the backbone of \CONTEXT. Abhorred by the
+%D concept of style file hacking, we took a considerable effort
+%D in building a parameterized system. Unfortunately there is a
+%D price to pay in terms of speed. Compared to other packages
+%D and taking the functionality of \CONTEXT\ into account, the
+%D total size of the format file is still very acceptable. Now
+%D how are these assignments done. 
+%D
+%D Assignments can be realized with:
+%D
+%D \starttypen
+%D \doassign[label][variable=value]
+%D \undoassign[label][variable=value]
+%D \stoptypen
+%D
+%D and:
+%D
+%D \starttypen
+%D \doassignempty[label][variable=value]
+%D \stoptypen
+%D
+%D Assignments like \type{\doassign} are compatible with:
+%D
+%D \starttypen
+%D \def\labelvariable{value}
+%D \stoptypen
+%D
+%D We do check for the presence of an \type{=} and loudly
+%D complain of it's missed. We will redefine this macro later
+%D on, when a more advanced message mechanism is implemented. 
+
+%\def\p!doassign#1[#2][#3=#4=#5]%
+%  {\let\donottest=\dontprocesstest
+%   \edef\!!stringa{#5}%
+%   \let\!!stringb=\relax
+%   \let\donottest=\doprocesstest
+%   \ifx\!!stringa\!!stringb
+%     \writestatus
+%       {setup}
+%       {missing '=' after '#3' in line \the\inputlineno}%
+%   \else
+%     #1{#2}{#3}{#4}%
+%   \fi}
+
+\def\p!doassign#1[#2][#3=#4=#5]% redefined in mult-ini
+  {\ifx\empty#3\else  % and definitely not \ifx#3\empty
+     \ifx\relax#5%
+     \writestatus
+       {setup}
+       {missing '=' after '#3' in line \the\inputlineno}%
+     \else
+       #1{#2}{#3}{#4}%
+     \fi
+   \fi}
+
+\def\doassign[#1][#2]%
+  {\p!doassign\dosetvalue[#1][#2==\relax]}
+
+\def\doeassign[#1][#2]%
+  {\p!doassign\dosetevalue[#1][#2==\relax]}
+
+\def\undoassign[#1][#2]%
+  {\p!doassign\doresetvalue[#1][#2==\relax]}
+
+\def\doassignempty[#1][#2=#3]%
+  {\doifundefined{#1#2}
+     {\dosetvalue{#1}{#2}{#3}}}
+
+%D \macros
+%D   {getparameters,geteparameters,forgetparameters}
+%D   {}
+%D
+%D Using the assignment commands directly is not our
+%D ideal of user friendly interfacing, so we take some further
+%D steps.
+%D
+%D \starttypen
+%D \getparameters    [label] [...=...,...=...]
+%D \forgetparameters [label] [...=...,...=...]
+%D \stoptypen
+%D
+%D Again, the label identifies the category a variable
+%D belongs to. The second argument can be a comma separated
+%D list of assignments.
+%D
+%D \starttypen
+%D \getparameters
+%D   [demo]
+%D   [alfa=1,
+%D    beta=2]
+%D \stoptypen
+%D
+%D is equivalent to
+%D
+%D \starttypen
+%D \def\demoalfa{1}
+%D \def\demobeta{2}
+%D \stoptypen
+%D
+%D
+%D In the pre||multi||lingual stadium \CONTEXT\ took the next
+%D approach. With
+%D
+%D \starttypen
+%D \def\??demo {@@demo}
+%D \def\!!alfa {alfa}
+%D \def\!!beta {beta}
+%D \stoptypen
+%D
+%D calling
+%D
+%D \starttypen
+%D \getparameters
+%D   [\??demo]
+%D   [\!!alfa=1,
+%D    \!!beta=2]
+%D \stoptypen
+%D
+%D lead to:
+%D
+%D \starttypen
+%D \def\@@demoalfa{1}
+%D \def\@@demobeta{2}
+%D \stoptypen
+%D
+%D Because we want to be able to distinguish the \type{!!}
+%D pre||tagged user supplied variables from internal
+%D counterparts, we will introduce a slightly different tag in
+%D the multi||lingual modules. There we will use \type{c!} or
+%D \type{v!}, depending on the context.
+%D
+%D By calling \type{\p!doassign} directly, we save ourselves
+%D some argument passing and gain some speed. Whatever
+%D optimizations we do, this  command will always be one of the
+%D bigger bottlenecks.
+%D
+%D The alternative \type{\geteparameters} --- it's funny to
+%D see that this alternative saw the light so lately --- can be
+%D used to do expanded assigments.
+
+\def\dogetparameters#1[#2]#3[#4]%
+  {\def\p!dogetparameter##1%
+     {\p!doassign#1[#2][##1==\relax]}%
+   \processcommalist[#4]\p!dogetparameter}
+
+\def\getparameters%
+  {\dogetparameters\dosetvalue}
+
+\def\geteparameters%
+  {\dogetparameters\dosetevalue}
+
+\def\forgetparameters%
+  {\dogetparameters\doresetvalue}
+
+\let\getexpandedparameters=\geteparameters
+
+%D \macros
+%D   {getemptyparameters}
+%D   {}
+%D
+%D Sometimes we explicitly want variables to default to an
+%D empty string, so we welcome:
+%D
+%D \starttypen
+%D \getemptyparameters [label] [...=...,...=...]
+%D \stoptypen
+
+\def\getemptyparameters[#1]#2[#3]%
+  {\def\p!dogetemptyparameter##1%
+     {\doassignempty[#1][##1]}%
+   \processcommalist[#3]\p!dogetemptyparameter}
+
+%D \macros
+%D   {copyparameters}
+%D   {}
+%D
+%D Some \CONTEXT\ commands take their default setups from
+%D others. All commands that are able to provide backgounds
+%D or rules around some content, for instance default to the
+%D standard command for ruled boxes. Is situations like this 
+%D we can use: 
+%D
+%D \starttypen
+%D \copyparameters [to-label] [from-label] [name1,name2,...]
+%D \stoptypen
+%D
+%D For instance
+%D
+%D \starttypen
+%D \copyparameters
+%D   [internal][external]
+%D   [alfa,beta]
+%D \stoptypen
+%D
+%D Leads to:
+%D
+%D \starttypen
+%D \def\internalalfa {\externalalfa}
+%D \def\internalbeta {\externalbeta}
+%D \stoptypen
+%D
+%D By using \type{\docopyvalue} we've prepared this command
+%D for use in a multi||lingual environment.
+
+\def\copyparameters[#1]#2[#3]#4[#5]%
+  {\doifnot{#1}{#3}
+     {\def\docopyparameter##1%
+        {\docopyvalue{#1}{#3}{##1}}%
+      \processcommalist[#5]\docopyparameter}}
+
+%D \macros
+%D   {doifassignmentelse}
+%D   {}
+%D
+%D A lot of \CONTEXT\ commands take optional arguments, for
+%D instance:
+%D
+%D \starttypen
+%D \dothisorthat[alfa,beta]
+%D \dothisorthat[first=foo,second=bar]
+%D \dothisorthat[alfa,beta][first=foo,second=bar]
+%D \stoptypen
+%D
+%D Although a combined solution is possible, we prefer a
+%D seperation. The next command takes care of propper
+%D handling of such multi||faced commands.
+%D
+%D \starttypen
+%D \doifassignmentelse {...} {then ...} {else ...}
+%D \stoptypen
+
+\def\doifassignmentelse%
+  {\doifinstringelse{=}}
+
+%D \macros
+%D   {ifparameters,checkparameters}
+%D   {}
+%D
+%D A slightly different one is \type{\checkparameters}, which
+%D also checks on the presence of a~\type{=}.
+%D
+%D The boolean \type{\ifparameters} can be used afterwards.
+%D Combining both in one \type{\if}||macro would lead to
+%D problems with nested \type{\if}'s.
+%D
+%D \starttypen
+%D \checkparameters[argument]
+%D \stoptypen
+
+\newif\ifparameters
+
+\def\c!checkparameters#1=#2#3\war%
+  {\if#2@\parametersfalse\else\parameterstrue\fi}
+
+\def\checkparameters[#1]%
+  {\c!checkparameters#1=@@\war}
+
+%D \macros
+%D   {getfromcommalist,getfromcommacommand,
+%D    commalistelement,
+%D    getcommalistsize,getcommacommandsize}
+%D   {}
+%D
+%D It's possible to get an element from a commalist or a
+%D command representing a commalist.
+%D
+%D \starttypen
+%D \getfromcommalist    [string] [n]
+%D \getfromcommacommand [string,\strings,string,...] [n]
+%D \stoptypen
+%D
+%D The difference betwee the two of them is the same as the
+%D difference between \type{\processcomma...}. The found string
+%D is stored in \type{\commalistelement}.
+%D
+%D We can calculate the size of a comma separated list by
+%D using:
+%D
+%D \starttypen
+%D \getcommalistsize    [string,string,...]
+%D \getcommacommandsize [string,\strings,string,...]
+%D \stoptypen
+%D
+%D Afterwards, the length is available in the macro
+%D \type{\commalistsize} (not a \COUNTER).
+
+\def\commalistsize{0}
+
+\def\p!dogetcommalistsize#1[#2]%
+  {\scratchcounter=0\relax
+   \def\p!dodogetcommalistsize##1%
+     {\advance\scratchcounter by 1\relax}%
+   #1[#2]\p!dodogetcommalistsize   % was [{#2}]
+   \edef\commalistsize{\the\scratchcounter}}
+
+\def\getcommalistsize%
+  {\p!dogetcommalistsize\processcommalist}
+
+\def\getcommacommandsize%
+  {\p!dogetcommalistsize\processcommacommand}
+
+\def\p!dodogetfromcommalist#1%
+  {\advance\scratchcounter by -1\relax
+   \ifnum\scratchcounter=0\relax
+     \gdef\globalcommalistelement{#1}%
+     \def\doprocesscommaitem##1]{}%
+   \fi}
+
+\def\p!dogetfromcommalist#1[#2]#3[#4]%
+  {\global\let\globalcommalistelement=\empty
+   \bgroup
+   \scratchcounter=#4\relax
+   #1[#2]\p!dodogetfromcommalist
+   \egroup
+   \let\commalistelement=\globalcommalistelement} 
+
+\def\getfromcommalist%
+  {\p!dogetfromcommalist\processcommalist}
+
+\def\getfromcommacommand%
+  {\p!dogetfromcommalist\processcommacommand}
+
+%D Watertight (and efficient) solutions are hard to find, due
+%D to the handling of braces during parameters passing and 
+%D scanning. Nevertheless:   
+%D 
+%D \startbuffer
+%D \def\dosomething#1{(#1=\commalistsize) }
+%D 
+%D \getcommalistsize [\hbox{$a,b,c,d,e,f$}] \dosomething 1
+%D \getcommalistsize [{a,b,c,d,e,f}]        \dosomething 1
+%D \getcommalistsize [{a,b,c},d,e,f]        \dosomething 4
+%D \getcommalistsize [a,b,{c,d,e},f]        \dosomething 4
+%D \getcommalistsize [a{b,c},d,e,f]         \dosomething 4
+%D \getcommalistsize [{a,b}c,d,e,f]         \dosomething 4
+%D \getcommalistsize []                     \dosomething 0
+%D \getcommalistsize [{[}]                  \dosomething 1
+%D \stopbuffer
+%D
+%D \typebuffer 
+%D
+%D reports: 
+%D 
+%D \haalbuffer
+
+%D \macros
+%D   {dosingleargument,dodoubleargument,dotripleargument,
+%D    doquadrupleargument,doquintupleargument,dosixtupleargument}
+%D   {}
+%D
+%D When working with delimited arguments, spaces and
+%D lineendings can interfere. The next set of macros uses
+%D \TEX' internal scanner for grabbing everything between
+%D arguments.
+%D
+%D \starttypen
+%D \dosingleargument\commando    = \commando[#1]
+%D \dodoubleargument\commando    = \commando[#1][#2]
+%D \dotripleargument\commando    = \commando[#1][#2][#3]
+%D \doquadrupleargument\commando = \commando[#1][#2][#3][#4]
+%D \doquintupleargument\commando = \commando[#1][#2][#3][#4][#5]
+%D \dosixtupleargument\commando  = \commando[#1][#2][#3][#4][#5][#6]
+%D \stoptypen
+%D
+%D These macros are used in the following way:
+%D
+%D \starttypen
+%D \def\dosetupsomething[#1][#2]%
+%D   {... #1 ... #2 ...}
+%D
+%D \def\setupsomething%
+%D   {\dodoubleargument\dosetupsomething}
+%D \stoptypen
+%D
+%D The implementation can be surprisingly simple and needs no
+%D further explanation, like:
+%D
+%D \starttypen
+%D \def\dosingleargument#1[#2]%
+%D   {#1[#2]}
+%D \def\dotripleargument#1[#2]#3[#4]#5[#6]%
+%D   {#1[#2][#4][#6]}
+%D \def\doquintupleargument#1%
+%D   {\def\dodoquintupleargument[##1]##2[##3]##4[##5]##6[##7]##8[##9]%
+%D      {#1[##1][##3][##5][##7][##9]}%
+%D    \dodoquintupleargument}
+%D \stoptypen
+%D
+%D Because \TEX\ accepts 9~arguments at most, we have to use
+%D two||step solution when getting five or more arguments.
+%D
+%D When developing more and more of the real \CONTEXT, we
+%D started using some alternatives that provided empty
+%D arguments (in fact optional ones) whenever the user failed
+%D to supply them. Because this more complicated macros enable
+%D us to do some checking, we reimplemented the non||empty 
+%D ones.
+
+\def\dosingleargument%
+  {\chardef\expectedarguments=1
+   \dosingleempty}
+
+\def\dodoubleargument%
+  {\chardef\expectedarguments=2
+   \dodoubleempty}
+
+\def\dotripleargument%
+  {\chardef\expectedarguments=3
+   \dotripleempty}
+
+\def\doquadrupleargument%
+  {\chardef\expectedarguments=4
+   \doquadrupleempty}
+
+\def\doquintupleargument%
+  {\chardef\expectedarguments=5
+   \doquintupleempty}
+
+\def\doquintupleargument%
+  {\chardef\expectedarguments=6
+   \dosixtupleempty}
+
+%D \macros
+%D   {iffirstagument,ifsecondargument,ifthirdargument,
+%D    iffourthargument,iffifthargument,ifsixthargument}
+%D   {}
+%D
+%D We use some signals for telling the calling macros if all
+%D wanted arguments are indeed supplied by the user.
+
+\newif\iffirstargument
+\newif\ifsecondargument
+\newif\ifthirdargument
+\newif\iffourthargument
+\newif\iffifthargument
+\newif\ifsixthargument
+
+%D \macros
+%D   {dosingleempty,dodoubleempty,dotripleempty,
+%D    doquadrupleempty,doquintupleempty}
+%D   {}
+%D
+%D The empty argument supplying macros mentioned before, look
+%D like:
+%D
+%D \starttypen
+%D \dosingleempty    \command
+%D \dodoubleempty    \command
+%D \dotripleempty    \command
+%D \doquadrupleempty \command
+%D \doquintupleempty \command
+%D \dosixtupleempty  \command
+%D \stoptypen
+%D
+%D So \type{\dodoubleempty} leades to:
+%D
+%D \starttypen
+%D \command[#1][#2]
+%D \command[#1][]
+%D \command[][]
+%D \stoptypen
+%D
+%D Depending of the generousity of the user. Afterwards one can
+%D use the \type{\if...argument} boolean. For novice: watch
+%D the stepwise doubling of \type{#}'s
+
+\chardef\noexpectedarguments=0
+\chardef\expectedarguments  =0
+
+\def\dogetargument#1#2#3#4% redefined in mult-ini
+  {\doifnextcharelse{#1}
+     {\let\expectedarguments=\noexpectedarguments
+      #3\dodogetargument}
+     {\ifnum\expectedarguments>\noexpectedarguments
+        \writestatus
+          {setup}
+          {\expectedarguments\space argument(s) expected
+           in line \the\inputlineno\space}%
+      \fi
+      \let\expectedarguments=\noexpectedarguments
+      #4\dodogetargument#1#2}}
+
+\def\getsingleempty#1#2#3%
+  {\def\dodogetargument%
+     {#3}%
+   \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getdoubleempty#1#2#3%
+  {\def\dodogetargument#1##1#2%
+     {\def\dodogetargument%
+        {#3#1##1#2}%
+      \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+   \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\gettripleempty#1#2#3%
+  {\def\dodogetargument#1##1#2%
+     {\def\dodogetargument#1####1#2%
+        {\def\dodogetargument%
+           {#3#1##1#2#1####1#2}%
+         \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+      \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+   \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getquadrupleempty#1#2#3%
+  {\def\dodogetargument#1##1#2%
+     {\def\dodogetargument#1####1#2%
+        {\def\dodogetargument#1########1#2%
+           {\def\dodogetargument%
+              {#3#1##1#2#1####1#2#1########1#2}%
+            \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}%
+         \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+      \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+   \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getquintupleempty#1#2#3%
+  {\def\dodogetargument#1##1#2%
+     {\def\dodogetargument#1####1#2%
+        {\def\dodogetargument#1########1#2%
+           {\def\dodogetargument#1################1#2%
+              {\def\dodogetargument%
+                 {#3#1##1#2#1####1#2#1########1#2#1################1#2}%
+               \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}%
+            \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}%
+         \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+      \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+   \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getsixtupleempty#1#2#3%
+  {\def\dodogetargument#1##1#2%
+     {\def\dodogetargument#1####1#2%
+        {\def\dodogetargument#1########1#2%
+           {\def\dodogetargument#1################1#2%
+              {\def\dodogetargument#1################################1#2%
+                 {\def\dodogetargument%
+                    {#3#1##1#2#1####1#2#1########1#2#1################1%
+                            #2#1################################1#2}%
+                 \dogetargument#1#2\sixthargumenttrue\sixthargumentfalse}%
+               \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}%
+            \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}%
+         \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+      \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+   \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\dosingleempty    {\getsingleempty    []}
+\def\dodoubleempty    {\getdoubleempty    []}
+\def\dotripleempty    {\gettripleempty    []}
+\def\doquadrupleempty {\getquadrupleempty []}
+\def\doquintupleempty {\getquintupleempty []}
+\def\dosixtupleempty  {\getsixtupleempty  []}
+
+%D \macros
+%D   {dosingleargumentwithset,
+%D    dodoubleargumentwithset,dodoubleemptywithset,
+%D    dotripleargumentwithset,dotripleemptywithset}
+%D   {}
+%D
+%D These maybe too mysterious macros enable us to handle more
+%D than one setup at once.
+%D
+%D \starttypen
+%D \dosingleargumentwithset \command[#1]
+%D \dodoubleargumentwithset \command[#1][#2]
+%D \dotripleargumentwithset \command[#1][#2][#3]
+%D \dodoubleemptywithset    \command[#1][#2]
+%D \dotripleemptywithset    \command[#1][#2][#3]
+%D \stoptypen
+%D
+%D The first macro calls \type{\command[##1]} for each string
+%D in the set~\type{#1}. The second one calls for
+%D \type{\commando[##1][#2]} and the third, well one may guess.
+%D These commands support constructions like:
+%D
+%D \starttypen
+%D \def\dodefinesomething[#1][#2]%
+%D   {\getparameters[\??xx#1][#2]}
+%D
+%D \def\definesomething%
+%D   {\dodoubleargumentwithset\dodefinesomething}
+%D \stoptypen
+%D
+%D Which accepts calls like:
+%D
+%D \starttypen
+%D \definesomething[alfa,beta,...][variable=...,...]
+%D \stoptypen
+%D
+%D Now a whole bunch of variables like \type{\@@xxalfavariable}
+%D and \type{\@@xxbetavariable} is defined.
+
+\def\dosingleargumentwithset#1%
+  {\def\dodosinglewithset[##1]%
+     {\def\dododosinglewithset####1%
+        {#1[####1]}%
+      \processcommalist[##1]\dododosinglewithset}%
+   \dosingleargument\dodosinglewithset}%
+
+\def\dodoublewithset#1#2%
+  {\def\dododoublewithset[##1][##2]%
+     {\doifnot{##1}{}
+        {\def\dodododoublewithset####1%
+           {#2[####1][##2]}%
+         \processcommalist[##1]\dodododoublewithset}}%
+   #1\dododoublewithset}%
+
+\def\dodoubleemptywithset%
+  {\dodoublewithset\dodoubleempty}
+
+\def\dodoubleargumentwithset%
+  {\dodoublewithset\dodoubleargument}
+
+\def\dotriplewithset#1#2%
+  {\def\dodotriplewithset[##1][##2][##3]%
+     {\doifnot{##1}{}
+        {\def\dododotriplewithset####1%
+           {#2[####1][##2][##3]}%
+         \processcommalist[##1]\dododotriplewithset}}%
+   #1\dodotriplewithset}%
+
+\def\dotripleemptywithset%
+  {\dotriplewithset\dotripleempty}
+
+\def\dotripleargumentwithset%
+  {\dotriplewithset\dotripleargument}
+
+%D \macros
+%D   {complexorsimple,complexorsimpleempty}
+%D   {}
+%D
+%D Setups can be optional. A command expecting a setup is
+%D prefixed by \type{\complex}, a command without one gets the
+%D prefix \type{\simple}. Commands like this can be defined by:
+%D
+%D \starttypen
+%D \complexorsimple {command}
+%D \stoptypen
+%D
+%D When \type{\command} is followed by a \type{[setup]}, then
+%D
+%D \starttypen
+%D \complexcommand [setup]
+%D \stoptypen
+%D
+%D executes, else we get 
+%D
+%D \starttypen
+%D \simplecommand
+%D \stoptypen
+%D
+%D An alternative for \type{\complexorsimple} is:
+%D
+%D \starttypen
+%D \complexorsimpleempty {command}
+%D \stoptypen
+%D
+%D Depending on the presence of \type{[setup]}, this one 
+%D leads to one of: 
+%D
+%D \starttypen
+%D \complexcommando [setup]
+%D \complexcommando []
+%D \stoptypen
+%D
+%D Many \CONTEXT\ commands started as complex or simple ones, 
+%D but changed into more versatile (more object oriented) ones
+%D using the \type{\get..argument} commands. 
+ 
+\def\complexorsimple#1%
+  {\doifnextcharelse{[}
+     {\firstargumenttrue\getvalue{\s!complex#1}}
+     {\firstargumentfalse\getvalue{\s!simple#1}}}
+
+\def\complexorsimpleempty#1%
+  {\doifnextcharelse{[}
+     {\firstargumenttrue\getvalue{\s!complex#1}}
+     {\firstargumentfalse\getvalue{\s!complex#1}[]}}
+
+%D \macros
+%D   {definecomplexorsimple,definecomplexorsimpleempty}
+%D   {}
+%D
+%D The previous commands are used that often that we found it
+%D worthwile to offer two more alternatives.
+
+\def\setnameofcommand#1%
+  {\bgroup
+   \escapechar=-1\relax
+   \xdef\nameofcommand{\string#1}%
+   \egroup}
+
+\def\definewithnameofcommand#1#2% watch the \donottest
+  {\setnameofcommand{#2}%
+   \@EA\def\@EA#2\@EA{\@EA\donottest\@EA#1\@EA{\nameofcommand}}}
+
+\def\definecomplexorsimple%
+  {\definewithnameofcommand\complexorsimple}
+
+\def\definecomplexorsimpleempty%
+  {\definewithnameofcommand\complexorsimpleempty}
+
+%D These commands are called as:
+%D
+%D \starttypen
+%D \definecomplexorsimple\command
+%D \stoptypen
+%D
+%D Of course, we must have available
+%D
+%D \starttypen
+%D \def\complexcommand[#1]{...}
+%D \def\simplecommand     {...}
+%D \stoptypen
+%D
+%D Using this construction saves a few string now and then.
+
+%D \macros
+%D   {definestartstopcommand}
+%D   {}
+%D
+%D Those who get the creeps of expansion may skip the next 
+%D one. It's one of the most recent additions and concerns 
+%D \type{\start}||\type{\stop} pairs with complicated 
+%D arguments.
+%D
+%D We won't go into details here, but the general form of 
+%D this using this command is: 
+%D
+%D \starttypen
+%D \definestartstopcommand\somecommand\v!specifier{arg}{arg}%
+%D   {do something with arg} 
+%D \stoptypen
+%D
+%D This expands to something like:
+%D
+%D \starttypen
+%D \def\somecommand arg \startspecifier arg \stopspecifier%
+%D   {do something with arg} 
+%D \stoptypen
+%D
+%D The argumentss can be anything reasonable, but double 
+%D \type{#}'s are needed in the specification part, like:
+%D
+%D \starttypen
+%D \definestartstopcommand\somecommand\v!specifier{[##1][##2]}{##3}%
+%D   {do #1 something #2 with #3 arg} 
+%D \stoptypen
+%D
+%D which becomes: 
+%D
+%D \starttypen
+%D \def\somecommand[#1][#2]\startspecifier#3\stopspecifier%
+%D   {do #1 something #2 with #3 arg} 
+%D \stoptypen
+%D
+%D We will see some real applications of this command in the 
+%D core modules. 
+
+\def\definestartstopcommand#1#2#3#4%
+  {\def\!stringa{#3}%
+   \def\!stringb{\e!start#2}%
+   \def\!stringc{#4}%
+   \def\!stringd{\e!stop#2}%
+   \@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA
+   \def\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA\@EA
+   #1\@EA\@EA\@EA\@EA\@EA\@EA\@EA
+   \!stringa\@EA\@EA\@EA
+   \csname\@EA\@EA\@EA\!stringb\@EA\@EA\@EA\endcsname\@EA
+   \!stringc
+   \csname\!stringd\endcsname}
+
+%D \macros
+%D   {dosinglegroupempty,dodoublegroupempty,dotriplegroupempty,
+%D    doquadruplegroupempty}
+%D   {}
+%D 
+%D We've already seen some commands that take care of 
+%D optional arguments between \type{[]}. The next two commands 
+%D handle the ones with \type{{}}. They are called as: 
+%D 
+%D \starttypen
+%D \dosinglegroupempty \IneedONEargument
+%D \dodoublegroupempty \IneedTWOarguments
+%D \dotriplegroupempty \IneedTHREEarguments
+%D \dotriplegroupempty \IneedFOURarguments
+%D \stoptypen
+%D 
+%D where \type{\IneedONEargument} takes one and the others 
+%D two and three arguments. These macro's were first needed in 
+%D \PPCHTEX. 
+
+\def\dogetgroupargument#1#2% redefined in mult-ini
+  {\def\nextnextargument%
+     {\ifx\nextargument\bgroup  
+        \let\expectedarguments=\noexpectedarguments
+        \def\nextargument{#1\dodogetargument}%
+      %\else\ifx\nextargument\lineending % this can be an option
+      %  \def\nextargument{\bgroup\def\\ {\egroup\dogetgroupargument#1#2}\\}%
+      %\else\ifx\nextargument\blankspace % but it may never be default
+      %  \def\nextargument{\bgroup\def\\ {\egroup\dogetgroupargument#1#2}\\}%
+      \else
+        \ifnum\expectedarguments>\noexpectedarguments
+          \writestatus
+             {setup}
+             {\the\expectedarguments\space argument(s) expected
+              in line \the\inputlineno\space}%
+        \fi
+        \let\expectedarguments=\noexpectedarguments
+        \def\nextargument{#2\dodogetargument{}}%
+      \fi%\fi\fi                 % so let's get rid of it
+      \nextargument}%
+   \futurelet\nextargument\nextnextargument}
+ 
+\def\dosinglegroupempty#1%
+  {\def\dodogetargument%
+     {#1}%
+   \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+\def\dodoublegroupempty#1%
+  {\def\dodogetargument##1%
+     {\def\dodogetargument%
+        {#1{##1}}%
+      \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
+   \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+\def\dotriplegroupempty#1%
+  {\def\dodogetargument##1%
+     {\def\dodogetargument####1%
+        {\def\dodogetargument%
+           {#1{##1}{####1}}%
+         \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}%
+      \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
+   \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+\def\doquadruplegroupempty#1%
+  {\def\dodogetargument##1%
+     {\def\dodogetargument####1%
+        {\def\dodogetargument########1%
+           {\def\dodogetargument%
+              {#1{##1}{####1}{########1}}%
+            \dogetgroupargument\fourthargumenttrue\fourthargumentfalse}%   
+         \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}%
+      \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
+   \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+
+%D These macros explictly take care of spaces, which means 
+%D that the next definition and calls are valid:
+%D 
+%D \starttypen
+%D \def\test#1#2#3{[#1#2#3]}
+%D 
+%D \dotriplegroupempty\test {a}{b}{c}
+%D \dotriplegroupempty\test {a}{b} 
+%D \dotriplegroupempty\test {a}
+%D \dotriplegroupempty\test 
+%D \dotriplegroupempty\test {a} {b} {c}
+%D \dotriplegroupempty\test {a} {b} 
+%D \dotriplegroupempty\test 
+%D   {a} 
+%D   {b} 
+%D \stoptypen
+%D
+%D And alike.
+
+%D \macros
+%D   {wait}
+%D   {}
+%D
+%D The next macro hardly needs explanation. Because no
+%D nesting is to be expected, we can reuse \type{\wait} within
+%D \type{\wait} itself.
+
+\def\wait%
+  {\bgroup
+   \read16 to \wait
+   \egroup}
+
+%D \macros
+%D   {writestring,writeline,
+%D    writestatus,statuswidth}
+%D   {}
+%D
+%D Maybe one didn't notice, but we've already introduced a
+%D macro for showing messages. In the multi||lingual modules,
+%D we will also introduce a mechanism for message passing. For
+%D the moment we stick to the core macros:
+%D
+%D \starttypen
+%D \writestring {string}
+%D \writeline
+%D \writestatus {category} {message}
+%D \stoptypen
+%D
+%D Messages are formatted. One can provide the maximum with
+%D of the identification string with the macro
+%D \type{\statuswidth}.
+
+\def\statuswidth {15}
+
+\def\writestring%
+  {\immediate\write16}
+
+\def\writeline%
+  {\writestring{}}
+
+\def\dosplitstatus#1#2\end%
+  {\ifx#1?%
+     \loop
+       \advance\scratchcounter by 1
+       \ifnum\scratchcounter<\statuswidth\relax
+         \edef\messagecontentA{\messagecontentA\space}%
+     \repeat
+   \else
+     \advance\scratchcounter by 1
+     \ifnum\scratchcounter<\statuswidth\relax
+       \edef\messagecontentA{\messagecontentA#1}%
+     \fi
+     \dosplitstatus#2\end
+   \fi}
+
+\def\writestatus#1#2%
+  {\bgroup
+   \edef\messagecontentA{}%
+   \edef\messagecontentB{#2}%  maybe it's \the\scratchcounter
+   \scratchcounter=0
+   \expandafter\dosplitstatus#1?\end
+   \writestring{\messagecontentA\space:\space\messagecontentB}%
+   \egroup}
+
+%D \macros
+%D   {debuggerinfo}
+%D   {}
+%D
+%D For debugging purposes we can enhance macros with the
+%D next alternative. Here \type{debuggerinfo} stands for both
+%D a macro accepting two arguments and a boolean (in fact a
+%D few macro's too).
+
+\newif\ifdebuggerinfo
+
+\def\debuggerinfo#1#2%
+  {\ifdebuggerinfo
+     \writestatus{debugger}{#1:: #2}%
+   \fi}
+
+%D Finally we do what from now on will be done at the top of
+%D the files: we tell the user what we are loading.
+
+\writestatus{loading}{Context System Macros / General}
+
+%D Well, the real final command is the one that resets the 
+%D unprotected characters \type{@}, \type{?} and \type{!}.
+
+\protect
+
+\endinput
+
-- 
cgit v1.2.3

