%D \module
%D   [       file=syst-gen,
%D        version=1996.03.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. See mreadme.pdf for
%C details.

% nagaan : \ifinstringelse in syst-ext.tex
% do => p! dodo pp! dododo ppp!

%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 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 \starttyping
%D \abortinputifdefined\command
%D \stoptyping
%D
%D where \type{\command} is a command defined in the module
%D to be loaded only once.
%D
%D \starttyping
%D \def\abortinputifdefined#1%
%D   {\ifx#1\undefined
%D      \let\next=\relax
%D    \else
%D      \let\next=\endinput
%D    \fi
%D    \next}
%D \stoptyping
%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 \starttyping
%D \ifx\somecommand\undefined
%D   \let\next=\relax
%D \else
%D   \let\next=\endinput
%D \fi
%D \next
%D \stoptyping
%D
%D We need the \type{\next} because we need to end the
%D \type{\fi}. The efficient one is:
%D
%D \starttyping
%D \ifx\somecommand\undefined
%D \else
%D   \expandafter\endinput
%D \fi
%D \stoptyping
%D
%D Because \type{\endinput} comes into action after the current
%D line, we can also say:
%D
%D \starttyping
%D \ifx\somecommand\undefined \else \endinput \fi
%D \stoptyping
%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 \starttyping
%D \writestatus{laden}{Context Systeem Macro's (a)}
%D \stoptyping

%D The next few macros are needed in case this module is
%D used outside \CONTEXT.

\ifx\beginTEX\undefined
  \let\beginTEX\relax\let\endTEX\relax
  \long\def\beginETEX  #1\endETEX {}
  \long\def\beginOMEGA #1\endOMEGA{}
%   \long\def\onlyTEX  #1{#1}
%   \long\def\onlyETEX #1{}
%   \long\def\onlyOMEGA#1{}
\fi

%D \macros
%D   [beschermen]
%D   {protect,unprotect}
%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 \starttyping
%D \unprotect
%D \def\!test{test}
%D \protect
%D \stoptyping
%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>}}
\else
  % a simple version is already defined
\fi

\let\normalprotect=\protect % only for latex

%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.

\chardef\protectionthreshold=2
%chardef\protectionthreshold=0 % for testing

% \def\unprotect
%   {\ifcase\protectionlevel
%      \edef\doprotectcharacters%
%        {\catcode`\noexpand @=\the\catcode`@
%         \catcode`\noexpand !=\the\catcode`!
%         \catcode`\noexpand ?=\the\catcode`? }%
%      \let\protect\doprotect
%    \fi
%    \catcode`@=11
%    \catcode`!=11
%    \catcode`?=11
%    \advance\protectionlevel 1
%    \ifnum\protectionlevel>\protectionthreshold
%      \message{<unprotect \the\protectionlevel>}%
%    \fi}
%
% \def\doprotect%
%   {\ifnum\protectionlevel=1
%      \doprotectcharacters
%      \let\doprotectcharacters\relax
%      \let\protect\normalprotect
%    \fi
%    \ifnum\protectionlevel>\protectionthreshold
%      \message{<protect \the\protectionlevel>}%
%    \fi
%    \advance\protectionlevel -1 }

\def\saveprotectedcharacters
  {\edef\doprotectcharacters
     {\catcode`\noexpand @\the\catcode`@
      \catcode`\noexpand !\the\catcode`!
      \catcode`\noexpand ?\the\catcode`? }}

\def\setprotectedcharacters
  {\catcode`@=11
   \catcode`!=11
   \catcode`?=11 }

\def\unprotect
  {\ifcase\protectionlevel
     \saveprotectedcharacters
     \let\protect\doprotect
   \fi
   \setprotectedcharacters
   \advance\protectionlevel 1
   \ifnum\protectionlevel>\protectionthreshold
     \reportunprotection
   \fi}

\def\doprotect
  {\ifcase\protectionlevel\or
     \doprotectcharacters
     \let\doprotectcharacters\relax
     \let\protect\normalprotect
   \fi
   \ifnum\protectionlevel>\protectionthreshold
     \reportprotection
   \fi
   \advance\protectionlevel -1 }

\def\reportunprotection   {\message{<unprotect       \protectionstate>}}
\def\reportprotection     {\message{<protect         \protectionstate>}}
\def\reportprotectionstate{\message{<protectionstate \protectionstate>}}

\def\protectionstate
  {\the\protectionlevel
   \ifcase\protectionthreshold
     :\space
     @=\the\catcode`@\space\space
     !=\the\catcode`!\space\space
     ?=\the\catcode`?%
   \fi}

\ifx\everyeof\undefined

  \let\checkprotection\relax

\else

  \def\checkprotection
    {\everyeof{\writestatus{protection}{state: \protectionstate}}}

\fi

%D Now it is defined, we can make use of this very useful
%D macro.

\unprotect

%D So, now we can redefine a previously defined macro as
%D follows:

\def\setprotectedcharacters
  {\catcode`@\@@letter
   \catcode`!\@@letter
   \catcode`?\@@letter}

%D \macros
%D   {@@escape,@@begingroup,@@endgroup,@@mathshift,@@alignment,
%D    @@endofline,@@parameter,@@superscript,@@subscript,
%D    @@ignore,@@space,@@letter,@@other,@@active,@@comment}
%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 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,globalscratchbox,
%D    scratchtoks,
%D    ifdone}
%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 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 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                    \dimendef\!!dimenf=10 %skipdef\!!skipa=0
                                      \dimendef\!!dimeng=12 %skipdef\!!skipb=2
                                      \dimendef\!!dimenh=14 %skipdef\!!skipc=4
                                      \dimendef\!!dimeni=16 %skipdef\!!skipd=6
                                      \dimendef\!!dimenj=18 %skipdef\!!skipe=8

\let\!!stringa=\empty \let\!!stringb=\empty \let\!!stringc=\empty
\let\!!stringd=\empty \let\!!stringe=\empty \let\!!stringf=\empty

\newdimen\!!widtha \newdimen\!!heighta \newdimen\!!deptha
\newdimen\!!widthb \newdimen\!!heightb \newdimen\!!depthb
\newdimen\!!widthc \newdimen\!!heightc \newdimen\!!depthc

\newif\if!!donea   \newif\if!!doneb    \newif\if!!donec
\newif\if!!doned   \newif\if!!donee    \newif\if!!donef

\ifx  \z@\undefined \else \let\zeropoint\z@   \fi
\ifx \@ne\undefined \else \let\plusone  \@ne  \fi
\ifx\m@ne\undefined \else \let\minusone \m@ne \fi

\ifx\zeropoint\undefined \csname newdimen\endcsname\zeropoint \fi % plain
\ifx\plusone  \undefined \chardef\plusone  =1                 \fi
\ifx\plustwo  \undefined \chardef\plustwo  =2                 \fi
\ifx\plusthree\undefined \chardef\plusthree=3                 \fi
\ifx\plusfour \undefined \chardef\plusfour =4                 \fi
\ifx\plusfive \undefined \chardef\plusfive =5                 \fi
\ifx\minusone \undefined \count\minusone \minusone=-1         \fi

\ifx\@m\undefined \else \let\plusthousand   \@m \fi
\ifx\@M\undefined \else \let\plusttenhousand\@M \fi

\ifx\plusten        \undefined \mathchardef\plusten        =   10 \fi
\ifx\plushundred    \undefined \mathchardef\plushundred    =  100 \fi
\ifx\plusthousand   \undefined \mathchardef\plusthousand   = 1000 \fi
\ifx\plustenthousand\undefined \mathchardef\plustenthousand=10000 \fi

\newcount\zerocount

%D \macros
%D   {s!,c!,e!,p!,v!,@@,??}
%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,@EAEA,@EAEAEA,@EAEAEAEAEAEA,expanded,startexpanded}
%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
\def\@EAEA  {\expandafter\expandafter}
\def\@EAEAEA{\expandafter\expandafter\expandafter}

