%D \module
%D   [       file=syst-aux, % merge of syst-gen cum suis
%D        version=1996.03.20,
%D          title=\CONTEXT\ System Macros,
%D       subtitle=General,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D In the process of being adapted to \LMTX\ flags so a bit of a mess now. Also
%D our playground.

\registerctxluafile{syst-aux}{autosuffix}
\registerctxluafile{syst-mac}{autosuffix}

%D This file is a follow up in \type {syst-aux.mkii} and \type {syst-aux.mkiv} where
%D you can find some more pure \TEX\ or \LUATEX\ variants. There are quite some
%D helpers here and many no longer are used but we keep them around because they
%D have always been there. However, the implementation in \LMTX\ can be somewhat
%D different that in \MKIV, because it's also a kind of a playground for new
%D features. Of course nostalgia also plays a role.
%D
%D For the original code we refer to \type {syst-aux.mkii} and its follow up \type
%D {syst-aux.mkiv}. These also have historic versions. As usual, the upgrade went
%D through stages. First I wrote variants usign the new \type {\ignorearguments}
%D feature, then I decided to implement a few more conditionals and new fancy code
%D could be ditched before it was even published. I kept some as examples.
%D
%D Of course I couldn't do this without Wolfgang looking over my shoulder. Changing
%D core code is kind of tricky.
%D
%D There are quite some helpers here that are effectively obsolete (read: there is no
%D need for them). Examples are \type {setflag} and \type {\uppercasestring} and their
%D relatives. We keep them around as illustration and possible usage in old styles.

\unprotect

%D These are for local helpers, the names are historic:

\mutable\let\docommand  \relax
\mutable\let\dodocommand\relax

%D \macros
%D   {unexpanded}
%D
%D Because we use this module only in \MKIV, we have removed the old protection
%D code.
%D
%D \starttyping
%D \protected\def\somecommand{... ... ...}
%D \stoptyping
%D
%D This overloads the \ETEX\ primitive but as we already had an \MKII\ solution we
%D keep the same name for a similar mechanism. So, effectively we have two ways to
%D protect a macro.
%D
%D In \LMTX\ we try to avoid this and use \type {\protected} instead, which is
%D possible because over time we got rid of using the \CONTEXT\ macro with that
%D name.

\pushoverloadmode

\aliased\let\unexpanded\normalprotected

\popoverloadmode

%D We're definitely in \LMTX\ mode here.

\permanent\protected\lettonothing\startlmtxmode
\permanent\protected\lettonothing\stoplmtxmode
\permanent                   \def\startmkivmode#-\stopmkivmode{}
\permanent\protected\lettonothing\stopmkivmode

%D As we don't have namespace definers yet, we use a special one. Later we will
%D do a better job.

\ifdefined\c_syst_helpers_n_of_namespaces

    % lets plug in a better error message

\else

    \newinteger\c_syst_helpers_n_of_namespaces \c_syst_helpers_n_of_namespaces\pluseight % 1-8 reserved for catcodes

    \def\v_interfaces_prefix_template_system{\the       \c_syst_helpers_n_of_namespaces>>}
    %def\v_interfaces_prefix_template_system{\characters\c_syst_helpers_n_of_namespaces>>} % no \characters yet

\fi

\permanent\protected\def\installsystemnamespace#1% maybe move this to syst-ini
  {\ifcsname ??#1\endcsname
     \writestatus\m!system{duplicate system namespace '#1'}\wait
   \else
     \global\advanceby\c_syst_helpers_n_of_namespaces\plusone
     \permanent\cdefcsname ??#1\endcsname{\v_interfaces_prefix_template_system}%
   \fi}

%D \macros
%D   {normalspace}
%D
%D There is already \type{\space} but just to be sure we also provide this one:

\permanent\def\normalspace{ }

\newif\if!!donea   \newif\if!!doneb    \newif\if!!donec  % soon obsolete in lmtx
\newif\if!!doned   \newif\if!!donee    \newif\if!!donef  % soon obsolete in lmtx

\permanent\cdef\!!zerocount {0} % alongside \zerocount
\permanent\cdef\!!minusone {-1} % ...
\permanent\cdef\!!plusone   {1} % ...
\permanent\cdef\!!plustwo   {2} % ...
\permanent\cdef\!!plusthree {3} % ...
\permanent\cdef\!!plusfour  {4} % ...
\permanent\cdef\!!plusfive  {5} % ...
\permanent\cdef\!!plussix   {6} % ...
\permanent\cdef\!!plusseven {7} % ...
\permanent\cdef\!!pluseight {8} % ...
\permanent\cdef\!!plusnine  {9} % alongside \plusnine

\setnewconstant   \uprotationangle    0
\setnewconstant\rightrotationangle   90
\setnewconstant \downrotationangle  180
\setnewconstant \leftrotationangle  270

%D \macros
%D   {s!,c!,e!,p!,v!,@@,??}
%D
%D To save memory, we use constants (sometimes called variables). Redefining these
%D constants can have disastrous results. Of course, expanding them costs time, so
%D that's the price to pay. More are defined elsewhere. Of course we later pay a
%D price when they need to be expanded.

% \def\v!prefix! {v!}
% \def\c!prefix! {c!}
% \def\s!prefix! {s!}
%
% \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!simple  {simple}
%
% \def\s!start{start}
% \def\s!stop {stop}

% \permanent\cdef\s!empty {empty}

%D Sometimes we pass macros as arguments to commands that don't expand them before
%D interpretation. Such commands can 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 commalist or when data
%D stored in macros is fed to index of list commands. If needed, one should use
%D \type {\noexpand} inside the argument. Later on we will meet some more clever
%D alternatives to this command. Beware, only the simple one has \type {\noexpand}
%D before its argument.

%\lettonothing\m_syst_helpers_expanded
%
% \pushoverloadmode
%
% \permanent\protected\def\expanded#1%
%   {\xdef\m_syst_helpers_expanded{\noexpand#1}\m_syst_helpers_expanded}
%
% \popoverloadmode

% \permanent\protected\def\startexpanded#1\stopexpanded
%   {\xdef\m_syst_helpers_expanded{#1}\m_syst_helpers_expanded}
%
% \permanent\protected\lettonothing\stopexpanded

%D Recent \TEX\ engines have a primitive \type {\expanded} and we will use that when
%D possible. After all, we can make not expandable macros now. The name clash is an
%D unfortunate fact and in retrospect I should nto have agreed to a primitive having
%D that same name. One problem is that our \expanded is protected ubut in \LMTX\ we can
%D assume we're okay.

% We cannot use the next variant as first we need to adapt \type {##}'s in callers:
%
% \def\expanded#1%
%   {\normalexpanded{\noexpand#1}}

% \def\startexpanded#1\stopexpanded
%   {\normalexpanded{#1}}

\permanent\protected\def\startexpanded#1\stopexpanded
  {\expanded{#1}}

\permanent\protected\lettonothing\stopexpanded

%D \macros
%D   {gobbleoneargument,gobble...arguments}
%D
%D The next set of macros just do nothing, except that they get rid of a number of
%D arguments. These zero references prevent intermediate storage. In principle that
%D is more efficient but it probably won't be noticed. It's anyway cheaper on memory
%D access. We use versions that don't even store the arguments.

%permanent\def\gobbleoneargument               #-{}
\permanent\def\gobbletwoarguments            #-#-{}
\permanent\def\gobblethreearguments        #-#-#-{}
\permanent\def\gobblefourarguments       #-#-#-#-{}
\permanent\def\gobblefivearguments       #-#-#-#-{}
\permanent\def\gobblesixarguments        #-#-#-#-{}
\permanent\def\gobblesevenarguments    #-#-#-#-#-{}
\permanent\def\gobbleeightarguments  #-#-#-#-#-#-{}
\permanent\def\gobbleninearguments #-#-#-#-#-#-#-{}

\permanent\tolerant\def\gobbleoneoptional   [#S#-]{}
\permanent\tolerant\def\gobbletwooptionals  [#S#-]#*[#S#-]{}
\permanent\tolerant\def\gobblethreeoptionals[#S#-]#*[#S#-]#*[#S#-]{}
\permanent\tolerant\def\gobblefouroptionals [#S#-]#*[#S#-]#*[#S#-]#*[#S#-]{}
\permanent\tolerant\def\gobblefiveoptionals [#S#-]#*[#S#-]#*[#S#-]#*[#S#-]#*[#S#-]{}

%D Reserved macros for tests:

%D A \type \type {\let} is more efficient than a \type {\def} so we often let something
%D to relax or do nothing. However, we then loose the name in tracing. For that we now
%D have \type {\lettonothing \foo} which is efficient but also keeps the name. Of course
%D this is no solution for commands that take arguments but at least it helps tracing a
%D bit. We keep of course \type {\donothing}.

%D Maybe even nicer is a let that aliases but keeps the name.

       % \lettonothing\donothing
         \permanent\def\donothing        {} % better in tracing
%untraced\permanent\def\untraceddonothing{}

\lettonothing\m_syst_string_one
\lettonothing\m_syst_string_two
\lettonothing\m_syst_string_three
\lettonothing\m_syst_string_four

\lettonothing\m_syst_action_yes
\lettonothing\m_syst_action_nop

%D \macros
%D   {doifnextcharelse}
%D
%D This macro has a long history. Among the things we had to deal with was ignoring
%D blank spaces but in the meantime we can use some \LUATEX\ trickery. Older versions
%D use more code and can be find in the \MKIV\ and \MKII\ files.

% \mutable\let\next          \relax
% \mutable\let\nextnext      \relax % kind of obsolete
% \mutable\let\nextnextnext  \relax % kind of obsolete
% \mutable\let\nexttoken     \relax

\permanent\protected\def\doifelsenextchar#1#2#3% #1 should not be {} !
  {\def\m_syst_action_yes{#2}%
   \def\m_syst_action_nop{#3}%
   \futureexpandis#1\m_syst_action_yes\m_syst_action_nop}

\permanent\protected\def\doifelsenextcharcs % #1#2#3% #1 should not be {} !
  {\futureexpandis}

\aliased\let\doifnextcharelse  \doifelsenextchar
\aliased\let\doifnextcharcselse\doifelsenextcharcs

%D Because we will mostly use this macro for testing if the next character is \type
%D {[}, we also make a slightly faster variant as it is not uncommon to have tens of
%D thousands of calls to this test in a run. Of course it also is more convenient to
%D read a trace then. Here we use a lookahead primitive that ignores (blank) spaces
%D which makes for less tracing clutter than the original definition. It's also
%D faster bit that will probably go unnoticed. Of course, hard||core \TEX ies whose
%D reputations depends on understanding obscure macro definitions will love the more
%D low level variants.

\permanent\protected\def\doifelsenextoptional#1#2%
  {\def\m_syst_action_yes{#1}%
   \def\m_syst_action_nop{#2}%
   \futureexpandis[\m_syst_action_yes\m_syst_action_nop}

\permanent\protected\def\doifelsenextoptionalcs
  {\futureexpandis[}

\aliased\let\doifnextoptionalelse  \doifelsenextoptional
\aliased\let\doifnextoptionalcselse\doifelsenextoptionalcs

\permanent\protected\def\doifelsenextbgroup#1#2%
  {\def\m_syst_action_yes{#1}%
   \def\m_syst_action_nop{#2}%
   \futureexpandis\bgroup\m_syst_action_yes\m_syst_action_nop}

\permanent\protected\def\doifelsenextbgroupcs % #1#2
  {\futureexpandis\bgroup}

\aliased\let\doifnextbgroupelse  \doifelsenextbgroup
\aliased\let\doifnextbgroupcselse\doifelsenextbgroupcs

\permanent\protected\def\doifelsenextparenthesis#1#2%
  {\def\m_syst_action_yes{#1}%
   \def\m_syst_action_nop{#2}%
   \futureexpandis(\m_syst_action_yes\m_syst_action_nop}

\aliased\let\doifnextparenthesiselse\doifelsenextparenthesis

%D The next one is handy in predictable situations:

\permanent\protected\def\doifelsefastoptionalcheck#1#2%
  {\def\m_syst_action_yes{#1}%
   \def\m_syst_action_nop{#2}%
   \futureexpandis[\m_syst_action_yes\m_syst_action_nop}

\permanent\protected\def\doifelsefastoptionalcheckcs
  {\futureexpandis[}

\aliased\let\doiffastoptionalcheckelse  \doifelsefastoptionalcheck
\aliased\let\doiffastoptionalcheckcselse\doifelsefastoptionalcheckcs

%D Here's one for skipping spaces and pars, handy for:
%D
%D \starttyping
%D \hbox
%D
%D   {a few lines later}
%D \stoptyping
%D
%D like:
%D
%D \starttyping
%D \def\somecommand{\dowithnextbox{\box\nextbox}\ruledhbox}
%D
%D \assumelongusagecs\somecommand
%D
%D \bgroup
%D     oeps
%D \egroup
%D \stoptyping
%D
%D The original kind of clumsy but working version is now replaced by a simple
%D macro. And it can be even less code in \LUAMETATEX:

\aliased\let\assumelongusagecs\expandafterpars % so we can replace it

%D It's used to skip over empty lines in some constructs that we like to set up
%D spacy. We already permit par tokens (and equivalents) in math and some other
%D places visa engine features. And, \type {\long} stuff has been dropped for a long
%D time already (it is still optional in \lUATEX). But the \quote  {long} in the
%D name kind of stuck.

%D \macros
%D   {blankspace}
%D
%D Here is how this works. The \type {\let} primitive first picks up the to be let
%D name. Then it scans for an optional equal and when that is found it will skip the
%D next space, which is why we need an extra one to achieve our goal. Such a \type
%D {\blankspace} has the meaning \typ {blank space}. A typical \TEX ie definition:

\expanded{\permanent\let\noexpand\blankspace=\space\space}

%D this is the same as \type {\relaxedspace} in \type {syst-ini.mkxl} but we had
%D it (name) from the start of \CONTEXT\ so we keep it; it is also a name used in
%D logging.

%D \macros
%D   {setvalue,setgvalue,setevalue,setxvalue,
%D    letvalue,letgvalue,getvalue,resetvalue,
%D    undefinevalue,ignorevalue}
%D
%D \TEX's primitive \type {\csname} can be used to construct all kind of commands
%D that cannot be defined with \type {\def} and \type {\let}. Every macro programmer
%D sooner 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}=\... = \glet\name=\...
%D \getvalue   {name}      = \name
%D \resetvalue {name}      = \def\name{}
%D \stoptyping
%D
%D As we will see, \CONTEXT\ uses these commands many times, which is mainly due to
%D its object oriented and parameter driven character.

\permanent\def\setvalue     #1{\defcsname #1\endcsname}
\permanent\def\setgvalue    #1{\gdefcsname#1\endcsname}
\permanent\def\setevalue    #1{\edefcsname#1\endcsname}
\permanent\def\setxvalue    #1{\xdefcsname#1\endcsname}
\permanent\def\getvalue     #1{\begincsname#1\endcsname}
\permanent\def\letvalue     #1{\letcsname #1\endcsname}
\permanent\def\letgvalue    #1{\gletcsname#1\endcsname}
\permanent\def\resetvalue   #1{\letcsname#1\endcsname\empty}
\permanent\def\undefinevalue#1{\letcsname#1\endcsname\undefined}
\permanent\def\ignorevalue#1#2{\letcsname#1\endcsname\empty}

\permanent\def\setuvalue    #1{\protected\defcsname #1\endcsname}
\permanent\def\setuevalue   #1{\protected\edefcsname#1\endcsname}
\permanent\def\setugvalue   #1{\protected\gdefcsname#1\endcsname}
\permanent\def\setuxvalue   #1{\protected\xdefcsname#1\endcsname}

\permanent\protected\def\getuvalue#1{\begincsname#1\endcsname}

%D \macros
%D   {globallet,glet}
%D
%D In \CONTEXT\ of May 2000 using \type {\globallet} instead of the two tokens will
%D save us some $300\times4=1200$ bytes of format file on a 32~bit system. Not that
%D it matters much today. But nowadays we can just alias to a primitive:

\aliased\let\globallet\glet

%D \macros
%D   {doifundefined,doifdefined,
%D    doifundefinedelse,doifdefinedelse,
%D    doifalldefinedelse}
%D
%D The standard way of testing if a macro is defined is comparing its meaning with
%D another undefined one, usually \type {\undefined}. To garantee correct working of
%D the next 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 table, which is of
%D limited size. It is expected that \ETEX\ will offer a less memory||consuming
%D alternative.
%D
%D Although it will probably never be a big problem, it is good to be aware of the
%D difference between testing on a macro name to be build by using \type {\csname} and
%D \type {\endcsname} and testing the \type {\name} directly.
%D
%D \starttyping
%D \expandafter\ifrelax\csname NameA\endcsname ... \else ... \fi
%D
%D \ifundefined\NameB ... \else ... \fi
%D \stoptyping
%D
%D Suppression of errors while constructing a control sequence is one of the (few)
%D things that I remember being discussed in the perspective of \ETEX\ but it was
%D rejected because it was not considered useful. Well, in \LUATEX\ we can surpress
%D it and that is what we do in \MKIV. We're probably the only macro package that
%D needs it. That kind of configuration happens elsewhere. These macros are (mostly
%D for historic reasons) fully expandable.

\permanent\def\doifelseundefined#1%
  {\ifcsname#1\endcsname
     \expandafter\secondoftwoarguments\else\expandafter\firstoftwoarguments
   \fi}

\permanent\def\doifelsedefined#1%
  {\ifcsname#1\endcsname
     \expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments
   \fi}

\permanent\def\doifundefined#1%
  {\ifcsname#1\endcsname
     \expandafter\gobbleoneargument\else\expandafter\firstofoneargument
   \fi}

\permanent\def\doifdefined#1%
  {\ifcsname#1\endcsname
     \expandafter\firstofoneargument\else\expandafter\gobbleoneargument
   \fi}

\aliased\let\doifundefinedelse\doifelseundefined
\aliased\let\doifdefinedelse  \doifelsedefined

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

\permanent\protected\def\letbeundefined#1%
  {\letcsname#1\endcsname\undefined}

\permanent\protected\def\localundefine#1% conditional
  {\ifcsname#1\endcsname\letcsname#1\endcsname\undefined\fi}

\permanent\protected\def\globalundefine#1% conditional
  {\ifcsname#1\endcsname\gletcsname#1\endcsname\undefined\fi}

%D Beware, being \type {\undefined} in \ETEX\ means that the macro {\em is} defined!
%D
%D When we were developing the scientific units module, we encountered different
%D behavior in text and math mode, which was due to this grouping subtilities. We
%D therefore decided to use \type {\begingroup} instead of \type {\bgroup}.
%D
%D \stoptyping
%D \doifelsealldefined  {foo,ofo}  {YES}{NOP}
%D \doifelseallundefined{foo,ofo}  {YES}{NOP}
%D \doifelsealldefined  {relax,ofo}{YES}{NOP}
%D \doifelseallundefined{foo,relax}{YES}{NOP}
%D \stoptyping

\def\syst_helpers_do_if_all_defined_else#1%
  {\ifcsname#1\endcsname\else
     \donefalse
     \expandafter\quitcommalist % added
   \fi}

\def\syst_helpers_do_if_all_undefined_else#1%
  {\ifcsname#1\endcsname
     \donefalse
     \expandafter\quitcommalist
   \fi}

\permanent\protected\def\syst_helpers_do_if_all_else#1#2%
  {\begingroup
   \donetrue % we could use a reserved one and avoid the group
   \processcommalist[#2]#1%
   \ifdone
     \endgroup\expandafter\firstoftwoarguments
   \else
     \endgroup\expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\doifelsealldefined  {\syst_helpers_do_if_all_else\syst_helpers_do_if_all_defined_else}
\permanent\protected\def\doifelseallundefined{\syst_helpers_do_if_all_else\syst_helpers_do_if_all_undefined_else}

\aliased\let\doifalldefinedelse  \doifelsealldefined
\aliased\let\doifallundefinedelse\doifelseallundefined

%D \macros
%D   {doif,doifelse,doifnot}
%D
%D Programming in \TEX\ differs from programming in procedural languages like
%D \MODULA. This means that one --- well, let me speek for myself --- tries to do
%D the things in the well known way. Therefore the next set of \type {ifthenelse}
%D commands were between the first ones we needed. A few years later, the opposite
%D became true: when programming in \MODULA, I sometimes miss handy things like
%D grouping, runtime redefinition, expansion etc. While \MODULA\ taught me to
%D 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 Again, we use some of the new primitives in \LUAMETATEX. Using straightforward
%D \type {\edef}'s and \type {\ifx} comparison works as well, but this saves tokens
%D and, more important, tracing clutter.

\permanent\protected\def\doifelse#1#2%
  {\iftok{#1}{#2}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\doif#1#2%
  {\iftok{#1}{#2}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifnot#1#2%
  {\iftok{#1}{#2}%
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

%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, but we use the dedicated empty checker
%D here.

\permanent\protected\def\doifelseempty#1%
  {\def\m_syst_string_one{#1}%
   \ifempty\m_syst_string_one
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

% or (test this):
%
% \permanent\protected\def\processallactionsinset[#1]%
%   {\ifempty{#1}%
%      \expandafter\processaction
%    \else
%      \expandafter\syst_helpers_process_all_actions_in_set_indeed
%    \fi[#1]}

\aliased\let\doifemptyelse\doifelseempty

\permanent\protected\def\doifempty#1%
  {\def\m_syst_string_one{#1}%
   \ifempty\m_syst_string_one
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifnotempty#1%
  {\def\m_syst_string_one{#1}%
   \ifempty\m_syst_string_one
     \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 set of strings.
%D Depending on the result, some action is taken.
%D
%D \starttyping
%D \doifinset     {string} {string,...} {...}
%D \doifnotinset  {string} {string,...} {...}
%D \doifinsetelse {string} {string,...} {then ...} {else ...}
%D \stoptyping

% !0nop=\doifinsetelse{ccc}{,}{yes}{nop}
% !0nop=\doifinsetelse{ccc}{,,}{yes}{nop}
% !0nop=\doifinsetelse{ccc}{,,,}{yes}{nop}

% !1nop=\doifinsetelse{}{}{yes}{nop}
% !2yes=\doifinsetelse{aaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
% !3nop=\doifinsetelse{aaa}{bbb}{yes}{nop}
% !4yes=\doifinsetelse{aaa}{aaa}{yes}{nop}
% !5nop=\doifinsetelse{aaaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
% !6nop=\doifinsetelse{}{}{yes}{nop}
% !7nop=\doifinsetelse{}{aaa}{yes}{nop}
% !8nop=\doifinsetelse{aaa}{}{yes}{nop}

% !1=\doifinset{}{}{yes}
% !2yes=\doifinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
% !3=\doifinset{aaa}{bbb}{yes}
% !4yes=\doifinset{aaa}{aaa}{yes}
% !5=\doifinset{}{}{yes}
% !6=\doifinset{aaa}{}{yes}

% !1yes=\doifnotinset{}{}{yes}
% !2=\doifnotinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
% !3yes=\doifnotinset{aaa}{bbb}{yes}
% !4=\doifnotinset{aaa}{aaa}{yes}
% !5yes=\doifnotinset{}{}{yes}
% !6yes=\doifnotinset{aaa}{}{yes}

%D These are normally only used for keywords, i.e.\ strings so we can delegate
%D the work to \LUA:

%protected\def\doifelseinset#1#2{\clf_doifelseinset{#1}{#2}}
%protected\def\doifinset    #1#2{\clf_doifinset    {#1}{#2}}
%protected\def\doifnotinset #1#2{\clf_doifnotinset {#1}{#2}}
%       % \let\firstinset        \clf_firstinset

% These don't accept spaces after commas:
%
% \protected\def\doifelseinset#1#2%
%   {\ifhasxtoks{,#1,}{,#2,}%
%      \expandafter\firstoftwoarguments
%    \else
%      \expandafter\secondoftwoarguments
%    \fi}

% \protected\def\doifinset#1#2%
%   {\ifhasxtoks{,#1,}{,#2,}%
%      \expandafter\firstofoneargument
%    \else
%      \expandafter\gobbleoneargument
%    \fi}

% \protected\def\doifnotinset#1#2%
%   {\ifhasxtoks{,#1,}{,#2,}%
%      \expandafter\gobbleoneargument
%    \else
%      \expandafter\firstofoneargument
%    \fi}

% But these do:

\permanent\edef\a!comma{\expandtoken \ignorecatcode \commaasciicode} % maybe \cdef
\permanent\edef\a!space{\expandtoken \ignorecatcode \spaceasciicode} % maybe \cdef

\expanded {

    \permanent \protected \def \noexpand \doifelseinset#1#2%
      {\noexpand\ifhasxtoks{,\a!space#1,}{,#2,}%
         \noexpand\expandafter\noexpand\firstoftwoarguments
       \noexpand\else
         \noexpand\expandafter\noexpand\secondoftwoarguments
       \noexpand\fi}

    \permanent \protected \def \noexpand \doifinset#1#2%
      {\noexpand\ifhasxtoks{,\a!space#1,}{,#2,}%
         \noexpand\expandafter\noexpand\firstofoneargument
       \noexpand\else
         \noexpand\expandafter\noexpand\gobbleoneargument
       \noexpand\fi}

    \permanent \protected \def \noexpand \doifnotinset#1#2%
      {\noexpand\ifhasxtoks{,\a!space#1,}{,#2,}%
         \noexpand\expandafter\noexpand\gobbleoneargument
       \noexpand\else
         \noexpand\expandafter\noexpand\firstofoneargument
       \noexpand\fi}

}

%D Done.

\aliased\let\doifinsetelse\doifelseinset

%D \macros
%D   {doifcommon,doifnotcommon,doifcommonelse}
%D
%D Probably the most time consuming tests are those that test for overlap in sets
%D of strings.
%D
%D \starttyping
%D \doifcommon     {string,...} {string,...} {...}
%D \doifnotcommon  {string,...} {string,...} {...}
%D \doifcommonelse {string,...} {string,...} {then ...} {else ...}
%D \stoptyping

% !1yes=\doifcommonelse{aaa,bbb,ccc}{aaa,bbb,ccc}{yes}{nop}
% !2nop=\doifcommonelse{aaa,bbb,ccc}{ddd,eee,fff}{yes}{nop}
% !3nop=\doifcommonelse{aaa}{ddd,eee,fff}{yes}{nop}
% !4yes=\doifcommonelse{aaa}{aaa}{yes}{nop}
% !5nop=\doifcommonelse{bbb}{aaa}{yes}{nop}
% !6nop=\doifcommonelse{}{aaa,bbb,ccc}{yes}{nop}
% !7nop=\doifcommonelse{aaa,bbb,ccc}{}{yes}{nop}
% !8nop=\doifcommonelse{}{}{yes}{nop}

% !9nop=\doifcommonelse{,,}{,,}{yes}{nop}
% !9yes=\doifcommonelse{,a,}{,a,}{yes}{nop}
% !9yes=\doifcommonelse{,,a,}{,a,}{yes}{nop}
% !9yes=\doifcommonelse{,a,}{,,a,}{yes}{nop}
% !9yes=\doifcommonelse{,a,}{,,,a,}{yes}{nop}
% !9yes=\doifcommonelse{,,a,}{,,,a,}{yes}{nop}

% \permanent\protected\def\doifelsecommon#1#2{\clf_doifelsecommon{#1}{#2}} % todo: define in lua
% \permanent\protected\def\doifcommon    #1#2{\clf_doifcommon    {#1}{#2}} % todo: define in lua
% \permanent\protected\def\doifnotcommon #1#2{\clf_doifnotcommon {#1}{#2}} % todo: define in lua

\permanent\protected\def\doifelsecommon#1#2{\clf_if_common{#1}{#2}\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
\permanent\protected\def\doifcommon    #1#2{\clf_if_common{#1}{#2}\expandafter\firstofoneargument \else\expandafter\gobbleoneargument   \fi}
\permanent\protected\def\doifnotcommon #1#2{\clf_if_common{#1}{#2}\expandafter\gobbleoneargument  \else\expandafter\firstofoneargument  \fi}

\aliased\let\doifcommonelse\doifelsecommon

%D Here no commalistelement is set:

\permanent\def\expdoifelsecommon#1#2{\ifcommon{#1}{#2}\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
\permanent\def\expdoifelseinset #1#2{\ifinset {#1}{#2}\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}

\aliased\let\expdoifcommonelse\expdoifelsecommon
\aliased\let\expdoifinsetelse \expdoifelseinset

%D \macros
%D   {processcommalist,processcommacommand,quitcommalist,
%D    processcommalistwithparameters}
%D
%D We've already seen some macros that take care of comma separated lists. Such
%D 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 argument: the string.
%D This command permits nesting and spaces after commas are skipped. Empty sets
%D 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 Or expanded:
%D
%D \blank \getbuffer \blank
%D
%D The original definitions can be found elsewhere and need a bit more code. In case of
%D issues, consult the \MKIV\ variant or previous \LMTX\ variants in the repository.
%D
%D When a list is saved in a macro, we can use a construction like:
%D
%D \starttyping
%D \expandafter\processcommalist\expandafter[\list]\command
%D \stoptyping
%D
%D Such solutions suit most situations, but we wanted a bit 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 use of this macro has its
%D limits. We use a new \LUAMETATEX\ feature that intercepts invalid macro arguments
%D by quitting when \type {\ignorearguments} is seen. That's why we act on the
%D arguments state. Again it permits leaner and meaner macro definitions with a bit
%D less clutter in tracing.

\mutable\lettonothing\commalistcommand

% \protected\def\syst_helpers_process_comma_item#+,%
%   {\ifarguments
%      \expandafter\syst_helpers_process_comma_item_gobble
%    \orelse\ifparameter#1\or
%      \commalistcommand{#1}%
%      \expandafter\syst_helpers_process_comma_item_next
%    \else
%      \expandafter\syst_helpers_process_comma_item_gobble
%    \fi}

% \def\syst_helpers_process_comma_item_next
%   {\expandafterspaces\syst_helpers_process_comma_item}

% \protected\def\processcommalist[#1]#2%
%   {\pushmacro\commalistcommand
%    \def\commalistcommand{#2}%
%    \expandafterspaces\syst_helpers_process_comma_item#1,\ignorearguments\ignorearguments\ignorearguments
%    \popmacro\commalistcommand}

% \protected\def\processcommacommand[#1]#2%
%   {\pushmacro\commalistcommand
%    \def\commalistcommand{#2}%
%    \expanded{\noexpand\expandafterspaces\syst_helpers_process_comma_item#1,}\ignorearguments\ignorearguments\ignorearguments
%    \popmacro\commalistcommand}

% \permanent\protected\def\processcommalist[#*#+]#2%
%   {\pushmacro\commalistcommand
%    \def\commalistcommand{#2}%
%    \expandafterspaces\syst_helpers_process_comma_item#1,\ignorearguments\ignorearguments\ignorearguments
%    \popmacro\commalistcommand}
%
% \permanent\protected\def\processcommacommand[#*#+]#2%
%   {\pushmacro\commalistcommand
%    \def\commalistcommand{#2}%
%    \expanded{\noexpand\expandafterspaces\syst_helpers_process_comma_item#1,}\ignorearguments\ignorearguments\ignorearguments
%    \popmacro\commalistcommand}

\tolerant\protected\def\syst_helpers_process_comma_item#*#1,%
  {\ifarguments\or
     \commalistcommand{#1}%
     \expandafter\syst_helpers_process_comma_item_next
   \fi}

\def\syst_helpers_process_comma_item_next
  {\expandafterspaces\syst_helpers_process_comma_item}

\permanent\protected\def\processcommalist[#1]#2%
  {\pushmacro\commalistcommand
   \def\commalistcommand{#2}%
   \syst_helpers_process_comma_item#1\ignorearguments\ignorearguments\ignorearguments
   \popmacro\commalistcommand}

\permanent\protected\def\processcommacommand[#1]#2%
  {\pushmacro\commalistcommand
   \def\commalistcommand{#2}%
   \expanded{\syst_helpers_process_comma_item#1}\ignorearguments\ignorearguments\ignorearguments
   \popmacro\commalistcommand}

% \let\syst_helpers_process_comma_item_next_a                                                            \syst_helpers_process_comma_item_next
% \def\syst_helpers_process_comma_item_next_b#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_a}
% \def\syst_helpers_process_comma_item_next_c#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_b}
% \def\syst_helpers_process_comma_item_gobble#-\ignorearguments{}

\let\syst_helpers_process_comma_item_next_a                                                            \syst_helpers_process_comma_item_next
\def\syst_helpers_process_comma_item_next_b#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_a}
\def\syst_helpers_process_comma_item_next_c#-\ignorearguments{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_b}
\def\syst_helpers_process_comma_item_gobble#-\ignorearguments{}

\permanent\protected\def\quitcommalist    {\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_b}
\permanent\protected\def\quitprevcommalist{\let\syst_helpers_process_comma_item_next\syst_helpers_process_comma_item_next_c}

%D \startbuffer
%D \def\foo#1{(#1)}
%D <\processcommalist[a,b,c,d]\foo>
%D
%D \def\foo#1{(#1)}
%D \def\oof#1{<\processcommalist[#1]\foo>}
%D <\processcommalist[{a,b},{c,d}]\oof>
%D
%D \def\foo#1{(#1)\quitcommalist}
%D <\processcommalist[a,b,c,d]\foo>
%D
%D \def\foo#1{(#1)}
%D \def\oof#1{<\processcommalist[#1]\foo\quitcommalist>}
%D <\processcommalist[{a,b},{c,d}]\oof>
%D
%D \def\foo#1{(#1)\quitcommalist}
%D \def\oof#1{<\processcommalist[#1]\foo>}
%D <\processcommalist[{a,b},{c,d},{e,f}]\oof>
%D
%D \def\foo#1{(#1)\quitprevcommalist}
%D \def\oof#1{<\processcommalist[#1]\foo>}
%D <\processcommalist[{a,b},{c,d},{e,f}]\oof>
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank

%D The argument to \type{\command} is not delimited. Because we often use \type {[]}
%D 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

\let\syst_helpers_do_process_comma_list_with_parameters\gobbleoneargument

\permanent\protected\def\processcommalistwithparameters[#1]#2%
  {\def\syst_helpers_do_process_comma_list_with_parameters##1{#2[##1]}%
   \processcommalist[#1]\syst_helpers_do_process_comma_list_with_parameters}

%D \macros
%D   {startprocesscommalist,startprocesscommacommand}
%D
%D Two more:

\let\syst_helpers_comma_list_step\relax

\mutable\lettonothing\currentcommalistitem

\permanent\protected\def\startprocesscommalist[#1]#2\stopprocesscommalist
  {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}%
   \processcommalist[#1]\syst_helpers_comma_list_step}

\permanent\protected\def\startprocesscommacommand[#1]#2\stopprocesscommacommand
  {\def\syst_helpers_comma_list_step##1{\def\currentcommalistitem{##1}#2}%
   \expanded{\processcommalist[#1]}\syst_helpers_comma_list_step}

\permanent\protected\lettonothing\stopprocesscommalist
\permanent\protected\lettonothing\stopprocesscommacommand

%D \macros
%D   {processaction,
%D    processfirstactioninset,
%D    processallactionsinset}
%D
%D \CONTEXT\ makes extensive use of a sort of case or switch command. Depending of
%D the presence of one or more provided items, some actions is taken. These macros
%D can be nested without problems.
%D
%D \starttyping
%D \processaction           [x]     [x=>a,y=>b,z=>c]
%D \processfirstactioninset [x,y,z] [x=>a,y=>b,z=>c]
%D \processallactionsinset  [x,y,z] [x=>a,y=>b,z=>c]
%D \stoptyping
%D
%D We can supply both a \type {default} action and an action to be undertaken when
%D 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 the keyword \type
%D {default} and executed the related action if present. When \type {#1} is non
%D empty and not in the list, the action related to \type {unknown} is executed.
%D Both keywords must be at the end of list \type{#2}. Afterwards, the actually
%D found keyword is available in \type {\commalistelement}. An advanced example of
%D the use of this macro can be found in \PPCHTEX, where we completely rely on \TEX\
%D for interpreting user supplied keywords like \type {SB}, \type {SB1..6}, \type
%D {SB125} etc.
%D
%D In the meantime we follow a different approach, often somewhat more heavy on the
%D number of control sequences used, but that is no lomger a real issue. The code
%D has been simplified and nwo uses the macro stack mechanism. If needed I can make
%D this more hip and a bit faster now but \unknown\ it's seldom used nowadays as we
%D have better ways now.

\mutable\lettonothing\commalistelement

\let\syst_helpers_do_compare_process_action\relax

\protected\def\syst_helpers_do_compare_process_action_a[#1=>#2][#3]%
  {\edef\m_syst_string_two{#1}%
   \ifx\m_syst_string_two\s!default
     \lettonothing\commalistelement
     #2%
   \fi}

\protected\def\syst_helpers_do_compare_process_action_b[#1=>#2][#3]%
  {\edef\m_syst_string_two{#1}%
   \ifx\m_syst_string_one\m_syst_string_two
     \def\commalistelement{#3}%
     #2%
     \expandafter\quitcommalist
   \orelse\ifx\m_syst_string_two\s!unknown
     \def\commalistelement{#3}% beware of loops
     #2%
   \fi}

\permanent\protected\def\processaction[#1]#2[%
  {\edef\m_syst_string_one{#1}%
   \ifempty\m_syst_string_one
     \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_a
   \else
     \let\syst_helpers_do_compare_process_action\syst_helpers_do_compare_process_action_b
   \fi
   \edef\syst_helpers_do_process_action##1{\syst_helpers_do_compare_process_action[##1][#1]}% expands #1
   \processnextcommalist\syst_helpers_do_process_action[}

\protected\def\syst_helpers_do_compare_process_action_c[#1=>#2][#3]%
  {\edef\m_syst_string_one{#1}%
   \edef\m_syst_string_two{#3}%
   \ifx\m_syst_string_one\m_syst_string_two
     \def\commalistelement{#3}%
     #2%
     \expandafter\quitprevcommalist
   \else
     \edef\m_syst_string_one{#1}%
     \ifx\m_syst_string_one\s!unknown
       \def\commalistelement{#3}%
       #2%
     \fi
   \fi}

\permanent\protected\def\processfirstactioninset[#1]%
  {\edef\m_syst_string_one{#1}%
   \ifempty\m_syst_string_one
     \expandafter\processaction
   \else
     \expandafter\syst_helpers_process_first_action_in_set_indeed
   \fi
   [#1]}

\let\syst_helpers_do_process_action   \gobbleoneargument
\let\syst_helpers_do_do_process_action\gobbleoneargument

\tolerant\protected\def\syst_helpers_process_first_action_in_set_indeed[#1]#*[#2]%
  {\def\syst_helpers_do_process_action##1%
     {\def\syst_helpers_do_do_process_action####1{\syst_helpers_do_compare_process_action_c[####1][##1]}%
      \processcommalist[#2]\syst_helpers_do_do_process_action}%
   \expanded{\processcommalist[#1]}\syst_helpers_do_process_action}

\protected\def\syst_helpers_do_compare_process_action_d[#1=>#2][#3]%
  {\edef\m_syst_string_one{#1}%
   \edef\m_syst_string_two{#3}%
   \ifx\m_syst_string_one\m_syst_string_two
     \def\commalistelement{#3}%
     #2%
     \expandafter\quitcommalist
   \else
     \edef\m_syst_string_one{#1}%
     \ifx\m_syst_string_one\s!unknown
       \def\commalistelement{#3}%
       #2%
     \fi
   \fi}

\let\syst_process_action_in_set_all\relax

\tolerant\protected\def\syst_helpers_process_all_actions_in_set_indeed[#1]#*[#2]%
  {\globalpushmacro\syst_process_action_in_set_all
   \def\syst_process_action_in_set##1%
     {\def\syst_process_action_in_set_one####1{\syst_helpers_do_compare_process_action_d[####1][##1]}%
      \processcommalist[#2]\syst_process_action_in_set_one}%
      \processcommacommand[#1]\syst_process_action_in_set
   \globalpopmacro\syst_process_action_in_set_all}

\permanent\protected\def\processallactionsinset[#1]%
  {\edef\m_syst_string_one{#1}%
   \ifempty\m_syst_string_one
     \expandafter\processaction
   \else
     \expandafter\syst_helpers_process_all_actions_in_set_indeed
   \fi[#1]}

%D These macros use:

% \protected\def\processnextcommalist#1[#2#3]%
%   {\pushmacro\commalistcommand
%    \def\commalistcommand{#1}%
%    \expandafterspaces\syst_helpers_process_comma_item#2#3\ignorearguments\ignorearguments\ignorearguments
%    \popmacro\commalistcommand}

\permanent\protected\def\processnextcommalist#1[#2#3]% watch out: mkiv has two extra initial arguments
  {\pushmacro\commalistcommand
   \def\commalistcommand{#1}%
   \expandafterspaces\syst_helpers_process_comma_item#2#3\ignorearguments\ignorearguments\ignorearguments
   \popmacro\commalistcommand}

%D \macros
%D   {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter}
%D
%D Sometimes the action to be undertaken depends on the next character. This macro
%D get this character and puts it in \type {\firstcharacter}.
%D
%D \starttyping
%D \getfirstcharacter {string}
%D \stoptyping
%D
%D A two step expansion is used to prevent problems with complicated arguments, for
%D instance arguments that consist of two or more expandable tokens.

\mutable\lettonothing\firstcharacter
\mutable\lettonothing\remainingcharacters

\permanent\protected\def\getfirstcharacter     #1{\clf_getfirstcharacter{#1}}
\permanent\protected\def\doifelsefirstchar   #1#2{\clf_doifelsefirstchar{#1}{#2}}
\permanent\protected\def\thefirstcharacter     #1{\clf_thefirstcharacter{#1}}
\permanent\protected\def\theremainingcharacters#1{\clf_theremainingcharacters{#1}}

\aliased\let\doiffirstcharelse\doifelsefirstchar

%D \macros
%D   {doifinstringelse, doifincsnameelse}
%D
%D We can check for the presence of a substring in a given sequence of characters.
%D
%D \starttyping
%D \doifinstringelse {substring} {string} {then ...} {else ...}
%D \stoptyping
%D
%D \startbuffer
%D \doifinstringelse{abc}{foo bar abc}{Y}{N}=Y\par
%D \doifinstringelse{abc}{foo bar cab}{Y}{N}=N\par
%D \doifinstring    {abc}{foo bar abc}{Y}=Y\par
%D \doifinstring    {abc}{foo bar cab}{Y}\par
%D \doifnotinstring {abc}{foo bar abc}{Y}\par
%D \doifnotinstring {abc}{foo bar cab}{Y}=Y\par
%D \doifinstringelse{}{foo bar abc}{Y}{N}=N\par
%D \doifinstring    {}{foo bar abc}{N}\par
%D \doifnotinstring {}{foo bar abc}{Y}=Y\par
%D \doifinstringelse{x}{}{Y}{N}=N\par
%D \doifinstring    {x}{}{N}\par
%D \doifnotinstring {x}{}{Y}=Y\par
%D \doifinstringelse{}{}{Y}{N}=N\par
%D \doifinstring    {}{}{N}\par
%D \doifnotinstring {}{}{Y}=Y\par
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank

%D I keep the following as example code:

% \let\syst_helpers_do_do_if_in_string_else\relax
% \let\syst_helpers_do_do_if_in_string     \relax
% \let\syst_helpers_do_do_if_not_in_string \relax
%
% \lettonothing\m_syst_sub_string
%
% \protected\def\doifelseinstring#1%
%   {\edef\m_syst_sub_string{#1}% expand #1 here
%    \ifempty\m_syst_sub_string
%      \expandafter\thirdofthreearguments
%    \else
%      \expandafter\syst_helpers_do_if_in_string_else
%    \fi}
%
% \let\doifinstringelse\doifelseinstring
%
% \protected\def\syst_helpers_do_if_in_string_else#1% ##2 can be {abc}
%   {\expanded{\protected\def\syst_helpers_do_do_if_in_string_else##1\m_syst_sub_string##2}%
%      {\ifarguments
%       \or
%         \expandafter\syst_helpers_do_if_in_string_else_nop
%       \or
%         \expandafter\syst_helpers_do_if_in_string_else_yes
%       \fi}%
%    \expanded{\syst_helpers_do_do_if_in_string_else#1}\s!e_o_t_token\ignorearguments\ignorearguments}
%
% \protected\def\syst_helpers_do_if_in_string_else_delimited#1% ##2 can be {abc}
%   {\expanded{\protected\def\syst_helpers_do_do_if_in_string_else##1,\m_syst_sub_string,##2}%
%      {\ifarguments
%       \or
%         \expandafter\syst_helpers_do_if_in_string_else_nop
%       \or
%         \expandafter\syst_helpers_do_if_in_string_else_yes
%       \fi}%
%    \expanded{\syst_helpers_do_do_if_in_string_else,#1,}\s!e_o_t_token\ignorearguments\ignorearguments}
%
% \protected\def\doifinstring#1%
%   {\edef\m_syst_sub_string{#1}% expand #1 here
%    \ifempty\m_syst_sub_string
%      \expandafter\gobbletwoarguments
%    \else
%      \expandafter\syst_helpers_do_if_in_string
%    \fi}
%
% \protected\def\syst_helpers_do_if_in_string#1% ##2 can be {abc}
%   {\expanded{\protected\def\syst_helpers_do_do_if_in_string##1\m_syst_sub_string##2}%
%      {\ifarguments
%       \or
%         \expandafter\syst_helpers_do_if_in_string_nop
%       \or
%         \expandafter\syst_helpers_do_if_in_string_yes
%       \fi}%
%    \expanded{\syst_helpers_do_do_if_in_string#1}\s!e_o_t_token\ignorearguments\ignorearguments}
%
% \protected\def\doifnotinstring#1%
%   {\edef\m_syst_sub_string{#1}% expand #1 here
%    \ifempty\m_syst_sub_string
%      \expandafter\secondoftwoarguments
%    \else
%      \expandafter\syst_helpers_do_if_not_in_string
%    \fi}
%
% \protected\def\syst_helpers_do_if_not_in_string#1% ##2 can be {abc}
%   {\expanded{\protected\def\syst_helpers_do_do_if_not_in_string##1\m_syst_sub_string##2}%
%      {\ifarguments
%       \or
%         \expandafter\syst_helpers_do_if_not_in_string_nop
%       \or
%         \expandafter\syst_helpers_do_if_not_in_string_yes
%       \fi}%
%    \expanded{\syst_helpers_do_do_if_not_in_string#1}\s!e_o_t_token\ignorearguments\ignorearguments}
%
% \def\syst_helpers_do_if_in_string_else_yes#0\ignorearguments\ignorearguments#2#0{#2} % of #- and #1
% \def\syst_helpers_do_if_in_string_else_nop#0\ignorearguments#0#3{#3}
% \def\syst_helpers_do_if_in_string_yes     #0\ignorearguments\ignorearguments#2{#2}
% \def\syst_helpers_do_if_in_string_nop     #0\ignorearguments#0{}
% \def\syst_helpers_do_if_not_in_string_yes #0\ignorearguments\ignorearguments#0{}
% \def\syst_helpers_do_if_not_in_string_nop #0\ignorearguments#2{#2}

\permanent\protected\def\doifelseinstring#1#2%
  {\ifhasxtoks{#1}{#2}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\doifinstring#1#2%
  {\ifhasxtoks{#1}{#2}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifnotinstring#1#2%
  {\ifhasxtoks{#1}{#2}%
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\aliased\let\doifinstringelse\doifelseinstring

%D The next one one of those variants that we used when speed was more of an issue
%D that today. Now we just expand the lot. We just use an alias now:

\aliased\let\doifelseincsname\doifelseinstring
\aliased\let\doifincsnameelse\doifinstringelse

%D \macros
%D   {doifnumberelse,doifnumber,doifnotnumber}
%D
%D The next macro executes a command depending of the outcome of a test on numerals.
%D We now use a \LUATEX\ feature that permits a more robust checking, but you might
%D want to take a look at the originals. It's typically one of these new features
%D that probably only \CONTEXT\ will use, which is probably true for more such
%D features that no one ever asked for (but they are pretty generic in nature
%D anyway).

\permanent\def\doifelsenumber#1%
  {\ifchknum#1\or
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\def\doifnumber#1%
  {\ifchknum#1\or
     \expandafter\firstoftwoarguments
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\def\doifnotnumber#1%
  {\ifchknum#1\or
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\aliased\let\doifnumberelse\doifelsenumber

%D \macros
%D   {setpercentdimen}
%D
%D \starttyping
%D \scratchdimen=100pt \setpercentdimen\scratchdimen{10\letterpercent}
%D \scratchdimen=100pt \setpercentdimen\scratchdimen{5pt}
%D \scratchdimen       \percentdimen   \hsize       {10\letterpercent}
%D \stoptyping

% todo: use the push back dimen trickery

\permanent\def\percentdimen#1#2% dimen percentage (with %)
  {\dimexpr\clf_percentageof{#2}{#1}\relax}

\permanent\protected\def\setpercentdimen#1#2% dimen percentage (with %)
  {#1=\clf_percentageof{#2}{#1}}

%D \macros
%D   {makerawcommalist,
%D    rawdoinsetelse,
%D    rawprocesscommalist,
%D    rawprocessaction}
%D
%D Some of the commands mentioned earlier are effective but slow. When one is
%D desperately in need of faster alternatives and when the conditions are
%D predictable safe, the \type {\raw} alternatives come into focus. A major drawback
%D is that they do not take \type {\c!constants} into account, simply because no
%D expansion is done. This is no problem with \type {\rawprocesscommalist}, because
%D this macro does not compare anything. Expandable macros are permitted as search
%D string.
%D
%D \starttyping
%D \makerawcommalist[string,string,...]\stringlist
%D \rawdoifelseinset{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, spoil the search process.
%D The gain in speed depends on the length of the argument (the longer the argument,
%D the less we gain). The question is: do we still need these raw variants?

\let\syst_helpers_do_make_raw_comma_list\gobbleoneargument

\permanent\protected\def\makerawcommalist[#1]#2% use \processnext ... here
  {\scratchtoks\emptytoks
   \def\syst_helpers_do_make_raw_comma_list##1{\ifempty\scratchtoks\scratchtoks{##1}\else\toksapp\scratchtoks{,##1}\fi}%
   \processcommalist[#1]\syst_helpers_do_make_raw_comma_list
   \edef#2{\the\scratchtoks}}

% beware: in mkiv { } were lost so it was not compatible with the non raw

\aliased\let\rawprocesscommalist   \processcommalist    % can go
\aliased\let\rawprocesscommacommand\processcommacommand % can go

%D Here is one without nesting .. still needed? Only used for modes (no nesting
%D there).

\mutable\let\fastcommalistcommand\relax

\protected\def\syst_helpers_process_fast_comma_item#1,%
  {\ifarguments
     \expandafter\syst_helpers_process_comma_item_gobble
   \or
     \fastcommalistcommand{#1}%
     \expandafter\syst_helpers_process_fast_comma_item_next
   \fi}

\protected\def\syst_helpers_process_fast_comma_item_next
  {\expandafterspaces\syst_helpers_process_fast_comma_item}

\permanent\protected\def\fastprocesscommalist[#1]#2%
  {\let\fastcommalistcommand#2%
   \expandafterspaces\syst_helpers_process_fast_comma_item#1\ignorearguments\ignorearguments\ignorearguments}

\permanent\protected\def\fastprocesscommacommand[#1]#2%
  {\let\fastcommalistcommand#2%
   \expanded{\noexpand\expandafterspaces\syst_helpers_process_fast_comma_item#1}\ignorearguments\ignorearguments\ignorearguments}

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

\lettonothing\m_syst_sub_string

\def\syst_helpers_do_if_else_in_set#1%
  {\ifhasxtoks{,\m_syst_sub_string,}{,#1,}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\rawdoifelseinset#1%
  {\edef\m_syst_sub_string{#1}% expand #1 here
   \ifempty\m_syst_sub_string
     \expandafter\thirdofthreearguments
   \else
     \expandafter\syst_helpers_do_if_else_in_set
   \fi}

\aliased\let\rawdoifinsetelse\rawdoifelseinset

\def\syst_helpers_do_if_in_set#1%
  {\ifhasxtoks{,\m_syst_sub_string,}{,#1,}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\def\m_syst_two_commas{,,} % should be a s! or so

\permanent\protected\def\rawdoifinset#1% or just alias this one
  {\edef\m_syst_sub_string{#1}% expand #1 here
   \ifx\m_syst_sub_string\m_syst_two_commas
     \expandafter\gobbletwoarguments
   \else
     \expandafter\syst_helpers_do_if_in_set
   \fi}

%D Some more raw material:

% probably never used
%
% \lettonothing\m_syst_helpers_process_action
% \lettonothing\m_syst_helpers_process_action_unknown
%
% \def\syst_helpers_raw_process_action#1=>#2,%
%   {\ifarguments
%     %\expandafter\syst_helpers_raw_process_action_gobble
%    \or
%      \expandafter\syst_helpers_raw_process_action_gobble
%    \or
%      \edef\m_syst_string_two{#1}%
%      \ifx\m_syst_string_one\m_syst_string_two
%        \def\m_syst_helpers_process_action{#2}%
%        \expandafter\expandafter\expandafter\syst_helpers_raw_process_action_gobble
%      \else
%        \ifx\s!unknown\m_syst_string_two
%          \def\m_syst_helpers_process_action_unknown{#2}%
%        \fi
%        \expandafter\expandafter\expandafter\syst_helpers_raw_process_action_next
%      \fi
%    \fi}
%
% \def\syst_helpers_raw_process_action_gobble#-\ignorearguments
%   {}
%
% \def\syst_helpers_raw_process_action_next
%   {\expandafterspaces\syst_helpers_raw_process_action}
%
% \permanent\protected\def\xrawprocessaction[#1]#*[#2]%
%   {\edef\m_syst_string_one{#1}%
%    \ifempty\m_syst_string_one
%       \let\m_syst_string_one\s!default
%    \fi
%    \let\m_syst_helpers_process_action\relax
%    \let\m_syst_helpers_process_action_unknown\relax
%    \syst_helpers_raw_process_action#2\ignorearguments\ignorearguments\ignorearguments
%    \ifrelax\m_syst_helpers_process_action
%      \m_syst_helpers_process_action_unknown
%    \else
%      \m_syst_helpers_process_action
%    \fi}

%D When we process the list \type {a,b,c,d,e}, the raw routine takes over 30\% less
%D time, when we feed $20+$ character strings we gain about 20\%. Alternatives which
%D use \type {\futurelet} perform worse. Part of the speedup is due to the \type
%D {\let} and \type {\expandafter} in the test.
%D
%D \macros
%D   {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue,
%D    dogetvalue}
%D
%D When we are going to do assignments, we have to take multi||linguality into account.
%D For the moment we keep 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 for use outside the
%D assignment macros.

\def\dosetvalue     #1#2{\defcsname        #1#2\endcsname} % takes #3
\def\dosetevalue    #1#2{\edefcsname       #1#2\endcsname} % takes #3
\def\dosetgvalue    #1#2{\global\edefcsname#1#2\endcsname} % takes #3
\def\doresetvalue   #1#2{\letcsname        #1#2\endcsname\empty}
\def\doignorevalue#1#2#3{\letcsname        #1#2\endcsname\empty}
\def\docopyvalue  #1#2#3{\defcsname        #1#3\endcsname{\csname#2#3\endcsname}}

%D \macros
%D   {doassign,undoassign,doassignempty}
%D
%D Assignments are the backbone of \CONTEXT. Abhorred by the concept of style file
%D hacking, we took a considerable effort in building a parameterized system.
%D Unfortunately there is a price to pay in terms of speed. Compared to other
%D packages and taking the functionality of \CONTEXT\ into account, the total size
%D of the format file is still very acceptable. Now 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 complain of it's missed. We
%D will redefine this macro later on, when a more advanced message mechanism is
%D implemented.

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

\permanent\protected\def\doassignempty[#1][#2=#3]% kind of obsolete
  {\ifcsname#1#2\endcsname\else\dosetvalue{#1}{#2}{#3}\fi}

%D \macros
%D   {getparameters,geteparameters,getgparameters,
%D    forgetparameters}
%D
%D Using the assignment commands directly is not our ideal of user friendly interfacing,
%D so we take some further steps.
%D
%D \starttyping
%D \getparameters    [label] [...=...,...=...]
%D \forgetparameters [label] [...=...,...=...]
%D \stoptyping
%D
%D Again, the label identifies the category a variable belongs to. The second argument
%D can be a comma separated 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 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{!!} pre||tagged user supplied
%D variables from internal counterparts, we will introduce a slightly different tag
%D in the multi||lingual modules. There we will use \type{c!} or \type{v!},
%D depending on the context.
%D
%D By calling \type{doassign} directly, we save ourselves some argument passing
%D and gain some speed. Whatever optimizations we do, this command will always be
%D one of the bigger bottlenecks. The alternative \type{\geteparameters} --- it's
%D funny to see that this alternative saw the light so lately --- can be used to do
%D expanded assigments.

% \mutable\lettonothing\currentvalue % only mkii

% \permanent\protected\def\getparameters   {\dogetparameters\dosetvalue}
% \permanent\protected\def\geteparameters  {\dogetparameters\dosetevalue}
% \permanent\protected\def\getgparameters  {\dogetparameters\dosetgvalue}
% \permanent\protected\def\getxparameters  {\dogetparameters\dosetxvalue}
% \permanent\protected\def\forgetparameters{\dogetparameters\doignorevalue}
%
% \aliased\let\getexpandedparameters\geteparameters
%
% \def\syst_helpers_grab_parameter_error#1%
%   {\showassignerror{#1}{\the\inputlineno\space(\m_syst_parameter_n)}}
%
% \def\syst_helpers_grab_parameter#1,%
%   {\ifarguments
%      % done
%    \else
%      \syst_helpers_grab_parameter_okay#1,\ignorearguments
%      \expandafter\syst_helpers_grab_parameter_next
%    \fi}
%
% \def\syst_helpers_grab_parameter_okay#1=#2,%
%   {\ifarguments
%    \or
%      \syst_helpers_grab_parameter_error{#1}%
%    \or
%      \m_syst_parameter_s\m_syst_parameter_n{#1}{#2}%
%    \fi}
%
% \def\syst_helpers_grab_parameter_next
%   {\expandafterspaces\syst_helpers_grab_parameter}
%
% \permanent\protected\def\dogetparameters#1[#2]#*[#3]%
%   {\def\m_syst_parameter_n{#2}%
%    \let\m_syst_parameter_s#1%
%    \expandafterspaces\syst_helpers_grab_parameter#3\ignorearguments\ignorearguments}

% Doesn't work with single entry empty values [foo=]
%
% \tolerant\def\syst_get_parameters_n#*#1=#S#2,#M,%
%   {\ifarguments             \expandafter\gobbleoneargument
%    \or                      \mult_interfaces_get_parameters_error_indeed\m_syst_parameter{#1}%
%    \orelse\ifparameter#2\or \defcsname\m_syst_parameter#1\endcsname{#2}%
%    \else                    \letcsname\m_syst_parameter#1\endcsname\empty
%    \fi                      \syst_get_parameters_n}
%
% so we do this instead (and also silently recover).

\lettonothing\m_syst_parameter
\lettonothing\m_syst_parameter_n
\lettonothing\m_syst_parameter_s

\tolerant\def\syst_get_parameters_n#*#1=#S#2,#M,%
  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
   \orelse\ifparameter#2\or\defcsname\m_syst_parameter#1\endcsname{#2}%
   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
   \fi                     \syst_get_parameters_n}
\tolerant\def\syst_get_parameters_e#*#1=#S#2,#M,%
  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
   \orelse\ifparameter#2\or\edefcsname\m_syst_parameter#1\endcsname{#2}%
   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
   \fi                     \syst_get_parameters_e}
\tolerant\def\syst_get_parameters_g#*#1=#S#2,#M,%
  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
   \orelse\ifparameter#2\or\gdefcsname\m_syst_parameter#1\endcsname{#2}%
   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
   \fi                     \syst_get_parameters_g}
\tolerant\def\syst_get_parameters_x#*#1=#S#2,#M,%
  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
   \orelse\ifparameter#2\or\xdefcsname\m_syst_parameter#1\endcsname{#2}%
   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
   \fi                     \syst_get_parameters_x}
\tolerant\def\syst_get_parameters_f#*#1=#S#2,#M,%
  {\unless\ifparameter#1\or\expandafter\gobbleoneargument
   \else                   \letcsname\m_syst_parameter#1\endcsname\empty
   \fi                     \syst_get_parameters_f}

\permanent\protected\def\getparameters   [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_n#2\ignorearguments\ignorearguments}
\permanent\protected\def\geteparameters  [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_e#2\ignorearguments\ignorearguments}
\permanent\protected\def\getgparameters  [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_g#2\ignorearguments\ignorearguments}
\permanent\protected\def\getxparameters  [#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_x#2\ignorearguments\ignorearguments}
\permanent\protected\def\forgetparameters[#1]#*[#S#2]{\cdef\m_syst_parameter{#1}\syst_get_parameters_f#2\ignorearguments\ignorearguments}

\aliased\let\getexpandedparameters\geteparameters

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

\let\syst_helpers_get_empty_parameters\gobbleoneargument

% \permanent\protected\def\getemptyparameters[#1]#*[#2]%
%   {\def\syst_helpers_get_empty_parameters##1{\doassignempty[#1][##1]}%
%    \processcommalist[#2]\syst_helpers_get_empty_parameters}

\let\syst_helpers_copy_parameter\relax

\permanent\protected\def\getemptyparameters[#1]#*[#2]%
  {\def\syst_helpers_copy_parameter##1{\letcsname#1##1\endcsname\empty}%
   \processcommalist[#2]\syst_helpers_get_empty_parameters}

%D We now just alias these as there is no need for a speedup. These have not been used
%D for a long time in core code.

\aliased\let\doassign  \getparameters    % obsolete, these will go
\aliased\let\doeassign \geteparameters   % obsolete, these will go
\aliased\let\undoassign\forgetparameters % obsolete, these will go

%D \macros
%D   {processassignmentlist,processassignmentcommand,
%D    startprocessassignmentlist,startprocessassignmentcommand}
%D
%D For Wolfgang:
%D
%D \starttyping
%D \def\showpair#1#2{key:#1, value:#2\par}
%D \processassignmentlist[a=1,b=2]\showpair
%D \stoptyping
%D
%D We can optimize this one if needed but it's not a core macro so hardly worth the
%D trouble and tokens.

\mutable\let\currentassignmentlistcommand\gobbletwoarguments

\mutable\lettonothing\currentassignmentlistkey
\mutable\lettonothing\currentassignmentlistvalue

\let\syst_helpers_process_assign_entry\gobbleoneargument

% \permanent\protected\def\processassignmentlist[#1]#2% #2 == \command{key}{value]
%   {\def\syst_helpers_process_assign_entry##1{#2}% {##2}{##3} % namespace is ignored
%    \dogetparameters\syst_helpers_process_assign_entry[][#1]}

\tolerant\def\syst_helpers_process_assign_value#*#1=#S#2,#M,%
  {\ifarguments
     \expandafter\gobbleoneargument
   \or
     \mult_interfaces_get_parameters_error_indeed\empty{#1}%
   \else
     \syst_helpers_process_assign_entry{#1}{#2}%
   \fi
   \syst_helpers_process_assign_value}

\permanent\protected\def\processassignmentlist[#S#1]#2% #2 == \command{key}{value]
  {\def\syst_helpers_process_assign_entry{#2}%
   \syst_helpers_process_assign_value#1\ignorearguments\ignorearguments}

\permanent\protected\def\processassignmentcommand[#1]%
  {\expanded{\processassignmentlist[#1]}}

\permanent\protected\def\startprocessassignmentlist[#1]#2\stopprocessassignmentlist
  {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}%
   \processassignmentlist[#1]\currentassignmentlistcommand}

\permanent\protected\lettonothing\stopprocessassignmentlist

\permanent\protected\def\startprocessassignmentcommand[#1]#2\stopprocessassignmentcommand
  {\def\currentassignmentlistcommand##1##2{\def\currentassignmentlistkey{##1}\def\currentassignmentlistvalue{##2}#2}%
   \expanded{\processassignmentlist[#1]}\currentassignmentlistcommand}

\permanent\protected\lettonothing\stopprocessassignmentcommand

%D \macros
%D   {currentvalue}
%D
%D Just in case a \type{\getparameter} argument itself ends up inside a \type
%D {\write} or other expandable location, our new macro needs a default value.
%D
%D \starttyping
%D \getparameters[xxx][aaa=bbb]\par
%D \getparameters[xxx][=bbb]\par
%D \getparameters[xxx][aaa=]\par
%D \getparameters[xxx][=]\par
%D \getparameters[xxx][aaa]\par
%D \stoptyping

%D \macros
%D   {copyparameters}
%D
%D Some \CONTEXT\ commands take their default setups from others. All commands that
%D are able to provide backgounds or rules around some content, for instance default
%D to the standard command for ruled boxes. Is situations like this 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 for use in a
%D multi||lingual environment.

% \let\syst_helpers_copy_parameter\relax
%
% \permanent\protected\def\copyparameters[#1]#*[#2]#*[#3]%
%   {\iftok{#1}{#2}\else
%      \def\syst_helpers_copy_parameter{\docopyvalue{#1}{#2}}% ##1
%      \processcommalist[#3]\syst_helpers_copy_parameter
%    \fi}

\let\syst_helpers_copy_parameter\relax

\permanent\protected\def\copyparameters[#1]#*[#2]#*[#3]%
  {\iftok{#1}{#2}\else
     \def\syst_helpers_copy_parameter##1{\defcsname#1##1\endcsname{\begincsname#2##1\endcsname}}%
     \processcommalist[#3]\syst_helpers_copy_parameter
   \fi}

% %D \macros
% %D   {ifparameters,checkparameters}
% %D
% %D A slightly different one is \type {\checkparameters}, which also checks on the
% %D presence of a~\type {=}.
% %D
% %D The boolean \type {\ifparameters} can be used afterwards. Combining both in one
% %D \type {\if}||macro would lead to problems with nested \type {\if}'s.
% %D
% %D \starttyping
% %D \checkparameters[argument]
% %D \stoptyping

% \newif\ifparameters

% \protected\def\checkparameters[#1]%
%   {\ifhastok={#1}\parameterstrue\else\parametersfalse\fi}

%D \macros
%D   {getfromcommalist,getfromcommacommand,
%D    commalistelement,
%D    getcommalistsize,getcommacommandsize}
%D
%D It's possible to get an element from a commalist or a command representing
%D 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 difference between
%D \type {\processcomma...}. The found string is stored in \type
%D {\commalistelement}.
%D
%D We can calculate the size of a comma separated list by 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 \type {\commalistsize}
%D (not a \COUNTER).

\newinteger\commalistcounter

\mutable\def\commalistsize{0}

\def\syst_helpers_get_comma_list_size#0,% no #- as we need to count
  {\ifarguments\or
     \advanceby\commalistcounter\plusone
     \expandafter\syst_helpers_get_comma_list_size
   \fi}

\permanent\protected\def\getcommalistsize[%
  {\futureexpand]\syst_helpers_get_comma_list_size_nop\syst_helpers_get_comma_list_size_yes}

\def\syst_helpers_get_comma_list_size_yes#+]%
  {\commalistcounter\zerocount
   \syst_helpers_get_comma_list_size #1,\ignorearguments\ignorearguments
   \edef\commalistsize{\the\commalistcounter}}

\def\syst_helpers_get_comma_list_size_nop]%
  {\commalistcounter\zerocount
   \let\commalistsize\!!zerocount}

\permanent\protected\def\getcommacommandsize[#1]%
  {\expanded{\getcommalistsize[#1]}}

\permanent\def\getcommalistcount[#1]%
  {\beginlocalcontrol
   \getcommalistsize[#1]%
   \endlocalcontrol
   \the\commalistcounter}

\permanent\def\getcommacommandcount[#1]%
  {\beginlocalcontrol
   \getcommacommandsize[#1]%
   \endlocalcontrol
   \the\commalistcounter}

%D Filters:

% \def\syst_helpers_gobble_comma_list#0\ignorearguments{}

\def\syst_helpers_gobble_comma_list#-\ignorearguments{}

\def\syst_helpers_get_from_comma_list#1,%
  {\ifarguments \or
     \advanceby\commalistcounter \minusone
     \ifcase\commalistcounter
       \def\commalistelement{#1}%
       \expandafter\expandafter\expandafter\syst_helpers_gobble_comma_list
     \else
       \expandafter\expandafter\expandafter\syst_helpers_get_from_comma_list_next
     \fi
   \fi}

\def\syst_helpers_get_from_comma_list_next
  {\expandafterspaces\syst_helpers_get_from_comma_list}

\permanent\protected\def\getfromcommalist[#1]#*[#2]%
  {\lettonothing\commalistelement
   \commalistcounter#2\relax
   \expandafterspaces\syst_helpers_get_from_comma_list#1\ignorearguments\ignorearguments}

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

%D Watertight (and efficient) solutions are hard to find, due to the handling of
%D braces during parameters passing and 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 alternative, which can
%D handle 9~elements at most.
%D
%D \starttyping
%D \dogetcommalistelement1\from a,b,c\to\commalistelement
%D \stoptyping

\def\syst_helpers_get_comma_list_element#1,#2,#3,#4,#5,#6,#7,#8,#9,%
  {\ifcase\scratchcounter\or#1\or#2\or#3\or#4\or#5\or#6\or#7\or#8\or#9\fi
   \syst_helpers_gobble_comma_list}

\permanent\protected\def\dogetcommacommandelement#1\from#2\to#3%
  {\scratchcounter#1\relax
   \edef#3{\expanded{\syst_helpers_get_comma_list_element#2\ignorearguments\ignorearguments}}}

%D \macros
%D   {dosingleargument,dodoubleargument,dotripleargument,
%D    doquadrupleargument,doquintupleargument,dosixtupleargument,
%D    doseventupleargument}
%D
%D When working with delimited arguments, spaces and lineendings can interfere. The
%D next set of macros uses \TEX' internal scanner for grabbing everything between
%D arguments. Forgive me the funny names.
%D
%D \starttyping
%D \dosingleargument    \command = \command[#1]
%D \dodoubleargument    \command = \command[#1][#2]
%D \dotripleargument    \command = \command[#1][#2][#3]
%D \doquadrupleargument \command = \command[#1][#2][#3][#4]
%D \doquintupleargument \command = \command[#1][#2][#3][#4][#5]
%D \dosixtupleargument  \command = \command[#1][#2][#3][#4][#5][#6]
%D \doseventupleargument\command = \command[#1][#2][#3][#4][#5][#6][#7]
%D \stoptyping
%D
%D These macros can be used in the following way:
%D
%D \starttyping
%D \def\dosetupsomething[#1][#2]%
%D   {... #1 ... #2 ...}
%D
%D \protected\def\setupsomething
%D   {\dodoubleargument\dosetupsomething}
%D \stoptyping
%D
%D The implementation can be surprisingly simple and needs no further explanation,
%D 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 two||step solution when
%D getting five or more arguments.
%D
%D When developing more and more of the real \CONTEXT, we started using some
%D alternatives that provided empty arguments (in fact optional ones) whenever the
%D user failed to supply them. Because this more complicated macros enable us to do
%D some checking, we reimplemented the non||empty ones.

%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 wanted arguments are
%D indeed supplied by the user.

\newinteger\nofarguments

\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 like:
%D
%D \starttyping
%D \dosingleempty    \command
%D \dodoubleempty    \command
%D \dotripleempty    \command
%D \doquadrupleempty \command
%D \doquintupleempty \command
%D \dosixtuple_empty  \command
%D \doseventupleempty\command
%D \stoptyping
%D
%D So \type{\dodoubleempty} leads 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 use the \type
%D {\if...argument} boolean. For novice: watch the stepwise doubling of \type {#}'s.

%D NB : experimental versions in cont-exp.mkiv

%D Common:

\newtoks\t_syst_aux

% \def\syst_helpers_single_empty_one_yes      {\firstargumenttrue  \the\t_syst_aux}
% \def\syst_helpers_double_empty_two_yes      {\secondargumenttrue \the\t_syst_aux}
% \def\syst_helpers_triple_empty_three_yes    {\thirdargumenttrue  \the\t_syst_aux}
% \def\syst_helpers_quadruple_empty_four_yes  {\fourthargumenttrue \the\t_syst_aux}
% \def\syst_helpers_quintuple_empty_five_yes  {\fifthargumenttrue  \the\t_syst_aux}
% \def\syst_helpers_sixtuple_empty_six_yes    {\sixthargumenttrue  \the\t_syst_aux}
% \def\syst_helpers_seventuple_empty_seven_yes{\seventhargumenttrue\the\t_syst_aux}
%
% %D Single:
%
% \protected\def\dosingleempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand[\syst_helpers_single_empty_one_yes\syst_helpers_single_empty_one_nop}
%
% \def\syst_helpers_single_empty_one_nop
%   {\firstargumentfalse
%    \the\t_syst_aux[]}
%
% %D Double
%
% \protected\def\dodoubleempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand[\syst_helpers_double_empty_one_yes\syst_helpers_double_empty_one_nop}
%
% % \def\syst_helpers_double_empty_one_yes[#1]%
% %   {\firstargumenttrue
% %    \toksapp\t_syst_aux{[{#1}]}%
% %    \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop}
% %
% % nicer is:
%
% \def\syst_helpers_double_empty_one_yes[#+]%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_double_empty_two_yes\syst_helpers_double_empty_two_nop}
%
% \def\syst_helpers_double_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \the\t_syst_aux[][]}
%
% \def\syst_helpers_double_empty_two_nop
%   {\secondargumentfalse
%    \the\t_syst_aux[]}
%
% % Triple
%
% \protected\def\dotripleempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand[\syst_helpers_triple_empty_one_yes\syst_helpers_triple_empty_one_nop}
%
% \def\syst_helpers_triple_empty_one_yes[#+]%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_triple_empty_two_yes\syst_helpers_triple_empty_two_nop}
%
% \def\syst_helpers_triple_empty_two_yes[#+]%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_triple_empty_three_yes\syst_helpers_triple_empty_three_nop}
%
% \def\syst_helpers_triple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \the\t_syst_aux[][][]}
%
% \def\syst_helpers_triple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \the\t_syst_aux[][]}
%
% \def\syst_helpers_triple_empty_three_nop
%   {\thirdargumentfalse
%    \the\t_syst_aux[]}
%
% %D Quadruple:
%
% \protected\def\doquadrupleempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand[\syst_helpers_quadruple_empty_one_yes\syst_helpers_quadruple_empty_one_nop}
%
% \def\syst_helpers_quadruple_empty_one_yes[#+]%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_quadruple_empty_two_yes\syst_helpers_quadruple_empty_two_nop}
%
% \def\syst_helpers_quadruple_empty_two_yes[#+]%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_quadruple_empty_three_yes\syst_helpers_quadruple_empty_three_nop}
%
% \def\syst_helpers_quadruple_empty_three_yes[#+]%
%   {\thirdargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_quadruple_empty_four_yes\syst_helpers_quadruple_empty_four_nop}
%
% \def\syst_helpers_quadruple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \the\t_syst_aux[][][][]}
%
% \def\syst_helpers_quadruple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \the\t_syst_aux[][][]}
%
% \def\syst_helpers_quadruple_empty_three_nop
%   {\thirdargumentfalse
%    \fourthargumentfalse
%    \the\t_syst_aux[][]}
%
% \def\syst_helpers_quadruple_empty_four_nop
%   {\fourthargumentfalse
%    \the\t_syst_aux[]}
%
% %D Quintuple:
%
% \protected\def\doquintupleempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand[\syst_helpers_quintuple_empty_one_yes\syst_helpers_quintuple_empty_one_nop}
%
% \def\syst_helpers_quintuple_empty_one_yes[#+]%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_quintuple_empty_two_yes\syst_helpers_quintuple_empty_two_nop}
%
% \def\syst_helpers_quintuple_empty_two_yes[#+]%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_quintuple_empty_three_yes\syst_helpers_quintuple_empty_three_nop}
%
% \def\syst_helpers_quintuple_empty_three_yes[#+]%
%   {\thirdargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_quintuple_empty_four_yes\syst_helpers_quintuple_empty_four_nop}
%
% \def\syst_helpers_quintuple_empty_four_yes[#+]%
%   {\fourthargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_quintuple_empty_five_yes\syst_helpers_quintuple_empty_five_nop}
%
% \def\syst_helpers_quintuple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux[][][][][]}
%
% \def\syst_helpers_quintuple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux[][][][]}
%
% \def\syst_helpers_quintuple_empty_three_nop
%   {\thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux[][][]}
%
% \def\syst_helpers_quintuple_empty_four_nop
%   {\fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux[][]}
%
% \def\syst_helpers_quintuple_empty_five_nop
%   {\fifthargumentfalse
%    \the\t_syst_aux[]}
%
% %D Sixtuple:
%
% \protected\def\dosixtupleempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand[\syst_helpers_sixtuple_empty_one_yes\syst_helpers_sixtuple_empty_one_nop}
%
% \def\syst_helpers_sixtuple_empty_one_yes[#+]%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_sixtuple_empty_two_yes\syst_helpers_sixtuple_empty_two_nop}
%
% \def\syst_helpers_sixtuple_empty_two_yes[#+]%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_sixtuple_empty_three_yes\syst_helpers_sixtuple_empty_three_nop}
%
% \def\syst_helpers_sixtuple_empty_three_yes[#+]%
%   {\thirdargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_sixtuple_empty_four_yes\syst_helpers_sixtuple_empty_four_nop}
%
% \def\syst_helpers_sixtuple_empty_four_yes[#+]%
%   {\fourthargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_sixtuple_empty_five_yes\syst_helpers_sixtuple_empty_five_nop}
%
% \def\syst_helpers_sixtuple_empty_five_yes[#+]%
%   {\fifthargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_sixtuple_empty_six_yes\syst_helpers_sixtuple_empty_six_nop}
%
% \def\syst_helpers_sixtuple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \the\t_syst_aux[][][][][][]}
%
% \def\syst_helpers_sixtuple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \the\t_syst_aux[][][][][]}
%
% \def\syst_helpers_sixtuple_empty_three_nop
%   {\thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \the\t_syst_aux[][][][]}
%
% \def\syst_helpers_sixtuple_empty_four_nop
%   {\fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \the\t_syst_aux[][][]}
%
% \def\syst_helpers_sixtuple_empty_five_nop
%   {\fifthargumentfalse
%    \sixthargumentfalse
%    \the\t_syst_aux[][]}
%
% \def\syst_helpers_sixtuple_empty_six_nop
%   {\sixthargumentfalse
%    \the\t_syst_aux[]}
%
% %D Seventuple:
%
% \protected\def\doseventupleempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand[\syst_helpers_seventuple_empty_one_yes\syst_helpers_seventuple_empty_one_nop}
%
% \def\syst_helpers_seventuple_empty_one_yes[#+]%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_seventuple_empty_two_yes\syst_helpers_seventuple_empty_two_nop}
%
% \def\syst_helpers_seventuple_empty_two_yes[#+]%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_seventuple_empty_three_yes\syst_helpers_seventuple_empty_three_nop}
%
% \def\syst_helpers_seventuple_empty_three_yes[#+]%
%   {\thirdargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_seventuple_empty_four_yes\syst_helpers_seventuple_empty_four_nop}
%
% \def\syst_helpers_seventuple_empty_four_yes[#+]%
%   {\fourthargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_seventuple_empty_five_yes\syst_helpers_seventuple_empty_five_nop}
%
% \def\syst_helpers_seventuple_empty_five_yes[#+]%
%   {\fifthargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_seventuple_empty_six_yes\syst_helpers_seventuple_empty_six_nop}
%
% \def\syst_helpers_seventuple_empty_six_yes[#+]%
%   {\sixthargumenttrue
%    \toksapp\t_syst_aux{[#1]}%
%    \futureexpand[\syst_helpers_seventuple_empty_seven_yes\syst_helpers_seventuple_empty_seven_nop}
%
% \def\syst_helpers_seventuple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \seventhargumentfalse
%    \the\t_syst_aux[][][][][][][]}
%
% \def\syst_helpers_seventuple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \seventhargumentfalse
%    \the\t_syst_aux[][][][][][]}
%
% \def\syst_helpers_seventuple_empty_three_nop
%   {\thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \seventhargumentfalse
%    \the\t_syst_aux[][][][][]}
%
% \def\syst_helpers_seventuple_empty_four_nop
%   {\fourthargumentfalse
%    \fifthargumentfalse
%    \sixthargumentfalse
%    \seventhargumentfalse
%    \the\t_syst_aux[][][][]}
%
% \def\syst_helpers_seventuple_empty_five_nop
%   {\fifthargumentfalse
%    \sixthargumentfalse
%    \seventhargumentfalse
%    \the\t_syst_aux[][][]}
%
% \def\syst_helpers_seventuple_empty_six_nop
%   {\sixthargumentfalse
%    \seventhargumentfalse
%    \the\t_syst_aux[][]}
%
% \def\syst_helpers_seventuple_empty_seven_nop
%   {\seventhargumentfalse
%    \the\t_syst_aux[]}

\tolerant\def\syst_single_empty#1\relax[#S#2]%
  {\ifarguments
   \or\firstargumentfalse
   \or\firstargumenttrue
   \fi
   #1[#2]}

\tolerant\def\syst_double_empty#1\relax[#S#+]#*[#S#+]%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse
   \or\firstargumenttrue \secondargumentfalse
   \or\firstargumenttrue \secondargumenttrue
   \fi
   #1[#2][#3]}

\tolerant\def\syst_triple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue
   \fi
   #1[#2][#3][#4]}

\tolerant\def\syst_quadruple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue
   \fi
   #1[#2][#3][#4][#5]}

\tolerant\def\syst_quintuple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue
   \fi
   #1[#2][#3][#4][#5][#6]}

\tolerant\def\syst_sixtuple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse\sixthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse\sixthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumenttrue
   \fi
   #1[#2][#3][#4][#5][#6][#7]}

\tolerant\def\syst_seventuple_empty#1\relax[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]#*[#S#+]%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse\sixthargumentfalse\seventhargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumentfalse\seventhargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumenttrue \seventhargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue \sixthargumenttrue \seventhargumenttrue
   \fi
   #1[#2][#3][#4][#5][#6][#7][#8]}

\permanent\protected\def\dosingleempty    #1{\syst_single_empty    #1\relax}
\permanent\protected\def\dodoubleempty    #1{\syst_double_empty    #1\relax}
\permanent\protected\def\dotripleempty    #1{\syst_triple_empty    #1\relax}
\permanent\protected\def\doquadrupleempty #1{\syst_quadruple_empty #1\relax}
\permanent\protected\def\doquintupleempty #1{\syst_quintuple_empty #1\relax}
\permanent\protected\def\dosixtupleempty  #1{\syst_sixtuple_empty  #1\relax}
\permanent\protected\def\doseventupleempty#1{\syst_seventuple_empty#1\relax}

%D Aliases:

\aliased\let\dosingleargument    \dosingleempty
\aliased\let\dodoubleargument    \dodoubleempty
\aliased\let\dotripleargument    \dotripleempty
\aliased\let\doquadrupleargument \doquadrupleempty
\aliased\let\doquintupleargument \doquintupleempty
\aliased\let\dosixtupleargument  \dosixtupleempty
\aliased\let\doseventupleargument\doseventupleempty

%D \macros
%D   {strippedcsname}
%D
%D The next macro can be very useful when using \type{\csname} like in:
%D
%D \starttyping
%D \csname if\strippedcsname\something\endcsname
%D \stoptyping
%D
%D This expands to \type{\ifsomething}.

\aliased\let\strippedcsname\csstring

%D \macros
%D   {complexorsimple,complexorsimpleempty}
%D
%D Setups can be optional. A command expecting a setup is prefixed by \type
%D {\complex}, a command without one gets the prefix \type {\simple}. Commands like
%D 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 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, but changed into more
%D versatile (more object oriented) ones using the \type {\get..argument} commands.

\permanent\protected\def\complexorsimple#1%
  {\doifelsenextoptional
     {\firstargumenttrue \csname\s!complex\csstring#1\endcsname}
     {\firstargumentfalse\csname\s!simple \csstring#1\endcsname}}

\permanent\protected\def\complexorsimpleempty#1%
  {\doifelsenextoptional
     {\firstargumenttrue \csname\s!complex\csstring#1\endcsname}
     {\firstargumentfalse\csname\s!complex\csstring#1\endcsname[]}}

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

\protected\def\syst_helpers_complex_or_simple#1#2%
  {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#2}}

\protected\def\syst_helpers_complex_or_simple_empty#1%
  {\doifelsenextoptional{\firstargumenttrue#1}{\firstargumentfalse#1[]}}

\permanent\protected\def\definecomplexorsimple#1%
  {\protected\edef#1{\syst_helpers_complex_or_simple
     \expandafter\noexpand\csname\s!complex\csstring#1\endcsname
     \expandafter\noexpand\csname\s!simple \csstring#1\endcsname}}

\permanent\protected\def\definecomplexorsimpleempty#1%
  {\protected\edef#1{\syst_helpers_complex_or_simple_empty
     \expandafter\noexpand\csname\s!complex\csstring#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   {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 We can add additional definitions later when we have defined \type {\appendtoks}.

\newconditional\c_syst_helpers_permit_spaces_between_groups

\permanent\protected\def    \permitspacesbetweengroups{\c_syst_helpers_permit_spaces_between_groups\conditionaltrue}
\permanent\protected\def\dontpermitspacesbetweengroups{\c_syst_helpers_permit_spaces_between_groups\conditionalfalse}

\dontpermitspacesbetweengroups

%D We can avoid the nasty if handling in \type {syst-gen} by splitting the lot in
%D pieces so that we have no nested \type {\nextarguments} potentially being an
%D \type {conditional} token. Okay, these macros are not called that often but it
%D saves crap when tracing.

% \protected\def\dosinglegroupempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_single_empty_one_yes\syst_helpers_single_group_empty_one_nop}
%
% \def\syst_helpers_single_group_empty_one_nop
%   {\firstargumentfalse
%    \the\t_syst_aux{}}
%
% \protected\def\dodoublegroupempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_double_empty_one_yes\syst_helpers_group_double_empty_one_nop}
%
% % \def\syst_helpers_group_double_empty_one_yes#1%
% %   {\firstargumenttrue
% %    \toksapp\t_syst_aux{{#1}}%
% %    \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop}
% %
% % nicer is:
%
% \def\syst_helpers_group_double_empty_one_yes#+%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_double_empty_two_yes\syst_helpers_group_double_empty_two_nop}
%
% \def\syst_helpers_group_double_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \the\t_syst_aux{}{}}
%
% \def\syst_helpers_group_double_empty_two_nop
%   {\secondargumentfalse
%    \the\t_syst_aux{}}
%
% \protected\def\dotriplegroupempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_triple_empty_one_yes\syst_helpers_group_triple_empty_one_nop}
%
% \def\syst_helpers_group_triple_empty_one_yes#+%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_triple_empty_two_yes\syst_helpers_group_triple_empty_two_nop}
%
% \def\syst_helpers_group_triple_empty_two_yes#+%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_triple_empty_three_yes\syst_helpers_group_triple_empty_three_nop}
%
% \def\syst_helpers_group_triple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \the\t_syst_aux{}{}{}}
%
% \def\syst_helpers_group_triple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \the\t_syst_aux{}{}}
%
% \def\syst_helpers_group_triple_empty_three_nop
%   {\thirdargumentfalse
%    \the\t_syst_aux{}}
%
% \protected\def\doquadruplegroupempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_quadruple_empty_one_yes\syst_helpers_group_quadruple_empty_one_nop}
%
% \def\syst_helpers_group_quadruple_empty_one_yes#+%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_quadruple_empty_two_yes\syst_helpers_group_quadruple_empty_two_nop}
%
% \def\syst_helpers_group_quadruple_empty_two_yes#+%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_quadruple_empty_three_yes\syst_helpers_group_quadruple_empty_three_nop}
%
% \def\syst_helpers_group_quadruple_empty_three_yes#+%
%   {\thirdargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_quadruple_empty_four_yes\syst_helpers_group_quadruple_empty_four_nop}
%
% \def\syst_helpers_group_quadruple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \the\t_syst_aux{}{}{}{}}
%
% \def\syst_helpers_group_quadruple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \the\t_syst_aux{}{}{}}
%
% \def\syst_helpers_group_quadruple_empty_three_nop
%   {\thirdargumentfalse
%    \fourthargumentfalse
%    \the\t_syst_aux{}{}}
%
% \def\syst_helpers_group_quadruple_empty_four_nop
%   {\fourthargumentfalse
%    \the\t_syst_aux{}}
%
% \protected\def\doquintuplegroupempty#1%
%   {\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_one_yes\syst_helpers_group_quintuple_empty_one_nop}
%
% \def\syst_helpers_group_quintuple_empty_one_yes#+%
%   {\firstargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_two_yes\syst_helpers_group_quintuple_empty_two_nop}
%
% \def\syst_helpers_group_quintuple_empty_two_yes#+%
%   {\secondargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_three_yes\syst_helpers_group_quintuple_empty_three_nop}
%
% \def\syst_helpers_group_quintuple_empty_three_yes#+%
%   {\thirdargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_group_quintuple_empty_four_yes\syst_helpers_group_quintuple_empty_four_nop}
%
% \def\syst_helpers_group_quintuple_empty_four_yes#+%
%   {\fourthargumenttrue
%    \toksapp\t_syst_aux{#1}%
%    \futureexpand\bgroup\syst_helpers_quintuple_empty_five_yes\syst_helpers_group_quintuple_empty_five_nop}
%
% \def\syst_helpers_group_quintuple_empty_one_nop
%   {\firstargumentfalse
%    \secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux{}{}{}{}{}}
%
% \def\syst_helpers_group_quintuple_empty_two_nop
%   {\secondargumentfalse
%    \thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux{}{}{}{}}
%
% \def\syst_helpers_group_quintuple_empty_three_nop
%   {\thirdargumentfalse
%    \fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux{}{}{}}
%
% \def\syst_helpers_group_quintuple_empty_four_nop
%   {\fourthargumentfalse
%    \fifthargumentfalse
%    \the\t_syst_aux{}{}}
%
% \def\syst_helpers_group_quintuple_empty_five_nop
%   {\fifthargumentfalse
%    \the\t_syst_aux{}}

\tolerant\def\syst_single_group_empty#1\relax#_%
  {\ifarguments
   \or\firstargumentfalse
   \or\firstargumenttrue
   \fi
   #1#2}

\tolerant\def\syst_double_group_empty#1\relax#_#*#_%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse
   \or\firstargumenttrue \secondargumentfalse
   \or\firstargumenttrue \secondargumenttrue
   \fi
   #1#2#3}

\tolerant\def\syst_triple_group_empty#1\relax#_#*#_#*#_%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue
   \fi
   #1#2#3#4}

\tolerant\def\syst_quadruple_group_empty#1\relax#_#*#_#*#_#*#_%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue
   \fi
   #1#2#3#4#5}

\tolerant\def\syst_quintuple_group_empty#1\relax#_#*#_#*#_#*#_#*#_%
  {\ifarguments
   \or\firstargumentfalse\secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumentfalse\thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumentfalse\fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumentfalse\fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumentfalse
   \or\firstargumenttrue \secondargumenttrue \thirdargumenttrue \fourthargumenttrue \fifthargumenttrue
   \fi
   #1#2#3#4#5#6}

\permanent\protected\def\dosinglegroupempty    #1{\syst_single_group_empty    #1\relax}
\permanent\protected\def\dodoublegroupempty    #1{\syst_double_group_empty    #1\relax}
\permanent\protected\def\dotriplegroupempty    #1{\syst_triple_group_empty    #1\relax}
\permanent\protected\def\doquadruplegroupempty #1{\syst_quadruple_group_empty #1\relax}
\permanent\protected\def\doquintuplegroupempty #1{\syst_quintuple_group_empty #1\relax}

%D These macros can explictly take care of spaces, which means that the next
%D 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 used to select
%D arguments. Their names explain their functionality.

\permanent\def\firstofoneargument            #1{#1}

\permanent\def\firstoftwoarguments         #1#-{#1}
\permanent\def\secondoftwoarguments        #-#1{#1}

\permanent\def\firstofthreearguments     #1#-#-{#1}
\permanent\def\secondofthreearguments    #-#1#-{#1}
\permanent\def\thirdofthreearguments     #-#-#1{#1}

\permanent\def\firstoffourarguments    #1#-#-#-{#1}
\permanent\def\secondoffourarguments   #-#1#-#-{#1}
\permanent\def\thirdoffourarguments    #-#-#1#-{#1}
\permanent\def\fourthoffourarguments   #-#-#-#1{#1}

\permanent\def\firstoffivearguments  #1#-#-#-#-{#1}
\permanent\def\secondoffivearguments #-#1#-#-#-{#1}
\permanent\def\thirdoffivearguments  #-#-#1#-#-{#1}
\permanent\def\fourthoffivearguments #-#-#-#1#-{#1}
\permanent\def\fifthoffivearguments  #-#-#-#-#1{#1}

\permanent\def\firstofsixarguments #1#-#-#-#-#-{#1}
\permanent\def\secondofsixarguments#-#1#-#-#-#-{#1}
\permanent\def\thirdofsixarguments #-#-#1#-#-#-{#1}
\permanent\def\fourthofsixarguments#-#-#-#1#-#-{#1}
\permanent\def\fifthofsixarguments #-#-#-#-#1#-{#1}
\permanent\def\sixthofsixarguments #-#-#-#-#-#1{#1}

\permanent\protected\def\firstofoneunexpanded       #1{#1}

\permanent\protected\def\firstoftwounexpanded     #1#-{#1}
\permanent\protected\def\secondoftwounexpanded    #-#1{#1}

\permanent\protected\def\firstofthreeunexpanded #1#-#-{#1}
\permanent\protected\def\secondofthreeunexpanded#-#1#-{#1}
\permanent\protected\def\thirdofthreeunexpanded #-#-#1{#1}

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

\permanent\protected\def\letempty      #1{\lettonothing #1}
\permanent\protected\def\globalletempty#1{\glettonothing#1}

\permanent\protected\def\letvalueempty #1{\letcsname #1\endcsname\empty}
\permanent\protected\def\letgvalueempty#1{\gletcsname#1\endcsname\empty}
\permanent\protected\def\letvaluerelax #1{\letcsname #1\endcsname\relax}
\permanent\protected\def\letgvaluerelax#1{\gletcsname#1\endcsname\relax}

\permanent\protected\def\relaxvalueifundefined#1%
  {\ifcsname#1\endcsname \else
     \aliased\letcsname#1\endcsname\relax
   \fi}

%D \macros
%D   {wait}
%D
%D The next macro hardly needs explanation. Because no nesting is to be expected, we
%D can reuse \type {\wait} within \type {\wait} itself.

\permanent\protected\def\wait
  {\begingroup
   \read16 to \wait
   \endgroup}

% %D \macros
% %D   {writestring,writeline,writestatus}
% %D
% %D Maybe one didn't notice, but we've already introduced a macro for showing
% %D messages. In the multi||lingual modules, we will also introduce a mechanism for
% %D message passing. For 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 of the identification
% %D string with the macro \type {\statuswidth}.
%
% \setnewconstant\statuswidth  15
% \setnewconstant\statuswrite 128 % \pluscxxviii
%
% \ifdefined\writestring \else
%
%     \protected\def\writestring{\immediate\write\statuswrite}
%     \protected\def\writeline  {\writestring{}}
%
% \fi
%
% \protected\def\normalwritestatus#1#2%
%   {\writestring{\expandafter\syst_helpers_split_status_yes\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\syst_helpers_split_status_yes#1#2%
%   {\ifcase#1 \expandafter\syst_helpers_split_status_nop\fi#2%
%    \expandafter\syst_helpers_split_status_yes\expandafter{\the\numexpr#1+\minusone\relax}}
%
% \def\syst_helpers_split_status_nop#1\end
%   {}

%D \macros
%D   {immediatemessage}
%D
%D A fully expandable message:

% \immediatemessage % {} mandate / defined at the lua end

%D \macros
%D   {rawgetparameters}
%D
%D A raw and dirty alternative for \type {\getparameters}; no checking is done!

\def\syst_helpers_grab_raw_parameter#1=#2,%
  {\ifarguments\or\or
     \defcsname\m_syst_parameter_n#1\endcsname{#2}%
     \expandafter\syst_helpers_grab_raw_parameter_next
   \fi}

\def\syst_helpers_grab_raw_parameter_next
  {\expandafterspaces\syst_helpers_grab_raw_parameter}

\permanent\protected\def\rawgetparameters#1[#2]#*[#3]%
  {\def\m_syst_parameter_n{#2}%
  %\expandafterspaces\syst_helpers_grab_raw_parameter#3\ignorearguments\ignorearguments}
   \expandafter\expandafterspaces\expandafter\syst_helpers_grab_raw_parameter#3\ignorearguments\ignorearguments}

%D \macros
%D   {doglobal,
%D    redoglobal,dodoglobal,resetglobal}
%D
%D The two macros \type {\redoglobal} and \type{\dodoglobal} are used in this and
%D some other modules to enforce a user specified \type {\doglobal} action. The last
%D and often only global assignment in a macro is done with \type {\dodoglobal}, but
%D all preceding ones with \type {\redoglobal}. When using only alternatives, one
%D can reset this mechanism with \type {\resetglobal}.

\permanent\protected\def\resetglobal
  {\enforced\let\redoglobal\relax
   \enforced\let\dodoglobal\relax}

\resetglobal

\permanent\protected\def\doglobal
  {\ifrelax\redoglobal
     \enforced\let\redoglobal\global
     \enforced\let\dodoglobal\syst_helpers_dodo_global
   \fi}

\def\syst_helpers_dodo_global
  {\resetglobal\global}

\let\syst_helpers_redo_global\relax

\permanent\protected\def\saveglobal
  {\let\syst_helpers_dodo_global\dodoglobal
   \let\syst_helpers_redo_global\redoglobal}

\permanent\protected\def\restoreglobal
  {\enforced\let\redoglobal\syst_helpers_redo_global
   \enforced\let\dodoglobal\syst_helpers_dodo_global}

% Maybe:
%
% \installmacrostack\globaldefs
%
% \protected\def\start_global
%   {\push_macro_globaldefs
%    \globaldefs\plusone}
%
% \protected\def\stop_global
%   {\pop_macro_globaldefs}

%D Whatever (will be overloaded):

\protected\def\define#1%
  {\ifdefined#1%
     \message{[\noexpand#1is already defined]}%
     \protected\expandafter\def\expandafter\gobbleddefinition
   \else
     \protected\expandafter\def
   \fi#1}

\protected\def\redefine#1%
  {\ifdefined#1%
     \message{[\noexpand#1is redefined]}%
   \fi
   \protected\def#1}

% \permanent\protected\def\definemacro#1%
%   {\ifdefined#1%
%      \message{[\noexpand#1is already defined]}%
%      \protected\expandafter\def\expandafter\gobbleddefinition
%    \else
%      \protected\expandafter\def
%    \fi#1}

% \define\hans{hans}
% \redefine\hans{hans}
% \define\hans#1[]#2#3{hans}

%D The next variant fits nicely in the setups syntax:
%D
%D \starttyping
%D \starttexdefinition bagger [#1] #2
%D     oeps
%D     #1
%D     oeps
%D \stoptexdefinition
%D
%D \bagger [a] {b}
%D \stoptyping

% \starttexdefinition test
% oeps
% \stoptexdefinition
%
% [\test]

%D When okay the parameter hack will also go into \MKIV.

\integerdef\c_syst_parameter_catcode\parametercatcode

% \catcode\endoflineasciicode\activecatcode\letcharcode\endoflineasciicode\par

\bgroup

\catcode\endoflineasciicode\activecatcode%
\letcharcode\endoflineasciicode\par%

\permanent\protected\gdef\starttexdefinition%
  {\integerdef\c_syst_parameter_catcode\catcode\hashasciicode%
   \catcode\hashasciicode\parametercatcode%
   \bgroup%
   \catcode\endoflineasciicode\activecatcode%
   \letcharcode\endoflineasciicode\par%
   \syst_helpers_start_tex_definition}

\gdef\syst_helpers_start_tex_definition#1
  {%catcodetable\ctxcatcodes% can be adapted
   \catcode\endoflineasciicode\ignorecatcode%
   \clf_texdefinition_one{#1}}

\permanent\protected\glettonothing\stoptexdefinition

\permanent\gdef\dostarttexdefinition#1\stoptexdefinition%
  {\egroup%
   \clf_texdefinition_two{#1}%
   \catcode\hashasciicode\c_syst_parameter_catcode}

\egroup

% \protected\def\texdefinition#1{\csname\ifcsname#1\endcsname#1\else donothing\fi\endcsname} % todo: a nop cs: char 0 or some corenamespace

\permanent\protected\def\texdefinition#1{\begincsname#1\endcsname}

%D \macros
%D   {newcounter,
%D    increment,decrement}
%D
%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited, but fortunately we
%D can store numbers in a macro. We can increment such pseudo \COUNTERS\ with \type
%D {\increment}.
%D
%D \starttyping
%D \increment(\counter,20)
%D \increment(\counter,-4)
%D \increment(\counter)
%D \increment\counter
%D \stoptyping
%D
%D After this sequence of commands, the value of \type {\counter} is 20, 16, 17
%D and~18. Of course there is also the complementary command \type {\decrement}.
%D
%D Global assignments are possible too, using \type{\doglobal}:
%D
%D \starttyping
%D \doglobal\increment\counter
%D \stoptyping
%D
%D When \type {\counter} is undefined, it's value is initialized at~0. It is
%D nevertheless better to define a \COUNTER\ explicitly. One reason could be that
%D the \COUNTER\ can be part of a test with \type {\ifnum} and this conditional does
%D not accept undefined macro's. The \COUNTER\ in our example can for instance be
%D defined with:
%D
%D \starttyping
%D \newcounter\counter
%D \stoptyping
%D
%D The command \type {\newcounter} must not be confused with \type {\newcount}! Of
%D course this mechanism is much slower than using \TEX's \COUNTERS\ directly. In
%D practice \COUNTERS\ (and therefore our pseudo counters too) are seldom the
%D bottleneck in the processing of a text. Apart from some other incompatilities we
%D want to mention a pitfal when using \type {\ifnum}.
%D
%D \starttyping
%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi
%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi
%D \stoptyping
%D
%D In the first test, \TEX\ continues it's search for the second number after
%D reading \type {\pseudocounter}, while in the second test, it stops reading after
%D having encountered a real one. Tests like the first one therefore can give
%D unexpected results, for instance execution of \type {\doif} even if both numbers
%D are unequal.

\permanent\cdef\zerocountervalue{0}

\permanent\protected\def\newcounter#1%
  {\dodoglobal\let#1\zerocountervalue}

%D Nowadays we don't mind a few more tokens if we can gain a bit of speed.

\def\syst_helpers_do_increment#1{\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi+\plusone }}}
\def\syst_helpers_do_decrement#1{\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi+\minusone}}}

\def\syst_helpers_do_do_do_increment#1,#2){\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi+#2}}}
\def\syst_helpers_do_do_do_decrement#1,#2){\dodoglobal\edef#1{\tointeger{\ifdefined#1\ifrelax#1\else#1\fi\fi-#2}}}

\def\syst_helpers_do_do_increment(#1%
  {\def\m_syst_action_yes{\syst_helpers_do_do_do_increment#1}%
   \def\m_syst_action_nop{\syst_helpers_do_do_do_increment#1,\plusone}%
   \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}

\def\syst_helpers_do_do_decrement(#1%
  {\def\m_syst_action_yes{\syst_helpers_do_do_do_decrement#1}%
   \def\m_syst_action_nop{\syst_helpers_do_do_do_decrement#1,\plusone}%
   \doifelsenextcharcs,\m_syst_action_yes\m_syst_action_nop}

\permanent\protected\def\increment{\doifelsenextcharcs(\syst_helpers_do_do_increment\syst_helpers_do_increment}
\permanent\protected\def\decrement{\doifelsenextcharcs(\syst_helpers_do_do_decrement\syst_helpers_do_decrement}

\permanent\protected\def\fastincrement#1{\dodoglobal\edef#1{\tointeger{#1+\plusone }}}
\permanent\protected\def\fastdecrement#1{\dodoglobal\edef#1{\tointeger{#1+\minusone}}}

\permanent\protected\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname}
\permanent\protected\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname}

%D \macros
%D  {newsignal}
%D
%D When writing advanced macros, we cannot do without signaling. A signal is a small
%D (invisible) kern or penalty that signals the next macro that something just
%D happened. This macro can take any action depending on the previous signal.
%D Signals must be unique and the next macro takes care of that.
%D
%D \starttyping
%D \newsignal\somesignal
%D \stoptyping
%D
%D Signals old dimensions and can be used in skips, kerns and tests like \type
%D {\ifdim}.

\newdimension\d_syst_maximum_signal % step is about 0.00025pt

\permanent\protected\def\newsignal#1%
  {\ifdefined#1\else
     \advanceby\d_syst_maximum_signal2\scaledpoint % to be save in rounding
     \permanent\dimensiondef#1\d_syst_maximum_signal
   \fi}

%D \macros
%D   {strippedcsname}
%D
%D The next macro can be very useful when using \type {\csname} like in:
%D
%D \starttyping
%D \csname if\strippedcsname\something\endcsname
%D \stoptyping

\aliased\let\checkedstrippedcsname\csstring

%D \macros
%D   {savenormalmeaning}
%D
%D We will use this one in:

\permanent\protected\def\savenormalmeaning#1%
  {\ifcsname normal\csstring#1\endcsname \else
     \aliased\letcsname normal\csstring#1\endcsname#1%
   \fi}

%D \macros
%D   {dorecurse,recurselevel,recursedepth,
%D    dostepwiserecurse}
%D
%D \TEX\ does not offer us powerfull for||loop mechanisms. On the other hand its
%D recursion engine is quite unique. We therefore identify the for||looping macros
%D by this method. The most simple alternative is the one that only needs a number.
%D
%D \starttyping
%D \dorecurse {n} {whatever we want}
%D \stoptyping
%D
%D This macro can be nested without problems and therefore be used in situations
%D where \PLAIN\ \TEX's \type {\loop} macro ungracefully fails. The current value of
%D the counter is available in \type {\recurselevel}, before as well as after the
%D \typ {whatever we wat} stuff.
%D
%D \starttyping
%D \dorecurse               % inner loop
%D   {10}
%D   {\recurselevel:          % outer value
%D      \dorecurse          % inner loop
%D        {\recurselevel}     % outer value
%D        {\recurselevel}     % inner value
%D      \dorecurse          % inner loop
%D        {\recurselevel}     % outer value
%D        {\recurselevel}     % inner value
%D    \endgraf}
%D \stoptyping
%D
%D In this example the first, second and fourth \type {\recurselevel} concern the
%D outer loop, while the third and fifth one concern the inner loop. The depth of
%D the nesting is available for inspection in \type {\recursedepth}.
%D
%D Both \type {\recurselevel} and \type {\recursedepth} are macros. The real
%D \COUNTERS\ are hidden from the user because we don't want any interference.
%D
%D We now use the macro stack which is somewhat leaner and meaner and a little
%D faster too.

\newinteger\outerrecurse
\newinteger\innerrecurse

% \mutable\def\recursedepth{\the\outerrecurse}
% \mutable\def\recurselevel{0}

\mutable\untraced\def\recursedepth{\the\outerrecurse}
\mutable\untraced\def\recurselevel{0}

\mutable\let\recurseaction\relax

\mutable\lettonothing\recursestring

%% \protected\def\syst_helpers_stepwise_recurse#1#2#3% from to step
%%   {\ifnum#1>#2\relax
%%      \expandafter\gobblefourarguments
%%    \else
%%      \def\recurselevel{#1}%
%%      \doubleexpandafter\syst_helpers_stepwise_recurse_yes
%%    \fi\expandafter{\the\numexpr\recurselevel+#3\relax}{#2}{#3}}
%%
%% \protected\def\syst_helpers_stepwise_recurse_yes
%%   {\syst_helpers_recurse_content
%%    \syst_helpers_stepwise_recurse}
%%
%% \protected\def\syst_helpers_stepwise_reverse#1#2#3% from to step
%%   {\ifnum#1<#2\relax
%%      \expandafter\gobblefourarguments
%%    \else
%%      \def\recurselevel{#1}%
%%      \innerrecurse#1\relax
%%      \advanceby\innerrecurse#3\relax
%%      \doubleexpandafter\syst_helpers_stepwise_reverse_yes
%%    \fi\expandafter{\the\numexpr\recurselevel+#3\relax}{#2}{#3}}
%%
%% \protected\def\syst_helpers_stepwise_reverse_yes
%%   {\syst_helpers_recurse_content
%%    \syst_helpers_stepwise_reverse}
%%
%% \permanent\def\doexpandedrecurse#1#2% user macro (also was \doxprecurse)
%%   {\ifnum#1>\zerocount
%%      #2\expandafter\doexpandedrecurse\expandafter{\the\numexpr#1-\plusone\relax}{#2}%
%%    \fi}

%D The next one might replace the above and provides the current step in \type {#1}
%D like \type {\dorecurse} do, but it comes with a tiny performance hit.

%% \installsystemnamespace{expandedrecurse}
%%
%% \mutable\let\m_expanded_recursed\gobbleoneargument
%%
%% \permanent\def\doexpandedrecursed#1#2% this might replace: \doexpandedrecurse
%%   {\beginlocalcontrol
%%    \localpushmacro\m_expanded_recursed
%%    \def\m_expanded_recursed##1{#2}%
%%    \endlocalcontrol
%%    \syst_do_expanded_recursed{1}{#1}{#2}% no \plusone !
%%    \beginlocalcontrol
%%    \localpopmacro\m_expanded_recursed
%%    \endlocalcontrol}
%%
%% \def\syst_do_expanded_recursed#1#2#3%
%%   {\ifnum#1>#2\norelax
%%      \expandafter\gobblethreearguments
%%    \else
%%      \m_expanded_recursed{#1}\doubleexpandafter\syst_do_expanded_recursed
%%    \fi
%%    {\the\numexpr#1+\plusone\relax}{#2}{#3}}

%D As we can see here, the simple command \type{\dorecurse} is a special case of the
%D more general:
%D
%D \starttyping
%D \dostepwiserecurse {from} {to} {step} {action}
%D \stoptyping
%D
%D This commands accepts positive and negative steps. Illegal values are handles as
%D good as possible and the macro accepts numbers and \COUNTERS.
%D
%D \starttyping
%D \dostepwiserecurse  {1} {10}  {2} {...}
%D \dostepwiserecurse {10}  {1} {-2} {...}
%D \stoptyping
%D
%D Because the simple case (n=1) is used often, we implement it more efficiently:

%% \permanent\protected\def\dorecurse#1%
%%   {\ifcase#1\relax
%%      \expandafter\gobbletwoarguments
%%    \or
%%      \expandafter\syst_helpers_recurse_y
%%    \else
%%      \expandafter\syst_helpers_recurse_x
%%    \fi{#1}}
%%
%% \protected\def\syst_helpers_recurse_indeed#1#2% from to
%% % {\ifnum#1>#2 %
%%   {\ifnum#1>#2\relax
%%      \expandafter\syst_helpers_recurse_indeed_nop
%%    \else
%%      \def\recurselevel{#1}%
%%      \innerrecurse#1\advanceby\innerrecurse\plusone
%%      \doubleexpandafter\syst_helpers_recurse_indeed_yes
%%    \fi\expandafter{\the\innerrecurse}{#2}}
%%
%% \protected\def\syst_helpers_recurse_indeed_yes
%%   {\syst_helpers_recurse_content
%%    \syst_helpers_recurse_indeed}
%%
%% \protected\def\syst_helpers_recurse_indeed_nop#0#0#0%
%%   {}

%D \macros
%D   {dowith}
%D
%D Here's a loop over whatever is in a list:
%D
%D \starttyping
%D \dowith{a,b,c}{[#1]}
%D \stoptyping

\let\syst_helpers_with\gobbleoneargument

\permanent\protected\def\dowith#1#2%
  {\def\syst_helpers_with##1{#2}%
   \expanded{\processcommalist[#1]}\syst_helpers_with}

%D \macros
%D   {doloop,exitloop}
%D
%D Sometimes loops are not determined by counters, but by (a combinations of)
%D conditions. We therefore implement a straightforward loop, which can only be left
%D when we explictly exit it. Nesting is supported. First we present a more
%D extensive alternative.
%D
%D \starttyping
%D \doloop
%D   {Some kind of typesetting punishment \par
%D    \ifnum\pageno>100 \exitloop \fi}
%D \stoptyping
%D
%D When needed, one can call for \type {\looplevel} and \type {\loopdepth}.

% \aliased\let\endofloop\donothing % maybe \syst_helpers_loop_end
%
% \permanent\protected\def\doloop#1%
%   {\global\advanceby\outerrecurse \plusone
%    \push_macro_recurseaction
%    \push_macro_recurselevel
%    \protected\gdef\recurseaction##1##2{#1}%
%    \enforced\let\endofloop\syst_helpers_loop
%    \syst_helpers_loop1}% no \plusone else \recurselevel wrong
%
% \protected\def\syst_helpers_loop#1%
%   {\def\recurselevel{#1}%
%    \expandafter\syst_helpers_loop_yes\expandafter{\the\numexpr\recurselevel+\plusone\relax}}
%
% %% \protected\def\syst_helpers_loop_yes
% %%   {\syst_helpers_recurse_content
% %%    \endofloop}
%
% \protected\def\syst_helpers_loop_yes
%   {\expanded{\recurseaction{\recurselevel}{\the\outerrecurse}}%
%    \endofloop}
%
% \protected\def\syst_helpers_loop_nop#-%
%   {\enforced\let\endofloop\syst_helpers_loop
%    \pop_macro_recurselevel
%    \pop_macro_recurseaction
%    \global\advanceby\outerrecurse\minusone}
%
% \permanent\protected\def\exitloop                % \exitloop quits at end
%   {\enforced\let\endofloop\syst_helpers_loop_nop}
%
% \permanent\protected\def\exitloopnow#-\endofloop % \exitloopnow quits directly
%   {\syst_helpers_loop_nop}

\permanent\protected\def\doloop#1%
  {\push_macro_recurseaction
   \push_macro_recurselevel
   \push_macro_recursedepth
   \protected\gdef\recurseaction##1##2{#1}%
   \untraced\edef\recurselevel{\noexpand\the\nestedloopiterator\the\currentloopnesting\space}%
   \untraced\edef\recursedepth{\tointeger{\currentloopnesting+\plusone}}%
   \localcontrolledendless
     {%\edef\recurselevel{\the\currentloopiterator}%
      %\edef\recursedepth{\the\currentloopnesting}%
      \expanded{\recurseaction{\the\currentloopiterator}{\the\currentloopnesting}}}%
   \pop_macro_recursedepth
   \pop_macro_recurselevel
   \pop_macro_recurseaction}

\aliased\let\exitloop   \quitloop
\aliased\let\exitloopnow\quitloopnow

%D The loop is executed at least once, so beware of situations like:
%D
%D \starttyping
%D \doloop {\exitloop some commands}
%D \stoptyping
%D
%D It's just a matter of putting the text into the \type {\if} statement that should
%D be there anyway, like in:
%D
%D \starttyping
%D \doloop {\ifwhatever \exitloop \else some commands\fi}
%D \stoptyping
%D
%D You can also quit a loop immediately, by using \type
%D {\exitloopnow} instead. Beware, this is more sensitive
%D for conditional errors.

%D Krzysztof Leszczynski suggested to provide access to the level by means of a
%D \type {#1}. I decided to pass the more frequently used level as \type {#1} and
%D the less favoured depth as \type {#2}. The intended usage is:
%D
%D \starttyping
%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]}
%D
%D \def\test{\dorecurse{3}{\definesymbol[test-##1][xx-##1]}} \test
%D
%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3]
%D \stoptyping
%D
%D Since the hashed arguments are expanded, we don't need tricky expansion here.
%D
%D \starttyping
%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}}
%D \stoptyping

%% \def\syst_helpers_recurse_content
%%   {\expanded{\recurseaction{\recurselevel}{\the\outerrecurse}}}
%%
%% \protected\def\syst_helpers_recurse_x#1#2%
%%   {\global\advanceby\outerrecurse\plusone
%%    \globalpushmacro\recurseaction
%%    \globalpushmacro\recurselevel
%%    \protected\gdef\recurseaction##1##2{#2}%
%%    \expandafter\syst_helpers_recurse_indeed\expandafter1\expandafter{\number#1}%
%%    \globalpopmacro\recurselevel
%%    \globalpopmacro\recurseaction
%%    \global\advanceby\outerrecurse\minusone}
%%
%% \protected\def\syst_helpers_recurse_y#1#2%
%%   {\global\advanceby\outerrecurse\plusone
%%    \globalpushmacro\recurseaction
%%    \globalpushmacro\recurselevel
%%    \let\recurselevel\!!plusone
%%    \protected\gdef\recurseaction##1##2{#2}%
%%    \syst_helpers_recurse_content
%%    \globalpopmacro\recurselevel
%%    \globalpopmacro\recurseaction
%%    \global\advanceby\outerrecurse\minusone}
%%
%% \permanent\protected\def\dostepwiserecurse#1#2#3#4% can be made faster by postponing #4 ... todo: remove unused helpers
%%   {\global\advanceby\outerrecurse \plusone
%%    \globalpushmacro\recurseaction
%%    \globalpushmacro\recurselevel
%%    \protected\gdef\recurseaction##1##2{#4}%
%%    \expanded{\ifcmpnum#3\zerocount
%%      \ifnum#1<#2\relax\relax % so we catch \the\numexpr xx without \relax's
%%        \doubleexpandafter\gobbletwoarguments
%%      \else
%%        \tripleexpandafter\syst_helpers_stepwise_reverse
%%      \fi
%%    \or
%%      \doubleexpandafter\gobbletwoarguments
%%    \orelse\ifnum#2<#1\relax\relax % so we catch \the\numexpr xx without \relax's
%%      \doubleexpandafter\gobbletwoarguments
%%    \else
%%      \doubleexpandafter\syst_helpers_stepwise_recurse
%%    \fi\expanded{{\number#1}{\number#2}{\number#3}}}%
%%    \globalpopmacro\recurselevel
%%    \globalpopmacro\recurseaction
%%    \global\advanceby\outerrecurse\minusone}

\newinteger\fastloopindex
\newinteger\fastloopfinal

\let\m_syst_helpers_fast_loop_cs\relax

\permanent\protected\def\dofastloopcs#1% kind of obsolete
  {\fastloopfinal{#1}%
   \ifcase\fastloopfinal
     \expandafter\gobbleoneargument
   \else
     \expandafter\syst_helpers_fast_loop_cs
   \fi}

\protected\def\syst_helpers_fast_loop_cs#1%
  {\let\m_syst_helpers_fast_loop_cs#1%
   \fastloopindex\plusone
   \syst_helpers_fast_loop_cs_step}

\protected\def\syst_helpers_fast_loop_cs_step
  {\ifnum\fastloopindex>\fastloopfinal
     \let\m_syst_helpers_fast_loop_cs\relax
   \else
     \m_syst_helpers_fast_loop_cs
     \advanceby\fastloopindex\plusone
     \expandafter\syst_helpers_fast_loop_cs_step
   \fi}

%D Here are the more modern implementations:

\permanent\protected\def\installmacrostack#1%
  {\ifdefined#1\else\mutable\lettonothing#1\fi
   \protected\gdefcsname push_macro_\csstring#1\endcsname{\localpushmacro#1}%
   \protected\gdefcsname  pop_macro_\csstring#1\endcsname{\localpopmacro #1}}

\permanent\protected\def\installglobalmacrostack#1%
  {\ifdefined#1\else\mutable\glettonothing#1\fi
   \protected\gdefcsname push_macro_\csstring#1\endcsname{\globalpushmacro#1}%
   \protected\gdefcsname  pop_macro_\csstring#1\endcsname{\globalpopmacro #1}}

\installglobalmacrostack \recurseaction
\installglobalmacrostack \recurselevel
\installglobalmacrostack \recursedepth
\installglobalmacrostack \recursestring

% \showmacrostack can be used to see if there are different entries

\permanent\protected\def\dostepwiserecurse#1#2#3#4%
  {\push_macro_recurseaction
   \push_macro_recurselevel
   \push_macro_recursedepth
   \protected\gdef\recurseaction##1##2{#4}%
%    \untraced\edef\recurselevel{\noexpand\the\nestedloopiterator\the\currentloopnesting\space}%
%    \untraced\edef\recursedepth{\the\numexpr\currentloopnesting+\plusone}%
%    \localcontrolledloop=#1=#2=#3%
\untraced\edef\recurselevel{\noexpand\tointeger\nestedloopiterator{\the\currentloopnesting}}%
\untraced\edef\recursedepth{\tointeger{\currentloopnesting+\plusone}}%
   \localcontrolledloop{#1}{#2}{#3}%
     {%\edef\recurselevel{\the\currentloopiterator}%
      %\edef\recursedepth{\the\currentloopnesting}%
      \expanded{\recurseaction{\the\currentloopiterator}{\the\currentloopnesting}}}%
   \pop_macro_recursedepth
   \pop_macro_recurselevel
   \pop_macro_recurseaction}

\permanent\protected\def\dorecurse#1#2%
  {\push_macro_recurseaction
   \push_macro_recurselevel
   \push_macro_recursedepth
   \protected\gdef\recurseaction##1##2{#2}%
%    \untraced\edef\recurselevel{\noexpand\the\nestedloopiterator\the\currentloopnesting\space}%
%    \untraced\edef\recursedepth{\the\numexpr\currentloopnesting+\plusone}%
%    \localcontrolledrepeat=#1%
   \untraced\edef\recurselevel{\noexpand\tointeger\nestedloopiterator{\the\currentloopnesting}}%
   \untraced\edef\recursedepth{\tointeger{\currentloopnesting+\plusone}}%
   \localcontrolledrepeat{#1}%
     {%\edef\recurselevel{\the\currentloopiterator}%
      %\edef\recursedepth{\the\currentloopnesting}%
      \expanded{\recurseaction{\the\currentloopiterator}{\the\currentloopnesting}}}%
   \pop_macro_recursedepth
   \pop_macro_recurselevel
   \pop_macro_recurseaction}

\permanent\def\doexpandedrecurse#1#2% user macro (also was \doxprecurse)
  {\expandedloop\plusone#1\plusone{#2}}

\mutable\let\m_expanded_recursed\gobbleoneargument

\installmacrostack\m_expanded_recursed

\permanent\def\doexpandedrecursed#1#2% this might replace: \doexpandedrecurse
  {\beginlocalcontrol
   \push_macro_m_expanded_recursed
   \def\m_expanded_recursed##1{#2}%
   \endlocalcontrol
   \expandedrepeat{#1}{\expandafter\m_expanded_recursed\expandafter{\the\currentloopiterator}}%
   \beginlocalcontrol
   \pop_macro_m_expanded_recursed
   \endlocalcontrol}

% Helper:

% \permanent\protected\def\resetrecurselevel{\let\recurselevel\!!zerocount}

\permanent\protected\def\resetrecurselevel{\untraced\let\recurselevel\!!zerocount}

% \appendtoks \resetrecurselevel \to \everydump

%D \macros
%D   {doloopoverlist}
%D
%D \starttyping
%D \doloopoverlist {red,green,blue} {
%D      \setuppalet[\recursestring]
%D      \doloopoverlist {light,normal,dark} {
%D          \blackrule[color=\recursestring,width=20cm,height=2cm,depth=0cm]\par
%D      }
%D  }
%D \stoptyping
%D
%D or:
%D
%D \starttyping
%D \doloopoverlist {red,green,blue} {
%D      \setuppalet[#1]
%D      \doloopoverlist {light,normal,dark} {
%D          \blackrule[color=##1,width=20cm,height=2cm,depth=0cm]\par
%D      }
%D  }
%D \stoptyping

\permanent\protected\def\doloopoverlist#1#2%
  {\global\advanceby\outerrecurse\plusone
%    \globalpushmacro\recurseaction
%    \globalpushmacro\recursestring
   \push_macro_recurseaction
   \push_macro_recursestring
   \protected\gdef\recurseaction##1{\edef\recursestring{##1}#2}%
   \processcommacommand[#1]\recurseaction
%    \globalpopmacro\recursestring
%    \globalpopmacro\recurseaction
   \pop_macro_recursestring
   \pop_macro_recurseaction
   \global\advanceby\outerrecurse\minusone}

%D This is some \LMTX\ experiment:
%D
%D Think of:
%D
%D \starttyping
%D \doloopovermatch {(\letterpercent w+) *(\letterpercent w*)} {aa bb cc dd} {
%D     [
%D     \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#1} {(##1 ##2)}
%D     \doloopovermatch{(\letterpercent w)(\letterpercent w)} {#2} {(##1 ##2)}
%D     ]
%D }
%D
%D and:
%D
%D \stoptyping
%D
%D \starttyping
%D \def\MyMacro#1{(#1)} \ctxluamatch \MyMacro {(.)} {abcd}
%D \stoptyping

\aliased\let\matchloopcommand\relax

\permanent\protected\def\doloopovermatch#1#2#3%
  {\pushmacro\matchloopcommand
   \enforced\def\matchloopcommand##1##2##3##4##5##6##7##8##9##A##B##C##D##E{#3}%
   \ctxluamatch\matchloopcommand{#1}{#2}%
   \popmacro\matchloopcommand}

\permanent\def\doloopovermatched#1#2#3%
  {\beginlocalcontrol
     \pushmacro\matchloopcommand
     \enforced\def\matchloopcommand##1##2##3##4##5##6##7##8##9##A##B##C##D##E{#3}%
   \endlocalcontrol
   \the\ctxluamatch\matchloopcommand{#1}{#2}%
   \beginlocalcontrol
     \popmacro\matchloopcommand
   \endlocalcontrol}

% \defineatluaend\ctxluamatch
% \defineatluaend\ctxluamatchfile

%D \starttyping
%D \ctxluamatch
%D     \Whatever
%D     {(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+)\letterpercent s*}
%D     {\cldloadfile{crap.txt}}
%D \ctxluamatchfile
%D     \Whatever
%D     {(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+) *(\letterpercent S+)\letterpercent s*}
%D     {crap.txt}
%D \stoptyping

%D \macros
%D   {newevery,everyline,EveryLine,EveryPar}
%D
%D Lets skip to something quite different. It's common use to use \type {\everypar}
%D for special purposes. In \CONTEXT\ we use this primitive for locating sidefloats.
%D This means that when user assignments to \type {\everypar} can interfere with
%D those of the package. We therefore introduce \type {\EveryPar}.
%D
%D The same goes for \type {\EveryLine}. Because \TEX\ offers no \type {\everyline}
%D primitive, we have to call for \type {\everyline} when we are working on a line
%D by line basis. Just by calling \type {\EveryPar{}} and \type {\EveryLine{}} we
%D restore the old situation.

% \dorecurse{2}{
%     \expanded{\everypar{before \recurselevel\space}}
%     \EveryPar{x } [before \recurselevel\space x] \par
%     \EveryPar{y } [before \recurselevel\space y] \par
%     \EveryPar{}   [before \recurselevel]   \par
%     \EveryPar{x } \EveryPar{y } \EveryPar{} [before \recurselevel] \par
%     \EveryPar{y } \everypar{before } [before] \par
% }

\installsystemnamespace{extraevery}

\permanent\protected\def\newevery#1#2%
  {\ifx#1\everypar\else\newtoks#1\fi% we test for redefinition elsewhere
   \ifrelax#2\orelse\ifdefined#2\else
     \expandafter\newtoks\csname\??extraevery\csstring#1\endcsname
     \frozen\protected\edef#2{\syst_helpers_every#1\csname\??extraevery\csstring#1\endcsname}%
   \fi}

\protected\def\syst_helpers_every#1#2%
  {\removetoks\the#2\from#1%
   \appendtoks\the#2\to  #1%
   #2}

%D This one permits definitions like:

\newevery \everypar  \EveryPar  % we get a warning which is ok
\newevery \everyline \EveryLine

%D and how about:

\newtoks \neverypar

\permanent\protected\def\forgeteverypar
  {\everypar{\expand\neverypar}}

%D Which we're going to use indeed! When the second argument equals \type {\relax},
%D the first token list is created unless it is already defined.
%D
%D Technically spoken we could have used the method we are going to present in the
%D visual debugger. First we save the primitive \type{\everypar}:
%D
%D \starttyping
%D \let\normaleverypar=\everypar
%D \stoptyping
%D
%D Next we allocate a \TOKENLIST\ named \type{\everypar}, which means that
%D \type{\everypar} is no longer a primitive but something like \type{\toks44}.
%D
%D \starttyping
%D \newtoks\everypar
%D \stoptyping
%D
%D Because \TEX\ now executes \type{\normaleverypar} instead of \type{\everypar}, we
%D are ready to assign some tokens to this internally known and used \TOKENLIST.
%D
%D \starttyping
%D \normaleverypar={all the things the system wants to do \the\everypar}
%D \stoptyping
%D
%D Where the user can provide his own tokens to be expanded every time he expects
%D them to expand.
%D
%D \starttyping
%D \everypar={something the user wants to do}
%D \stoptyping
%D
%D We don't use this method because it undoubtly leads to confusing situations,
%D especially when other packages are used, but it's this kind of tricks that make
%D \TEX\ so powerful.

%D \macros
%D   {convertargument,convertcommand,convertvalue}
%D
%D Some persistent experimenting led us to the next macro. This macro converts a
%D parameter or an expanded macro to it's textual meaning.
%D
%D \starttyping
%D \convertargument ... \to \command
%D \stoptyping
%D
%D For example,
%D
%D \starttyping
%D \convertargument{one \two \three{four}}\to\ascii
%D \stoptyping
%D
%D The resulting macro \type{\ascii} can be written to a file or the terminal
%D without problems. In \CONTEXT\ we use this macro for generating registers and
%D tables of contents.
%D
%D The second conversion alternative accepts a command:
%D
%D \starttyping
%D \convertcommand\command\to\ascii
%D \stoptyping
%D
%D Both commands accept the prefix \type{\doglobal} for global assignments.

\permanent\protected\def\convertvalue#1\to
  {\expandafter\convertcommand\csname#1\endcsname\to}

\permanent\protected\def\defconvertedvalue#1#2% less sensitive for \to
  {\expandafter\defconvertedcommand\expandafter#1\csname#2\endcsname}

%D \macros
%D   {doifassignmentelse}
%D
%D A lot of \CONTEXT\ commands take optional arguments, for 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 seperation. The next
%D command takes care of propper handling of such multi||faced commands.
%D
%D \starttyping
%D \doifassignmentelse {...} {then ...} {else ...}
%D \stoptyping
%D
%D So
%D \startbuffer
%D \doifelseassignment{a=b}{Y}{N}
%D \doifelseassignment{a+b}{Y}{N}
%D
%D \ifcondition\validassignment  {a=b}Y\else N\fi
%D \ifcondition\novalidassignment{a=b}N\else Y\fi
%D \ifcondition\novalidassignment {ab}Y\else N\fi
%D \stopbuffer
%D
%D \typebuffer gives: \blank \getbuffer \blank

\permanent\protected\def\doifelseassignment#1%
  {\ifhastok={#1}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\doifelseassignmentcs#1#2#3%
  {\ifhastok={#1}%
     \expandafter#2%
   \else
     \expandafter#3%
   \fi}

\aliased\let\doifassignmentelse  \doifelseassignment
\aliased\let\doifassignmentelsecs\doifelseassignmentcs

\newif\ifassignment

\permanent\protected\def\docheckassignment#1%
  {\ifhastok={#1}%
     \assignmenttrue
   \else
     \assignmentfalse
   \fi}

\permanent\protected\def\validassignment  #1{\ifhastok={#1}} % can become: {\ifhastok=} as we enforce {}
\permanent\protected\def\novalidassignment#1{\ifnum\ifhastok={#1}\zerocount\else\plusone\fi=\plusone} % or use unless

%D In \ETEX\ we can use \type {\detokenize} and gain some speed, but in general far
%D less that 1\% for \type {\convertargument} and nil for \type {\convertcommand}.
%D This macro is more robust than the pure \TEX\ one, something I found out when
%D primitives like \type {\jobname} were fed (or something undefined).

\permanent\protected\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}}
\permanent\protected\def\convertcommand #1\to#2{\dodoglobal\edef#2{\expandafter\detokenize\expandafter{#1}}} % hm, only second is also ok

\permanent\protected\def\defconvertedargument #1#2{\edef#1{\detokenize{#2}}}
\permanent\protected\def\defconvertedcommand  #1#2{\edef#1{\detokenize\expandafter{#2}}}
\permanent\protected\def\edefconvertedargument#1#2{\edef#1{#2}%
                                                   \edef#1{\detokenize\expandafter{#1}}}
\permanent\protected\def\gdefconvertedargument#1#2{\xdef#1{\detokenize{#2}}}
\permanent\protected\def\gdefconvertedcommand #1#2{\xdef#1{\detokenize\expandafter{#2}}}
\permanent\protected\def\xdefconvertedargument#1#2{\xdef#1{#2}%
                                                   \xdef#1{\detokenize\expandafter{#1}}}

%D When you try to convert a primitive command, you'll find out that the \ETEX\
%D method fails on for instance \type {\jobname} in the sense that it returns the
%D filename instead of just \type {\jobname}. So far this does not give real
%D problems.

%D This is typically a macro that one comes to after reading the \TEX book
%D carefully. Even then, the definite solution was found after rereading the \TEX
%D book. The first implementation was:
%D
%D \starttyping
%D \def\doconvertargument#1->#2\\\\{#2}
%D \stoptyping
%D
%D The \type {-}, the delimiter \type {\\\\} and the the second argument are
%D completely redundant.

%D \macros
%D   {showvalue}
%D
%D Ahandy macro, for testing purposes only:

\permanent\protected\def\showvalue#1%
  {\ifcsname#1\endcsname
     \expandafter\show\csname#1\endcsname
   \else
     \show\undefined
   \fi}

%D \macros
%D   {doifmeaningelse}
%D
%D We can use both commands in testing, but alas, not all meanings expand to
%D something \type {->}. This is no problem in the \ETEX\ implementation, but since
%D we want compatibility, we need:
%D
%D \starttyping
%D \doifmeaningelse {\next} {\something} {true} {false}
%D \stoptyping
%D
%D Watch the one level expansion of the second argument.

% This is only used in \spac_lines_between .. pretty ugly. Never change
% this one!

\permanent\protected\def\doifelsemeaning#1#2%
  {\edef\m_syst_string_one{\normalmeaning#1}%
   \def \m_syst_string_two{#2}%
   \edef\m_syst_string_two{\normalmeaning\m_syst_string_two}%
   \ifx\m_syst_string_one\m_syst_string_two
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifmeaningelse\doifelsemeaning

%D \macros
%D   {doifsamestringselse,doifsamestring,doifnotsamestring}
%D
%D The next comparison macro converts the arguments into expanded strings. This
%D command can be used to compare for instance \type {\jobname} with a name stored
%D in a macro.
%D
%D \starttyping
%D \doifelse          {\jobname}{oeps}{YES}{NO}
%D \doifsamestringelse{\jobname}{oeps}{YES}{NO}
%D \stoptyping

\def\syst_helpers_if_samestring_else#1#2#3#4%
  {\edef\m_syst_string_one{\detokenize\expandafter{\expanded{#3}}}%
   \edef\m_syst_string_two{\detokenize\expandafter{\expanded{#4}}}%
   \ifx\m_syst_string_one\m_syst_string_two\expandafter#1\else\expandafter#2\fi}

\permanent\protected\def\doifelsesamestring{\syst_helpers_if_samestring_else\firstoftwoarguments\secondoftwoarguments}
\permanent\protected\def\doifsamestring    {\syst_helpers_if_samestring_else\firstofoneargument \gobbleoneargument   }
\permanent\protected\def\doifnotsamestring {\syst_helpers_if_samestring_else\gobbleoneargument  \firstofoneargument  }

\aliased\let\doifsamestringelse\doifelsesamestring

%D These are obsolete in MTX:
%D
%D \starttyping
%D \ConvertToConstant    #1#2#3
%D \CheckConstantAfter   #1#2
%D \ConvertConstantAfter #1#2#3
%D \stoptyping

%D \macros
%D   {assignifempty}
%D
%D We can assign a default value to an empty macro using:
%D
%D \starttyping
%D \assignifempty \macros {default value}
%D \stoptyping
%D
%D We don't explicitly test if the macro is defined.

\permanent\protected\def\assignifempty#1#2%
  {\ifempty{#1}\def#1{#2}\fi}

%D \macros
%D   {gobbleuntil,grabuntil,gobbleuntilrelax,
%D    processbetween,processuntil}
%D
%D In \TEX\ gobbling usually stand for skipping arguments, so here are our gobbling
%D macros.
%D
%D In \CONTEXT\ we use a lot of \type {\start}||\type {\stop} like constructions.
%D Sometimes, the \type {\stop} is used as a hard coded delimiter like in: %D
%D \starttyping
%D \protected\def\startcommand#1\stopcommand%
%D   {... #1 ...}
%D \stoptyping
%D
%D In many cases the \type {\start}||\type {\stop} pair is defined at format
%D generation time or during a job. This means that we cannot hardcode the \type
%D {\stop} criterium. Only after completely understanding \type {\csname} and \type
%D {\expandafter} I was able to to implement a solution, starting with:
%D
%D \starttyping
%D \grabuntil{stop}\command
%D \stoptyping
%D
%D This commands executes, after having encountered \type {\stop} the command \type
%D {\command}. This command receives as argument the text preceding the \type
%D {\stop}. This means that:
%D
%D \starttyping
%D \protected\def\starthello%
%D   {\grabuntil{stophello}\message}
%D
%D \starthello Hello world!\stophello
%D \stoptyping
%D
%D results in: \type{\message{Hello world!}}.

\let\syst_helpers_grab_indeed\relax

\protected\def\syst_helpers_grab#1#2%
  {\def\syst_helpers_grab_indeed##1#1{#2{##1}}\syst_helpers_grab_indeed}

\permanent\protected\def\grabuntil#1%
  {\expandafter\syst_helpers_grab\expandafter{\csname#1\endcsname}}

%D The next command build on this mechanism:
%D
%D \starttyping
%D \processbetween{string}\command
%D \stoptyping
%D
%D Here:
%D
%D \starttyping
%D \processbetween{hello}\message
%D \starthello Hello again!\stophello
%D \stoptyping
%D
%D leads to: \type{\message{Hello again!}}. The command
%D
%D \starttyping
%D \gobbleuntil{sequence}
%D \stoptyping
%D
%D is related to these commands. This one simply throws away
%D everything preceding \type{\command}.

\let\syst_helpers_gobble_indeed\relax

\permanent\protected\def\processbetween#1#2%
  {\setvalue{\s!start#1}{\grabuntil{\s!stop#1}{#2}}}

% \protected\def\gobbleuntil#1%
%   {\def\syst_helpers_gobble_indeed##1#1{}\syst_helpers_gobble_indeed}
%
% \protected\def\gobbleuntilrelax#1\relax
%   {}

\permanent\protected\def\gobbleuntil#1%
  {\def\syst_helpers_gobble_indeed##-#1{}\syst_helpers_gobble_indeed}

\permanent\protected\def\gobbleuntilandfinalize#1%
  {\def\syst_helpers_gobble_indeed##-#1{#1}\syst_helpers_gobble_indeed}

\permanent\protected\def\gobbleuntilrelax#-\relax
  {}

%D The next one simply expands the pickup up tokens.
%D
%D \starttyping
%D \processuntil{sequence}
%D \stoptyping

\let\syst_helpers_until_indeed\relax

\permanent\protected\def\processuntil#1%
  {\def\syst_helpers_until_indeed##1#1{##1}\syst_helpers_until_indeed}

%D \macros
%D   {groupedcommand}
%D
%D Commands often manipulate argument as in:
%D
%D \starttyping
%D \def\doezomaarwat#1{....#1....}
%D \stoptyping
%D
%D A disadvantage of this approach is that the tokens that form \type{#1} are fixed
%D the the moment the argument is read in. Normally this is no problem, but for
%D instance verbatim environments adapt the \CATCODES\ of characters and therefore
%D are not always happy with already fixed tokens.
%D
%D Another problem arises when the argument is grouped not by \type {{}} but by
%D \type {\bgroup} and \type {\egroup}. Such an argument fails, because the \type
%D {\bgroup} is een as the argument (which is quite normal).
%D
%D The next macro offers a solution for both unwanted situations:
%D
%D \starttyping
%D \groupedcommand {before} {after}
%D \stoptyping
%D
%D Which can be used like:
%D
%D \starttyping
%D \def\cite%
%D   {\groupedcommand{\rightquote\rightquote}{\leftquote\leftquote}}
%D \stoptyping
%D
%D This command is equivalent to, but more 'robust' than:
%D
%D \starttyping
%D \def\cite#1%
%D   {\rightquote\rightquote#1\leftquote\leftquote}
%D \stoptyping
%D
%D \starttyping
%D \def\rightword%
%D   {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}}
%D
%D .......... \rightword{the right way}
%D \stoptyping
%D
%D Here \TEX\ typesets \type {\bf the right way} unbreakable at the end of the line.
%D The solution mentioned before does not work here. We also handle
%D
%D \starttyping
%D to be \bold{bold} or not, that's the question
%D \stoptyping
%D
%D and
%D
%D \starttyping
%D to be {\bold bold} or not, that's the question
%D \stoptyping
%D
%D This alternative checks for a \type {\bgroup} token first. The internal
%D alternative does not accept the box handling mentioned before, but further
%D nesting works all right. The extra \type {\bgroup}||\type {\egroup} is needed to
%D keep \type {\m_syst_helpers_handle_group_after} both into sight and local.

%D Todo: use more modern features like atendofgroup

\let\m_syst_helpers_handle_group_after \relax
\let\m_syst_helpers_handle_group_before\relax

% weird names \m_syst_helpers_handle_group_normal_before
% weird names \m_syst_helpers_handle_group_normal_before_x
% weird names \m_syst_helpers_handle_group_pickup_before
% weird names \m_syst_helpers_handle_group_simple_after
% weird names \m_syst_helpers_handle_group_simple_before

\lettonothing\m_syst_helpers_handle_group_a
\lettonothing\m_syst_helpers_handle_group_b
\lettonothing\m_syst_helpers_handle_group_p

\protected\def\syst_helpers_handle_group_nop
  {\ifnum\currentgrouptype=\semisimplegroupcode
     \expandafter\syst_helpers_handle_group_nop_a
   \else
     \expandafter\syst_helpers_handle_group_nop_b
   \fi}

\def\syst_helpers_handle_group_nop_a
  {\begingroup
   \aftergroup\m_syst_helpers_handle_group_a
   \aftergroup\endgroup
   \m_syst_helpers_handle_group_b}

\def\syst_helpers_handle_group_nop_b
  {\beginsimplegroup
   \aftergroup\m_syst_helpers_handle_group_a
   \aftergroup\egroup
   \m_syst_helpers_handle_group_b}

\protected\def\syst_helpers_handle_group_normal
  {\beginsimplegroup
   \afterassignment\m_syst_helpers_handle_group_normal_before
   \let\next=}

\def\m_syst_helpers_handle_group_normal_before
  {\beginsimplegroup
   \m_syst_helpers_handle_group_b
   \bgroup
   \aftergroup\m_syst_helpers_handle_group_a
   \aftergroup\egroup
   \aftergroup\egroup}

\protected\def\syst_helpers_handle_group_simple% no inner group (so no kerning interference)
  {\beginsimplegroup
   \afterassignment\m_syst_helpers_handle_group_simple_before
   \let\next=}

\def\m_syst_helpers_handle_group_simple_before
  {\beginsimplegroup
   \aftergroup\m_syst_helpers_handle_group_simple_after
   \m_syst_helpers_handle_group_b}

\def\m_syst_helpers_handle_group_simple_after
  {\m_syst_helpers_handle_group_a
   \egroup}

\protected\def\syst_helpers_handle_group_pickup% no inner group (so no kerning interference)
  {\beginsimplegroup
   \afterassignment\m_syst_helpers_handle_group_pickup_before
   \let\next=}

\def\m_syst_helpers_handle_group_pickup_before
  {\beginsimplegroup
   \aftergroup\m_syst_helpers_handle_group_a
   \aftergroup\egroup
   \aftergroup\m_syst_helpers_handle_group_p
   \m_syst_helpers_handle_group_b}

\protected\def\syst_helpers_handle_group_nop_x
  {% why this ...
   \ifnum\currentgrouptype=\semisimplegroupcode
     \begingroup
     \aftergroup\endgroup
   \else
     \beginsimplegroup
     \aftergroup\egroup
   \fi
   % ... till here
   \m_syst_helpers_handle_group_b}

\protected\def\syst_helpers_handle_group_normal_x
  {\beginsimplegroup
   \afterassignment\m_syst_helpers_handle_group_normal_before_x
   \let\next=}

\def\m_syst_helpers_handle_group_normal_before_x
  {\beginsimplegroup
   \expandafter\m_syst_helpers_handle_group_b
   \ifmmode\beginsimplegroup\else\bgroup\fi % is this save enough? also the other ones?
   \aftergroup\egroup
   \aftergroup\egroup}

%D I considered it a nuisance that
%D
%D \starttyping
%D \color[green]
%D   {as grass}
%D \stoptyping
%D
%D was not interpreted as one would expect. This is due to the fact that \type
%D {\futurelet} obeys blank spaces, and a line||ending token is treated as a blank
%D space. So the final implementation became:

\permanent\protected\def\groupedcommand#1#2%
  {\def\m_syst_helpers_handle_group_b{#1}%
   \def\m_syst_helpers_handle_group_a{#2}%
   \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop}

\permanent\protected\def\groupedcommandcs#1#2%
  {\let\m_syst_helpers_handle_group_b#1%
   \let\m_syst_helpers_handle_group_a#2%
   \futureexpandis\bgroup\syst_helpers_handle_group_normal\syst_helpers_handle_group_nop}

\permanent\protected\def\simplegroupedcommand#1#2%
  {\def\m_syst_helpers_handle_group_b{#1}%
   \def\m_syst_helpers_handle_group_a{#2}%
   \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop}

\permanent\protected\def\simplegroupedcommandcs#1#2%
  {\let\m_syst_helpers_handle_group_b#1%
   \let\m_syst_helpers_handle_group_a#2%
   \futureexpandis\bgroup\syst_helpers_handle_group_simple\syst_helpers_handle_group_nop}

\permanent\protected\def\pickupgroupedcommand#1#2#3%
  {\def\m_syst_helpers_handle_group_b{#1}%
   \def\m_syst_helpers_handle_group_a{#2}%
   \def\m_syst_helpers_handle_group_p{#3}%
   \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop}

\permanent\protected\def\pickupgroupedcommandcs#1#2#3%
  {\let\m_syst_helpers_handle_group_b#1%
   \let\m_syst_helpers_handle_group_a#2%
   \let\m_syst_helpers_handle_group_p#3%
   \futureexpandis\bgroup\syst_helpers_handle_group_pickup\syst_helpers_handle_group_nop}

\permanent\protected\def\triggergroupedcommand#1%
  {\def\m_syst_helpers_handle_group_b{#1}%
   \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x}

\permanent\protected\def\triggergroupedcommandcs#1%
  {\let\m_syst_helpers_handle_group_b#1%
   \futureexpandis\bgroup\syst_helpers_handle_group_normal_x\syst_helpers_handle_group_nop_x}

%D Users should be aware of the fact that grouping can interfere with ones paragraph
%D settings that are executed after the paragraph is closed. One should therefore
%D explictly close the paragraph with \type {\par}, else the settings will be
%D forgotten and not applied. So it's:
%D
%D \starttyping
%D \def\BoldRaggedCenter%
%D   {\groupedcommand{\raggedcenter\bf}{\par}}
%D \stoptyping
%D
%D In \LUAMETATEX\ this is less of an issue as we can save the state (and do so in
%D \CONTEXT).

%D For math we use this:

\permanent\protected\def\mathgroupedcommandcs#1%
  {\let\m_syst_helpers_handle_group_b#1%
   \futureexpandis\bgroup\syst_helpers_handle_math_group_normal\syst_helpers_handle_math_group_nop}

\protected\def\syst_helpers_handle_math_group_normal#1%
  {\beginmathgroup
   \m_syst_helpers_handle_group_b
   #1%
   \endmathgroup}

\protected\def\syst_helpers_handle_math_group_nop
  {\m_syst_helpers_handle_group_b}

% %D \macros
% %D   {checkdefined}
% %D
% %D The bigger the system, the greater the change that user defined commands collide
% %D with those that are part of the system. The next macro gives a warning when a
% %D command is already defined. We considered blocking the definition, but this is
% %D not always what we want.
% %D
% %D \starttyping
% %D \checkdefined {category} {class} {command}
% %D \stoptyping
% %D
% %D The user is warned with the suggestion to use \type {CAPITALS}. This suggestion
% %D is feasible, because \CONTEXT only defines lowcased macros. These are obsolete:
%
% \protected\def\showdefinederror#1#2%
%   {\writestatus\m!system{#1 #2 replaces a macro, use CAPITALS!}}
%
% \protected\def\checkdefined#1#2#3%
%   {\doifdefined{#3}{\showdefinederror{#2}{#3}}}

%D \macros
%D   {GotoPar,GetPar}
%D
%D Typesetting a paragraph in a special way can be done by first grabbing the
%D contents of the paragraph and processing this contents grouped. The next macro
%D for instance typesets a paragraph in boldface.
%D
%D \starttyping
%D \def\remark#1\par%
%D   {\bgroup\bf#1\egroup}
%D \stoptyping
%D
%D This macro has to be called like
%D
%D \starttyping
%D \remark some text ... ending with \par
%D \stoptyping
%D
%D Instead of \type {\par} we can of course use an empty line. When we started
%D typesetting with \TEX, we already had produced lots of text in plain \ASCII. In
%D producing such simple formatted texts, we adopted an open layout, and when
%D switching to \TEX, we continued this open habit. Although \TEX\ permits a cramped
%D and badly formatted source, it adds to confusion and sometimes introduces errors.
%D So we prefer:
%D
%D \starttyping
%D \remark
%D
%D some text ... ending with an empty line
%D \stoptyping
%D
%D We are going to implement a mechanism that allows such open specifications. The
%D definition of the macro handling \type {\remark} becomes:
%D
%D \starttyping
%D \def\remark%
%D   {\BeforePar{\bgroup\bf}%
%D    \AfterPar{\egroup}%
%D    \GetPar}
%D \stoptyping
%D
%D A macro like \type {\GetPar} can be defined in several ways. The recent version,
%D the fourth one in a row, originally was far more complicated, but some
%D functionality has been moved to other macros.
%D
%D We start with the more simple but in some cases more appropriate alternative is
%D \type {\GotoPar}. This one leaves \type {\par} unchanged and is therefore more
%D robust. On the other hand, \type {\AfterPar} is not supported.

\let\syst_helpers_par_before\relax
\let\syst_helpers_par_around\relax

% \permanent\protected\def\dowithpar#1#2%
%   {\globalpushmacro\syst_helpers_par_around
%    \def\syst_helpers_par_around##1\par{#1##1#2\globalpopmacro\syst_helpers_par_around}%
%    \expandafter\syst_helpers_par_around\ignorepars}

% \permanent\protected\def\dogotopar#1%
%   {\globalpushmacro\syst_helpers_par_before
%    \def\syst_helpers_par_before{#1\globalpopmacro\syst_helpers_par_before}%
%    \expandafter\syst_helpers_par_before\ignorepars}

\permanent\protected\def\dowithpar#1#2%
  {\begingroup\aftergrouped{#1\dontleavehmode\wrapuppar{#2}}\expandafter\endgroup\ignorepars}

\permanent\protected\def\dogotopar#1%
  {\begingroup\aftergrouped{#1}\expandafter\endgroup\ignorepars}

\aliased\let\dogotoparcs\dogotopar

\permanent\protected\def\dogotoparstart
  {\ignorepars}

%D This is old and kind of obsolete:

\newtoks\BeforePar
\newtoks\AfterPar

\permanent\protected\def\GetPar
  {\expanded
     {\dowithpar
        {\the\BeforePar
         \BeforePar\emptytoks}
        {\the\AfterPar
         \BeforePar\emptytoks
         \AfterPar\emptytoks}}}

\permanent\protected\def\GotoPar
  {\expanded
     {\dogotopar
        {\the\BeforePar
         \BeforePar\emptytoks}}}

%D \macros
%D   {dowithpargument,dowithwargument}
%D
%D The next macros are a variation on \type {\GetPar}. When macros expect an
%D argument, it interprets a grouped sequence of characters a one token. While this
%D adds to robustness and less ambiguous situations, we sometimes want to be a bit
%D more flexible, or at least want to be a bit more tolerant to user input.
%D
%D We start with a commands that acts on paragraphs. This
%D command is called as:
%D
%D \starttyping
%D \dowithpargument\command
%D \dowithpargument{\command ... }
%D \stoptyping
%D
%D In \CONTEXT\ we use this one to read in the titles of chapters, sections etc. The
%D commands responsible for these activities accept several alternative ways of
%D argument passing. In these examples, the \type {\par} can be omitted when an
%D empty line is present.
%D
%D \starttyping
%D \command{...}
%D \command ... \par
%D \command
%D   {...}
%D \command
%D   ... \par
%D \stoptyping

\let\syst_helpers_next_par\relax
\let\syst_helpers_next_arg\relax

\permanent\protected\def\dowithpargument#1%
  {\def\syst_helpers_next_par##1 \par{#1{##1}}%
   \def\syst_helpers_next_arg##1{#1{##1}}%
   \doifelsenextbgroup\syst_helpers_next_arg{\doifelsenextchar\par{#1{}}\syst_helpers_next_par}}

%D The \type {p} in the previous command stands for paragraph. When we want to act
%D upon words we can use the \type{w} alternative.
%D
%D \starttyping
%D \dowithwargument\command
%D \dowithwargument{... \command ...}
%D \stoptyping
%D
%D The main difference bwteen two alternatives is in the handling of \type {\par}'s.
%D This time the space token acts as a delimiter.
%D
%D \starttyping
%D \command{...}
%D \command ...
%D \command
%D   {...}
%D \command
%D   ...
%D \stoptyping

\let\syst_helpers_next_war\relax
\let\syst_helpers_next_arg\relax

\permanent\protected\def\dowithwargument#1%
  {\def\syst_helpers_next_war##1 {#1{##1}}%
   \def\syst_helpers_next_arg##1{#1{##1}}%
   \doifelsenextbgroup\syst_helpers_next_arg\syst_helpers_next_war}

%D \macros
%D   {dorepeat,dorepeatwithcommand}
%D
%D When doing repetitive tasks, we stromgly advice to use \type {\dorecurse}. The
%D next alternative however, suits better some of the \CONTEXT\ interface commands.
%D
%D \starttyping
%D \dorepeat[n*\command]
%D \stoptyping
%D
%D The value of the used \COUNTER\ can be called within
%D \type{\command} by \type{\repeater}.
%D
%D A slightly different alternative is:
%D
%D \starttyping
%D \dorepeatwithcommand[n*{...}]\command
%D \stoptyping
%D
%D When we call for something like:
%D
%D \starttyping
%D \dorepeatwithcommand[3*{Hello}]\message
%D \stoptyping
%D
%D we get ourselves three \type {\message{Hello}} messages in a row. In both
%D commands, the \type {n*} is optional. When this specification is missing, the
%D command executes once.

\permanent\protected\def\dorepeatwithcommand[#1]%
  {\syst_helpers_repeat_with_command#1*\empty*\relax}

\def\syst_helpers_repeat_with_command#1*#2#3*#4\relax#5%
  {\ifx#2\empty\syst_helpers_repeat_with_command_again[#1]#5\else\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5\fi}

\def\syst_helpers_repeat_with_command_indeed#1#2#3#4%
  {\ifx#2\empty % redundant but gives cleaner extensions
     #4{#1}%
   \orelse\ifnum#1<\zerocount
    %\expanded{\dorecurse{\number-\number#1}}{#4{-#2#3}}%
     \dorecurse{-#1}{#4{-#2#3}}%
   \orelse\ifx#2+%
     \dorecurse{#1}{#4{#3}}%
   \else
     \dorecurse{#1}{#4{#2#3}}%
   \fi}

\def\syst_helpers_repeat_with_command_again[#1]#2%
  {#2{#1}}

%D The extension hook permits something like:
%D
%D \starttyping
%D \bgroup
%D
%D \catcode`\*=\superscriptcatcode
%D
%D \gdef\syst_helpers_repeat_with_command_again[#1]%
%D   {\redodorepeatwithcommand#1*\empty*\relax}
%D
%D \gdef\redodorepeatwithcommand#1*#2#3*#4\relax#5%
%D   {\syst_helpers_repeat_with_command_indeed{#1}{#2}{#3}#5}
%D
%D \egroup
%D \stoptyping
%D
%D although one may wonder if changing the catcode of \type {*} is wise.

%D \macros
%D   {doifstringinstringelse}
%D
%D The next macro is meant for situations where both strings are macros. This save
%D some unneeded expansion. But now we just alias.

\aliased\let\doifelsestringinstring\doifelseinstring
\aliased\let\doifstringinstringelse\doifelseinstring

%D \macros
%D   {appendtoks,prependtoks,appendtoksonce,prependtoksonce,
%D    doifintokselse,flushtoks,dotoks}
%D
%D We use tokenlists sparsely within \CONTEXT, because the comma separated lists are
%D more suitable for the user interface. Nevertheless we have:
%D
%D \starttyping
%D (\doglobal) \appendtoks ... \to\tokenlist
%D (\doglobal) \prependtoks ... \to\tokenlist
%D (\doglobal) \flushtoks\tokenlist
%D             \dotoks\tokenlist
%D \stoptyping
%D
%D These macros are clones of the ones implemented in page~378 of Knuth's \TEX book.

\newtoks\t_syst_helpers_scratch

\lettonothing\m_syst_helpers_scratch

\permanent\protected\def\appendtoks#1\to#2%
  {\ifrelax\dodoglobal
     \expandafter\toksapp
   \else
     \resetglobal
     \expandafter\gtoksapp
   \fi#2{#1}}

\permanent\protected\def\prependtoks#1\to#2%
  {\ifrelax\dodoglobal
     \expandafter\tokspre
   \else
     \resetglobal
     \expandafter\gtokspre
   \fi#2{#1}}

\permanent\protected\def\appendtoksonce#1\to#2%
  {\ifhasxtoks{#1}#2\else
     \toksapp#2{#1}%
   \fi}

\permanent\protected\def\prependtoksonce#1\to#2%
  {\ifhasxtoks{#1}#2\else
     \tokspre#2{#1}%
   \fi}

% Soon (check usage):
%
% \permanent\protected\def\appendtoks #1\to#2{\toksapp#2{#1}}
% \permanent\protected\def\prependtoks#1\to#2{\tokspre#2{#1}}
%
% \permanent\protected\def\appendtoksonce #1\to#2{\ifhasxtoks{#1}#2\else\toksapp#1{#1}\fi}
% \permanent\protected\def\prependtoksonce#1\to#2{\ifhasxtoks{#1}#2\else\tokspre#2{#1}\fi}

%D The test macro:

\permanent\protected\def\doifelseintoks#1#2% #1 en #2 zijn toks
  {\ifhasxtoks#1#2%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifintokselse\doifelseintoks

%D Moved from \type {lxml-ini.tex} to here. This one is for generators that collect
%D stuff piecewise, which is sometimes hard on mechanisms that grab content using
%D delimiters:
%D
%D \starttyping
%D \startcollecting
%D \startcollect \bTABLE \stopcollect
%D     \startcollect \bTR \stopcollect
%D         \startcollect \bTD \stopcollect
%D         \startcollect   foo\stopcollect
%D         \startcollect \eTD \stopcollect
%D         \startcollect \bTD \stopcollect
%D         \startcollect   bar\stopcollect
%D         \startcollect \eTD \stopcollect
%D     \startcollect \eTR \stopcollect
%D \startcollect \eTABLE \stopcollect
%D \stopcollecting
%D \stoptyping

\newtoks \collectingtoks

\permanent\protected\lettonothing\stopcollect
\permanent\protected\lettonothing\stopexpandedcollect

\permanent\protected\def\startcollect        #1\stopcollect        {\toksapp \collectingtoks{#1}}
\permanent\protected\def\startexpandedcollect#1\stopexpandedcollect{\etoksapp\collectingtoks{#1}}

\permanent\protected\def\startcollecting{\collectingtoks\emptytoks}
\permanent\protected\def\stopcollecting {\the\collectingtoks}

\permanent\protected\def\collect        {\toksapp \collectingtoks}
\permanent\protected\def\collectexpanded{\etoksapp\collectingtoks}

%D A nice one too:

% {\scratchtoks{abc} \removetoks b\from\scratchtoks [\the\scratchtoks]}
% {\scratchtoks{abc} \removetoks x\from\scratchtoks [\the\scratchtoks]}
% {\scratchtoks{} \removetoks x\from\scratchtoks [\the\scratchtoks]}
% {\scratchtoks{xaa} \removetoks x\from\scratchtoks [\the\scratchtoks]}
% {\scratchtoks{a\relax b} \removetoks \relax\from\scratchtoks [\showthe\scratchtoks]}

\let\syst_helpers_remove_toks\relax

\permanent\protected\def\removetoks#1\from#2%
  {\def\syst_helpers_remove_toks##1#1##2\empty\empty\empty##3^^^^0004%
     {\def\m_syst_string_one{##3}%
      \ifempty\m_syst_string_one#2{##1}\else#2{##1##2}\fi}%
   \expandafter\syst_helpers_remove_toks\the#2\empty\empty\empty#1\empty\empty\empty^^^^0004}

%D Also:

\permanent\protected\def\appendetoks#1\to#2%
  {\ifrelax\dodoglobal
     \expandafter\etoksapp
   \else
     \resetglobal
     \expandafter\xtoksapp
   \fi#2{#1}}

\permanent\protected\def\prependetoks#1\to#2%
  {\ifrelax\dodoglobal
     \expandafter\etokspre
   \else
     \resetglobal
     \expandafter\xtokspre
   \fi#2{#1}}

%D Hm.

\permanent\protected\def\flushtoks#1% nb: can reassign to #1 again, hence the indirectness
  {\t_syst_helpers_scratch#1\relax
   \dodoglobal#1\emptytoks
   \the\t_syst_helpers_scratch\relax}

\aliased\let\dotoks\the

%D \macros
%D   {beforesplitstring,aftersplitstring}
%D
%D These both commands split a string at a given point in two
%D parts, so \type{x.y} becomes \type{x} or \type{y}.
%D
%D \starttyping
%D \beforesplitstring test.tex\at.\to\filename
%D \aftersplitstring  test.tex\at.\to\extension
%D \stoptyping
%D
%D The first routine looks (and is indeed) a bit simpler than the second one. The
%D alternative looking more or less like the first one did not always give the
%D results we needed. Both implementations show some insight in the manipulation of
%D arguments.

%D This is typically something that we can delegate to \LUA:

\let\syst_helpers_split_string\relax

\permanent\protected\def\beforesplitstring#1\at#2\to#3%
  {\def\syst_helpers_split_string##1#2##0^^^^0004% no #- as we need to count
     {\ifarguments
        \lettonothing#3%
      \or
        \lettonothing#3%
      \else
        \def#3{##1}%
     \fi}%
   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}

\permanent\protected\def\aftersplitstring#1\at#2\to#3%
  {\def\syst_helpers_split_string##0#2##2^^^^0004% no #- as we need to count
     {\ifarguments
        \lettonothing#3%
      \or
        \def#3{#1}%
      \else
        \def#3{##2}%
     \fi}%
   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}

%D \macros
%D   {splitstring,greedysplitstring}
%D
%D A bonus macro.

\permanent\protected\def\splitstring#1\at#2\to#3\and#4%
  {\def\syst_helpers_split_string##1#2##2^^^^0004%
     {\ifarguments
        \lettonothing#3*
        \lettonothing#4*
      \or
        \def#3{#1}%
        \lettonothing#4%
      \else
        \def#3{##1}%
        \def#4{##2}%
     \fi}%
   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}

\permanent\protected\def\greedysplitstring#1\at#2\to#3\and#4%
  {\def\syst_helpers_split_string##1#2##2^^^^0004%
     {\ifarguments
        \lettonothing#3%
        \lettonothing#4%
      \or
        \def#3{#1}%
        \lettonothing#4%
      \else
        \def#3{##1}%
        \def#4{##2}%
        \def\syst_helpers_split_string####1#2####2^^^^0004%
          {\ifarguments
           \or
           \else
             \expandafter\def\expandafter#3\expandafter{#3####1}%
             \def#4{####2}%
             \syst_helpers_split_string####2^^^^0004\ignorearguments\ignorearguments
          \fi}%
        \syst_helpers_split_string##2^^^^0004\ignorearguments\ignorearguments
     \fi}%
   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}

%D \macros
%D   {beforetestandsplitstring,
%D    aftertestandsplitstring,
%D    testandsplitstring}

\aliased\let\beforetestandsplitstring\beforesplitstring

\permanent\protected\def\aftertestandsplitstring#1\at#2\to#3%
  {\def\syst_helpers_split_string##0#2##2^^^^0004% no #- as we need to count
     {\ifarguments
        \lettonothing#3%
      \or
        \lettonothing#3%
      \else
        \def#3{##2}%
     \fi}%
   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}

\permanent\protected\def\testandsplitstring#1\at#2\to#3\and#4%
  {\def\syst_helpers_split_string##1#2##2^^^^0004%
     {\ifarguments
        \lettonothing#3%
        \lettonothing#4%
      \or
        \lettonothing#3%
        \lettonothing#4%
      \else
        \def#3{##1}%
        \def#4{##2}%
     \fi}%
   \expandafter\syst_helpers_split_string#1^^^^0004\ignorearguments\ignorearguments}

%D \macros
%D   {splitatperiod, splitatcomma, splitatasterisk, splitatcolon, splitatcolons}

\protected\def\syst_helpers_splitatperiod    #1.#2.#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
\protected\def\syst_helpers_splitatcomma     #1,#2,#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
\protected\def\syst_helpers_splitatasterisk  #1*#2*#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
\protected\def\syst_helpers_splitatcolon     #1:#2:#-^^^^0004#3#4{\def #3{#1}\def #4{#2}}
\protected\def\syst_helpers_splitatcolons  #1::#2::#-^^^^0004#3#4{\edef#3{#1}\edef#4{#2}}

\permanent\protected\def\splitatperiod  #1{\expanded{\syst_helpers_splitatperiod  #1}..^^^^0004}
\permanent\protected\def\splitatcomma   #1{\expanded{\syst_helpers_splitatcomma   #1},,^^^^0004}    % not at ", "
\permanent\protected\def\splitatasterisk#1{\expanded{\syst_helpers_splitatasterisk#1}**^^^^0004}
\permanent\protected\def\splitatcolon   #1{\expanded{\syst_helpers_splitatcolon   #1}::^^^^0004}
\permanent\protected\def\splitatcolons  #1{\expanded{\syst_helpers_splitatcolons  #1}::::^^^^0004}

%D \macros
%D   {replacewildcard}
%D
%D \starttyping
%D \replacewildcard{foo:*}{bar} == foo:bar
%D \stoptyping

% This one is defined at the \LUA\ end.

%D \macros
%D   {removesubstring}
%D
%D A first application of the two routines defined above is:
%D
%D \starttyping
%D \removesubstring-\from first-last\to\nothyphenated
%D \stoptyping
%D
%D Which in terms of \TEX\ looks like:

\permanent\protected\def\removesubstring#1\from#2\to#3%
  {\splitstring#2\at#1\to\m_syst_string_one\and\m_syst_string_two
   \dodoglobal\def#3{\m_syst_string_one\m_syst_string_two}}

%D \macros
%D   {appendtocommalist,prependtocommalist,
%D    addtocommalist,removefromcommalist}
%D
%D When working with comma separated lists, one sooner or later want the tools to
%D append or remove items from such a list. When we add an item, we first check if
%D it's already there. This means that every item in the list is unique.
%D
%D \starttyping
%D \addtocommalist      {alfa}  \name
%D \addtocommalist      {beta}  \name
%D \addtocommalist      {gamma} \name
%D \removefromcommalist {beta}  \name
%D \stoptyping
%D
%D These commands can be prefixed with \type {\doglobal}. The implementation of the
%D second command is more complecated, because we have to take leading spaces into
%D account. Keep in mind that users may provide lists with spaces after the commas.
%D When one item is left, we also have to get rid of trailing spaces.
%D
%D \starttyping
%D \def\words{alfa, beta, gamma, delta}
%D \def\words{alfa,beta,gamma,delta}
%D \stoptyping
%D
%D Removing an item takes more time than adding one. A fast appending alternative,
%D without any testing, is also provided:
%D
%D \starttyping
%D \appendtocommalist  {something} \name
%D \prependtocommalist {something} \name
%D \stoptyping
%D
%D This can be implemented as follows:
%D
%D \starttyping
%D \def\appendtocommalist#1#2%
%D   {\ifx#2\empty
%D      \dodoglobal\edef#2{#1}%
%D    \else % no test on empty
%D      \dodoglobal\edef#2{#2,#1}%
%D    \fi}
%D
%D \def\prependtocommalist#1#2%
%D   {\ifx#2\empty
%D      \dodoglobal\edef#2{#1}%
%D    \else % no test on empty
%D      \dodoglobal\edef#2{#1,#2}%
%D    \fi}
%D \stoptyping
%D
%D The faster alternatives are:

\permanent\protected\def\appendtocommalist#1#2%
  {\dodoglobal\edef#2{\ifempty#2\else#2,\fi#1}}

\permanent\protected\def\prependtocommalist#1#2%
  {\dodoglobal\edef#2{#1\ifempty#2\else,#2\fi}}

\permanent\protected\def\addtocommalist#1#2% {item} \cs
  {\rawdoifelseinset{#1}#2\resetglobal
     {\dodoglobal\edef#2{\ifempty#2\else#2,\fi#1}}}

\permanent\protected\def\pretocommalist#1#2% {item} \cs
  {\rawdoifelseinset{#1}#2\resetglobal
     {\dodoglobal\edef#2{#1\ifempty#2\else,#2\fi}}}

\permanent\protected\def\robustdoifelseinset#1#2%
  {\edef\m_syst_string_one{\detokenize\expandafter{\expanded{#1}}}%
   \edef\m_syst_string_two{\detokenize\expandafter{\expanded{#2}}}%
   \rawdoifelseinset\m_syst_string_one\m_syst_string_two}

\aliased\let\robustdoifinsetelse\robustdoifelseinset

\permanent\protected\def\robustaddtocommalist#1#2% {item} \cs
  {\robustdoifelseinset{#1}#2\resetglobal
     {\dodoglobal\edef#2{\ifempty#2\else#2,\fi#1}}}

\permanent\protected\def\robustpretocommalist#1#2% {item} \cs
  {\robustdoifelseinset{#1}#2\resetglobal
     {\dodoglobal\edef#2{#1\ifempty#2\else,#2\fi}}}

\permanent\protected\def\xsplitstring#1#2% \cs {str}
  {\def\syst_helpers_split_string##1,#2,##2,#2,##-\\%
     {\edef\m_syst_string_one{\syst_cleanedup_commalist_b##1\empty\empty\relax}%
      \edef\m_syst_string_two{\syst_cleanedup_commalist_a##2,,\relax}}%
   \expandafter\syst_helpers_split_string\expandafter,#1,,#2,,#2,\\}

\def\syst_cleanedup_commalist_b#1#2\relax{\if#1,\else#1\fi#2}
\def\syst_cleanedup_commalist_a#1,,#-\relax{#1}

\permanent\protected\def\removefromcommalist#1#2% to be sped up
  {\rawdoifelseinset{#1}#2%
     {\expanded{\xsplitstring\noexpand#2{#1}}%
      \dodoglobal\edef#2%
        {\ifempty\m_syst_string_one
           \m_syst_string_two
         \else
           \m_syst_string_one\ifempty\m_syst_string_two\else,\m_syst_string_two\fi
         \fi}}
     \resetglobal}

%D \macros
%D   {substituteincommalist}
%D
%D Slow but seldom used, so for the moment we stick to this implementation.
%D
%D \starttyping
%D \substituteincommalist{old}{new}{list}
%D \stoptyping

\def\syst_helpers_substitute_in_comma_list_step#1%
  {\edef\m_syst_string_three{#1}%
   \ifx\m_syst_string_one\m_syst_string_three
     \ifempty\m_syst_string_two \else
       \edef\m_syst_string_four{\ifempty\m_syst_string_four\else\m_syst_string_four,\fi\m_syst_string_two}%
     \fi
   \else
     \edef\m_syst_string_four{\ifempty\m_syst_string_four\else\m_syst_string_four,\fi#1}%
   \fi}

\permanent\protected\def\substituteincommalist#1#2#3% old, new, list (slooow)
  {\edef\m_syst_string_one{#1}%
   \edef\m_syst_string_two{#2}%
   \lettonothing\m_syst_string_four
   \expanded{\rawprocesscommacommand[#3]}\syst_helpers_substitute_in_comma_list_step
   \let#3\m_syst_string_four}

%D \macros
%D   {replaceincommalist}
%D
%D The next macro can be used to replace an indexed element in a commalist:
%D
%D \starttyping
%D \replaceincommalist\MyList{2}
%D \stoptyping
%D
%D Element~2 will be replaced by the current meaning of the macro \type
%D {\newcommalistelement}. The old meaning is saved in \type {\commalistelement}.
%D The replacement honors grouped items, like in:
%D
%D \starttyping
%D \def\MyList{a,b,c,d,e,f}   \replaceincommalist\MyList{3}
%D \def\MyList{a,b,c,d,e,f}   \replaceincommalist\MyList{3}
%D \def\MyList{a,{b,c},d,e,f} \replaceincommalist\MyList{3}
%D \def\MyList{a,b,c,{d,e,f}} \replaceincommalist\MyList{3}
%D \stoptyping
%D
%D This macro was used in the bibtex code (and is probably no longer needed).

\newinteger\c_syst_helpers_comma_list_index

\lettonothing\m_syst_helpers_comma_list_target

\mutable\lettonothing\newcommalistelement

\def\syst_helpers_replace_in_comma_list_step#1% we can use #+ here too
  {\ifnum\commalistcounter=\c_syst_helpers_comma_list_index\relax
     \ifempty\newcommalistelement\else
       \ifempty\m_syst_helpers_comma_list_target
         \let\m_syst_helpers_comma_list_target\newcommalistelement
       \else
         \expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter
           \m_syst_helpers_comma_list_target\expandafter\expandafter\expandafter
             {\expandafter\m_syst_helpers_comma_list_target\expandafter,\newcommalistelement}%
       \fi
     \fi
     \def\commalistelement{#1}%
   \else
     \ifempty\m_syst_helpers_comma_list_target
       \ifx\nexttoken\bgroup % is known -)
         \def\m_syst_helpers_comma_list_target{{#1}}%
       \else
         \def\m_syst_helpers_comma_list_target{#1}%
       \fi
     \else
       \ifx\nexttoken\bgroup % is known -)
         \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,{#1}}%
       \else
         \expandafter\def\expandafter\m_syst_helpers_comma_list_target\expandafter{\m_syst_helpers_comma_list_target,#1}%
       \fi
     \fi
   \fi
   \advanceby\commalistcounter\plusone}

\permanent\protected\def\replaceincommalist#1#2% #1 = commalistelement #2 = position starts at 1
  {\c_syst_helpers_comma_list_index#2\relax
   \lettonothing\m_syst_helpers_comma_list_target
   \lettonothing\commalistelement
   \commalistcounter\plusone
   \expandafter\processcommalist\expandafter[#1]\syst_helpers_replace_in_comma_list_step
   \dodoglobal\let#1\m_syst_helpers_comma_list_target}

%D \macros
%D   {globalprocesscommalist}
%D
%D The commalist processing commands are characterized by the fact that the way they
%D handle expansion as well as the fact that they can be nested. This makes them
%D kind of useless for handling comma lists in alignments. In these situations the
%D next macro can be of use.

\lettonothing\m_syst_helpers_comma_list_command_global

\def\syst_helpers_comma_list_command_global_step#1,%
  {\if]#1\else
     \m_syst_helpers_comma_list_command_global{#1}%
     \expandafter\syst_helpers_comma_list_command_global_step
   \fi}

\permanent\protected\def\globalprocesscommalist[#1]#2%
  {\glet\m_syst_helpers_comma_list_command_global#2%
   \expandafter\syst_helpers_comma_list_command_global_step#1,],}

%D \macros
%D   {withoutpt,PtToCm,
%D    numberofpoints,dimensiontocount}
%D
%D We can convert point into centimeters with:
%D
%D \starttyping
%D \PtToCm{dimension}
%D \stoptyping

% {\catcode`\.=\othercatcode
%  \catcode`\p=\othercatcode
%  \catcode`\t=\othercatcode
%  \gdef\WITHOUTPT#1pt{#1}}
%
% \def\withoutpt#1%
%   {\expandafter\WITHOUTPT#1}
%
% Okay, not really an impressive extension to the engine, but better than some macro
% that is demonstrating deeper understanding of \TEX. It's anyway a trivial extension
% anyway. There are actually many examples of very advanced macros and exposure of
% how clever one is that could be done cheap in the engine. It's just that at the time
% that \TEX\ was written, it made no sense to add a lot of that. After decades we know
% what extras we need.

% \permanent\def\withoutpt#1{\thewithoutunit\dimexpr#1}

\aliased\let\withoutpt\toscaled

%D The capitals are needed because \type {p} and \type {t} have catcode~12, while
%D macronames only permit tokens with the catcode~11. As a result we cannot use the
%D \type {.group} primitives. Those who want to know more about this kind of
%D manipulations, we advice to study the \TEX book in detail. Because this macro
%D does not do any assignment, we can use it in the following way too.

% \permanent\def\PtToCm#1{\thewithoutunit\dimexpr0.0351459804\dimexpr#1\relax\relax cm}

\permanent\def\PtToCm#1{\toscaled\dimexpr0.0351459804\dimexpr#1\relax\relax cm}

%D We also support:
%D
%D \starttyping
%D \numberofpoints   {dimension}
%D \dimensiontocount {dimension} {\count}
%D \stoptyping
%D
%D Both macros return a rounded number.

% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt}
% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt}

\permanent\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax}
\permanent\def\numberofpoints    #1{\tointeger{\dimexpr#1\relax/\maxcard}}

%D \macros
%D   {swapdimens,swapskips,swapcounts,swapmacros,
%D    globalswapdimens,globalswapcounts,globalswapmacros}
%D
%D Simple but effective are the next two macros. There name exactly states their
%D purpose.

\newdimension\d_syst_helpers_swapped
\newgluespec \s_syst_helpers_swapped
\newinteger  \c_syst_helpers_swapped
\let         \m_syst_helpers_swapped\relax

% \protected\def\swapdimens#1#2{\d_syst_helpers_swapped#1#1#2#2\d_syst_helpers_swapped}
% \protected\def\swapskips #1#2{\s_syst_helpers_swapped#1#1#2#2\s_syst_helpers_swapped}
% \protected\def\swapcounts#1#2{\c_syst_helpers_swapped#1#1#2#2\c_syst_helpers_swapped}
% \protected\def\swapmacros#1#2{\let\m_syst_helpers_swapped#1\let#1#2\let#2\m_syst_helpers_swapped}

\aliased\let\swapdimens\swapcsvalues
\aliased\let\swapskips \swapcsvalues
\aliased\let\swapcounts\swapcsvalues
\aliased\let\swapmacros\swapcsvalues

% \protected\def\globalswapdimens#1#2{\d_syst_helpers_swapped#1\global#1#2\global#2\d_syst_helpers_swapped}
% \protected\def\globalswapskips #1#2{\s_syst_helpers_swapped#1\global#1#2\global#2\s_syst_helpers_swapped}
% \protected\def\globalswapcounts#1#2{\c_syst_helpers_swapped#1\global#1#2\global#2\c_syst_helpers_swapped}
% \protected\def\globalswapmacros#1#2{\let\m_syst_helpers_swapped#1\glet#1#2\glet#2\m_syst_helpers_swapped}

\permanent\protected\def\globalswapdimens{\global\swapcsvalues}
\permanent\protected\def\globalswapskips {\global\swapcsvalues}
\permanent\protected\def\globalswapcounts{\global\swapcsvalues}
\permanent\protected\def\globalswapmacros{\global\swapcsvalues}

%D \macros
%D   {pushmacro,popmacro}
%D
%D Premature and a bit of beta, we offer:
%D
%D \starttyping
%D \pushmacro\macro
%D \popmacro\macro
%D \stoptyping

\permanent\let\pushmacro\localpushmacro
\permanent\let\popmacro \localpopmacro

%D \macros
%D   {setlocalhsize,distributedhsize}
%D
%D Sometimes we need to work with the \type{ \hsize} that is corrected for
%D indentation and left and right skips. The corrected value is available in \type
%D {\localhsize}, which needs to be calculated with \type {\setlocalhsize} first. %D
%D
%D \starttyping
%D \setlocalhsize        \hbox to \localhsize{...}
%D \setlocalhsize[-1em]  \hbox to \localhsize{...}
%D \setlocalhsize[.5ex]  \hbox to \localhsize{...}
%D \stoptyping
%D
%D These examples show us that an optional can be used. The value provided is added
%D to \type {\localhsize}.

\newdimension\localhsize

\permanent\protected\def\setlocalhsize % don't change !
  {\doifelsenextoptional
     \syst_helpers_set_local_hsize_yes
     \syst_helpers_set_local_hsize_nop}

\def\syst_helpers_set_local_hsize_nop
  {\localhsize\availablehsize}

\def\syst_helpers_set_local_hsize_yes[#1]%
  {\syst_helpers_set_local_hsize_nop
   \advanceby\localhsize#1\relax}

\permanent\def\availablehsize
  {\dimexpr
     \hsize-\leftskip-\rightskip
     \ifnum\hangafter<\zerocount
       \ifdim\hangindent>\zeropoint-\else+\fi\hangindent
     \fi
   \relax}

\permanent\def\distributedhsize#1#2#3%
  {\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}

\permanent\def\hsizefraction#1#2%
  {\dimexpr#1/#2\relax}

%D \macros
%D   {doifvalue,doifnotvalue,doifelsevalue,
%D    doifnothing,doifsomething,doifelsenothing,
%D    doifvaluenothing,doifvaluesomething,doifelsevaluenothing}
%D
%D These \type {\if} commands can be used to access macros (or variables) that are
%D normally accessed by using \type {\getvalue}. Using these alternatives safes us
%D three tokens per call. Anyone familiar with the not||values ones, can derive
%D their meaning from the definitions.

\permanent\protected\def\doifvalue#1#2%
  {\iftok{\csname#1\endcsname}{#2}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifnotvalue#1#2%
  {\iftok{\csname#1\endcsname}{#2}%
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\protected\def\doifelsevalue#1#2%
  {\iftok{\csname#1\endcsname}{#2}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\doifnothing#1%
  {\ifempty{#1}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifsomething#1%
  {\ifempty{#1}%
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\protected\def\doifelsenothing#1%
  {\ifempty{#1}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\permanent\protected\def\doifelsesomething#1%
  {\ifempty{#1}%
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

\permanent\protected\def\doifvaluenothing#1%
  {\ifempty{\csname#1\endcsname}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\protected\def\doifvaluesomething#1%
  {\ifempty{\csname#1\endcsname}%
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\protected\def\doifelsevaluenothing#1%
  {\ifempty{\csname#1\endcsname}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifvalueelse       \doifelsevalue
\aliased\let\doifnothingelse     \doifelsenothing
\aliased\let\doifsomethingelse   \doifelsesomething
\aliased\let\doifvaluenothingelse\doifelsevaluenothing

%D \macros
%D   {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue}
%D
%D Also handy:

\permanent\def\doifelseemptyvalue#1%
  {\expandafter\ifempty\csname#1\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifemptyvalueelse\doifelseemptyvalue

\permanent\def\doifemptyvalue#1%
  {\expandafter\ifempty\csname#1\endcsname
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\permanent\def\doifnotemptyvalue#1%
  {\expandafter\ifempty\csname#1\endcsname
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

%D \macros
%D   {doifallcommonelse}
%D
%D A complete match of two sets can be tested with \type {\doifallcommonelse}, where
%D the first two arguments are sets.

\let\syst_helpers_do_common_check_all\gobbleoneargument

\def\syst_helpers_do_if_all_common_else#1#2#3#4% slow
  {\def\syst_helpers_do_common_check_all##1%
     {\ifinset{##1}{#4}\else\donefalse\fi
      \ifdone\else\expandafter\quitcommalist\fi}%
   \donetrue
   \processcommalist[#3]\syst_helpers_do_common_check_all
   \ifdone\expandafter#1\else\expandafter#2\fi}

\permanent\protected\def\doifelseallcommon{\syst_helpers_do_if_all_common_else\firstoftwoarguments\secondoftwoarguments}
\permanent\protected\def\doifallcommon    {\syst_helpers_do_if_all_common_else\firstofoneargument \gobbleoneargument   }
\permanent\protected\def\doifnotallcommon {\syst_helpers_do_if_all_common_else\gobbleoneargument  \firstofoneargument  }

\aliased\let\doifallcommonelse\doifelseallcommon

%D \macros
%D   {DOIF,DOIFELSE,DOIFNOT}
%D
%D \TEX\ is case sensitive. When comparing arguments, this feature sometimes is less
%D desirable, for instance when we compare filenames. The next three alternatives
%D upcase their arguments before comparing them.
%D
%D \starttyping
%D \DOIF     {string1} {string2} {...}
%D \DOIFNOT  {string1} {string2} {...}
%D \DOIFELSE {string1} {string2} {then ...}{else ...}
%D \stoptyping
%D
%D We have to use a two||step implementation, because the
%D expansion has to take place outside \type{\uppercase}.
%D
%D These might end up as \LUA based helpers (i.e. consider these
%D obsolete:

\protected\def\syst_helpers_do_IF#1#2%
  {\uppercase{\iftok{#1}{#2}}%
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\protected\def\syst_helpers_do_IF_NOT#1#2%
  {\uppercase{\iftok{#1}{#2}}%
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\protected\def\syst_helpers_do_IF_ELSE#1#2%
  {\uppercase{\iftok{#1}{#2}}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\protected\def\syst_helpers_do_IF_INSTRING_ELSE#1#2%
  {\uppercase{\doifelseinstring{#1}{#2}}}

\permanent\protected\def\DOIF             #1#2{\expanded{\syst_helpers_do_IF              {#1}{#2}}}% will become obsolete
\permanent\protected\def\DOIFNOT          #1#2{\expanded{\syst_helpers_do_IF_NOT          {#1}{#2}}}% will become obsolete
\permanent\protected\def\DOIFELSE         #1#2{\expanded{\syst_helpers_do_IF_ELSE         {#1}{#2}}}% will become obsolete
\permanent\protected\def\DOIFINSTRINGELSE #1#2{\expanded{\syst_helpers_do_IF_INSTRING_ELSE{#1}{#2}}}% will become obsolete

%D \macros
%D   {dosingleargumentwithset,
%D    dodoubleargumentwithset,dodoubleemptywithset,
%D    dotripleargumentwithset,dotripleemptywithset}
%D
%D These maybe too mysterious macros enable us to handle more 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 in the set~\type
%D {#1}. The second one calls for \typ {\command [##1][#2]} and the third, well one
%D may guess. These commands support constructions like:
%D
%D \starttyping
%D \def\dodefinesomething[#1][#2]%
%D   {\getparameters[\??xx#1][#2]}
%D
%D \protected\def\definesomething%
%D   {\dodoubleargumentwithset\dodefinesomething}
%D \stoptyping
%D
%D Which accepts calls like:
%D
%D \starttyping
%D \definesomething[alfa,beta,...][variable=...,...]
%D \stoptyping

\let\syst_helpers_with_set_step\relax % maybe push pop

\permanent\tolerant\protected\def\dodoubleemptywithset#1#*[#2]#*[#3]%
  {\ifempty{#2}\else
     \def\syst_helpers_with_set_step##1{#1[##1][#3]}%
     \processcommalist[#2]\syst_helpers_with_set_step
   \fi}

\permanent\tolerant\protected\def\dotripleemptywithset#1#*[#2]#*[#3]#*[#4]%
  {\ifempty{#2}\else
     \def\syst_helpers_with_set_step##1{#1[##1][#3][#4]}%
     \processcommalist[#2]\syst_helpers_with_set_step
   \fi}

\aliased\let\dodoubleargumentwithset\dodoubleemptywithset
\aliased\let\dotripleargumentwithset\dotripleemptywithset

%D \macros
%D   {stripcharacters,stripspaces}
%D
%D The next command was needed first when we implemented the \CONTEXT\ interactivity
%D macros. When we use labeled destinations, we often cannot use all the characters
%D we want. We therefore strip some of the troublemakers, like spaces, from the
%D labels before we write them to the \DVI||file, which passes them to for instance
%D a \POSTSCRIPT\ file.
%D
%D \starttyping
%D \stripspaces\from\one\to\two
%D \stoptyping
%D
%D Both the old string \type {\one} and the new one \type {\two} are expanded. This
%D command is a special case of:
%D
%D \starttyping
%D \stripcharacter\char\from\one\to\two
%D \stoptyping
%D
%D As we can see below, spaces following a control sequence are to enclosed in \type
%D {{}}.

\let\syst_helpers_strip_character\relax

\lettonothing\m_syst_helpers_strip_character

\permanent\protected\def\stripcharacter#1\from#2\to#3%
  {\def\syst_helpers_strip_character##1#1##2\end
     {\edef\m_syst_helpers_strip_character{\m_syst_helpers_strip_character##1}%
      \doifnotempty{##2}{\syst_helpers_strip_character##2\end}}%
   \lettonothing\m_syst_helpers_strip_character
   \edef\m_syst_string_one{#2}%
   \expandafter\syst_helpers_strip_character\m_syst_string_one#1\end
   \dodoglobal\let#3\m_syst_helpers_strip_character}

\permanent\protected\def\stripspaces\from#1\to#2% will become \unspacestring#1\from#2
  {\stripcharacter{ }\from#1\to#2}

%D \macros
%D   {unspacestring}
%D
%D The next macro does the same but is more compatible with other macros, like \type
%D {\convert...}.

\permanent\protected\def\unspacestring#1\to#2%
  {\stripcharacter{ }\from#1\to#2}

%D \macros
%D   {executeifdefined}
%D
%D \CONTEXT\ uses one auxiliary file for all data concerning tables of contents,
%D references, two||pass optimizations, sorted lists etc. This file is loaded as
%D many times as needed. During such a pass we skip the commands thate are of no use
%D at that moment. Because we don't want to come into trouble with undefined
%D auxiliary commands, we call the macros in a way similar to \type {\getvalue}. The
%D next macro take care of such executions and when not defined, gobbles the
%D unwanted arguments.
%D
%D \starttyping
%D \executeifdefined{name}\gobbleoneargument
%D \stoptyping
%D
%D We can of course gobble more arguments using the appropriate gobbling command.

\permanent\def\executeifdefined#1% #2 / never change this one again
  {\ifcsname#1\endcsname
     \expandafter\expandafter\expandafter\lastnamedcs\expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

%D This one also has the advantage that it is fully expandable and that it can be
%D used after an assignment.

%D \macros
%D   {doifsomespaceelse}
%D
%D The next command checks a string on the presence of a space and executed a
%D command accordingly.
%D
%D \starttyping
%D \doifsomespaceelse {tekst} {then ...} {else ...}
%D \stoptyping
%D
%D We use this command in \CONTEXT\ for determing if an argument must be broken into
%D words when made interactive. Watch the use of \type {\noexpand}.

%D Is this one still needed?

% \def\syst_helpers_if_some_space_else#1 #2#3^^^^0004{\if\noexpand#2@}
%
% \def\doifelsesomespace#1%                     % #2#3%
%   {\syst_helpers_if_some_space_else#1 @ @^^^^0004% #3\else#2\fi}
%      \expandafter\secondoftwoarguments
%    \else
%      \expandafter\firstoftwoarguments
%    \fi}

\permanent\edef\doifelsesomespace#1%
  {\noexpand\ifhastok\space{#1}%
     \noexpand\expandafter\noexpand\firstoftwoarguments
   \noexpand\else
     \noexpand\expandafter\noexpand\secondoftwoarguments
   \noexpand\fi}

\aliased\let\doifsomespaceelse\doifelsesomespace

%D \macros
%D   {processseparatedlist}
%D
%D Maybe a bit late, but here is a more general version of the \type
%D {\processcommalist} command. This time we don't handle nesting but accept
%D arbitrary seperators.
%D
%D \starttyping
%D \processseparatedlist[list][separator]\command
%D \stoptyping
%D
%D One can think of things like:
%D
%D \starttyping
%D \processseparatedlist[alfa+beta+gamma][+]\message
%D \stoptyping
%D
%D We want to handle all situations, like:
%D
%D \startbuffer
%D \processseparatedlist[{aap noot}]  [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
%D \processseparatedlist[{aap} {noot}][ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
%D \processseparatedlist[aap {noot}]  [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
%D \processseparatedlist[aap noot]    [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D Therefore we smuggle a \type {\relax} in front of the argument, which we remove
%D afterwards.

\let\syst_helpers_process_separated_list_step\relax

% \def\syst_helpers_process_separated_list#1]#*[#2]#3%
%    {\def\syst_helpers_process_separated_list_step##1##2#2%
%       {\def\m_syst_string_one{##2}% suggested by VZ
%        \if]##1%
%          \let\syst_helpers_process_separated_list_step\relax
%        \orelse\ifx\blankspace\m_syst_string_one
%          #3{##1}%
%        \orelse\if]##2%
%          \let\syst_helpers_process_separated_list_step\relax
%        \else
%          #3{##1##2}%
%        \fi
%        \syst_helpers_process_separated_list_step}%
%     \expandafter\syst_helpers_process_separated_list_step\gobbleoneargument#1#2]#2}

% \def\syst_helpers_process_separated_list#1]#*[#2]#3%
%    {\def\syst_helpers_process_separated_list_step##1##2#2%
%       {\def\m_syst_string_one{##2}% suggested by VZ
%        \if]##1%
%        \orelse\ifx\blankspace\m_syst_string_one
%          #3{##1}%
%          \expandafter\syst_helpers_process_separated_list_step
%        \orelse\if]##2%
%        \else
%          #3{##1##2}%
%          \expandafter\syst_helpers_process_separated_list_step
%        \fi
%        }%
%     \expandafter\syst_helpers_process_separated_list_step\gobbleoneargument#1#2]#2}

% \permanent\protected\def\processseparatedlist[%
%   {\syst_helpers_process_separated_list\relax}

\permanent\protected\def\processseparatedlist[#+]#*[#2]#3%
   {\tolerant\def\syst_helpers_process_separated_list_step##1#2%
      {\ifarguments\or
         #3{##1}%
         \expandafter\syst_helpers_process_separated_list_step
       \fi}%
    \syst_helpers_process_separated_list_step#1\ignorearguments\ignorearguments}

%D \macros
%D   {processlist}
%D
%D An even more general list processing macro is the following one:
%D
%D \starttyping
%D \processlist{beginsym}{endsym}{separator}\docommand list
%D \stoptyping
%D
%D This one supports arbitrary open and close symbols as well as user defined
%D separators.
%D
%D \starttyping
%D \processlist(){=>}\docommand(a=>b=>c=>d)
%D \stoptyping

\let\syst_helpers_process_any_list       \relax
\let\syst_helpers_process_any_list_indeed\relax
\let\syst_helpers_process_any_list_step  \relax

\permanent\protected\def\processlist#1#2#3#4% no blank skipping !
  {\def\syst_helpers_process_any_list_indeed##1#2%
     {\def\syst_helpers_process_any_list_step####1####2#3%
        {\ifx#2####1%
           \let\syst_helpers_process_any_list_step\relax
         \orelse\ifx#2####2%
           \let\syst_helpers_process_any_list_step\relax
         \else
           #4{####1####2}%
         \fi
         \syst_helpers_process_any_list_step}%
      \expandafter\syst_helpers_process_any_list_step\gobbleoneargument##1#3#2#3}%
   \def\syst_helpers_process_any_list#1%
     {\syst_helpers_process_any_list_indeed\relax}%
    \syst_helpers_process_any_list}

%D \macros
%D   {processassignlist}
%D
%D Is possible to combine an assignment list with one containing keywords.
%D Assignments are treated accordingly, keywords are treated by \type {\command}.
%D
%D \starttyping
%D \processassignlist[...=...,...=...,...]\commando
%D \stoptyping
%D
%D This command can be integrated in \type {\getparameters}, but we decided best not
%D to do so.

\let\syst_helpers_process_assign_list_assign\gobbleoneoptional
\let\syst_helpers_process_assign_list_step  \gobbleoneargument

\permanent\protected\def\processassignlist#1[#2]#3%
  {\def\syst_helpers_process_assign_list_assign[##1=##-=##2]%
     {\iftok{##2}{\relax}#3{##1}\fi}%
   \def\syst_helpers_process_assign_list_step##1%
     {\syst_helpers_process_assign_list_assign[##1==\relax]}%
   \processcommalist[#2]\syst_helpers_process_assign_list_step}

%D \macros
%D   {untextargument
%D    untexcommand}
%D
%D When manipulating data(bases) and for instance generating index entries, the next
%D three macros can be of help:
%D
%D \starttyping
%D \untextargument{...}\to\name
%D \untexcommand  {...}\to\name
%D \stoptyping
%D
%D They remove braces and backslashes and give us something to sort.

\lettonothing\m_syst_helpers_untexed

\permanent\protected\def\untexsomething
  {\begingroup
   \catcode\leftbraceasciicode \ignorecatcode
   \catcode\rightbraceasciicode\ignorecatcode
   \escapechar\minusone
   \syst_helpers_untex_something}

\def\syst_helpers_untex_something#1#2\to#3%
  {\doglobal#1#2\to\m_syst_helpers_untexed
   \endgroup
   \let#3\m_syst_helpers_untexed}

\permanent\protected\def\untexargument{\untexsomething\convertargument}
\permanent\protected\def\untexcommand {\untexsomething\convertcommand}

%D \macros
%D   {ScaledPointsToBigPoints,ScaledPointsToWholeBigPoints}
%D
%D One characteristic of \POSTSCRIPT\ and \PDF\ is that both used big points (\TEX's
%D bp). The next macros convert points and scaled points into big points. The magic
%D factor $72/72.27$ can be found in most \TEX\ related books.
%D
%D \starttyping
%D \ScaledPointsToBigPoints      {number} \target
%D \ScaledPointsToWholeBigPoints {number} \target
%D \stoptyping

\aliased\let\tobigpoints     \clf_tobigpoints      % todo: permanent at lua end
\aliased\let\towholebigpoints\clf_towholebigpoints % todo: permanent at lua end

\permanent\protected\def\PointsToBigPoints           #1#2{\edef#2{\tobigpoints     #1}}             % can be avoided
\permanent\protected\def\PointsToWholeBigPoints      #1#2{\edef#2{\towholebigpoints#1}}             % can be avoided
\permanent\protected\def\ScaledPointsToBigPoints     #1#2{\edef#2{\tobigpoints     #1\scaledpoint}} % obsolete
\permanent\protected\def\ScaledPointsToWholeBigPoints#1#2{\edef#2{\towholebigpoints#1\scaledpoint}} % obsolete

%D \macros
%D   {PointsToReal}
%D
%D Points can be stripped from their suffix by using \type {\withoutpt}. The next
%D macro enveloppes this macro.
%D
%D \starttyping
%D \PointsToReal {dimension} \target
%D \stoptyping

% \permanent\protected\def\PointsToReal#1#2{\edef#2{\thewithoutunit\dimexpr#1}}

\permanent\protected\def\PointsToReal#1#2{\edef#2{\toscaled#1}}

%D \macros
%D  {dontleavehmode}
%D
%D Sometimes when we enter a paragraph with some command, the first token gets the
%D whole first line. We can prevent this by saying:
%D
%D \starttyping
%D \dontleavehmode
%D \stoptyping
%D
%D This command is used in for instance the language module \type {lang-ini}. The
%D first version was:
%D
%D \starttyping
%D \def\dontleavehmode{\ifhmode\orelse\ifmmode\else$ $\fi}
%D \stoptyping
%D
%D Next, Taco came with a better alternative (using mathsurround):
%D
%D \starttyping
%D \def\dontleavehmode
%D   {\ifhmode\orelse\ifmmode\else
%D      {\mathsurround\zeropoint\everymath\emptytoks$ $}%
%D    \fi}
%D \stoptyping
%D
%D And finaly we got the following alternative, one that avoids interfering grouping
%D at the cost of a box.
%D
%D \starttyping
%D \newbox\b_syst_helpers_dlh
%D
%D \protected\def\dontleavehmode
%D   {\ifhmode\orelse\ifmmode\else
%D      \setbox\b_syst_helpers_dlh\hbox{\mathsurround\zeropoint\everymath\emptytoks$ $}\unhbox\b_syst_helpers_dlh
%D    \fi}
%D \stoptyping
%D
%D But, as we run a recent version of \TEX, we can use the new primitive:

% \untraced\aliased\let\dontleavehmode\quitvmode % defined in syst-ini.mkxl

%D \macros
%D   {utfupper, utflower, uppercasestring, lowercasestring}
%D
%D The names tell what they do:
%D
%D \starttyping
%D \uppercasestring somestring\to\somestring
%D \lowercasestring somestring\to\somestring
%D \stoptyping
%D
%D The first argument may be a \type{\macro}.
%D
%D These macros are sort of obsolete as we never use uppercase this way. But
%D nevertheless we provide them:

% Defined at the \LUA\ end (which saves us one step. I need to check the macro
% tables for more candidates):
%
% \permanent\def\utfupper#1{\clf_upper{#1}} % expandable
% \permanent\def\utflower#1{\clf_lower{#1}} % expandable
% \permanent\def\utfshape#1{\clf_shape{#1}} % expandable
% \permanent\def\utfstrip#1{\clf_strip{#1}} % expandable

% This are obsolete because we can just do an \type {\edef} and avoid the
% somewhat weird \type {\to} interface.

% \permanent\protected\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\clf_upper{#1}}}
% \permanent\protected\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\clf_lower{#1}}}

\permanent\protected\def\uppercasestring#1\to#2{\dodoglobal\edef#2{\utfupper{#1}}}
\permanent\protected\def\lowercasestring#1\to#2{\dodoglobal\edef#2{\utflower{#1}}}

%D \macros
%D   {handletokens}
%D
%D With the next macro we enter a critical area of macro expansion. What we want is
%D a macro that looks like:
%D
%D \starttyping
%D \handletokens some tokens\with \somemacro
%D \stoptyping
%D
%D A bonus example:
%D
%D \starttyping
%D \hbox{\handletokens tekst en meer tekst\with\ruledhbox}
%D
%D \def\weetikveel#1{\if#1\blankspace\space\else\ruledhbox{#1}\fi}
%D
%D \hbox{\handletokens tekst en meer tekst\with\weetikveel}
%D \stoptyping

%D \macros
%D   {counttoken,counttokens}
%D
%D For the few occasions that we want to know the number of specific tokens in a
%D string, we can use:
%D
%D \starttyping
%D \counttoken  token\in string\to \somecount
%D \counttokens          string\to \somecount
%D \stoptyping
%D
%D This macro, that for instance is used in \type {cont-tab}, takes a real counter.
%D The macro can be preceded by \type {\doglobal}.

\def\syst_helpers_count_token#1% obeys {}
  {\def\m_syst_string_three{#1}%
   \ifx\m_syst_string_two\m_syst_string_three \else
     \ifx\m_syst_string_one\m_syst_string_three
       \advanceby\privatescratchcounter\plusone
     \fi
     \expandafter\syst_helpers_count_token
   \fi}

\permanent\protected\def\counttoken#1\in#2\to#3%
  {\privatescratchcounter\zerocount
   \def\m_syst_string_one{#1}%
   \def\m_syst_string_two{\end}%
   \syst_helpers_count_token#2\end
   \dodoglobal#3\privatescratchcounter}

\permanent\protected\def\counttokens#1\to#2%
  {\privatescratchcounter\zerocount
   \def\syst_helpers_count_token##1{\advanceby\privatescratchcounter\plusone}%
   \handletokens#1\with\syst_helpers_count_token
   \dodoglobal#2\privatescratchcounter}

%D \macros
%D   {splitofftokens}
%D
%D Running this one not always gives the expected results. Consider for instance the
%D macro for which I originally wrote this token handler.

\let\syst_helpers_split_off_tokens\gobbleoneargument

\permanent\protected\def\splitofftokens#1\from#2\to#3% slow but hardly used
  {\ifnum#1>\zerocount
     \privatescratchcounter#1\relax
     \def\syst_helpers_split_off_tokens##1%
       {\ifnum\privatescratchcounter>\zerocount
          \advanceby\privatescratchcounter \minusone
          \edef#3{#3##1}%
        \fi}%
   % \lettonothing#3% #3 can be #2, so:
     \expandafter\let\expandafter#3\expandafter\empty
     \expandafter\handletokens#2\with\syst_helpers_split_off_tokens
   \else
     \edef#3{#2}%
   \fi}

%D This macro can be called like:
%D
%D \startbuffer[example]
%D \splitofftokens10\from01234567 890123456789\to\test [\test]
%D \stopbuffer
%D
%D up there. The reason for this is not that logical but follows from \TEX's
%D However, the characters that we expect to find in \type {\test} just don't show
%D sometimes mysterious way of expanding. Look at this:
%D
%D \startbuffer[next]
%D \def\next{a} \edef\test{\next}                                          [\test]
%D \let\next=b  \edef\test{\test\next}                                     [\test]
%D \let\next=c  \edef\test{\next}                                          [\test]
%D \let\next=d  \edef\test{\test\next}                                     [\test]
%D \let\next=e  \expandafter\edef\expandafter\test\expandafter{\test\next} [\test]
%D \stopbuffer
%D
%D \typebuffer[next]
%D
%D Careful reading shows that inside an \type {\edef} macro's that are \type {\let}
%D are not expanded!
%D
%D \unprotect\getbuffer[next]\protect
%D
%D That's why we finally end up with a macro that looks ahead by using an
%D assignment, this time by using \type {\futurelet}, and grabbing an argument as
%D well. That way we can handle the sentinal, a blank space and grouped tokens.

\mutable\lettonothing\nexthandledtoken % part of public interface

\let\syst_helpers_handle_tokens_command\relax

\protected\def\syst_helpers_handle_tokens
  {\futurelet\nexthandledtoken\syst_helpers_handle_tokens_indeed}

\permanent\protected\def\handletokens#1\with#2%
  {\gdef\syst_helpers_handle_tokens_command{#2}% permits more complex #2's
   \syst_helpers_handle_tokens#1\end}

\def\syst_helpers_handle_tokens_indeed
  {\ifx\nexthandledtoken\blankspace
     \expandafter\syst_helpers_handle_tokens_indeed_one
   \orelse\ifx\nexthandledtoken\end
     \expandafter\gobbletwoarguments % also gobble the \end
   \else
     \expandafter\syst_helpers_handle_tokens_indeed_two
   \fi *}

\def\syst_helpers_handle_tokens_indeed_one * %
  {\syst_helpers_handle_tokens_command{ }\syst_helpers_handle_tokens}

\def\syst_helpers_handle_tokens_indeed_two *#1%
  {\syst_helpers_handle_tokens_command{#1}\syst_helpers_handle_tokens}

%D This macro is tested on:
%D
%D \def\xxx#1{[#1]}
%D
%D \startlines
%D \handletokens         abc\with\xxx
%D \handletokens       a b c\with\xxx
%D \handletokens     a  b  c\with\xxx
%D \handletokens      a{bc}d\with\xxx
%D \handletokens a\space bc \with\xxx
%D \stoplines
%D
%D And our previous example shows up as:
%D
%D \getbuffer[example]

%D \macros
%D   {iftrialtypesetting, ifvisible}
%D
%D The next boolean is at first sight a strange one. Sometimes one does a trial
%D typesetting run, for instance to determine dimensions. Some mechanisms, like
%D object inclusion, can fail on such trials. Temporary setting the next boolean to
%D true, helps a lot. The second boolena can be used to inhibit processing
%D completely.

\newif\ifvisible \visibletrue

\newtoks\everysettrialtypesetting
\newtoks\everyresettrialtypesetting

\permanent\protected\def\settrialtypesetting  {\expand\everysettrialtypesetting  } % obeys grouping so
\permanent\protected\def\resettrialtypesetting{\expand\everyresettrialtypesetting} % this one is seldom needed

\aliased\let\iftrialtypesetting\iffalse % so we have no \trialtypesettingtrue|false in mkiv !

\appendtoks \enforced\aliased\let\iftrialtypesetting\iftrue  \to \everysettrialtypesetting
\appendtoks \enforced\aliased\let\iftrialtypesetting\iffalse \to \everyresettrialtypesetting

%D \macros
%D   {twodigitrounding}
%D
%D The next macro rounds a real number to two digits. They are probably no longer needed
%D but we keep them around for a while.

\permanent\def\integerrounding   #1{\clf_rounded\zerocount{#1}}
\permanent\def\onedigitrounding  #1{\clf_rounded\plusone  {#1}}
\permanent\def\twodigitrounding  #1{\clf_rounded\plustwo  {#1}}
\permanent\def\threedigitrounding#1{\clf_rounded\plusthree{#1}}

%D \macros
%D   {processcontent}
%D
%D This macro is first used in the tabulation macros.
%D
%D \starttyping
%D \protected\def\starthans%
%D   {\processcontent{stophans}\test{\message{\test}\wait}}
%D \stoptyping

% \starttabulate[|||]
%     \NC \type{#} \NC # \NC \NR
% \stoptabulate
%
% \def\test#1%
%   {\starttabulate[|||]
%      \NC \type{#1} \NC #1 \NC \NR
%    \stoptabulate}
%
% \test{!}

%% \permanent\protected\def\processcontent#1%
%%   {\begingroup\expandafter\syst_helpers_process_content\csname#1\endcsname}

\protected\def\syst_helpers_process_content#1#2#3%
  {\protected\def\syst_helpers_process_content##1#1%
     {\endgroup\def#2{##1}#3}%
   \syst_helpers_process_content}

\permanent\protected\def\processcontent#1%
  {\begingroup
   \catcode\hashasciicode\othercatcode
   \expandafter\syst_helpers_process_content\csname#1\endcsname}

%D \macros
%D   {dogobblesingleempty, dogobbledoubleempty}
%D
%D These two macros savely grab and dispose two arguments. We also have a few
%D private ones defined earlier.

\permanent\tolerant\protected\def\dogobbledoubleempty[#S#-]#*[#S#-]{}
\permanent\tolerant\protected\def\dogobblesingleempty        [#S#-]{}

\aliased\let\gobblesingleempty\dogobblesingleempty % also used
\aliased\let\gobbledoubleempty\dogobbledoubleempty % also used

%D \macros
%D   {setdimensionwithunit, freezedimensionwithunit}
%D
%D The next assignments are all valid:
%D
%D \starttyping
%D \setdimensionwithunit\scratchdimen{10}  {cm}
%D \setdimensionwithunit\scratchdimen{10cm}{cm}
%D \setdimensionwithunit\scratchdimen{10cm}{}
%D \freezedimensionwithunit\SomeWidth{\textwidth}
%D \freezedimensionwithunit\SomeDepth{\strutdp}
%D \stoptyping
%D
%D As an alternative for the next macro we can use a global assignment inside a box.
%D The \type {\empty}'s permits gobbling while preventing spurious \type {\relax}'s.

\permanent\protected\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick
  {\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty}

\permanent\protected\def\freezedimensionwithunit#1#2%
  {\setdimensionwithunit\privatescratchdimen#1{#2}\edef#1{\the\privatescratchdimen}}

%D \macros
%D   {doifsometokselse, doifsometoks}
%D
%D Not that fast I guess, but here's a way to test for token registers being empty.

\permanent\protected\def\doifelsesometoks#1%
  {\iftok#1\emptytoks
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

\permanent\protected\def\doifsometoks#1%
  {\iftok#1\emptytoks
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\protected\def\doifemptytoks#1%
  {\iftok#1\emptytoks
     \expandafter\firstofoneargument
   \else
     \expandafter\gobbleoneargument
   \fi}

\aliased\let\doifsometokselse\doifelsesometoks

%D \macros
%D   {startstrictinspectnextcharacter}
%D
%D This one is for the bibliography module (still?):

\let\syst_helpers_strict_inspect_next_character[

\def\syst_helpers_strict_inspect_next_character% no user macro !
  {\ifx\nexttoken[%
     \expandafter\m_syst_action_yes
   \else
     \expandafter\m_syst_action_nop
   \fi}

\permanent\protected\def\strictdoifelsenextoptional#1#2%
  {\def\m_syst_action_yes{#1}%
   \def\m_syst_action_nop{#2}%
   \futurelet\nexttoken\syst_helpers_strict_inspect_next_character}

\aliased\let\strictdoifnextoptionalelse\strictdoifelsenextoptional

%D \macros
%D   {gobblespacetokens}
%D
%D This macro needs a speed-up!

%\def\gobblespacetokens
%  {\doifnextcharelse\empty\donothing\donothing} % no {}\do\do !

\permanent\def\gobblespacetokens
  {\afterassignment\nexttoken\let\nexttoken=}

%D \macros
%D   {verbatimargument}
%D
%D As the name says, this macro converts its argument to a (rather safe) string.

\aliased\let\verbatimstring\detokenize

%D These are needed in ordinal number conversions:

\permanent\def\lastdigit#1%
  {\expandafter\thelastdigit\number#1\relax}

\permanent\def\thelastdigit#1#2%
  {\ifrelax#2#1\else\expandafter\thelastdigit\expandafter#2\fi}

\permanent\def\lasttwodigits#1%
  {\expandafter\thelasttwodigits\expandafter0\number#1\relax}

\permanent\def\thelasttwodigits#1#2#3% 0 dig ... \relax
  {\ifrelax#3#1#2\else\expandafter\thelasttwodigits\expandafter#2\expandafter#3\fi}

%D \macros
%D   {serializecommalist}
%D
%D Concatenate commalists:

\let\syst_helpers_serialize_comma_list_step\relax

\mutable\lettonothing\serializedcommalist

\def\syst_helpers_serialize_comma_list_step#1%
  {\edef\serializedcommalist{\serializedcommalist#1}}

\permanent\protected\def\serializecommalist[#1]%
  {\lettonothing\serializedcommalist
   \processcommacommand[#1]\syst_helpers_serialize_comma_list_step}

%D \macros
%D   {purenumber}
%D
%D Sometimes we need control over when \TEX\ stops reading a number, especially in
%D full expandable macros where using \type {\relax} would lead to disasters.
%D
%D \starttyping
%D \ifodd\purenumber{...}\space ... \else ... \fi
%D \stoptyping
%D
%D Here we use a space as number delimiter in combination with a space- and
%D relax-less \type {\purenumber}. This macro works ok with \type {\the}, \type
%D {\number} as well as \ETEX's \type {\numexpr}.

\permanent\def\purenumber#1{\expandafter\firstofoneargument\expandafter{\number#1}}

%D \macros
%D   {filterfromvalue, filterfromnext}
%D
%D \starttyping
%D \setvalue{xx}{{A}{B}{C}}
%D
%D \filterfromvalue{xx}{3}{3}
%D \filterfromvalue{xx}{3}{2}
%D \filterfromvalue{xx}{3}{1}
%D \stoptyping

% can be sped up with ignored arguments

\def\syst_filter_from_next_yes#1%
  {\advanceby\scratchcounterone\plusone
   \ifnum\scratchcounterone=\scratchcountertwo
     \scratchtoks{#1}%
   \fi
   \ifnum\scratchcounterone=\scratchcounterthree
     \expandafter\syst_filter_from_next_nop
   \else
     \expandafter\syst_filter_from_next_yes
   \fi}

\def\syst_filter_from_next_nop
  {\expandafter\endgroup
   \expandafter\endlocalcontrol
   \the\scratchtoks}

\permanent\def\filterfromnext#1#2% max n {..}{..}{..}{..}
  {\beginlocalcontrol
   \begingroup
   \scratchcounterone   \zerocount
   \scratchcountertwo   #2%
   \scratchcounterthree #1%
   \syst_filter_from_next_yes}

\permanent\def\filterfromvalue#1#2#3% max n {..}{..}{..}{..}
  {\beginlocalcontrol
   \begingroup
   \scratchcounterone   \zerocount
   \scratchcountertwo   #3%
   \scratchcounterthree #2%
   \expandafter\expandafter\expandafter\syst_filter_from_next_yes\csname#1\endcsname}

%D \macros
%D   {definemeasure}
%D
%D \starttyping
%D \definemeasure[mywidth][\dimexpr(\textwidth-1cm)]
%D
%D ... \measure{mywidth} ...
%D \stoptyping

\installsystemnamespace{measure}

\permanent\tolerant\protected\def\definemeasure[#1]#*[#2]{\defcsname \??measure#1\endcsname{#2}}
\permanent\tolerant\protected\def\freezemeasure[#1]#*[#2]{\edefcsname\??measure#1\endcsname{\todimension{#2}}}

\permanent\protected\def\setmeasure #1#2{\defcsname \??measure#1\endcsname{#2}}               % quick way
\permanent\protected\def\setgmeasure#1#2{\gdefcsname\??measure#1\endcsname{#2}}               % quick way
\permanent\protected\def\setemeasure#1#2{\edefcsname\??measure#1\endcsname{\todimension{#2}}} % quick way
\permanent\protected\def\setxmeasure#1#2{\xdefcsname\??measure#1\endcsname{\todimension{#2}}} % quick way

\permanent\def\measure #1{\todimension{\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi}}
\permanent\def\measured#1{\dimexpr    {\ifcsname\??measure#1\endcsname\lastnamedcs\else\zeropoint\fi}}

% #2 could be omitted, but we want to support spaces
%
% \setmeasure {x}  {1cm}
% \setmeasure {xx} {1cm}
% \setmeasure {xxx}{1cm}

%D \macros
%D   {definequantity}
%D
%D These do the same but for numbers.

\installsystemnamespace{quantity}

\permanent\tolerant\protected\def\definequantity[#1]#*[#2]{\defcsname \??quantity#1\endcsname{#2}}
\permanent\tolerant\protected\def\freezequantity[#1]#*[#2]{\edefcsname\??quantity#1\endcsname{\tointeger{#2}}}

\permanent\protected\def\setquantity #1#2{\defcsname \??quantity#1\endcsname{#2}}             % quick way
\permanent\protected\def\setgquantity#1#2{\gdefcsname\??quantity#1\endcsname{#2}}             % quick way
\permanent\protected\def\setequantity#1#2{\edefcsname\??quantity#1\endcsname{\tointeger{#2}}} % quick way
\permanent\protected\def\setxquantity#1#2{\xdefcsname\??quantity#1\endcsname{\tointeger{#2}}} % quick way

\permanent\def\quantity        {\the\quantitied}
\permanent\def\quantitied    #1{\numexpr\ifcsname\??quantity#1\endcsname\lastnamedcs\else\zeropoint\fi\relax}
\permanent\def\directquantity#1{\tointeger{#1}}

% let\quantified\quantitied

%D \macros
%D   {dividedsize}
%D
%D This one can be used inside a measure (used in m4all):
%D
%D \starttyping
%D \definemeasure[columnwidth][\dividebydsize\textwidth{1em}{3}]
%D \stoptyping

\permanent\def\dividebydsize#1#2#3% size gap n
  {\dimexpr
     \ifnum\dimexpr#1\relax>\plusone
       (\dimexpr#1\relax-\numexpr#3-\plusone\relax\dimexpr#2\relax)/#3\else#1%
     \fi
   \relax}

%D \macros
%D   {doifdimensionelse}
%D
%D This is a dirty one: we simply append a unit and discard it when needed. We no longer
%D use this in core code because we just use th econditional.

\permanent\def\doifelsedimension#1%
  {\ifchkdim#1\or % or \ifchkdimension
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifdimensionelse\doifelsedimension

%D Ok, here's another one, slower but seldom used. This one scans the text.
%D
%D \starttabulate[|Tc|Tc|]
%D \NC pt      \NC  \doifdimenstringelse     {pt}{yes}{no} \NC \NR
%D \NC 12pt    \NC  \doifdimenstringelse  {-12pt}{yes}{no} \NC \NR
%D \NC 1pt     \NC  \doifdimenstringelse    {1pt}{yes}{no} \NC \NR
%D \NC 12pt    \NC  \doifdimenstringelse   {12pt}{yes}{no} \NC \NR
%D \NC 12.0pt  \NC  \doifdimenstringelse {12.0pt}{yes}{no} \NC \NR
%D \NC -.12pt  \NC  \doifdimenstringelse {-.12pt}{yes}{no} \NC \NR
%D \NC .12pt   \NC  \doifdimenstringelse  {.12pt}{yes}{no} \NC \NR
%D \NC -12pt   \NC  \doifdimenstringelse  {-12pt}{yes}{no} \NC \NR
%D \NC -12.0pt \NC  \doifdimenstringelse{-12.0pt}{yes}{no} \NC \NR
%D \NC big     \NC  \doifdimenstringelse    {big}{yes}{no} \NC \NR
%D \NC 10      \NC  \doifdimenstringelse     {10}{yes}{no} \NC \NR
%D \NC 1       \NC  \doifdimenstringelse      {1}{yes}{no} \NC \NR
%D \stoptabulate

\aliased\let\doifelsedimenstring\doifelsedimension
\aliased\let\doifdimenstringelse\doifelsedimenstring

%D \macros
%D   {comparedimension,comparedimensioneps}
%D
%D We no longer use the \MKIV\ dirty trick. These are obsolete anyway.

\newdimension\roundingeps \roundingeps=10sp
\newconstant \compresult

\permanent\protected\def\comparedimension#1#2%
  {\compresult
     \ifcmpdim#1#2 % space wil be skipped
       \zerocount
     \or
       \plusone
     \else
       \plustwo
     \fi}

\permanent\protected\def\comparedimensioneps#1#2% todo: use eps feature
  {\compresult
     \ifabsdim{(#1)-(#2)}<\roundingeps
       \zerocount
     \orelse\ifdim{#1}<{#2}%
       \plusone
     \else
       \plustwo
     \fi}

% pretty ugly but fast

% \copycsname xxx\endcsname\csname ..\endcsname

\permanent\protected\def\copycsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter\csname}

% \letcscsname    \crap               \csname ..\endcsname
% \letcsnamecs    \csname ..\endcsname\crap
% \letcsnamecsname\csname ..\endcsname\csname ..\endcsname

\permanent\protected\def\letcscsname    {\expandafter\let\expandafter}
\permanent\protected\def\letcsnamecs    {\expandafter\let}
\permanent\protected\def\letcsnamecsname{\expandafter\expandafter\expandafter\let\expandafter\expandafter}

% Another one, add an item to a commalist, was only used in definesymbol

\permanent\protected\def\addvalue#1#2% cs item
  {\ifcsname#1\endcsname\else\letcsname#1\endcsname\empty\fi
   \expanded{\addtocommalist{#2}\expandafter\noexpand\csname#1\endcsname}}

%D Are these ever used? Anyway, these variants are somewhat more efficient than
%D the \MKIV variants for larger strings.

% A variant:
%
% \permanent\def\unspaced#1%
%   {\localcontrolled{\begingroup\catcode\spaceasciicode\ignorecatcode}%
%    \tokenized{#1}%
%    \localcontrolled{\endgroup}}
%
% but we can also do this:

\permanent\def\unspaced#1%
  {\tokenized \s!catcodetable \ctdcatcodes {#1}}

\permanent\protected\def\unspaceargument#1\to#2%
  {\edef#2{\tokenized \s!catcodetable \ctdcatcodes {#1}}}

\permanent\protected\def\unspaceafter#1#2%
  {\expandafter#1\expandafter{\tokenized \s!catcodetable \ctdcatcodes {#2}}}

\permanent\protected\def\doifelsehasspace#1%
  {\expandafter\ifhastok\space{#1}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifhasspaceelse\doifelsehasspace

% this will replace loadfile once and alike !!! todo

\installsystemnamespace{flag}

\permanent\protected\def\setflag  #1{\dodoglobal\letcsname\??flag#1\endcsname\zerocount}
\permanent\protected\def\resetflag#1{\dodoglobal\letcsname\??flag#1\endcsname\plusone}

\permanent\def\flag#1{\csname\??flag#1\endcsname}

\permanent\def\doifelseflagged#1%
  {\expandafter\ifrelax\csname\??flag#1\endcsname
     \expandafter\secondoftwoarguments
   \orelse\ifcase\csname\??flag#1\endcsname
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

\aliased\let\doifflaggedelse\doifelseflagged

\permanent\def\doifnotflagged#1%
  {\expandafter\ifrelax\csname\??flag#1\endcsname
     \expandafter\firstofoneargument
   \orelse\ifcase\csname\??flag#1\endcsname
     \expandafter\gobbleoneargument
   \else
     \expandafter\firstofoneargument
   \fi}

\permanent\protected\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey
  {\defcsname#1#3\expandafter\endcsname\expandafter{\csname#1#5\endcsname}}

\def\syst_helpers_if_non_zero_positive_else#1#2\end % #3#4%
  {\ifrelax#1%
     \ifcase\privatescratchcounter
       \endgroup
       \doubleexpandafter\secondoftwoarguments
     \else
       \endgroup
       \doubleexpandafter\firstoftwoarguments
     \fi
   \else
      \endgroup
      \expandafter\secondoftwoarguments
   \fi}

% used ?

\permanent\def\doifelsenonzeropositive#1%
  {\begingroup\afterassignment\syst_helpers_if_non_zero_positive_else\privatescratchcounter=0#1\relax\empty\end}

\aliased\let\doifnonzeropositiveelse\doifelsenonzeropositive

%D Some old|-|time favourites:

% \permanent\protected\def\dosetrawvalue #1#2#3{\defcsname #1#2\endcsname{#3}}
% \permanent\protected\def\dosetrawevalue#1#2#3{\edefcsname#1#2\endcsname{#3}}
% \permanent\protected\def\dosetrawgvalue#1#2#3{\gdefcsname#1#2\endcsname{#3}}
% \permanent\protected\def\dosetrawxvalue#1#2#3{\xdefcsname#1#2\endcsname{#3}}
%
% \permanent\protected\def\getrawparameters      {\dogetparameters\dosetrawvalue }
% \permanent\protected\def\getraweparameters     {\dogetparameters\dosetrawevalue}
% \permanent\protected\def\getrawgparameters     {\dogetparameters\dosetrawgvalue}
% \permanent\protected\def\getrawxparameters     {\dogetparameters\dosetrawxvalue}
%
% \permanent\protected\def\globalgetrawparameters{\dogetparameters\dosetrawgvalue} % obsolete

\aliased\let\getrawparameters \getparameters  % obsolete
\aliased\let\getraweparameters\geteparameters % obsolete
\aliased\let\getrawgparameters\getgparameters % obsolete
\aliased\let\getrawxparameters\getxparameters % obsolete

%D Sort of obsolete:

\newinteger\c_syst_helpers_mod

\permanent\protected\def\dosetmodulo#1#2#3%
  {\c_syst_helpers_mod#1\divideby\c_syst_helpers_mod#2\multiplyby\c_syst_helpers_mod#2%
   #3#1\advanceby#3-\c_syst_helpers_mod}

\permanent\protected\def\dosetdivision#1#2#3%
  {#3#1\divideby#3 #2\relax}

\permanent\protected\def\DoMod#1by#2to#3{\dosetmodulo  {#1}{#2}{#3}}
\permanent\protected\def\DoDiv#1by#2to#3{\dosetdivision{#1}{#2}{#3}}

%D This is obsolete, just use \type {\unprotect} and \type {\protect} instead.

% \def\syst_helpers_unprotected#1\par
%   {#1\protect}
%
% \permanent\protected\def\unprotected
%   {\unprotect
%    \syst_helpers_unprotected}

\aliased\let\resettimer    \clf_resettimer  % todo: at lua end
\aliased\let\elapsedtime   \clf_elapsedtime % todo: at lua end
\aliased\let\elapsedseconds\elapsedtime

\aliased\let\elapsedsteps\!!zerocount

\permanent\protected\def\elapsedsteptime % unexpanded ! a bit useless but who knows ...
  {\clf_elapsedsteptime\elapsedsteps\relax}

\newinteger\c_syst_helpers_test_feature_n
\newinteger\c_syst_helpers_test_feature_m

\let\syst_helpers_test_feature_yes\relax
\let\syst_helpers_test_feature_nop\relax

\permanent\def\currentfeaturetest{\the\c_syst_helpers_test_feature_n}

\permanent\protected\def\testfeature#1#2%
  {\c_syst_helpers_test_feature_m\ifparameter#1\or#1\else\maxiterator\fi\relax
   \enforced\xdef\elapsedsteps{\the\c_syst_helpers_test_feature_m}%
   \def\syst_helpers_test_feature_yes
     {\advanceby\c_syst_helpers_test_feature_n\plusone
      \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
        #2\expandafter\syst_helpers_test_feature_yes
      \fi}%
   \def\syst_helpers_test_feature_nop
     {\advanceby\c_syst_helpers_test_feature_n\plusone
      \ifnum\c_syst_helpers_test_feature_n>\c_syst_helpers_test_feature_m\else
        \expandafter\syst_helpers_test_feature_nop
      \fi}%
   \retestfeature}

\permanent\protected\def\retestfeature % timer support is new per 10/5/2005
  {\bgroup
   \ifcase\interactionmode\enforced\let\wait\relax\fi
   \clf_resettimer
   \c_syst_helpers_test_feature_n\zerocount
   \syst_helpers_test_feature_nop
   \clf_benchmarktimer
   \writestatus\m!system
     {starting feature test: %
      \the\c_syst_helpers_test_feature_m\space steps}%
   \c_syst_helpers_test_feature_n\zerocount
   \syst_helpers_test_feature_yes
   \writestatus\m!system
     {feature test done: %
      \the\c_syst_helpers_test_feature_m\space steps, %
      \clf_elapsedtime\space seconds, %
      \clf_elapsedsteptime\elapsedsteps\space\space per step}%
   \egroup}

\permanent\protected\def\showtimer#1%
  {\writestatus{runtime}{\elapsedseconds\space s / #1}}

\permanent\protected\def\testfeatureonce#1#2%
  {\begingroup
   \enforced\let\wait\relax
   \testfeature{#1}{#2}%
   \endgroup}

%D \macros
%D   {freezedimenmacro}
%D
%D This macro is use as:
%D
%D \starttyping
%D \freezedimenmacro\leftmargindistance
%D \stoptyping

\permanent\protected\def\freezedimenmacro#1%
  {\edef#1{\todimension{#1}}}

%D The next macro negates a macro (dimension or number, or actually, whatever. It's
%D a typical example of \type {\if} usage:
%D
%D \starttyping
%D \if-\whatever \else-\whatever\fi => else => -whatever
%D \if--\whatever\else-\whatever\fi => then =>  whatever
%D \stoptyping
%D
%D Do we still need this? If not it will go away:

\permanent\def\negated#1{\if-#1\else-#1\fi} % does only work in macros or text

% \def\gobbleassigndimen#1\\{}
%
% \permanent\def\assigndimen#1#2%
%   {\afterassignment\gobbleassigndimen#1=#2\zeropoint\\}

%D Maybe ... toksapp should deal with this ...

\permanent\protected\def\appendvalue#1#2%
  {\edefcsname#1\endcsname{%
     \notexpanded\expandafter\expandafter\expandafter{\begincsname#1\endcsname}%
     \notexpanded{#2}}}

\permanent\protected\def\prependvalue#1#2%
  {\edefcsname#1\endcsname{%
     \notexpanded{#2}%
     \notexpanded\expandafter\expandafter\expandafter{\begincsname#1\endcsname}}}

\permanent\protected\def\appendgvalue #1#2{\global\appendvalue}
\permanent\protected\def\prependgvalue#1#2{\global\prependvalue}

%D \macros
%D   {dowithrange}
%D
%D This one is for Mojca Miklavec, who made me aware of the fact that \type
%D {page-imp.tex} was not the best place to hide it.
%D
%D \startbuffer
%D \def\DoSomething#1{ [item #1] }
%D
%D \processranges[1,4:5]\DoSomething \par
%D \dowithrange  {1,4:5}\DoSomething \par
%D \stopbuffer
%D
%D \typebuffer \blank \getbuffer \blank

%D We have a better splitter at the \LUA\ end.

\integerdef\c_helpers_range_min    \zerocount
\integerdef\c_helpers_range_max    \zerocount
\integerdef\c_helpers_range_abs_min\zerocount
\integerdef\c_helpers_range_abs_max\zerocount

\lettonothing\m_syst_helpers_range_action
\lettonothing\m_syst_helpers_range_from
\lettonothing\m_syst_helpers_range_to

\def\syst_helpers_with_range#1%
  {\splitstring#1\at:\to\m_syst_helpers_range_from\and\m_syst_helpers_range_to
   \ifx\m_syst_helpers_range_from\wildcardsymbol
     \edef\m_syst_helpers_range_from{\number\c_helpers_range_min}%
   \fi
   \ifx\m_syst_helpers_range_to\wildcardsymbol
     \edef\m_syst_helpers_range_to{\number\c_helpers_range_max}%
   \fi
   \ifempty\m_syst_helpers_range_to
     \let\m_syst_helpers_range_to\m_syst_helpers_range_from
   \fi
   \dostepwiserecurse\m_syst_helpers_range_from\m_syst_helpers_range_to\plusone{\m_syst_helpers_range_action{##1}}}%

\permanent\protected\def\processranges[#1]#2% #1= n:m,p,q:r
  {\def\m_syst_helpers_range_action{#2}%
   \integerdef\c_helpers_range_min\zerocount
   \integerdef\c_helpers_range_max\zerocount
   \processcommacommand[#1]\syst_helpers_with_range}

\permanent\protected\def\dowithrange#1#2% set action
  {\def\m_syst_helpers_range_action{#2}%
   \integerdef\c_helpers_range_min\zerocount
   \integerdef\c_helpers_range_max\zerocount
   \processcommacommand[#1]\syst_helpers_with_range}

\permanent\protected\def\dowithminmaxrange#1#2#3#4% min max set action
  {\def\m_syst_helpers_range_action{#4}%
   \integerdef\c_helpers_range_min#1\relax
   \integerdef\c_helpers_range_max#2\relax
   \processcommacommand[#3]\syst_helpers_with_range}

% todo: use the helper that we made in lua (sets)

\def\syst_helpers_with_range_slice#1%
  {\splitstring#1\at:\to\m_syst_helpers_range_from\and\m_syst_helpers_range_to
   \ifx\m_syst_helpers_range_from\wildcardsymbol
     \edef\m_syst_helpers_range_from{\number\c_helpers_range_min}%
   \fi
   \ifx\m_syst_helpers_range_to\wildcardsymbol
     \edef\m_syst_helpers_range_to{\number\c_helpers_range_max}%
   \fi
   \ifempty\m_syst_helpers_range_to
     \let\m_syst_helpers_range_to\m_syst_helpers_range_from
   \fi
   \ifnum\m_syst_helpers_range_from<\zerocount
     \dostepwiserecurse
       \m_syst_helpers_range_from
       \m_syst_helpers_range_to
       {\ifnum\m_syst_helpers_range_from>\m_syst_helpers_range_to\minusone\else\plusone\fi}%
       {%(\the\numexpr\c_helpers_range_abs_max+##1+\plusone\relax)
        \m_syst_helpers_range_action{\tointeger{\c_helpers_range_abs_max+##1+\plusone}}}%
   \else
     \dostepwiserecurse
       \m_syst_helpers_range_from
       \m_syst_helpers_range_to
       {\ifnum\m_syst_helpers_range_from>\m_syst_helpers_range_to\minusone\else\plusone\fi}
       {%(\the\numexpr\c_helpers_range_abs_min+##1-\plusone\relax)
        \m_syst_helpers_range_action{\tointeger{\c_helpers_range_abs_min+##1-\plusone}}}%
   \fi}

\permanent\protected\def\dowithminmaxrangeslice#1#2#3#4#5#6% absmin absmax min max set action
  {\def\m_syst_helpers_range_action{#6}%
   \integerdef\c_helpers_range_abs_min#1\relax
   \integerdef\c_helpers_range_abs_max#2\relax
   \integerdef\c_helpers_range_min    #3\relax
   \integerdef\c_helpers_range_max    #4\relax
   \processcommacommand[#5]\syst_helpers_with_range_slice}

% \def\DoSomething#1{ [item #1] }
% \dowithrange[1,4:5]\DoSomething

%D \macros
%D   {ignoreimplicitspaces}
%D
%D \startbuffer
%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignorespaces}
%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignoreimplicitspaces}
%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
%D \stopbuffer
%D
%D \typebuffer \getbuffer

\permanent\protected\def\ignoreimplicitspaces
  {\doifelsenextchar\relax\relax\relax}

% %D \macros
% %D   {processwords}
% %D
% %D Not that sophisticated but sometimes users (like in metafun).
%
% %D This will be overloaded.
%
% \def\syst_helpers_process_word#1 #2\s!e_o_t_token
%   {\doifsomething{#1}{\processword{#1} \syst_helpers_process_word#2 \s!e_o_t_token}}
%
% \def\processwords#1%
%   {\syst_helpers_process_word#1 \s!e_o_t_token}% no \unskip
%
% \let\processword\relax

%D \macros
%D   {startnointerference}
%D
%D \starttyping
%D \startnointerference
%D all kind of code
%D \stopnointerference
%D \stoptyping

\newbox\b_syst_helpers_no_interference

\permanent\protected\def\startnointerference % not even grouped !
  {\setbox\b_syst_helpers_no_interference\vbox
   \bgroup}

\permanent\protected\def\stopnointerference
  {\egroup
   \setbox\b_syst_helpers_no_interference\emptybox}

%D A variant for \type {\executeifdefined}:

\permanent\def\expandcheckedcsname#1#2% #2 is often a \xxxparameter  so let's expand it once
  {\expanded{\noexpand\syst_helpers_expand_checked_csname{#1}{#2}}}

\def\syst_helpers_expand_checked_csname#1#2#3%
  {\csname#1\ifcsname#1#2\endcsname#2\else#3\fi\endcsname}

%D Signal. Some fonts have a char0 rendering so we need to make sure that it is not
%D set in the font! (This will be overloaded)

\protected\def\signalcharacter{\char\zerocount} % overloaded in spac-ver !

% %D A few secial variants of commands defined here. Some more will be moved here
% %D e.g.from the table modules. This code is no longer needed.
%
% \permanent\def\dodirectdoubleempty#1#2% used in math (lookahead issues)
%   {\ifx#2[%
%      \expandafter\syst_helpers_direct_double_empty_one_yes
%    \else
%      \expandafter\syst_helpers_direct_double_empty_one_nop
%    \fi#1#2}
%
% \def\syst_helpers_direct_double_empty_one_yes#1[#2]#3%
%   {\ifx#3[\else\expandafter\syst_helpers_direct_double_empty_two_nop\fi#1[#2]#3}
%
% \def\syst_helpers_direct_double_empty_one_nop#1{#1[][]}
% \def\syst_helpers_direct_double_empty_two_nop#1[#2]{#1[#2][]}

% %D Used in math definitions (in an \type {\edef}). This will be replaced.
% %D
% %D \startbuffer
% %D [\docheckedpair{}]
% %D [\docheckedpair{a}]
% %D [\docheckedpair{a,b}]
% %D [\docheckedpair{a,b,c}]
% %D \stopbuffer
% %D
% %D \typebuffer \startlines \getbuffer \stoplines
%
% \permanent\def\docheckedpair#1%
%   {\syst_helpers_checked_pair#1,,\s!e_o_t_token}
%
% \def\syst_helpers_checked_pair#1,#2,#-\s!e_o_t_token
%   {#1,#2}

%D Here are some nasty helpers. They can be used to fill often expanded token
%D lists efficiently (see tabulate for an example).

\permanent\def\constantnumber#1%
  {\ifcase#1\zerocount
   \or      \plusone
   \or      \plustwo
   \or      \plusthree
   \or      \plusfour
   \or      \plusfive
   \or      \plussix
   \or      \plusseven
   \or      \pluseight
   \or      \plusnine
   \or      \plusten
   \else    \number#1\relax\fi}

\permanent\def\constantnumberargument#1%
  {\ifcase#1\zerocount
   \or      \plusone
   \or      \plustwo
   \or      \plusthree
   \or      \plusfour
   \or      \plusfive
   \or      \plussix
   \or      \plusseven
   \or      \pluseight
   \or      \plusnine
   \or      \plusten
   \else    {\number#1}\fi}

% \permanent\def\constantdimen#1% takes register
%   {\ifdim#1=\zeropoint
%      \zeropoint
%    \else
%      \the#1\relax
%    \fi}

\permanent\def\constantdimen#1% takes register
  {\ifzeropt#1\norelax
     \zeropoint
   \else
     \todimension#1\norelax
   \fi}

% \permanent\def\constantdimenargument#1% takes register
%   {\ifdim#1=\zeropoint
%      \zeropoint
%    \else
%      {\the#1}%
%    \fi}

\permanent\def\constantdimenargument#1%
  {\ifzeropt#1%\norelax
     \zeropoint
   \else
     {\todimension#1}%
   \fi}

\permanent\def\constantemptyargument#1%
  {\ifempty#1%
     \noexpand\empty
   \else
     {#1}%
   \fi}

%D \macros
%D   {getsubstring}
%D \startbuffer
%D
%D \getsubstring{4}{}{Who Wants This}
%D \getsubstring{4}{9}{Who Wants This}
%D \getsubstring{9}{-2}{Who Wants This}
%D \getsubstring{1}{5}{Who Wants This}
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlines
%D \getbuffer
%D \stoplines

% expandable:

\permanent\def\getsubstring#1#2#3{\clf_getsubstring{#3}{#1}{#2}}

%D Other dimensions than pt (used in mb-mp)

\permanent\def\converteddimen#1#2{\clf_converteddimen{#1}{#2}}

%D Maybe (looks ugly):
%D
%D \starttyping
%D \doifcase {foo}
%D     {bar}     {BAR}
%D     {foo}     {FOO}
%D     {default} {DEFAULT}
%D
%D \doifcase {foo}
%D     {bar}     {BAR}
%D     {foo}     {\doifcase {bar}
%D                     {bar}     {BAR}
%D                     {foo}     {FOO}
%D                     {default} {DEFAULT}
%D               }
%D     {default} {DEFAULT}
%D \stoptyping

% \doifcase {\btxfoundname{author}}
%     {author}  {\btxflush{author}}
%     {editor}  {\texdefinition{btx:apa:editor-or-editors}}
%     {title}   {\texdefinition{btx:apa:title-subtitle-type}}
%     {default} {\btxflush{author}}

% \protected\def\doifcase#1%
%   {\edef\m_case_asked{#1}%
%    \syst_aux_case}
%
% \def\syst_aux_case#1%
%   {\edef\m_case_temp{#1}%
%    \ifx\m_case_temp\m_case_asked
%       \expandafter\syst_aux_case_yes
%    \orelse\ifx\m_case_temp\s!default
%       \expandafter\firstofoneargument
%    \else
%       \expandafter\syst_aux_case_nop
%    \fi}
%
% \def\syst_aux_skip#1#2%
%   {\edef\m_case_temp{#1}%
%    \ifx\m_case_temp\s!default
%      \expandafter\syst_aux_done
%    \else
%      \expandafter\syst_aux_skip
%    \fi}
%
% \def\syst_aux_case_yes#1%
%   {\def\syst_aux_done{#1}%
%    \syst_aux_skip}
%
% \def\syst_aux_case_nop#1%
%   {\syst_aux_case}

%D \macros
%D   {ntimes}
%D
%D some repetition:
%D
%D \startbuffer
%D \ntimes{*}{20}
%D \stopbuffer
%D
%D \typebuffer \blank gives: \getbuffer \blank
%D
%D This is not real fast but quite okay:

%def\ntimes#1#2{\ifnum#2>\zerocount#1\ntimes{#1}{\numexpr#2-\plusone\relax}\fi} % 1.72
\permanent\def\ntimes#1#2{\clf_ntimes{#1}{#2}}                                  % 0.33

%D Experiment (sometimes looks nicer in code):

\permanent\protected\def\sameargumentscondition#1#2%
  {\edef\m_syst_string_one{#1}%
   \edef\m_syst_string_two{#2}%
   \ifx\m_syst_string_one\m_syst_string_two}

\permanent\protected\def\emptyargumentcondition#1%
  {\edef\m_syst_string_one{#1}%
   \ifempty\m_syst_string_one}

%D New (also serves as an example):
%D
%D \starttyping
%D \commandflags\defineframed
%D \stoptyping

\permanent\def\commandflags#1%
  {\beginlocalcontrol\begingroup\scratchtoks\emptytoks\donefalse
     \ifflags#1=   \frozenflagcode\etoksapp\scratchtoks{\ifdone \space\fi    frozen}\donetrue\fi
     \ifflags#1=\permanentflagcode\etoksapp\scratchtoks{\ifdone \space\fi permanent}\donetrue\fi
     \ifflags#1=\immutableflagcode\etoksapp\scratchtoks{\ifdone \space\fi immutable}\donetrue\fi
     \ifflags#1=\primitiveflagcode\etoksapp\scratchtoks{\ifdone \space\fi primitive}\donetrue\fi
     \ifflags#1=  \mutableflagcode\etoksapp\scratchtoks{\ifdone \space\fi   mutable}\donetrue\fi
     \ifflags#1=\noalignedflagcode\etoksapp\scratchtoks{\ifdone \space\fi noaligned}\donetrue\fi
     \ifflags#1= \instanceflagcode\etoksapp\scratchtoks{\ifdone \space\fi  instance}\donetrue\fi
    %\ifflags#1= \reservedflagcode\etoksapp\scratchtoks{\ifdone \space\fi  reserved}\donetrue\fi
     \ifflags#1= \tolerantflagcode\etoksapp\scratchtoks{\ifdone \space\fi  tolerant}\donetrue\fi
     \ifflags#1=\protectedflagcode\etoksapp\scratchtoks{\ifdone \space\fi protected}\donetrue\fi
   \expandafter\endgroup\expandafter\endlocalcontrol\the\scratchtoks}

%D \macros
%D   {resetmacros}
%D
%D The next macro can be used to reset a macro:
%D
%D \starttyping
%D \resetmacros[startfoo,\stopfoo]
%D \stoptyping

\permanent\protected\def\syst_reset_macro#1%
  {\overloaded\letcsname\csstring#1\endcsname\undefined} % so only frozen (instances(

\permanent\protected\def\resetmacros[#1]%
  {\processcommalist[#1]\syst_reset_macro}

%D These demos are for hvdm who needs ways to manipulate arguments but
%D in a fully expandable way (some explanation is given in the low level
%D expansion manual).
%D
%D \startbuffer
%D \edef\xxx{[\wipetokens {123}{abc123abc123abc123abc123abc}]}1 : \meaningless\xxx\par
%D \edef\xxx{[\wipetokens {123}{abc}]}                        2 : \meaningless\xxx\par
%D \edef\xxx{[\wipetokens {123}{123}]}                        3 : \meaningless\xxx\par
%D \edef\xxx{[\wipetokens {123}{123123}]}                     4 : \meaningless\xxx\par
%D \edef\xxx{[\wipetokens {123}{}]}                           5 : \meaningless\xxx\par
%D \edef\xxx{[\wipetokens {}{123}]}                           6 : \meaningless\xxx\par
%D \edef\xxx{[\wipetokens {\relax}{1\relax2\relax3}]}         7 : \meaningless\xxx\par
%D \edef\xxx{[\wipetokens {1}{1{2}3}]}                        8 : \meaningless\xxx\par
%D \edef\xxx{[\wipedtokens{{1}}{{1}23}]}                      9 : \meaningless\xxx\par
%D \edef\xxx{[\wipedtokens{{1}}{123}]}                        0 : \meaningless\xxx\par
%D \stopbuffer
%D
%D \typebuffer \startpacked \getbuffer \stoppacked

\lettonothing\syst_helpers_wipe_tokens_yes

\def\syst_helpers_wipe_tokens_nop#-^^04{}%

\permanent\def\wipetokens#1#2%
  {\beginlocalcontrol
   \tolerant\def\syst_helpers_wipe_tokens_yes##1#1##2^^04%
     {##1%
      \ifparameter##2\or
        \expandafter\syst_helpers_wipe_tokens_yes
      \else
        \expandafter\syst_helpers_wipe_tokens_nop
      \fi
      ##2^^04}%
   \endlocalcontrol
   \syst_helpers_wipe_tokens_yes#2#1^^04}

\permanent\def\wipedtokens#1#2%
  {\tokenized{\expanded{\noexpand\wipetokens{\detokenize{#1}}{\detokenize{#2}}}}}

%D \startbuffer
%D                \def\abc{abc}
%D \semiprotected \def\xyz{xyz}
%D               \edef\pqr{\expandtoken\notcatcodes`p%
%D                         \expandtoken\notcatcodes`q%
%D                         \expandtoken\notcatcodes`r}
%D
%D 1: \ifcondition\similartokens{abc} {def}YES\else NOP\fi (NOP) \quad
%D 2: \ifcondition\similartokens{abc}{\abc}YES\else NOP\fi (YES)
%D
%D 3: \ifcondition\similartokens{xyz} {pqr}YES\else NOP\fi (NOP) \quad
%D 4: \ifcondition\similartokens{xyz}{\xyz}YES\else NOP\fi (YES)
%D
%D 5: \ifcondition\similartokens{pqr} {pqr}YES\else NOP\fi (YES) \quad
%D 6: \ifcondition\similartokens{pqr}{\pqr}YES\else NOP\fi (YES)
%D \stopbuffer
%D
%D \typebuffer \startpacked \getbuffer \stoppacked

\permanent\protected\def\similartokens#1#2%
 %{\expanded{\noexpand\iftok{\noexpand\detokenize{#1}}{\noexpand\detokenize{#2}}}}
  {\semiexpanded{\noexpand\iftok{\noexpand\detokenize{#1}}{\noexpand\detokenize{#2}}}}

\permanent\protected\def\doifelsesimilartokens#1#2%
  {\ifcondition\similartokens{#1}{#2}%
     \expandafter\firstoftwoarguments
   \else
     \expandafter\secondoftwoarguments
   \fi}

%D This one is used in math-frc so don't change it

\untraced\permanent\protected\def\glyphscaled#1% name will change
  {\dimexpr#1*\plusthousand/\glyphscale\relax}

%D \macros {nologbuffering, linebuffering}
%D
%D This saves one sec on luametatex manual in console. And in the case of an error
%D no buffering will make sure what is cached gets flushed too. We define these two
%D at the LUA end: \typ {\nologbuffering} and \typ {\linebuffering}.

% maybe:
%
% \tolerant\def\foo[#1]{}  \avoidarguments\foo[test]
%
% \permanent\protected\untraced\def\avoidarguments#1{#1\noarguments}

\protect \endinput