\def\@EAEAEAEAEAEA{\expandafter\@EAEAEA\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 \starttyping
%D \expanded{\setupsomething[\alfa]}
%D \stoptyping
%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.

\long\def\@@expanded{} % always long; global (less restores)

\long\def\expanded#1%
  {\long\xdef\@@expanded{\noexpand#1}\@@expanded}

%D Beware, the next one has no \type {\noexpand} before its
%D argument.

\long\def\startexpanded#1\stopexpanded % see x-fo for example
  {\long\xdef\@@expanded{#1}\@@expanded}

%D \macros
%D   {safeexpanded,everysafeexpanded}
%D
%D In addition we provide:

\newtoks\everysafeexpanded

\long\def\safeexpanded#1%
  {\begingroup
   \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#1}%
   \endgroup
   \@@expanded}

\def\safeedef#1#2%
  {\begingroup
   \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#2}%
   \endgroup
   \let#1\@@expanded}

\def\safexdef#1#2%
  {\begingroup
   \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#2}%
   \endgroup
   \global\let#1\@@expanded}

%D You can append protective measures to the token register if
%D needed, as we will do later.

%D \macros
%D   {expandoneargafter,expandtwoargsafter}
%D
%D These two commands make macros more readable by hiding a
%D lot of \type {\expandafter}'s. They expand the arguments
%D after the first command.
%D
%D \starttyping
%D \expandoneargafter \command{\abc}
%D \expandtwoargsafter\command{\abc}{\def}
%D \stoptyping
%D
%D These commands expect the arguments to be macros.

\def\expandoneargafter   #1{\@EA#1\@EA}
\def\expandtwoargsafter#1#2{\@EA\@EA\@EA#1\@EA\@EA\@EA{\@EA#2\@EA}\@EA}

%D These two do a full expansion:

\def\fullexpandoneargafter   #1#2{\long\xdef\@@expanded{\noexpand#1{#2}}\@@expanded}
\def\fullexpandtwoargsafter#1#2#3{\long\xdef\@@expanded{\noexpand#1{#2}{#3}}\@@expanded}

%D \macros
%D   {gobbleoneargument,gobble...arguments}
%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{}
\long\def\gobbletenarguments   #1{\gobbleninearguments}

%D \macros
%D   {doifnextcharelse}
%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 \starttyping
%D \doifnextcharelse {karakter} {then ...} {else ...}
%D \stoptyping
%D
%D This macro differs from the original in the use of \type
%D {\localnext} because we don't want clashes with \type
%D {\next}.

\long\def\doifnextcharelse#1#2#3% #1 should not be {} !
  {\let\charactertoken=#1% = needed here
   \def\!!stringa{#2}%
   \def\!!stringb{#3}%
   \futurelet\nexttoken\inspectnextcharacter}

\def\inspectnextcharacter
  {\ifx\nexttoken\blankspace
     \@EA\reinspectnextcharacter
   \else\ifx\nexttoken\charactertoken
     \@EAEAEA\!!stringa
   \else
     \@EAEAEA\!!stringb
   \fi\fi}

%\let\endoflinetoken=^^M
%
%\long\def\reinspectaftercharacter#1%
%  {\futurelet\nexttoken\inspectnextcharacter}

%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 \starttyping
%D \expandafter\def\reinspectnextcharacter %
%D   {\futurelet\nexttoken\inspectnextcharacter}
%D \stoptyping
%D
%D However complicated it may look, I'm still glad I stumbled
%D into this construction. Saving and restoring \type {\:} is
%D needed when we use \PPCHTEX\ in \LATEX.

\let\next\:

\def\:{\let\blankspace= }  \:

\def\:{\reinspectnextcharacter}

\expandafter\def\: {\futurelet\nexttoken\inspectnextcharacter}

\let\:\next

%D \macros
%D   {setvalue,setgvalue,setevalue,setxvalue,
%D    letvalue,
%D    getvalue,
%D    resetvalue}
%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 \starttyping
%D \setvalue   {name}{...} = \def\name{...}
%D \setgvalue  {name}{...} = \gdef\name{...}
%D \setevalue  {name}{...} = \edef\name{...}
%D \setxvalue  {name}{...} = \xdef\name{...}
%D \letvalue   {name}=\... = \let\name=\...
%D \letgvalue  {name}=\... = \global\let\name=\...
%D \getvalue   {name}      = \name
%D \resetvalue {name}      = \def\name{}
%D \stoptyping
%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\letgvalue    #1{\global\expandafter\let\csname#1\endcsname}
\def\resetvalue   #1{\expandafter\let\csname#1\endcsname\empty}
\def\ignorevalue#1#2{\expandafter\let\csname#1\endcsname\empty}

%D \macros
%D   {globallet,glet}
%D
%D In \CONTEXT\ of May 2000 using \type {\globallet}
%D instead of the two tokens will save us some
%D $300\times4=1200$ bytes of format file on a 32~bit
%D system. So:

\def\globallet{\global\let}  \let\glet\globallet

%D \macros
%D   {donottest,unexpanded}
%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 \ETEX\ protection is 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 \starttyping
%D \def\dosomecommand {... ... ...}
%D \def\somecommand   {\donottest\dosomecommand}
%D \stoptyping
%D
%D This double definition can be made transparant by using
%D \type{\unexpanded}, as in:
%D
%D \starttyping
%D \unexpanded\def\somecommand{... ... ...}
%D \stoptyping
%D
%D The protection mechanism uses:

\beginTEX

\def\dontprocesstest#1{==}
\def\doprocesstest  #1{#1}

\let\donottest=\doprocesstest

\endTEX

\beginETEX \detokenize

\def\donottest#1{#1} % {\detokenize{#1}}

\endETEX

%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 \macros
%D   {honorunexpanded,forceunexpanded}
%D
%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 \starttyping
%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 \stoptyping
%D
%D Well, in fact we use the bit more versatile alternative. The
%D \type {\honorunexpanded} can be used to \type {\string}
%D the protected command, which by the way is seldom needed
%D in \CONTEXT.

\beginTEX

\def\dosetunexpanded#1#2%
  {\@EA#1\@EA{\@EA#2\@EA}%
     \@EA{\@EA\donottest\csname\s!do\@EA\string\csname#2\endcsname\endcsname}%
   \@EA#1\@EA{\@EA\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}

\def\honorunexpanded% for writing to a file or message
  {\def\donottest##1{\expandafter\gobblethreearguments\string##1}}

\def\forceunexpanded% for preventing expansion in \xdef
  {\def\donottest##1%
     {\expandafter\noexpand\csname\expandafter\gobblefourarguments\string##1\endcsname}}

\def\resetunexpanded%
  {\let\donottest\doprocesstest}

\endTEX

\beginETEX \protected

\let \unexpanded      \normalprotected
\let \honorunexpanded \empty % \relax
\let \forceunexpanded \empty % \relax
\let \resetunexpanded \empty % \relax

\endETEX

%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 \starttyping
%D \def\csname do\somecommand\endcsname{... ... ...}
%D \def\somecommand{\donottest\csname do\somecommand\endcsname}
%D \stoptyping
%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 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 \starttyping
%D \doifundefined      {string}    {...}
%D \doifdefined        {string}    {...}
%D \doifundefinedelse  {string}    {then ...} {else ...}
%D \doifdefinedelse    {string}    {then ...} {else ...}
%D \doifalldefinedelse {commalist} {then ...} {else ...}
%D \stoptyping
%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 \starttyping
%D \expandafter\ifx\csname NameA\endcsname\relax ... \else ... \fi
%D
%D \ifx\NameB\undefined ... \else ... \fi
%D \stoptyping
%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 \starttyping
%D \expandafter\show\csname NameA\endcsname
%D
%D \show\NameB
%D \stoptyping
%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 \starttyping
%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   {\begingroup
%D    \donetrue
%D    \def\checkcommand##1%
%D      {\doifundefined{##1}{\donefalse}}%
%D    \processcommalist[#1]\checkcommand
%D    \ifdone
%D      \endgroup#2%
%D    \else
%D      \endgroup#3%
%D    \fi}
%D \stoptyping
%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. Watch how we reach over the
%D \type {\else} and \type {\fi}: this way they cannot get
%D into the way (and we can avoid those \type {\next}
%D hacks); I started using this method after I did some
%D speed optimization tests in the xtag modules; the
%D efficiency of such hacks depends on the length of the
%D argument etc. etc.)

\beginTEX

\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%
  {\p!doifundefined{#1}%
     \let\donottest\doprocesstest\@EA\firstoftwoarguments
   \else
     \let\donottest\doprocesstest\@EA\secondoftwoarguments
   \fi}

\def\doifdefinedelse#1%
  {\p!doifundefined{#1}%
     \let\donottest\doprocesstest\@EA\secondoftwoarguments
   \else
     \let\donottest\doprocesstest\@EA\firstoftwoarguments
   \fi}

\def\doifundefined#1%
  {\p!doifundefined{#1}%
     \let\donottest\doprocesstest\@EA\firstofoneargument
   \else
     \let\donottest\doprocesstest\@EA\gobbleoneargument
   \fi}

\def\doifdefined#1%
  {\p!doifundefined{#1}%
     \let\donottest\doprocesstest\@EA\gobbleoneargument
   \else
     \let\donottest\doprocesstest\@EA\firstofoneargument
   \fi}

\endTEX

\beginETEX \ifcsname

\def\ifundefined#1% ongelukkige naam
  {\unless\ifcsname#1\endcsname}

\def\p!doifundefined#1%
  {\edef\p!defined{#1}%
   \unless\ifcsname\detokenize\@EA{\p!defined}\endcsname}

\def\doifundefinedelse#1%
  {\edef\p!defined{#1}%
   \ifcsname\detokenize\@EA{\p!defined}\endcsname
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

\def\doifdefinedelse#1%
  {\edef\p!defined{#1}%
   \ifcsname\detokenize\@EA{\p!defined}\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\def\doifundefined#1%
  {\edef\p!defined{#1}%
   \ifcsname\detokenize\@EA{\p!defined}\endcsname
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\def\doifdefined#1%
  {\edef\p!defined{#1}%
   \ifcsname\detokenize\@EA{\p!defined}\endcsname
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\endETEX

%D \macros
%D   {letbeundefined}
%D
%D Testing for being undefined comes down to testing on \type
%D {\relax} when we use \type {\csname}, but when using \type
%D {\ifx}, we test on being \type {\undefined}! In \ETEX\ we
%D have \type {\ifcsname} and that way of testing on existance
%D is not the same as the one described here. Therefore we
%D introduce:

\beginTEX

\def\letbeundefined#1%
  {\expandafter\let\csname#1\endcsname\relax}

\endTEX

\beginETEX \undefined

\def\letbeundefined#1% potential stack buildup when used \global
  {\expandafter\let\csname#1\endcsname\undefined}

\endETEX

%D Beware, being \type {\undefined} in \ETEX\ means that the macro
%D {\em is} defined!

%D Before we start using this variant, we used another one,
%D which is even a bit faster. This one looked like:
%D
%D \starttyping
%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 \stoptyping
%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 \starttyping
%D $\kern10pt\showthe\lastkern$
%D $\kern10pt{\showthe\lastkern}$
%D $\kern10pt\begingroup\showthe\lastkern\endgroup$
%D \stoptyping
%D
%D Also in math mode, one can better use \type {\begingroup}
%D and companion instead of \type {\bgroup}.
%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}.

\beginTEX

\def\docheckonedefined#1%
  {\ifundefined{#1}%
     \donefalse
   \fi}

\def\doifalldefinedelse#1%
  {\begingroup
   \let\donottest\dontprocesstest
   \donetrue
   \processcommalist[#1]\docheckonedefined
   \ifdone
     \endgroup\let\donottest\doprocesstest
     \expandafter\firstoftwoarguments
   \else
     \endgroup\let\donottest\doprocesstest
     \expandafter\secondoftwoarguments
   \fi}

\endTEX

\beginETEX \ifcsname

\def\docheckonedefined#1%
  {\unless\ifcsname#1\endcsname
     \donefalse
   \fi}

\def\doifalldefinedelse#1%
  {\begingroup
   \donetrue \processcommalist[#1]\docheckonedefined
   \ifdone
     \endgroup\expandafter\firstoftwoarguments
   \else
     \endgroup\expandafter\secondoftwoarguments
   \fi}

\endETEX

%D \macros
%D   {doif,doifelse,doifnot,
%D    donottest}
%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 \starttyping
%D \doif     {string1} {string2} {...}
%D \doifnot  {string1} {string2} {...}
%D \doifelse {string1} {string2} {then ...}{else ...}
%D \stoptyping
%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 \starttyping
%D \ifx\!!stringa\!!stringb
%D   \def\next{#3}%
%D \else
%D   \def\next{#4}%
%D \fi
%D \next
%D \stoptyping
%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.

\beginTEX

% \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 Slightly faster on big arguments, as well as \type
%D {\next} avoiding:

\long\def\doif#1#2%
  {\let\donottest\dontprocesstest
   \edef\!!stringa{#1}%
   \edef\!!stringb{#2}%
   \let\donottest\doprocesstest
   \ifx\!!stringa\!!stringb
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\long\def\doifnot#1#2%
  {\let\donottest\dontprocesstest
   \edef\!!stringa{#1}%
   \edef\!!stringb{#2}%
   \let\donottest\doprocesstest
   \ifx\!!stringa\!!stringb
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}


\long\def\doifelse#1#2%
  {\let\donottest\dontprocesstest
   \edef\!!stringa{#1}%
   \edef\!!stringb{#2}%
   \let\donottest\doprocesstest
   \ifx\!!stringa\!!stringb
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\endTEX

\beginETEX \protected

% \long\def\doif#1#2#3%
%   {\edef\!!stringa{#1}\edef\!!stringb{#2}%
%    \ifx\!!stringa\!!stringb#3\fi}
%
% \long\def\doifnot#1#2#3%
%   {\edef\!!stringa{#1}\edef\!!stringb{#2}%
%    \unless\ifx\!!stringa\!!stringb#3\fi}
%
% \long\def\doifelse#1#2#3#4%
%   {\edef\!!stringa{#1}\edef\!!stringb{#2}%
%    \ifx\!!stringa\!!stringb#3\else#4\fi}

%D Slightly faster on big arguments, as well as \type
%D {\next} avoiding:

\long\def\doif#1#2%
  {\edef\!!stringa{#1}\edef\!!stringb{#2}%
   \ifx\!!stringa\!!stringb
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\long\def\doifnot#1#2%
  {\edef\!!stringa{#1}\edef\!!stringb{#2}%
   \ifx\!!stringa\!!stringb
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\long\def\doifelse#1#2%
  {\edef\!!stringa{#1}\edef\!!stringb{#2}%
   \ifx\!!stringa\!!stringb
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\endETEX

%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 \starttyping
%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 \stoptyping
%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 We complete our set of conditionals with:
%D
%D \starttyping
%D \doifempty     {string} {...}
%D \doifnotempty  {string} {...}
%D \doifemptyelse {string} {then ...} {else ...}
%D \stoptyping
%D
%D This time, the string is not expanded.

\long\def\doifemptyelse#1%
  {\def\!!stringa{#1}%
   \ifx\!!stringa\empty
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\long\def\doifempty#1%
  {\def\!!stringa{#1}%
   \ifx\!!stringa\empty
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\long\def\doifnotempty#1%
  {\def\!!stringa{#1}%
   \ifx\!!stringa\empty
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

%D \macros
%D   {doifinset,doifnotinset,doifinsetelse}
%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 \starttyping
%D \doifinset     {string} {string,...} {...}
%D \doifnotinset  {string} {string,...} {...}
%D \doifinsetelse {string} {string,...} {then ...} {else ...}
%D \stoptyping
%D
%D The second argument is the comma separated set of strings.
%D
%D \starttyping
%D \long\def\doifinsetelse#1#2#3#4%
%D   {\doifelse{#1}{}
%D      {#4}
%D      {\donefalse
%D       \def\p!checkiteminset##1%
%D         {\doif{#1}{##1}
%D            {\donetrue
%D             \let\p!checkiteminset=\gobbleoneargument}}%
%D       \processcommalist[#2]\p!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 \stoptyping
%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}
%
% \beginTEX
%
% \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}
%
% \endTEX
%
% \beginETEX \protected
%
% \def\p!doifinsetelse#1#2%
%   {\donefalse
%    \edef\!!stringa{#1}%
%    \ifx\!!stringa\empty
%    \else
%      \let\p!docheckiteminset\p!dodocheckiteminset
%      \processcommalist[#2]\p!docheckiteminset
%    \fi
%    \ifdone}
%
% \endETEX

% then we had:
%
% \def\p!docheckiteminset#1%
%   {\edef\!!stringb{#1}%
%    \ifx\!!stringa\!!stringb
%      \donetrue
%      \expandafter\quitcommalist
%    \fi}
%
% \beginTEX
%
% \def\p!doifinsetelse#1#2%
%   {\let\donottest\dontprocesstest
%    \donefalse
%    \edef\!!stringa{#1}%
%    \ifx\!!stringa\empty
%    \else
%      \processcommalist[#2]\p!docheckiteminset
%    \fi
%    \let\donottest\doprocesstest
%    \ifdone}
%
% \endTEX
%
% % can be sped up with processnext...
%
% \beginETEX \protected
%
% \def\p!doifinsetelse#1#2%
%   {\donefalse
%    \edef\!!stringa{#1}%
%    \ifx\!!stringa\empty
%    \else
%      \processcommalist[#2]\p!docheckiteminset
%    \fi
%    \ifdone}
%
% \endETEX
%
% \long\def\doifinsetelse#1#2%
%   {\p!doifinsetelse{#1}{#2}%
%      \expandafter\firstoftwoarguments
%    \else
%      \expandafter\secondoftwoarguments
%    \fi}
%
% \long\def\doifinset#1#2%
%   {\p!doifinsetelse{#1}{#2}%
%      \expandafter\firstofoneargument
%    \else
%      \expandafter\gobbleoneargument
%    \fi}
%
% \long\def\doifnotinset#1#2%
%   {\p!doifinsetelse{#1}{#2}%
%      \expandafter\gobbleoneargument
%    \else
%      \expandafter\firstofoneargument
%     \fi}
%
% now we have

\def\p!docheckiteminset#1%
  {\edef\!!stringb{#1}%
   \ifx\!!stringa\!!stringb
     \donetrue
     \expandafter\quitcommalist
   \fi}

\beginTEX

\def\p!doifinsetelse#1#2#3#4%
  {\let\donottest\dontprocesstest
   \donefalse
   \edef\!!stringa{#3}%
   \ifx\!!stringa\empty
   \else
     \processcommalist[#4]\p!docheckiteminset
   \fi
   \let\donottest\doprocesstest
   \ifdone\expandafter#1\else\expandafter#2\fi}

\endTEX

\beginETEX \protected

\def\p!doifinsetelse#1#2#3#4%
  {\donefalse
   \edef\!!stringa{#3}%
   \ifx\!!stringa\empty
   \else
     \processcommalist[#4]\p!docheckiteminset
   \fi
   \ifdone\expandafter#1\else\expandafter#2\fi}

\endETEX

\long\def\doifinsetelse
  {\p!doifinsetelse\firstoftwoarguments\secondoftwoarguments}

\long\def\doifinset
  {\p!doifinsetelse\firstofoneargument\gobbleoneargument}

\long\def\doifnotinset
  {\p!doifinsetelse\gobbleoneargument\firstofoneargument}

%D \macros
%D   {doifcommon,doifnotcommon,doifcommonelse}
%D
%D Probably the most time consuming tests are those that test
%D for overlap in sets of strings.
%D
%D \starttyping
%D \doifcommon     {string,...} {string,...} {...}
%D \doifnotcommon  {string,...} {string,...} {...}
%D \doifcommonelse {string,...} {string,...} {then ...} {else ...}
%D \stoptyping
%D
%D We show the slower alternative first, because it shows us
%D how things are done.
%D
%D \starttyping
%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 \stoptyping
%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}
%
% \beginTEX
%
% \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}
%
% \endTEX
%
% \beginETEX \protected
%
% \def\p!doifcommonelse#1#2%
%   {\donefalse
%    \let\p!dodocommoncheck\p!dododocommoncheck
%    \def\p!docommoncheck##1%
%      {\edef\!!stringa{##1}%
%       \def\commalistelement{##1}%
%       \processcommalist[#2]\p!dodocommoncheck}%
%    \processcommalist[#1]\p!docommoncheck
%    \ifdone}
%
% \endETEX

% \def\p!dodocommoncheck#1%
%   {\edef\!!stringb{#1}%
%    \ifx\!!stringa\!!stringb
%      \donetrue
%      \expandafter\quitprevcommalist
%    \fi}
%
% \beginTEX
%
% \def\p!doifcommonelse#1#2%
%   {\donefalse
%    \let\donottest\dontprocesstest
%    \def\p!docommoncheck##1%
%      {\edef\!!stringa{##1}%
%       \def\commalistelement{##1}% no let to stringa
%       \processcommalist[#2]\p!dodocommoncheck}%
%    \processcommalist[#1]\p!docommoncheck
%    \let\donottest\doprocesstest
%    \ifdone}
%
% \endTEX
%
% \beginETEX \protected
%
% \def\p!doifcommonelse#1#2%
%   {\donefalse
%    \def\p!docommoncheck##1%
%      {\edef\!!stringa{##1}%
%       \def\commalistelement{##1}%
%       \processcommalist[#2]\p!dodocommoncheck}%
%    \processcommalist[#1]\p!docommoncheck
%    \ifdone}
%
% \endETEX
%
% \long\def\doifcommonelse#1#2%  % #3#4%
%   {\p!doifcommonelse{#1}{#2}%  % #3\else#4\fi}
%      \expandafter\firstoftwoarguments
%    \else
%      \expandafter\secondoftwoarguments
%    \fi}
%
% \long\def\doifcommon#1#2%
%   {\p!doifcommonelse{#1}{#2}%
%      \expandafter\firstofoneargument
%    \else
%      \expandafter\gobbleoneargument
%    \fi}
%
% \long\def\doifnotcommon#1#2%
%   {\p!doifcommonelse{#1}{#2}%
%      \expandafter\gobbleoneargument
%    \else
%      \expandafter\firstofoneargument
%    \fi}

\def\p!dodocommoncheck#1%
  {\edef\!!stringb{#1}%
   \ifx\!!stringa\!!stringb
     \donetrue
     \expandafter\quitprevcommalist
   \fi}

\beginTEX

\def\p!doifcommonelse#1#2#3#4%
  {\donefalse
   \let\donottest\dontprocesstest
   \def\p!docommoncheck##1%
     {\edef\!!stringa{##1}%
      \def\commalistelement{##1}% no let to stringa
      \processcommalist[#4]\p!dodocommoncheck}%
   \processcommalist[#3]\p!docommoncheck
   \let\donottest\doprocesstest
   \ifdone\expandafter#1\else\expandafter#2\fi}

\endTEX

\beginETEX \protected

\def\p!doifcommonelse#1#2#3#4%
  {\donefalse
   \def\p!docommoncheck##1%
     {\edef\!!stringa{##1}%
      \def\commalistelement{##1}%
      \processcommalist[#4]\p!dodocommoncheck}%
   \processcommalist[#3]\p!docommoncheck
   \ifdone\expandafter#1\else\expandafter#2\fi}

\endETEX

\def\doifcommonelse
  {\p!doifcommonelse\firstoftwoarguments\secondoftwoarguments}

\def\doifcommon
  {\p!doifcommonelse\firstofoneargument \gobbleoneargument}

\def\doifnotcommon
  {\p!doifcommonelse\gobbleoneargument  \firstofoneargument}

%D \macros
%D   {processcommalist,processcommacommand,quitcommalist,
%D    processcommalistwithparameters}
%D
%D We've already seen some macros that take care of comma
%D separated lists. Such list can be processed with
%D
%D \starttyping
%D \processcommalist[string,string,...]\commando
%D \stoptyping
%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 1: \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par
%D 2: \processcommalist [{a,b,c,d,e,f}]        \dosomething \par
%D 3: \processcommalist [{a,b,c},d,e,f]        \dosomething \par
%D 4: \processcommalist [a,b,{c,d,e},f]        \dosomething \par
%D 5: \processcommalist [a{b,c},d,e,f]         \dosomething \par
%D 6: \processcommalist [{a,b}c,d,e,f]         \dosomething \par
%D 7: \processcommalist []                     \dosomething \par
%D 8: \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]%
%     \let\nextcommaitem\gobbleoneargument
%   \else
%     \let\nextcommaitem\dododoprocesscommaitem
%   \fi\fi
%   \nextcommaitem}
%
% faster ?

\def\dodoprocesscommaitem
  {\ifx\nexttoken\blankspace
     \@EA\redoprocesscommaitem
   \else\ifx\nexttoken]%
     \@EAEAEA\gobbleoneargument
   \else
     \@EAEAEA\dododoprocesscommaitem
   \fi\fi}

\def\doprocesscommaitem
  {\futurelet\nexttoken\dodoprocesscommaitem}

%D Empty arguments are not processed. Empty items (\type{,,})
%D however are treated. We have to check for the special case
%D \type{[{a,b,c}]}.
%D
%D \starttyping
%D \def\processcommalist[%
%D   {\futurelet\nexttoken\docheckcommaitem}
%D
%D \def\docheckcommaitem%
%D   {\ifx\nexttoken]%
%D      \let\nextcommaitem\gobbletwoarguments
%D    \else\ifx\nexttoken\bgroup
%D      \let\nextcommaitem\doprocesscommalistA
%D    \else
%D      \let\nextcommaitem\doprocesscommalistB
%D    \fi\fi
%D    \nextcommaitem}
%D
%D \def\doprocesscommalistA#1#2]#3%
%D   {\global\advance\commalevel 1
%D    \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,%
%D      {#3{##1}\doprocesscommaitem}%
%D    \doprocesscommaitem{#1}#2,]\relax
%D    \global\advance\commalevel -1 }
%D
%D \def\doprocesscommalistB#1]#2%
%D   {\global\advance\commalevel 1
%D    \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,%
%D      {#2{##1}\doprocesscommaitem}%
%D    \doprocesscommaitem#1,]\relax
%D    \global\advance\commalevel -1 }
%D \stoptyping
%D
%D However, this is not a the most straightforward solution!
%D We can misuse one of \TEX's hidden features, and prepend
%D and remove a \type {\relax}. By the way, although it
%D involves less testing, this cleaner alternative is not
%D faster.

\def\processcommalist[%
  {\futurelet\nexttoken\docheckcommaitem}

\def\docheckcommaitem
  {\ifx\nexttoken]%
     \expandafter\gobblethreearguments
   \else
     \expandafter\doprocesscommalist
   \fi
   \relax} % this one preserved the next {}

\def\doprocesscommalist#1]#2%
  {\global\advance\commalevel \plusone
   \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,%
     {#2{##1}\doprocesscommaitem}%
   \@EA\dodoprocesscommaitem\gobbleoneargument#1,]\relax
   \global\advance\commalevel \minusone }

%D One way of quitting a commalist halfway is:

\def\quitcommalist
  {\begingroup\let\doprocesscommaitem\doquitcommalist}

\def\doquitcommalist#1]%
  {\endgroup}

\def\quitprevcommalist
  {\begingroup\let\doprocesscommaitem\doquitprevcommalist}

\def\doquitprevcommalist#1]%
  {\let\doprocesscommaitem\doquitcommalist}

%D The hack we used for checking the next character
%D \type {\doifnextcharelse} is also used here.

\def\:{\redoprocesscommaitem}

\expandafter\def\: {\futurelet\nexttoken\dodoprocesscommaitem}

%D The previous examples lead to:
%D
%D \getbuffer

%D When a list is saved in a macro, we can use a construction
%D like:
%D
%D \starttyping
%D \expandafter\processcommalist\expandafter[\list]\command
%D \stoptyping
%D
%D Such solutions suit most situations, but we wanted a bit
%D more.
%D
%D \starttyping
%D \processcommacommand[string,\stringset,string]\commando
%D \stoptyping
%D
%D where \type{\stringset} is a predefined set, like:
%D
%D \starttyping
%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 \stoptyping
%D
%D Commands that are part of the list are expanded, so the
%D use of this macro has its limits.

\def\processcommacommand[#1]%
  {\expanded{\processcommalist[#1]}}

%D The argument to \type{\command} is not delimited. Because
%D we often use \type{[]} as delimiters, we also have:
%D
%D \starttyping
%D \processcommalistwithparameters[string,string,...]\command
%D \stoptyping
%D
%D where \type{\command} looks like:
%D
%D \starttyping
%D \def\command[#1]{... #1 ...}
%D \stoptyping

\def\processcommalistwithparameters[#1]#2%
  {\def\docommand##1{#2[##1]}%
   \processcommalist[#1]\docommand}

%D \macros
%D   {processaction,
%D    processfirstactioninset,
%D    processallactionsinset}
%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 \starttyping
%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 \stoptyping
%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 \starttyping
%D \processallactionsinset
%D   [x,y,z]
%D   [      a=>\a,
%D          b=>\b,
%D          c=>\c,
%D    default=>\default,
%D    unknown=>\unknown{... \commalistelement ...}]
%D \stoptyping
%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 \starttyping
%D \newcount\processlevel
%D
%D \def\processaction[#1]#2[#3]%
%D   {\doifelse{#1}{}
%D      {\def\p!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\p!compareprocessaction[##1=>##2]%
%D         {\edef\!!stringa{##1}%
%D          \ifx\!!stringa\!!stringb
%D            \def\commalistelement{#1}%
%D            ##2%
%D            \let\p!doprocessaction=\gobbleoneargument
%D          \else\ifx\!!stringa\s!unknown
%D            \def\commalistelement{#1}%
%D            ##2%
%D          \fi\fi}}%
%D    \def\p!doprocessaction##1%
%D      {\p!compareprocessaction[##1]}%
%D    \processcommalist[#3]\p!doprocessaction}
%D
%D \def\processfirstactioninset[#1]#2[#3]%
%D   {\doifelse{#1}{}
%D      {\processaction[][#3]}
%D      {\def\p!compareprocessaction[##1=>##2][##3]%
%D         {\edef\!!stringa{##1}%
%D          \edef\!!stringb{##3}%
%D          \ifx\!!stringa\!!stringb
%D            \def\commalistelement{##3}%
%D            ##2%
%D            \let\p!doprocessaction=\gobbleoneargument
%D            \let\p!dodoprocessaction=\gobbleoneargument
%D          \else\ifx\!!stringa\s!unknown
%D            \def\commalistelement{##3}%
%D            ##2%
%D          \fi\fi}%
%D       \def\p!doprocessaction##1%
%D         {\def\p!dodoprocessaction####1%
%D            {\p!compareprocessaction[####1][##1]}%
%D          \processcommalist[#3]\p!dodoprocessaction}%
%D       \processcommalist[#1]\p!doprocessaction}}
%D
%D \def\processallactionsinset[#1]#2[#3]%
%D   {\doifelse{#1}{}
%D      {\processaction[][#3]}
%D      {\advance\processlevel by 1
%D       \def\p!compareprocessaction[##1=>##2][##3]%
%D         {\edef\!!stringa{##1}%
%D          \edef\!!stringb{##3}%
%D          \ifx\!!stringa\!!stringb
%D            \def\commalistelement{##3}%
%D            ##2%
%D            \let\p!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\p!dodoprocessaction####1%
%D            {\p!compareprocessaction[####1][##1]}%
%D          \processcommalist[#3]\p!dodoprocessaction}%
%D       \processcommalist[#1]{\getvalue{\s!do\the\processlevel}}%
%D       \advance\processlevel by -1 }}
%D \stoptyping
%D
%D The gain of speed in the (again) next implementation is
%D around 20\%, depending on the application.

\newcount\processlevel

\def\p!compareprocessactionA[#1=>#2][#3]%
  {\edef\!!stringb{#1}%
   \ifx\!!stringb\s!default
     \let\commalistelement\empty
     #2%
   \fi}

% \def\p!compareprocessactionB[#1=>#2][#3]%
%   {\expandedaction\!!stringb{#1}%
%    \ifx\!!stringa\!!stringb
%      \def\commalistelement{#3}%
%      #2%
%      \let\p!doprocessaction\gobbleoneargument
%    \else
%      \edef\!!stringb{#1}%
%      \ifx\!!stringb\s!unknown
%        \def\commalistelement{#3}% beware of loops
%        #2%
%      \fi
%    \fi}

% met \quitcommalist tot meer dan 25\% sneller

\def\p!compareprocessactionB[#1=>#2][#3]%
  {\expandedaction\!!stringb{#1}%
   \ifx\!!stringa\!!stringb
     \def\commalistelement{#3}%
     #2%
     \expandafter\quitcommalist
   \else
     \edef\!!stringb{#1}%
     \ifx\!!stringb\s!unknown
       \def\commalistelement{#3}% beware of loops
       #2%
     \fi
   \fi}

\beginTEX

\def\processaction[#1]#2[#3]%
  {\let\donottest\dontprocesstest
   \expandedaction\!!stringa{#1}%
   \let\donottest\doprocesstest
   \ifx\!!stringa\empty
     \let\p!compareprocessaction\p!compareprocessactionA
   \else
     \let\p!compareprocessaction\p!compareprocessactionB
   \fi
   \def\p!doprocessaction##1%
     {\p!compareprocessaction[##1][#1]}%
   \processcommalist[#3]\p!doprocessaction
   \expandactions}

\endTEX

\beginETEX \protected

\def\processaction[#1]#2[#3]% faster version follows
  {\expandedaction\!!stringa{#1}%
   \ifx\!!stringa\empty
     \let\p!compareprocessaction\p!compareprocessactionA
   \else
     \let\p!compareprocessaction\p!compareprocessactionB
   \fi
   \def\p!doprocessaction##1%
     {\p!compareprocessaction[##1][#1]}%
   \processcommalist[#3]\p!doprocessaction
   \expandactions}

\endETEX

% \def\p!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\p!compareprocessactionC[#1=>#2][#3]%
  {\expandedaction\!!stringa{#1}%
   \expandedaction\!!stringb{#3}%
   \ifx\!!stringa\!!stringb
     \def\commalistelement{#3}%
     #2%
     \expandafter\quitprevcommalist
   \else
     \edef\!!stringa{#1}%
     \ifx\!!stringa\s!unknown
       \def\commalistelement{#3}%
       #2%
     \fi
   \fi}

\def\processfirstactioninset[#1]#2[#3]% faster version follows
  {\expandedaction\!!stringa{#1}%
   \ifx\!!stringa\empty
     \processaction[][#3]%
   \else
     \def\p!doprocessaction##1%
       {\def\p!dodoprocessaction####1%
          {\p!compareprocessactionC[####1][##1]}%
        \processcommalist[#3]\p!dodoprocessaction}%
     \processcommalist[#1]\p!doprocessaction
   \fi
   \expandactions}

% \def\p!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\p!compareprocessactionD[#1=>#2][#3]%
  {\expandedaction\!!stringa{#1}%
   \expandedaction\!!stringb{#3}%
   \ifx\!!stringa\!!stringb
     \def\commalistelement{#3}%
     #2%
     \expandafter\quitcommalist
   \else
     \edef\!!stringa{#1}%
     \ifx\!!stringa\s!unknown
       \def\commalistelement{#3}%
       #2%
     \fi
   \fi}

\def\doprocessallactionsinset
  {\csname\s!do\the\processlevel\endcsname}

\def\processallactionsinset[#1]#2[#3]% faster version follows
  {\expandedaction\!!stringa{#1}%
   \ifx\!!stringa\empty
     \processaction[][#3]%
   \else
     \advance\processlevel \plusone
     \expandafter\def\csname\s!do\the\processlevel\endcsname##1%
       {\def\p!dodoprocessaction####1%
          {\p!compareprocessactionD[####1][##1]}%
        \processcommalist[#3]\p!dodoprocessaction}%
     \processcommalist[#1]\doprocessallactionsinset
     \advance\processlevel \minusone
   \fi
   \expandactions}

%D We can speed up these macros a bit when we use a dedicated
%D commalist processor, one that avoids passing the (often)
%D big action list.

\beginTEX

\def\processaction[#1]#2[%
  {\let\donottest\dontprocesstest
   \expandedaction\!!stringa{#1}%
   \let\donottest\doprocesstest
   \ifx\!!stringa\empty
     \let\p!compareprocessaction\p!compareprocessactionA
   \else
     \let\p!compareprocessaction\p!compareprocessactionB
   \fi
   \def\p!doprocessaction##1%
     {\p!compareprocessaction[##1][#1]}%
   \processnextcommalist\relax\expandactions\p!doprocessaction[}

\endTEX

\beginETEX

\def\processaction[#1]#2[%
  {\expandedaction\!!stringa{#1}%
   \ifx\!!stringa\empty
     \let\p!compareprocessaction\p!compareprocessactionA
   \else
     \let\p!compareprocessaction\p!compareprocessactionB
   \fi
   \def\p!doprocessaction##1%
     {\p!compareprocessaction[##1][#1]}%
   \processnextcommalist\relax\expandactions\p!doprocessaction[}

\endETEX

\def\processfirstactionsinset[#1]%
  {\expandedaction\!!stringa{#1}%
   \ifx\!!stringa\empty
     \expandafter\processaction
   \else
     \expandafter\processfirstactionsinsetindeed
   \fi
   [#1]}

\def\processfirstactioninsetindeed[#1]#2[#3]%
  {\def\p!doprocessaction##1%
     {\def\p!dodoprocessaction####1%
        {\p!compareprocessactionC[####1][##1]}%
      \processcommalist[#3]\p!dodoprocessaction}%
   \processcommalist[#1]\p!doprocessaction
   \expandactions}

\def\processallactionsinset[#1]%
  {\expandedaction\!!stringa{#1}%
   \ifx\!!stringa\empty
     \expandafter\processaction
   \else
     \expandafter\processallactionsinsetindeed
   \fi
   [#1]}

\def\processallactionsinsetindeed[#1]#2[#3]%
  {\advance\processlevel \plusone
   \expandafter\def\csname\s!do\the\processlevel\endcsname##1%
     {\def\p!dodoprocessaction####1%
        {\p!compareprocessactionD[####1][##1]}%
      \processcommalist[#3]\p!dodoprocessaction}%
   \processcommalist[#1]\doprocessallactionsinset
   \advance\processlevel \minusone
   \expandactions}

\def\processnextcommalist#1#2#3[#4#5]%
  {#1%
   \let\nexttoken#4%
   \global\advance\commalevel \plusone
   \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,%
     {#3{##1}\doprocesscommaitem}%
   \dodoprocesscommaitem#4#5,]\relax
   \global\advance\commalevel \minusone
   #2}

%D I do have an even faster version (saving 3 sec on a 13
%D sec run for 50K invocations, but normally we don't have
%D that many calls and that alternative uses more macros and is
%D even less readable. What we did add, was \type {\@EA}, so
%D that we can pass a command.

%D \macros
%D   {unexpandedprocessaction,
%D    unexpandedprocessfirstactioninset,
%D    unexpandedprocessallactionsinset}
%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, doiffirstcharacter}
%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 \starttyping
%D \getfirstcharacter {string}
%D \stoptyping
%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\\}

\def\doiffirstcharelse#1#2% char string
% kort (maar onleesbaar)
% {\expanded{\dogetfirstcharacter#2}\\\doifelse{#1}\firstcharacter}
% korter (en begrijpelijk))
  {\getfirstcharacter{#2}\doifelse{#1}\firstcharacter}
% snel (maar zelden gebruikt, dus niet zo belangrijk)
% {\getfirstcharacter{#2}%
%  \edef\!!stringa{#1}%
%  \ifx\!!stringa\firstcharacter
%    \expandafter\firstoftwoarguments
%  \else
%    \expandafter\secondoftwoarguments
%  \fi}

%D \macros
%D   {doifinstringelse, doifincsnameelse}
%D
%D We can check for the presence of a substring in a given
%D sequence of characters.
%D
%D \starttyping
%D \doifinsetelse {substring} {string} {then ...} {else ...}
%D \stoptyping
%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 \starttyping
%D \long\def\p!doifinstringelse#1#2#3#4%
%D   {\def\pp!doifinstringelse##1#1##2##3\war%
%D      {\if##2@%
%D         #4%
%D       \else
%D         #3%
%D       \fi}%
%D    \pp!doifinstringelse#2#1@@\war}
%D
%D \def\doifinstringelse%
%D   {\ExpandBothAfter\p!doifinstringelse}
%D \stoptyping
%D
%D After this we came to:
%D
%D \starttyping
%D \def\p!doifinstringelse#1#2%
%D   {\def\pp!doifinstringelse##1#1##2##3\war%
%D      {\if##2@}%
%D    \pp!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 \stoptyping
%D
%D Sometimes the second argument is passed as a macro. By
%D postponing the expansion of this macro, we gain quite some
%D run time, simply because the less tokens we pass, the faster
%D \TEX\ runs. So finally the definition became:

\long\def\doifinstringelse#1%
  {\edef\@@@instring{#1}% expand #1 here
   \ifx\@@@instring\empty
     \@EA\thirdofthreearguments
   \else
     \@EA\dodoifinstringelse
   \fi}

\long\def\dodoifinstringelse#1%
  {\p!doifinstringelse\@@@instring{#1}%
     \@EA\firstoftwoarguments
   \else
     \@EA\secondoftwoarguments
   \fi}

\long\def\doifinstring#1%%
  {\edef\@@@instring{#1}% expand #1 here
   \ifx\@@@instring\empty
     \@EA\gobbletwoarguments
   \else
     \@EA\dodoifinstring
   \fi}

\long\def\dodoifinstring#1%
  {\p!doifinstringelse\@@@instring{#1}%
     \@EA\firstofoneargument
   \else
     \@EA\gobbleoneargument
   \fi}

%D \starttyping
%D \beginTEX
%D
%D \long\def\p!doifinstringelse#1#2%
%D   {\long\def\pp!doifinstringelse##1#1##2##3\war%
%D      {\csname if\if##2@fals\else tru\fi e\endcsname}%
%D    \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here
%D
%D \endTEX
%D
%D \beginETEX \unless
%D
%D \long\def\p!doifinstringelse#1#2%
%D   {\long\def\pp!doifinstringelse##1#1##2##3\war%
%D      {\unless\if##2@}%
%D    \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here
%D
%D \endETEX
%D \stoptyping
%D
%D And then \unknown\ after a couple of years, we ran into a
%D situation where \type {##2} was something \type {{bla}}. So
%D finally we need to use an auxiliary macro, otherwise we get
%D funny strings in the output.

% \long\def\p!doifinstringelse#1#2% ##2 can be {abc}
%   {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war % expand #1 here
%      {\ppp!doifinstringelse##2\war}%
%    \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here
%
% \beginTEX
%
% \def\ppp!doifinstringelse#1#2\war%
%   {\csname if\ifx#1@fals\else tru\fi e\endcsname}%
%
% \endTEX
%
% \beginETEX \unless
%
% \def\ppp!doifinstringelse#1#2\war%
%   {\unless\ifx#1@}
%
% \endETEX

\beginETEX

\long\def\p!doifinstringelse#1#2% ##2 can be {abc}
  {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war % expand #1 here
     {\unless\if##2@}%
%  \expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here
   \expanded{\pp!doifinstringelse#2#1}@@\war} % expand #2 here

\endETEX

\beginTEX

\long\def\p!doifinstringelse#1#2% ##2 can be {abc}
  {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war % expand #1 here
     {\csname if\if##2@fals\else tru\fi e\endcsname}%
  %\expanded{\pp!doifinstringelse#2#1@@\noexpand\war}} % expand #2 here
   \expanded{\pp!doifinstringelse#2#1}@@\war} % expand #2 here

\endTEX

%D The next alternative proved to be upto twice as fast on
%D tasks like checking reserved words in pretty verbatim
%D typesetting! This is mainly due to the fact that passing
%D (expanded) strings is much slower that passing a macro.
%D
%D \starttyping
%D \doifincsnameelse {substring} {\string} {then ...} {else ...}
%D \stoptyping
%D
%D Where \type{\doifinstringelse} does as much expansion as
%D possible, the latter alternative does minimal (one level)
%D expansion.

\beginTEX

\long\def\p!doifincsnameelse#1#2%
  {\long\def\pp!doifincsnameelse##1#1##2##3\war
     {\csname if\if##2@fals\else tru\fi e\endcsname}%
   \@EA\pp!doifincsnameelse#2#1@@\war}

\endTEX

\beginETEX \unless

\long\def\p!doifincsnameelse#1#2%
  {\long\def\pp!doifincsnameelse##1#1##2##3\war
     {\unless\if##2@}%
   \@EA\pp!doifincsnameelse#2#1@@\war}

\endETEX

\long\def\doifincsnameelse#1#2%                   % #3#4%
  {\edef\@@@instring{#1}%
   \@EA\p!doifincsnameelse\@EA{\@@@instring}{#2}% % #3\else#4\fi}
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

%D \macros
%D   {doifnumberelse}
%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 \starttyping
%D \doifnumberelse {string} {then ...} {else ...}
%D \stoptyping
%D
%D The macro accepts \type{123}, \type{abc}, \type{{}},
%D \type{\getal} and \type{\the\count...}. This macro is a
%D rather dirty one.
%D
%D \starttyping
%D \long\def\doifnumberelse#1#2#3%
%D   {\begingroup\donefalse
%D    \ifcase1#1\or\or\or\or\or\or\or\or\or\else\donetrue\fi
%D    \ifdone\endgroup#2\else\endgroup#3\fi}
%D \stoptyping
%D
%D Or better:
%D
%D \starttyping
%D \long\def\doifnumberelse#1%
%D   {\begingroup\donefalse
%D    \ifcase1#1\or\or\or\or\or\or\or\or\or\else\donetrue\fi
%D    \ifdone
%D      \endgroup\expandafter\firstoftwoarguments
%D    \else
%D      \endgroup\expandafter\secondoftwoarguments
%D    \fi}
%D \stoptyping
%D
%D A previous implementation was:
%D
%D \starttyping
%D \long\def\doifnumberelse#1#2#3%
%D   {\getfirstcharacter{#1}%
%D    \@EA\p!doifinstringelse\@EA{\firstcharacter}{1234567890}%
%D      #2%
%D    \else
%D      #3%
%D    \fi}
%D \starttyping
%D
%D And before we had \type{\p!doifinstringelse} available, we
%D used:
%D
%D \starttyping
%D \def\doifnumberelse#1%
%D   {\getfirstcharacter{#1}%
%D    \rawdoifinsetelse{\firstcharacter}{1,2,3,4,5,6,7,8,9,0}}
%D \stoptyping
%D
%D The implementation using \type {\ifcase} is much faster, but
%D the next one is not, not even when testing milion calls.
%D
%D \starttyping
%D \newif\ifitsanumber
%D
%D \long\def\isitanumber#1%
%D   {\itsanumberfalse
%D    \ifcase1#1\or\or\or\or\or\or\or\or\or\else\itsanumbertrue\fi}
%D
%D \long\def\doifnumberelse#1#2#3%
%D   {\isitanumber{#1}\ifitsanumber#2\else#3\fi}
%D \stoptyping
%D
%D After a while the next evolved and this one is the one we
%D will use. This one is some 5\% faster than the group/done
%D one (partly because it does not have to pass arguments).
%D Even more important is that this alternative is fully
%D expandable!

\long\def\doifnumberelse#1%
  {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

%D \macros
%D   {makerawcommalist,
%D    rawdoinsetelse,
%D    rawprocesscommalist,
%D    rawprocessaction}
%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 \starttyping
%D \makerawcommalist[string,string,...]\stringlist
%D \rawdoifinsetelse{string}{string,...}{...}{...}
%D \rawprocesscommalist[string,string,...]\commando
%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c]
%D \stoptyping
%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).
%D
%D The slow alternative looks like:
%D
%D \starttyping
%D \def\makerawcommalist[#1]#2%
%D   {\def\appendtocommalist##1%
%D      {\doifelse{#2}{}
%D         {\edef#2{##1}}
%D         {\edef#2{#2,##1}}}%
%D    \def#2{}%
%D    \processcommalist[#1]\appendtocommalist}
%D \stoptyping
%D
%D But we prefer:

% \appendtocommalist is defined in syst-ext

\def\makerawcommalist[#1]#2% use \processnext ... here
  {\def\domakerawcommalist##1% we don't expand ##1
     {\ifx#2\empty
        \def#2{##1}%
      \else
        \@EA\def\@EA#2\@EA{#2,##1}%
      \fi}%
   \let#2\empty
   \processcommalist[#1]\domakerawcommalist}

\def\rawprocesscommaitem#1,#2% #2 eats up preceding space
  {\if]#1\else
     \csname\s!next\the\commalevel\endcsname{#1}%
     \expandafter\rawprocesscommaitem
   \fi#2}

\def\rawprocesscommalist[#1]#2% accepteert ook [\cs]
  {\global\advance\commalevel \plusone
   \expandafter\let\csname\s!next\the\commalevel\endcsname#2%
   \expandafter\rawprocesscommaitem#1,],% \relax
   \global\advance\commalevel \minusone }

\def\rawprocesscommacommand[#1]% not really needed
  {\expanded{\rawprocesscommalist[#1]}}

% \def\rawdoifinsetelse#1#2{\doifinstringelse{,#1,}{,#2,}}
% \def\rawdoifinset    #1#2{\doifinstring    {,#1,}{,#2,}}

\def\@@rawempty{,,}

\long\def\rawdoifinsetelse#1%
  {\edef\@@@instring{,#1,}% expand #1 here
   \ifx\@@@instring\@@rawempty
     \@EA\thirdofthreearguments
   \else
     \@EA\rawdodoifinsetelse
   \fi}

\long\def\rawdodoifinsetelse#1%
  {\p!doifinstringelse\@@@instring{,#1,}%
     \@EA\firstoftwoarguments
   \else
     \@EA\secondoftwoarguments
   \fi}

\long\def\rawdoifinset#1%
  {\edef\@@@instring{,#1,}% expand #1 here
   \ifx\@@@instring\@@rawempty
     \@EA\gobbletwoarguments
   \else
     \@EA\rawdodoifinset
   \fi}

\long\def\rawdodoifinset#1%%
  {\p!doifinstringelse\@@@instring{,#1,}%
     \@EA\firstofoneargument
   \else
     \@EA\gobbleoneargument
   \fi}

%D Some more raw material:

\def\p!rawprocessaction[#1][#2]%
  {\def\pp!rawprocessaction##1,#1=>##2,##3\war%
     {\if##3@\else
        \def\!!processaction{##2}%
      \fi}%
   \pp!rawprocessaction,#2,#1=>,@\war}

\def\rawprocessaction[#1]#2[#3]%
  {\edef\!!stringa{#1}%
   \edef\!!stringb{undefined}% better \!!undefined
   \let\!!processaction\!!stringb
   \ifx\!!stringa\empty
     \@EA\p!rawprocessaction\@EA[\s!default][#3]%
   \else
      \expandafter\p!rawprocessaction\expandafter[\!!stringa][#3]%
      \ifx\!!processaction\!!stringb
        \@EA\p!rawprocessaction\@EA[\s!unknown][#3]%
      \fi
   \fi
   \ifx\!!processaction\!!stringb
   \else
     \!!processaction
   \fi}

% not needed
%
% \def\rawprocessallactionsinset[#1]#2[#3]%
%   {\def\docommando##1%
%      {\rawprocessaction[##1][#3]}%
%    \processcommalist[#1]\docommando}

%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 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 \starttyping
% %D \processunexpandedcommalist
% %D   [\alfa\beta,\gamma,\delta\epsilon]
% %D   \handleitem
% %D \stoptyping
% %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}
%
% faster:
%
% \def\processunexpandedcommaitem#1,%
%   {\if]\noexpand#1\else
%      \handleunexpandedcommaitem{#1}%
%      \expandafter\processunexpandedcommaitem
%    \fi}
%
% \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,dosetgvalue,docopyvalue,doresetvalue,
%D    dogetvalue}
%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 \starttyping
%D \dosetvalue   {label}    {variable}   {value}
%D \dosetevalue  {label}    {variable}   {value}
%D \dosetgvalue  {label}    {variable}   {value}
%D \docopyvalue  {to label} {from label} {variable}
%D \doresetvalue {label}    {variable}
%D \stoptyping
%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\dosetgvalue#1#2% #3
  {\@EA\gdef\csname#1#2\endcsname} % {#3}}

\def\doresetvalue#1#2%
  {\@EA\let\csname#1#2\endcsname\empty}

\def\doignorevalue#1#2#3%
  {\@EA\let\csname#1#2\endcsname\empty}

\def\docopyvalue#1#2#3%
  {\@EA\def\csname#1#3\endcsname{\csname#2#3\endcsname}}

%D \macros
%D   {doassign,undoassign,doassignempty}
%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 \starttyping
%D \doassign[label][variable=value]
%D \undoassign[label][variable=value]
%D \stoptyping
%D
%D and:
%D
%D \starttyping
%D \doassignempty[label][variable=value]
%D \stoptyping
%D
%D Assignments like \type{\doassign} are compatible with:
%D
%D \starttyping
%D \def\labelvariable{value}
%D \stoptyping
%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.

\newif\iferrorisfatal

\def\waitonfatalerror
  {\iferrorisfatal\wait\fi}

\def\showassignerror#1#2%
  {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}%
   \waitonfatalerror}

%\def\p!doassign#1[#2][#3=#4=#5]%
%  {\let\donottest\dontprocesstest
%   \edef\!!stringa{#5}%
%   \let\!!stringb\relax
%   \let\donottest\doprocesstest
%   \ifx\!!stringa\!!stringb
%     \showassignerror{#3}%
%   \else
%     #1{#2}{#3}{#4}%
%   \fi}

\def\p!doassign#1[#2][#3=#4=#5]%
  {\ifx\empty#3\else  % and definitely not \ifx#3\empty
     \ifx\relax#5%
       \showassignerror{#3}{\the\inputlineno\space(#2)}%
     \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]%
  {\ifundefined{#1#2}\dosetvalue{#1}{#2}{#3}\fi}

%D \macros
%D   {getparameters,geteparameters,getgparameters,
%D    forgetparameters}
%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 \starttyping
%D \getparameters    [label] [...=...,...=...]
% %D \forgetparameters [label] [...=...,...=...]
%D \stoptyping
%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 \starttyping
%D \getparameters
%D   [demo]
%D   [alfa=1,
%D    beta=2]
%D \stoptyping
%D
%D is equivalent to
%D
%D \starttyping
%D \def\demoalfa{1}
%D \def\demobeta{2}
%D \stoptyping
%D
%D
%D In the pre||multi||lingual stadium \CONTEXT\ took the next
%D approach. With
%D
%D \starttyping
%D \def\??demo {@@demo}
%D \def\!!alfa {alfa}
%D \def\!!beta {beta}
%D \stoptyping
%D
%D calling
%D
%D \starttyping
%D \getparameters
%D   [\??demo]
%D   [\!!alfa=1,
%D    \!!beta=2]
%D \stoptyping
%D
%D lead to:
%D
%D \starttyping
%D \def\@@demoalfa{1}
%D \def\@@demobeta{2}
%D \stoptyping
%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\getgparameters  {\dogetparameters\dosetgvalue}
\def\forgetparameters{\dogetparameters\doignorevalue}

\let\getexpandedparameters=\geteparameters

%D This one is slightly faster:

\def\dogetparameters#1[#2]#3[#4%
  {\if\noexpand#4]%
     \expandafter\gobbleoneargument
   \else
     \def\p!dogetparameter##1{\p!doassign#1[#2][##1==\relax]}%
     \expandafter\xdogetparameters
   \fi#4}

\def\xdogetparameters#1]%
  {\processcommalist[#1]\p!dogetparameter}

%D The next alternative is much faster but also uglier. Because
%D in \XML\ processing we will probably set much more parameters
%D than normally we need this faster one.

\def\dogetparameters#1[#2]#3[#4%
  {\if\noexpand#4]%
     \expandafter\gobbleoneargument
   \else
     \def\p!dogetparameter{\p!doassign#1#2}%
     \expandafter\xdogetparameters
   \fi#4}

\def\xdogetparameters#1]%
  {\xprocesscommaitem#1,],\@relax@}

% \long\def\xprocesscommaitem#1,#2% #2 takes space before ,
%   {\if]#1%
%      \expandafter\gobbleoneargument
%    \else
%      \p!dogetparameter\@relax@#1==\@relax@
%      \expandafter\xprocesscommaitem
%    \fi#2}

\long\def\xprocesscommaitem#1,#2% #2 takes space before ,
  {\if,#1,% dirty trick for testing #1=empty
     \@EA\xprocesscommaitem
   \else\if]#1%
     \@EAEAEA\gobbleoneargument
   \else
     \p!dogetparameter\@relax@#1==\empty\@relax@
     \@EAEAEA\xprocesscommaitem
   \fi\fi#2}

%D Here we use a slightly different assignment macro:

% \def\p!doassign#1#2\@relax@#3=#4=#5\@relax@
%   {\ifx\@relax@#5\@EA\xshowassignerror\else\@EA#1\fi{#2}{#3}{#4}}

% \def\p!doassign#1#2\@relax@#3=#4=#5\@relax@
%   {\ifx#5\empty\@EA\xshowassignerror\else\@EA#1\fi{#2}{#3}{#4}}

\def\p!doassign#1#2\@relax@#3=#4=#5#6\@relax@
  {\ifx#5\empty
     \@EA\xshowassignerror
   \else\ifx#5=%
     \@EAEAEA#1%
   \else
     \@EAEAEA\xshowassignerror
   \fi\fi
   {#2}{#3}{#4}}

\def\xshowassignerror#1#2#3%
  {\showassignerror{#2}{\the\inputlineno\space(#1)}}

%D Now we also have to change the other macros that depend
%D on this low level one.

% \def\doassign  [#1][#2]{\p!doassign\dosetvalue  #1\@relax@#2==\@relax@}
% \def\doeassign [#1][#2]{\p!doassign\dosetevalue #1\@relax@#2==\@relax@}
% \def\undoassign[#1][#2]{\p!doassign\doresetvalue#1\@relax@#2==\@relax@}

\def\doassign  [#1][#2]{\p!doassign\dosetvalue  #1\@relax@#2==\empty\@relax@}
\def\doeassign [#1][#2]{\p!doassign\dosetevalue #1\@relax@#2==\empty\@relax@}
\def\undoassign[#1][#2]{\p!doassign\doresetvalue#1\@relax@#2==\empty\@relax@}

%D \macros
%D   {getemptyparameters}
%D
%D Sometimes we explicitly want variables to default to an
%D empty string, so we welcome:
%D
%D \starttyping
%D \getemptyparameters [label] [...=...,...=...]
%D \stoptyping

\def\getemptyparameters[#1]#2[#3]%
  {\def\p!dogetemptyparameter##1%
     {\doassignempty[#1][##1]}%
   \processcommalist[#3]\p!dogetemptyparameter}

%D \macros
%D   {copyparameters}
%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 \starttyping
%D \copyparameters [to-label] [from-label] [name1,name2,...]
%D \stoptyping
%D
%D For instance
%D
%D \starttyping
%D \copyparameters
%D   [internal][external]
%D   [alfa,beta]
%D \stoptyping
%D
%D Leads to:
%D
%D \starttyping
%D \def\internalalfa {\externalalfa}
%D \def\internalbeta {\externalbeta}
%D \stoptyping
%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{\docopyvalue{#1}{#3}}%
     %\def\docopyparameter##1{\docopyvalue{#1}{#3}{##1}}%
      \processcommalist[#5]\docopyparameter}}

%D \macros
%D   {doifassignmentelse}
%D
%D A lot of \CONTEXT\ commands take optional arguments, for
%D instance:
%D
%D \starttyping
%D \dothisorthat[alfa,beta]
%D \dothisorthat[first=foo,second=bar]
%D \dothisorthat[alfa,beta][first=foo,second=bar]
%D \stoptyping
%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 \starttyping
%D \doifassignmentelse {...} {then ...} {else ...}
%D \stoptyping

% not robust
%
% \def\doifassignmentelse%
%   {\doifinstringelse{=}}
%
% readable
%
% \def\doifassignmentelse#1%
%   {\convertargument#1\to\ascii
%    \doifinstringelse{=}{\ascii}}

\def\doifassignmentelse#1%
  {\convertargument#1\to\ascii
   \doifinstringelse=\ascii}

%D \macros
%D   {ifparameters,checkparameters}
%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 \starttyping
%D \checkparameters[argument]
%D \stoptyping

\newif\ifparameters

\def\p!checkparameters#1=#2#3\war%
  {\if#2@\parametersfalse\else\parameterstrue\fi}

\def\checkparameters[#1]%
  {\p!checkparameters#1=@@\war}

%D \macros
%D   {getfromcommalist,getfromcommacommand,
%D    commalistelement,
%D    getcommalistsize,getcommacommandsize}
%D
%D It's possible to get an element from a commalist or a
%D command representing a commalist.
%D
%D \starttyping
%D \getfromcommalist    [string] [n]
%D \getfromcommacommand [string,\strings,string,...] [n]
%D \stoptyping
%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 \starttyping
%D \getcommalistsize    [string,string,...]
%D \getcommacommandsize [string,\strings,string,...]
%D \stoptyping
%D
%D Afterwards, the length is available in the macro
%D \type{\commalistsize} (not a \COUNTER).

\newcount\commalistcounter

\def\commalistsize{0}

\def\p!dogetcommalistsize#1%
  {\advance\commalistcounter\plusone}

\def\getcommalistsize[#1]%
  {\commalistcounter\zerocount
   \processcommalist[#1]\p!dogetcommalistsize   % was [{#1}]
   \edef\commalistsize{\the\commalistcounter}}

\def\getcommacommandsize[#1]%
  {\edef\commacommand{#1}%
   \scratchtoks\expandafter{\expandafter[\commacommand]}%
   \expandafter\getcommalistsize\the\scratchtoks }

% to be tested first
%
% \def\getcommacommandsize[#1]%
%   {\expanded{\getcommalistsize[#1]}}

% \def\p!dogetfromcommalist#1%
%   {\advance\commalistcounter \minusone
%    \ifcase\commalistcounter
%      \def\commalistelement{#1}%
%      \begingroup\def\doprocesscommaitem##1]{\endgroup}%
%    \fi}

\def\p!dogetfromcommalist#1%
  {\advance\commalistcounter \minusone
   \ifcase\commalistcounter
     \def\commalistelement{#1}%
     \expandafter\quitcommalist
   \fi}

\def\getfromcommalist[#1]#2[#3]%
  {\let\commalistelement\empty
   \commalistcounter#3\relax
   \processcommalist[#1]\p!dogetfromcommalist}

% \def\getfromcommacommand[#1]% why so complicated, still needed?
%   {\edef\commacommand{#1}%
%    \toks0=\expandafter{\expandafter[\commacommand]}%
%    \expandafter\getfromcommalist\the\toks0 }

\def\getfromcommacommand[#1]%
  {\expanded{\getfromcommalist[#1]}}

%D Because 0, 1 and~2 are often asked for, we optimize this
%D macro for those cases. The indirect call however slows
%D down the other cases.
%D
%D \starttyping
%D \def\p!dogetfirstfromcommalist    [#1,#2]{\def\commalistelement{#1}}
%D \def\p!dogetsecondfromcommalist[#1,#2,#3]{\def\commalistelement{#2}}
%D \let\p!dogetotherfromcommalist=\getfromcommalist
%D
%D \def\getfromcommalist[#1]#2[#3]% optimized for 0,1,2
%D   {\ifcase#3\relax
%D      \let\commalistelement\empty
%D    \or
%D      \p!dogetfirstfromcommalist[#1,]%
%D    \or
%D      \p!dogetsecondfromcommalist[#1,,]%
%D    \else
%D      \p!dogetotherfromcommalist[#1][#3]%
%D    \fi}
%D \stoptyping
%D
%D Even worse, this alternative does not strip preceding
%D spaces, which is what we want. So, we stick to the slow
%D alternative.

%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 \getbuffer

%D \macros
%D   {dogetcommalistelement,dogetcommacommandelement}
%D
%D For low level (fast) purposes, we can also use the next
%D alternative, which can handle 8~elements at most.
%D
%D \starttyping
%D \dogetcommalistelement1\from a,b,c\to\commalistelement
%D \stoptyping

\def\dodogetcommalistelement#1\from#2,#3,#4,#5,#6,#7,#8\to#9%
  {\edef#9{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}}

% maybe better:
%
%  {\@EA\edef\@EA#9\@EA{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}}

\def\dogetcommalistelement#1\from#2\to%
  {\dodogetcommalistelement#1\from#2,,,,,,\to}

% check sources

\def\dogetcommacommandelement#1\from#2\to%
  {\@EA\dodogetcommalistelement\@EA#1\@EA\from#2,,,,,,\to}

%D \macros
%D   {dosingleargument,dodoubleargument,dotripleargument,
%D    doquadrupleargument,doquintupleargument,dosixtupleargument,
%D    doseventupleargument}
%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. Forgive me the funny names.
%D
%D \starttyping
%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 \doseventupleargument\command= \commando[#1][#2][#3][#4][#5][#6][#7]
%D \stoptyping
%D
%D These macros are used in the following way:
%D
%D \starttyping
%D \def\dosetupsomething[#1][#2]%
%D   {... #1 ... #2 ...}
%D
%D \def\setupsomething%
%D   {\dodoubleargument\dosetupsomething}
%D \stoptyping
%D
%D The implementation can be surprisingly simple and needs no
%D further explanation, like:
%D
%D \starttyping
%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 \stoptyping
%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\dosixtupleargument  {\chardef\expectedarguments 6 \dosixtupleempty  }
\def\doseventupleargument{\chardef\expectedarguments 7 \doseventupleempty}

%D \macros
%D   {iffirstagument,ifsecondargument,ifthirdargument,
%D    iffourthargument,iffifthargument,ifsixthargument,
%D    ifseventhargument}
%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
\newif\ifseventhargument

%D \macros
%D   {dosingleempty,dodoubleempty,dotripleempty,
%D    doquadrupleempty,doquintupleempty,dosixtupeempty,
%D    doseventupleempty}
%D
%D The empty argument supplying macros mentioned before, look
%D like:
%D
%D \starttyping
%D \dosingleempty    \command
%D \dodoubleempty    \command
%D \dotripleempty    \command
%D \doquadrupleempty \command
%D \doquintupleempty \command
%D \dosixtupleempty  \command
%D \doseventupleempty\command
%D \stoptyping
%D
%D So \type{\dodoubleempty} leades to:
%D
%D \starttyping
%D \command[#1][#2]
%D \command[#1][]
%D \command[][]
%D \stoptyping
%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

% idea: \ignorespaces afterwards

\chardef\noexpectedarguments=0
\chardef\expectedarguments  =0

\def\showargumenterror#1#2%
  {\writestatus{system}{#1 argument(s) expected in line #2}}

% \long\def\dogetargument#1#2#3#4% redefined in mult-ini
%   {\doifnextcharelse{#1}
%      {\let\expectedarguments\noexpectedarguments
%       #3\dodogetargument}
%      {\ifnum\expectedarguments>\noexpectedarguments
%         \showargumenterror{\expectedarguments}
%       \fi
%       \let\expectedarguments\noexpectedarguments
%       #4\dodogetargument#1#2}}
%
% less to pass

\def\doshowargumenterror
  {\ifnum\expectedarguments>\noexpectedarguments
     \showargumenterror{\number\expectedarguments}{\number\inputlineno}%
   \fi
   \noshowargumenterror}

\def\noshowargumenterror
  {\let\expectedarguments\noexpectedarguments}

% \long\def\dogetargument#1#2#3#4%
%  {\doifnextcharelse#1%
%     {\noshowargumenterror#3\dodogetargument}
%     {\doshowargumenterror#4\dodogetargument#1#2}}
%
% faster ?

\long\def\dogetargument#1#2#3#4%
  {\let\charactertoken=#1%
   \def\!!stringa{\noshowargumenterror#3\dodogetargument}%
   \def\!!stringb{\doshowargumenterror#4\dodogetargument#1#2}%
   \futurelet\nexttoken\inspectnextcharacter}

%\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\getseventupleempty#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#1###############################%
%                                        ################################1#2%
%                    {\def\dodogetargument%
%                       {#3#1##1#2%
%                          #1####1#2%
%                          #1########1#2%
%                          #1################1#2%
%                          #1################################1#2%
%                          #1###############################%
%                            ################################1#2}%
%                   \dogetargument#1#2\seventhargumenttrue\seventhargumentfalse}%
%                 \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\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\getseventupleempty#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#1################################%
                                        ################################1#2%
                    {\def\dodogetargument%
                       {#3#1{##1}#2%
                          #1{####1}#2%
                          #1{########1}#2%
                          #1{################1}#2%
                          #1{################################1}#2%
                          #1{################################%
                             ################################1}#2}%
                   \dogetargument#1#2\seventhargumenttrue\seventhargumentfalse}%
                 \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  []}
\def\doseventupleempty{\getseventupleempty[]}

%D Because some of these are called quite often, we will now
%D replace the more general version by alternatives tuned for
%D speed.

\def\dosingleempty#1%
  {\noshowargumenterror % \relax % prevents lookahead, brr
   \doifnextcharelse[%
     {\firstargumenttrue#1}
     {\dosinglefakeempty#1}}

\def\dodoubleempty#1%
  {\noshowargumenterror % \relax % prevents lookahead, brr
   \doifnextcharelse[%
     {\dodoubletestempty#1}
     {\dodoublefakeempty#1}}

\def\dotripleempty#1%
  {\noshowargumenterror % \relax % prevents lookahead, brr
   \doifnextcharelse[%
     {\dotripletestempty#1}
     {\dotriplefakeempty#1}}

\def\dosinglefakeempty#1%
  {\firstargumentfalse#1[]}

\def\dodoublefakeempty#1%
  {\firstargumentfalse\secondargumentfalse#1[][]}

\def\dotriplefakeempty#1%
  {\firstargumentfalse\secondargumentfalse\thirdargumentfalse#1[][][]}

\long\def\dodoubletestempty#1[#2]%
  {\firstargumenttrue
   \doifnextcharelse[%
     {\secondargumenttrue #1[{#2}]}
     {\secondargumentfalse#1[{#2}][]}}

\long\def\dotripletestempty#1[#2]%
  {\firstargumenttrue
   \doifnextcharelse[%
     {\dotripletestemptyx #1[{#2}]}
     {\secondargumentfalse
      \thirdargumentfalse #1[{#2}][][]}}

\long\def\dotripletestemptyx#1[#2][#3]%
  {\secondargumenttrue
   \doifnextcharelse[%
     {\thirdargumenttrue #1[{#2}][{#3}]}
     {\thirdargumentfalse#1[{#2}][{#3}][]}}

%D \macros
%D   {dosingleargumentwithset,
%D    dodoubleargumentwithset,dodoubleemptywithset,
%D    dotripleargumentwithset,dotripleemptywithset}
%D
%D These maybe too mysterious macros enable us to handle more
%D than one setup at once.
%D
%D \starttyping
%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 \stoptyping
%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 \starttyping
%D \def\dodefinesomething[#1][#2]%
%D   {\getparameters[\??xx#1][#2]}
%D
%D \def\definesomething%
%D   {\dodoubleargumentwithset\dodefinesomething}
%D \stoptyping
%D
%D Which accepts calls like:
%D
%D \starttyping
%D \definesomething[alfa,beta,...][variable=...,...]
%D \stoptyping
%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   {strippedcsname}
%D
%D The next macro can be very useful when using \type{\csname}
%D like in:
%D
%D \starttyping
%D \csname if\strippedcsname\something\endcsname
%D \stoptyping
%D
%D This expands to \type{\ifsomething}.

\def\strippedcsname%
  {\expandafter\gobbleoneargument\string}

%D \macros
%D   {complexorsimple,complexorsimpleempty}
%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 \starttyping
%D \complexorsimple\command
%D \stoptyping
%D
%D When \type{\command} is followed by a \type{[setup]}, then
%D
%D \starttyping
%D \complexcommand [setup]
%D \stoptyping
%D
%D executes, else we get
%D
%D \starttyping
%D \simplecommand
%D \stoptyping
%D
%D An alternative for \type{\complexorsimple} is:
%D
%D \starttyping
%D \complexorsimpleempty {command}
%D \stoptyping
%D
%D Depending on the presence of \type{[setup]}, this one
%D leads to one of:
%D
%D \starttyping
%D \complexcommando [setup]
%D \complexcommando []
%D \stoptyping
%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.

% This method is needed when traditional tex is used with
% the efficient definition (marked **) below.

% an old one:
%
% \def\setnameofcommand#1% handles {abc} as well as \abc
%   {\begingroup
%    \escapechar=-1
%    \globaldefs=0 % pretty important!
%    \xdef\nameofcommand{\string#1}%
%    \endgroup}
%
% \def\complexorsimple#1%
%   {\setnameofcommand{#1}%
%    \doifnextcharelse{[}
%      {\firstargumenttrue \getvalue{\s!complex\nameofcommand}}
%      {\firstargumentfalse\getvalue{\s!simple \nameofcommand}}}
%
% \def\complexorsimpleempty#1%
%   {\setnameofcommand{#1}%
%    \doifnextcharelse{[}
%      {\firstargumenttrue \getvalue{\s!complex\nameofcommand}}
%      {\firstargumentfalse\getvalue{\s!complex\nameofcommand}[]}}
%
% a newer one:

\def\complexorsimple#1%
  {% \relax % prevents lookahead, brrr
   \doifnextcharelse[%
     {\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
     {\firstargumentfalse\csname\s!simple \strippedcsname#1\endcsname}}

\def\complexorsimpleempty#1%
  {% \relax % prevents lookahead, brrr
   \doifnextcharelse[%
     {\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
     {\firstargumentfalse\csname\s!complex\strippedcsname#1\endcsname[]}}

%D \macros
%D   {definecomplexorsimple,definecomplexorsimpleempty}
%D
%D The previous commands are used that often that we found it
%D worthwile to offer two more alternatives. Watch the build
%D in protection.

% See earlier. Because we don't want \type {\simple..} and
% \type {\complex..} commands to show up in expansions, we need
% to pass them as \type {simple..} and \type {complex..}.

% \beginTEX
%
% \def\definewithnameofcommand#1#2%
%   {\setnameofcommand{#2}%
%    \@EA\def\@EA#2\@EA{\@EA\donottest\@EA#1\@EA{\nameofcommand}}}
%
% \def\definecomplexorsimple%
%   {\definewithnameofcommand\complexorsimple}
%
% \def\definecomplexorsimpleempty%
%   {\definewithnameofcommand\complexorsimpleempty}
%
% \endTEX
%
% \beginETEX \protected
%
% \def\definecomplexorsimple#1%
%   {\normalprotected\def#1{\complexorsimple#1}}
%
% \def\definecomplexorsimpleempty#1%
%   {\normalprotected\def#1{\complexorsimpleempty#1}}
%
% \endETEX

% However, since this one uses an idirect method, things go
% okay (at the cost of extra macros).

% \def\definecomplexorsimple#1%
%   {\unexpanded\def#1{\complexorsimple#1}}
%
% \def\definecomplexorsimpleempty#1%
%   {\unexpanded\def#1{\complexorsimpleempty#1}}
%
% faster, since no \strippedcsname needed in call, but more spacy

\def\docomplexorsimple#1#2%
  {\doifnextcharelse[{\firstargumenttrue#1}{\firstargumentfalse#2}}

\def\docomplexorsimpleempty#1%
  {\doifnextcharelse[{\firstargumenttrue#1}{\firstargumentfalse#1[]}}

\def\definecomplexorsimple#1%
  {\unexpanded\edef#1%
     {\noexpand\docomplexorsimple
        \@EA\noexpand\csname\s!complex\strippedcsname#1\endcsname
        \@EA\noexpand\csname\s!simple \strippedcsname#1\endcsname}}

\def\definecomplexorsimpleempty#1%
  {\unexpanded\edef#1%
     {\noexpand\docomplexorsimpleempty
        \@EA\noexpand\csname\s!complex\strippedcsname#1\endcsname}}

%D These commands are called as:
%D
%D \starttyping
%D \definecomplexorsimple\command
%D \stoptyping
%D
%D Of course, we must have available
%D
%D \starttyping
%D \def\complexcommand[#1]{...}
%D \def\simplecommand     {...}
%D \stoptyping
%D
%D Using this construction saves a few string now and then.

%D \macros
%D   {definestartstopcommand}
%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 \starttyping
%D \definestartstopcommand\somecommand\e!specifier{arg}{arg}%
%D   {do something with arg}
%D \stoptyping
%D
%D This expands to something like:
%D
%D \starttyping
%D \def\somecommand arg \startspecifier arg \stopspecifier%
%D   {do something with arg}
%D \stoptyping
%D
%D The arguments can be anything reasonable, but double
%D \type{#}'s are needed in the specification part, like:
%D
%D \starttyping
%D \definestartstopcommand\somecommand\e!specifier{[##1][##2]}{##3}%
%D   {do #1 something #2 with #3 arg}
%D \stoptyping
%D
%D which becomes:
%D
%D \starttyping
%D \def\somecommand[#1][#2]\startspecifier#3\stopspecifier%
%D   {do #1 something #2 with #3 arg}
%D \stoptyping
%D
%D We will see some real applications of this command in the
%D core modules.

\def\definestartstopcommand#1#2#3#4% can be done with \expanded ot better, toks
  {\def\!stringa{#3}%              % but let's keep this unused one crappy
   \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, doquintuplegroupempty}
%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 \starttyping
%D \dosinglegroupempty    \ineedONEargument
%D \dodoublegroupempty    \ineedTWOarguments
%D \dotriplegroupempty    \ineedTHREEarguments
%D \doquadruplegroupempty \ineedFOURarguments
%D \doquintuplegroupempty \ineedFIVEarguments
%D \stoptyping
%D
%D where \type{\ineedONEargument} takes one and the others
%D two and three arguments. These macro's were first needed in
%D \PPCHTEX.
%D
%D \starttyping
%D \def\dogetgroupargument#1#2% redefined in mult-ini
%D   {\def\nextnextargument%
%D      {\ifx\nextargument\bgroup
%D         \let\expectedarguments\noexpectedarguments
%D         \def\nextargument{#1\dodogetargument}%
%D       %\else\ifx\nextargument\lineending % this can be an option
%D       %  \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
%D       %\else\ifx\nextargument\blankspace % but it may never be default
%D       %  \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
%D       \else
%D         \ifnum\expectedarguments>\noexpectedarguments
%D           \writestatus
%D              {setup}
%D              {\the\expectedarguments\space argument(s) expected
%D               in line \the\inputlineno\space}%
%D         \fi
%D         \let\expectedarguments\noexpectedarguments
%D         \def\nextargument{#2\dodogetargument{}}%
%D       \fi%\fi\fi                 % so let's get rid of it
%D       \nextargument}%
%D    \futurelet\nextargument\nextnextargument}
%D \stoptyping
%D
%D In order to catch \type {\nextargument}'s that expand to
%D \type {\if} and friends, in practice we will use a
%D slightly more complicated macro.

\let\normalif       \if
\let\normalifx      \ifx
\let\normalifnum    \ifnum
\let\normalifdim    \ifdim
\let\normalifcat    \ifcat
\let\normalifcase   \ifcase
\let\normalifcsname \ifcsname
\let\normalifhmode  \ifhmode
\let\normalifvmode  \ifvmode
\let\normalor       \or
\let\normalelse     \else
\let\normalfi       \fi

\def\beginrobusttest
  {\begingroup
   \let\if      \relax
   \let\ifx     \relax
   \let\ifnum   \relax
   \let\ifdim   \relax
   \let\ifcat   \relax
   \let\ifcase  \relax
   \let\ifcsname\relax
   \let\or      \relax
   \let\else    \relax
   \let\fi      \relax}

\let\endrobusttest\endgroup

% \def\dogetgroupargument#1#2%
%   {\def\nextnextargument%
%      {\normalifx\nextargument\bgroup
%         \endrobusttest
%         \let\expectedarguments\noexpectedarguments
%         \def\nextargument{#1\dodogetargument}%
%      %\normalelse\normalifx\nextargument\lineending % this can be an option
%      %  \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
%      %\normalelse\normalifx\nextargument\blankspace % but may never be default
%      %  \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
%       \normalelse
%         \endrobusttest
%         \ifnum\expectedarguments>\noexpectedarguments
%           \showargumenterror{\number\expectedarguments}{\number\inputlineno}%
%         \fi
%         \let\expectedarguments\noexpectedarguments
%         \def\nextargument{#2\dodogetargument{}}%
%       \normalfi%\normalfi\normalfi                  % so let's get rid of it
%       \nextargument}%
%    \beginrobusttest
%    \futurelet\nextargument\nextnextargument}

% \def\dogetgroupargument#1#2%
%   {\def\nextnextargument%
%      {\normalifx\nextargument\bgroup
%         \endrobusttest
%         \noshowargumenterror
%         \def\nextargument{#1\dodogetargument}%
%      %\normalelse\normalifx\nextargument\lineending % this can be an option
%      %  \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
%      %\normalelse\normalifx\nextargument\blankspace % but may never be default
%      %  \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
%       \normalelse
%         \endrobusttest
%         \doshowargumenterror
%         \def\nextargument{#2\dodogetargument{}}%
%       \normalfi%\normalfi\normalfi                  % so let's get rid of it
%       \nextargument}%
%    \beginrobusttest
%    \futurelet\nextargument\nextnextargument}

% we need to use an \ifcase in order to honor the \normal...

\def    \permitspacesbetweengroups{\chardef\@@permitspacesbetweengroups=0 }
\def\dontpermitspacesbetweengroups{\chardef\@@permitspacesbetweengroups=1 }

\dontpermitspacesbetweengroups

\def\dogetgroupargument#1#2%
  {\def\nextnextargument%
     {\normalifx\nextargument\bgroup
        \endrobusttest
        \noshowargumenterror
        \def\nextargument{#1\dodogetargument}%
      \normalelse
        \normalifcase\@@permitspacesbetweengroups
          \normalifx\nextargument\lineending
            \endrobusttest
            \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
          \normalelse\normalifx\nextargument\blankspace
            \endrobusttest
            \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
          \normalelse
            \endrobusttest
            \doshowargumenterror
            \def\nextargument{#2\dodogetargument{}}%
          \normalfi\normalfi
        \normalelse
          \endrobusttest
          \doshowargumenterror
          \def\nextargument{#2\dodogetargument{}}%
        \normalfi
      \normalfi
      \nextargument}%
   \beginrobusttest
   \futurelet\nextargument\nextnextargument}

\def\dosinglegroupempty#1%
  {\def\dodogetargument%
     {\dontpermitspacesbetweengroups
      #1}%
   \dogetgroupargument\firstargumenttrue\firstargumentfalse}

\def\dodoublegroupempty#1%
  {\def\dodogetargument##1%
     {\def\dodogetargument%
        {\dontpermitspacesbetweengroups
         #1{##1}}%
      \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
   \dogetgroupargument\firstargumenttrue\firstargumentfalse}

\def\dotriplegroupempty#1%
  {\def\dodogetargument##1%
     {\def\dodogetargument####1%
        {\def\dodogetargument%
           {\dontpermitspacesbetweengroups
            #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%
              {\dontpermitspacesbetweengroups
               #1{##1}{####1}{########1}}%
            \dogetgroupargument\fourthargumenttrue\fourthargumentfalse}%
         \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}%
      \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
   \dogetgroupargument\firstargumenttrue\firstargumentfalse}

\def\doquintuplegroupempty#1%
  {\def\dodogetargument##1%
     {\def\dodogetargument####1%
        {\def\dodogetargument########1%
           {\def\dodogetargument################1%
             {\def\dodogetargument%
                {\dontpermitspacesbetweengroups
                 #1{##1}{####1}{########1}{################1}}%
              \dogetgroupargument\fifthargumenttrue\fifthargumentfalse}%
            \dogetgroupargument\fourthargumenttrue\fourthargumentfalse}%
         \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}%
      \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
   \dogetgroupargument\firstargumenttrue\firstargumentfalse}

%D These macros can explictly take care of spaces, which means
%D that the next definition and calls are valid:
%D
%D \starttyping
%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 \stoptyping
%D
%D And alike.

%D \macros
%D   {firstofoneargument, firstoftwoarguments, firstofthreearguments
%D    secondoftwoarguments, secondofthreearguments,
%D    thirdofthreearguments}
%D
%D The next six macros (dedicated to Taco) can conveniently
%D used to select arguments. Their names explain their
%D functionality.

\long\def\firstofoneargument            #1{#1}
\long\def\firstoftwoarguments         #1#2{#1}
\long\def\firstofthreearguments     #1#2#3{#1}
\long\def\firstoffourarguments    #1#2#3#4{#1}
\long\def\firstoffivearguments  #1#2#3#4#5{#1}
\long\def\secondoftwoarguments        #1#2{#2}
\long\def\secondofthreearguments    #1#2#3{#2}
\long\def\secondoffourarguments   #1#2#3#4{#2}
\long\def\secondoffivearguments #1#2#3#4#5{#2}
\long\def\thirdofthreearguments     #1#2#3{#3}
\long\def\thirdoffourarguments    #1#2#3#4{#3}
\long\def\thirdoffivearguments  #1#2#3#4#5{#3}
\long\def\fourthoffourarguments   #1#2#3#4{#4}
\long\def\fourthoffivearguments #1#2#3#4#5{#4}
\long\def\fifthoffivearguments  #1#2#3#4#5{#5}

%D \macros
%D   {globalletempty,letempty,letvalueempty,letgvalueempty}
%D
%D Trivial:

\def\letempty             #1{\let#1\empty}
\def\globalletempty#1{\global\let#1\empty}

\def\letvalueempty        #1{\expandafter\let\csname#1\endcsname\empty}
\def\letgvalueempty#1{\global\expandafter\let\csname#1\endcsname\empty}

%D \macros
%D   {wait}
%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
  {\begingroup
   \read16 to \wait
   \endgroup}

%D \macros
%D   {writestring,writeline,
%D    writestatus,statuswidth}
%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 \starttyping
%D \writestring {string}
%D \writeline
%D \writestatus {category} {message}
%D \stoptyping
%D
%D Messages are formatted. One can provide the maximum with
%D of the identification string with the macro \type
%D {\statuswidth}.

% \chardef\statuswidth=15
%
% \def\writestring%
%   {\immediate\write16}
%
% \def\writeline%
%   {\writestring{}}
%
% \def\dosplitstatus#1#2\end%
%   {\ifx#1?%
%      \loop
%        \advance\scratchcounter by 1
%        \ifnum\scratchcounter<\statuswidth
%          \edef\messagecontentA{\messagecontentA\space}%
%      \repeat
%    \else
%      \advance\scratchcounter by 1
%      \ifnum\scratchcounter<\statuswidth
%        \edef\messagecontentA{\messagecontentA#1}%
%      \fi
%      \dosplitstatus#2\end
%    \fi}
%
% \def\writestatus#1#2%
%   {\begingroup
%    \let\messagecontentA=\empty
%    \edef\messagecontentB{#2}%  maybe it's \the\scratchcounter
%    \scratchcounter=0
%    \expandafter\dosplitstatus#1?\end
%    \writestring{\messagecontentA\space:\space\messagecontentB}%
%    \endgroup}

\chardef\statuswidth=15
\chardef\statuswrite=16

\def\writestring
  {\immediate\write\statuswrite}

\def\writeline
  {\writestring{}}

%D First we present the normal \TEX\ variant, later we will
%D show the \ETEX-way.

\beginTEX

\newcount\statuscounter

\def\dosplitstatus#1%
  {\advance\statuscounter \minusone
   \ifcase\statuscounter
     \expandafter\nosplitstatus
   \else
     \scratchtoks\@EA{\the\scratchtoks#1}%
     \expandafter\dosplitstatus
   \fi}

\def\nosplitstatus#1\end
  {}

\def\writestatus#1#2%
  {\begingroup
   \scratchtoks\emptytoks
   \statuscounter\statuswidth
   \expandafter\dosplitstatus#1%
     \space\space\space\space\space\space\space
     \space\space\space\space\space\space\space
     \space\space\space\space\space\space\end
  %\expanded{\writestring{\the\scratchtoks\space:\space#2}}%
   \@EA\writestring\@EA{\the\scratchtoks\space:\space#2}%
   \endgroup}

\endTEX

%D Because we're grouped, we could have initialized at forehand:
%D
%D \starttyping
%D \statuscounter\statuswidth
%D \stoptyping
%D
%D The next implementation saves only some 10 words of format
%D memory, but we hardly gain any speed.
%D
%D \starttyping
%D \def\dosplitstatus#1#2#3#4#5#6#7#8#9%
%D   {#1#2#3#4#5#6#7#8#9\dodosplitstatus}
%D
%D \def\dodosplitstatus#1#2#3#4#5#6\end
%D   {#1#2#3#4#5}
%D
%D \def\writestatus#1#2%
%D   {\writestring
%D      {\expandafter\dosplitstatus#1%
%D         \space\space\space\space\space
%D         \space\space\space\space\space
%D         \space\space\space\space\space\end
%D         \space:\space#2}}
%D \stoptyping

%D Okay then, more obscure but slightly faster: no split grabs
%D the do split part and skipping the else branch has to happen
%D anyway, so:

\beginTEX

\def\dosplitstatus#1%
  {\advance\statuscounter \minusone
   \ifcase\statuscounter
     \expandafter\nosplitstatus
   \fi
   \scratchtoks\@EA{\the\scratchtoks#1}%
   \dosplitstatus}

\endTEX

%D The next (\ETEX\ specific) variant is twice as fast in 5/40
%D situations, only gains some speed when multiple runs of large docs
%D are done; fully expandable, no statuscounter needed, no restore (due
%D to grouping) needed etc.

\beginETEX \numexpr

\def\writestatus#1#2%
  {\writestring{\expandafter\dosplitstatus\expandafter\statuswidth#1%
     \space\space\space\space\space\space\space
     \space\space\space\space\space\space\space
     \space\space\space\space\space\space\end
     \space:\space#2}}

\def\dosplitstatus#1#2%
  {\ifcase#1 \expandafter\nosplitstatus\fi#2%
   \expandafter\dosplitstatus\expandafter{\the\numexpr#1+\minusone\relax}}

\def\nosplitstatus#1\end
  {}

\endETEX

%D \macros
%D   {emptytoks}
%D
%D For this we need an empty token register, analogous
%D to \type {\empty}.

\newtoks\emptytoks

%D \macros
%D   {debuggerinfo}
%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
