% \iffalse meta-comment
%
% File: expkv.dtx Copyright (C) 2020-2023 Jonathan P. Spratte
%
% This work  may be  distributed and/or  modified under  the conditions  of the
% LaTeX Project Public License (LPPL),  either version 1.3c  of this license or
% (at your option) any later version.  The latest version of this license is in
% the file:
%
%   http://www.latex-project.org/lppl.txt
%
% ------------------------------------------------------------------------------
%
%<*driver>^^A>>=
\def\expkvDocNoGenerate{}
\input expkv-bundle.ins
\generate{\file{expkv.sty}{\from{expkv.dtx}{pkg}}}
\generate{\file{expkv.tex}{\from{expkv.dtx}{tex}}}
\generate{\file{t-expkv.tex}{\from{expkv.dtx}{ctx}}}
\endbatchfile
%</driver>^^A=<<
% \fi
%
% \section{\expkv}
%^^A the LaTeX package >>=
% \subsection{The \LaTeX\ Package}
% First we set up the \LaTeX\ package. That one doesn't really do much except
% |\input|ting the generic code and identifying itself as a package. Additional
% an |all| option is declared to load all the sub modules in one go.
% \gobbledocstriptag
%<*pkg>
%    \begin{macrocode}
\def\ekv@tmp
  {%
    \ProvidesFile{expkv.tex}%
      [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]%
  }
\input{expkv.tex}
\ProvidesPackage{expkv}%
  [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]
\let\ekv@tmp\@empty
\DeclareOption{all}
  {%
    \def\ekv@tmp
      {\RequirePackage{expkv-pop,expkv-cs,expkv-def,expkv-opt}}%
  }
\ProcessOptions\relax
\ekv@tmp
%    \end{macrocode}
% \gobbledocstriptag
%</pkg>
%^^A=<<
%^^A the ConTeXt module >>=
% \subsection{The \ConTeXt\ module}
% This is pretty straight forward, we just have to change the error throwing
% mechanism for \ConTeXt\ (the approach taken for plain and \LaTeX\ breaks in
% \ConTeXt, effectively breaking \ConTeXt, dropping you in an interactive \TeX\
% session with almost no means of escape).
% \gobbledocstriptag
%<*ctx>
%    \begin{macrocode}
\writestatus{loading}{ConTeXt User Module / expkv}
\unprotect
\input expkv.tex
\long\def\ekv@err@collect#1\par#2%
  {\directlua{tex.error[[\detokenize{#2} Error: #1]]}}
\writestatus{loading}
  {ConTeXt User Module / expkv / Version \ekvVersion\space loaded}
\protect\endinput
%    \end{macrocode}
% \gobbledocstriptag
%</ctx>
%^^A=<<
%^^A main file >>=
% \subsection{The Generic Code}
% The rest of this implementation will be the generic code.
% \gobbledocstriptag
%<*tex>
%
% We make sure that it's only input once:
%    \begin{macrocode}
\expandafter\ifx\csname ekvVersion\endcsname\relax
\else
  \expandafter\endinput
\fi
%    \end{macrocode}
%
% Check whether \eTeX\ and |\expanded| are available -- \expkv\ requires \eTeX.
%    \begin{macrocode}
\begingroup
  \edef\ekvtmpa{\string\expanded}
  \edef\ekvtmpb{\meaning\expanded}
  \expandafter
\endgroup
\ifx\ekvtmpa\ekvtmpb
  \expandafter\let\csname ekv@expanded\endcsname\expanded
  \expandafter\let\csname ekv@unexpanded\endcsname\unexpanded
\else
  \begingroup
    \edef\ekvtmpa{\string\expanded}
    \edef\ekvtmpb{\meaning\normalexpanded}
    \expandafter
  \endgroup
  \ifx\ekvtmpa\ekvtmpb
    \expandafter\let\csname ekv@expanded\endcsname\normalexpanded
    \expandafter\let\csname ekv@unexpanded\endcsname\normalunexpanded
  \else
    \errmessage
      {expkv Error: e-TeX and the \noexpand\expanded primitive required}%
    \expandafter\endinput
  \fi
\fi
%    \end{macrocode}
%
% \begin{macro}{\ekvVersion,\ekvDate}
% We're on our first input, so lets store the version and date in a macro.
%    \begin{macrocode}
\def\ekvVersion{2.0}
\def\ekvDate{2023-01-23}
%    \end{macrocode}
% \end{macro}
%
% If the \LaTeX\ format is loaded we want to be a good file and report back who
% we are, for this the package will have defined |\ekv@tmp| to use
% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
%    \begin{macrocode}
\csname ekv@tmp\endcsname
%    \end{macrocode}
%
% Store the category code of |@| to later be able to reset it and change it to
% 11 for now.
%    \begin{macrocode}
\expandafter\chardef\csname ekv@tmp\endcsname=\catcode`\@
\catcode`\@=11
%    \end{macrocode}
% |\ekv@tmp| might later be reused to gobble any prefixes which might be
% provided to |\ekvdef| and similar in case the names are invalid, we just
% temporarily use it here as means to store the current category code of |@| to
% restore it at the end of the file, we never care for the actual definition of
% it.
%
% \begin{macro}[internal]{\ekv@if@lastnamedcs}
% If the primitive |\lastnamedcs| is available, we can be a bit faster than
% without it. So we test for this and save the test's result in this macro.
%    \begin{macrocode}
\begingroup
  \edef\ekv@tmpa{\string \lastnamedcs}
  \edef\ekv@tmpb{\meaning\lastnamedcs}
  \ifx\ekv@tmpa\ekv@tmpb
    \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##1}}
  \else
    \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##2}}
  \fi
  \expandafter
\endgroup
\ekv@if@lastnamedcs
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@empty}
% Sometimes we have to introduce a token to prevent accidental brace stripping.
% This token would then need to be removed by |\@gobble| or similar. Instead we
% can use |\ekv@empty| which will just expand to nothing, that is faster than
% gobbling an argument.
%    \begin{macrocode}
\def\ekv@empty{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \@gobble,\@gobbletwo,\@gobblethree,
%     \@firstofone,\@firstoftwo,\@secondoftwo,
%     \ekv@fi@gobble,\ekv@fi@firstofone,\ekv@fi@firstoftwo,\ekv@fi@secondoftwo,
%     \ekv@gobble@mark,\ekv@gobbleto@stop,\ekv@gobble@from@mark@to@stop
%   }
% Since branching tests are often more versatile than |\if...\else...\fi|
% constructs, we define helpers that are branching pretty fast. Also here are
% some other utility functions that just grab some tokens. The ones that are
% also contained in \LaTeX\ don't use the |ekv| prefix. Not all of the ones
% defined here are really needed by \expkv\ but are provided because packages
% like \expkvd\ or \expkvo\ need them (and I don't want to define them in each
% package which might need them).
%    \begin{macrocode}
\long\def\@gobble#1{}
\long\def\@gobbletwo#1#2{}
\long\def\@gobblethree#1#2#3{}
\long\def\@firstofone#1{#1}
\long\def\@firstoftwo#1#2{#1}
\long\def\@secondoftwo#1#2{#2}
\long\def\ekv@fi@gobble\fi\@firstofone#1{\fi}
\long\def\ekv@fi@firstofone\fi\@gobble#1{\fi#1}
\long\def\ekv@fi@firstoftwo\fi\@secondoftwo#1#2{\fi#1}
\long\def\ekv@fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2}
\def\ekv@gobble@mark\ekv@mark{}
\long\def\ekv@gobbleto@stop#1\ekv@stop{}
\long\def\ekv@gobble@from@mark@to@stop\ekv@mark#1\ekv@stop{}
%    \end{macrocode}
% \end{macro}
% As you can see |\ekv@gobbleto@stop| uses a special marker |\ekv@stop|. The
% package will use three such markers, the one you've seen already, |\ekv@mark|
% and |\ekv@nil|. Contrarily to how for instance \pkg{expl3} does things, we
% don't define them, as we don't need them to have an actual meaning. This has
% the advantage that if they somehow get expanded -- which should never happen
% if things work out -- they'll throw an error directly.
%
% \begin{macro}[internal]
%   {
%     \ekv@ifempty,\ekv@ifempty@,\ekv@ifempty@true,\ekv@ifempty@false,
%     \ekv@ifempty@true@F,\ekv@ifempty@true@F@gobble,
%     \ekv@ifempty@true@F@gobbletwo
%   }
% We can test for a lot of things building on an if-empty test, so lets define a
% really fast one. Since some tests might have reversed logic (true if something
% is not empty) we also set up macros for the reversed branches.
%    \begin{macrocode}
\long\def\ekv@ifempty#1%
  {%
    \ekv@ifempty@\ekv@ifempty@A#1\ekv@ifempty@B\ekv@ifempty@true
      \ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
  }
\long\def\ekv@ifempty@#1\ekv@ifempty@A\ekv@ifempty@B{}
\long\def\ekv@ifempty@true\ekv@ifempty@A\ekv@ifempty@B\@secondoftwo#1#2{#1}
\long\def\ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo#1#2{#2}
\long\def\ekv@ifempty@true@F\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1{}
\long\def\ekv@ifempty@true@F@gobble\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2%
  {}
\long\def\ekv@ifempty@true@F@gobbletwo
    \ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2#3%
  {}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {\ekv@ifblank,\ekv@ifblank@,\ekv@ifblank@false,\ekv@ifblank@gobbletrue}
% The obvious test that can be based on an if-empty is if-blank, meaning a test
% checking whether the argument is empty or consists only of spaces. But instead
% of building atop |\ekv@ifempty| our version will utilise the fact that the
% argument in none of our usages can contain |\ekv@stop| (due to the way we
% check for end-of-list), and hence we can use an even faster check. This here
% works due to the fact that \TeX\ will read at least one token (or a group) for
% an undelimited parameter which might be the end marker of the delimited next
% parameter. So if |#1| to |\ekv@ifblank| is indeed blank, |#1| of
% |\ekv@ifblank@| will be the placed |\ekv@stop| and |#2| will be anything until
% the next |\ekv@stop|. The wrapper |\ekv@ifblank| will not be used by \expkv\
% for speed reasons but \expkvo\ uses it. Also, not only a |TF| variant is
% provided but also a rather strange one that assumes that only the |F| branch
% is provided and that this branch consists only of a single token.
%    \begin{macrocode}
\long\def\ekv@ifblank#1%
  {\ekv@ifblank@#1\ekv@stop\ekv@ifblank@false\ekv@stop\@firstoftwo}
\long\def\ekv@ifblank@\ekv@mark#1#2\ekv@stop{}
\long\def\ekv@ifblank@false\ekv@stop\@firstoftwo#1#2{#2}
\def\ekv@ifblank@gobbletrue\ekv@stop#1{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@ifdefined}
% We'll need to check whether something is defined quite frequently, so why not
% define a macro that does this. The following test is expandable and pretty
% fast. The version with |\lastnamedcs| is the fastest version to test for an
% undefined macro I know of (that considers both undefined macros and those with
% the meaning |\relax|).
%    \begin{macrocode}
\ekv@if@lastnamedcs
  {%
    \long\def\ekv@ifdefined#1{\ifcsname#1\endcsname\ekv@ifdef@\fi\@secondoftwo}
    \def\ekv@ifdef@\fi\@secondoftwo
      {%
        \fi
        \expandafter\ifx\lastnamedcs\relax
          \ekv@fi@secondoftwo
        \fi
        \@firstoftwo
      }
  }
  {%
    \long\def\ekv@ifdefined#1%
      {%
        \ifcsname#1\endcsname\ekv@ifdef@\fi\ekv@ifdef@false#1\endcsname\relax
          \ekv@fi@secondoftwo
        \fi
        \@firstoftwo
      }
    \def\ekv@ifdef@\fi\ekv@ifdef@false{\fi\expandafter\ifx\csname}
    \long\def\ekv@ifdef@false
        #1\endcsname\relax\ekv@fi@secondoftwo\fi\@firstoftwo#2#3%
      {#3}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@strip,\ekv@strip@a,\ekv@strip@b,\ekv@strip@c}
% We borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
% from keys and values. This |\ekv@strip| also strips one level of outer braces
% \emph{after} stripping spaces, so an input of | {abc} | becomes |abc| after
% stripping. It should be used with |#1| prefixed by |\ekv@mark|. Also this
% implementation at most strips \emph{one} space from both sides (which should
% be fine most of the time, since \TeX\ reads consecutive spaces as a single one
% during tokenisation).
%    \begin{macrocode}
\def\ekv@strip#1%
  {%
    \long\def\ekv@strip##1%
      {%
        \ekv@strip@a
          ##1\ekv@nil
          \ekv@mark#1%
          #1\ekv@nil
      }%
    \long\def\ekv@strip@a##1\ekv@mark#1{\ekv@strip@b##1\ekv@mark}%
  }
\ekv@strip{ }
\long\def\ekv@strip@b#1 \ekv@nil{\ekv@strip@c#1\ekv@nil}
\long\def\ekv@strip@c\ekv@mark#1\ekv@nil\ekv@mark#2\ekv@nil#3{#3{#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {\ekv@strip@key,\ekv@strip@key@a,\ekv@strip@key@b,\ekv@strip@key@c}
%   Same idea and code as |\ekv@strip|, but the second argument to
%   |\ekv@strip@key| must be a single token and the result of the stripping will
%   be |\detokenize|d.
%    \begin{macrocode}
\def\ekv@strip@key#1%
  {%
    \long\def\ekv@strip@key##1{\ekv@strip@key@a##1\ekv@nil\ekv@mark#1#1\ekv@nil}
    \long\def\ekv@strip@key@a##1\ekv@mark#1{\ekv@strip@key@b##1\ekv@mark}
  }
\ekv@strip@key{ }
\long\def\ekv@strip@key@b#1 \ekv@nil{\ekv@strip@key@c#1\ekv@nil}
\long\def\ekv@strip@key@c\ekv@mark#1\ekv@nil\ekv@mark#2\ekv@nil#3%
  {\expandafter#3\detokenize{#1}\ekv@mark{#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \ekv@exparg,\ekv@exparg@,
%     \ekv@expandedarg,\ekv@fexparg,\ekv@expandafter
%     \ekv@expargtwice,\ekv@expargtwice@,\ekv@zero
%   }
% To reduce some code doublets while gaining some speed (and also as convenience
% for other packages in the family), it is often useful to expand the first
% token in a definition once. Let's define a wrapper for this. And while we're
% at it, also define a helper for |f|-~and |e|-expansion as well.
%
% Also, to end a |\romannumeral| expansion, we want to use |\z@|, which is
% contained in both plain \TeX\ and \LaTeX, but we use a private name for it to
% make it easier to spot and hence easier to manage.
%    \begin{macrocode}
\let\ekv@zero\z@
\long\def\ekv@exparg#1#2%
  {\ekv@expanded{\ekv@unexpanded{#1}\expandafter}\expandafter{#2}}
\long\def\ekv@expandafter#1{\ekv@expanded{\ekv@unexpanded{#1}\expandafter}}
\long\def\ekv@exparg@#1#2{#2{#1}}%
\long\def\ekv@expandedarg#1#2{\ekv@expanded{\ekv@unexpanded{#1}{#2}}}
\long\def\ekv@fexparg#1#2%
  {%
    \ekv@expanded{\ekv@unexpanded{#1}\expandafter}\expandafter
      {\romannumeral`\^^@#2}%
  }
\long\def\ekv@expargtwice#1#2{\expandafter\ekv@expargtwice@\expandafter{#2}{#1}}
\def\ekv@expargtwice@{\expandafter\ekv@exparg@\expandafter}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvcsvloop}
% \begin{macro}[internal]{\ekv@csv@loop@active,\ekv@csv@loop@active@end}
%   An |\ekvcsvloop| will just loop over a csv list in a simple manner. First we
%   split at active commas (gives better performance this way), next we have to
%   check whether we're at the end of the list (checking for |\ekv@stop|). If
%   not we go on splitting at commas of category other.
%    \begin{macrocode}
\begingroup
\def\ekvcsvloop#1{%
\endgroup
\long\def\ekvcsvloop##1##2%
  {\ekv@csv@loop@active{##1}\ekv@mark##2#1\ekv@stop#1}
%    \end{macrocode}
%   This does the same as |\ekv@csv@loop| but for active commas.
%    \begin{macrocode}
\long\def\ekv@csv@loop@active##1##2#1%
  {%
    \ekv@gobble@from@mark@to@stop##2\ekv@csv@loop@active@end\ekv@stop
    \ekv@csv@loop{##1}##2,\ekv@stop,%
  }%
\long\def\ekv@csv@loop@active@end
    \ekv@stop
    \ekv@csv@loop##1\ekv@mark\ekv@stop,\ekv@stop,%
  {}%
}
%    \end{macrocode}
%   Do the definitions with the weird catcode.
%    \begin{macrocode}
\catcode`\,=13
\ekvcsvloop,
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@csv@loop,\ekv@csv@loop@do,\ekv@csv@loop@end}
%   We use temporary macros and an |\expandafter| chain to preexpand
%   |\ekv@strip| here. After splitting at other commas we check again for end
%   the end of the sublist, check for blank elements which should be ignored,
%   and else strip spaces and execute the user code (protecting it from further
%   expanding with |\unexpanded|).
%    \begin{macrocode}
\def\ekv@csv@loop#1%
  {%
    \long\def\ekv@csv@loop##1##2,%
      {%
        \ekv@gobble@from@mark@to@stop##2\ekv@csv@loop@end\ekv@stop
        \ekv@ifblank@##2\ekv@stop\ekv@ifblank@gobbletrue
          \ekv@stop\ekv@csv@loop@blank
        #1\ekv@csv@loop@do{##1}%
      }%
  }
\expandafter\ekv@csv@loop\expandafter{\ekv@strip{#2}}
\long\def\ekv@csv@loop@do#1#2{\ekv@unexpanded{#2{#1}}\ekv@csv@loop{#2}\ekv@mark}
\def\ekv@csv@loop@end#1%
  {%
    \long\def\ekv@csv@loop@end
        \ekv@stop
        \ekv@ifblank@\ekv@mark\ekv@stop\ekv@stop\ekv@ifblank@gobbletrue
        \ekv@stop\ekv@csv@loop@blank
        #1\ekv@csv@loop@do##1%
      {\ekv@csv@loop@active{##1}\ekv@mark}%
  }
\expandafter\ekv@csv@loop@end\expandafter{\ekv@strip{\ekv@mark\ekv@stop}}
\long\expandafter\def\expandafter\ekv@csv@loop@blank
    \ekv@strip{\ekv@mark#1}\ekv@csv@loop@do#2%
  {\ekv@csv@loop{#2}\ekv@mark}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekv@name,\ekv@name@set,\ekv@name@key}
% The keys will all follow the same naming scheme, so we define it here.
%    \begin{macrocode}
\def\ekv@name@set#1{ekv#1(}
\long\def\ekv@name@key#1{#1)}
\edef\ekv@name
  {%
    \ekv@unexpanded\expandafter{\ekv@name@set{#1}}%
    \ekv@unexpanded\expandafter{\ekv@name@key{\detokenize{#2}}}%
  }
\long\ekv@exparg{\def\ekv@name#1#2}{\ekv@name}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@undefined@set}
% We can misuse the macro name we use to expandably store the set-name in a
% single token -- since this increases performance drastically, especially for
% long set-names -- to throw a more meaningful error message in case a set isn't
% defined. The name of |\ekv@undefined@set| is a little bit misleading, as it is
% called in either case inside of |\csname|, but the result will be a control
% sequence with meaning |\relax| if the set is undefined, hence will break the
% |\csname| building the key-macro which will throw the error message.
%    \begin{macrocode}
\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@checkvalid}
% We place some restrictions on the allowed names, though, namely sets and
% keys are not allowed to be empty -- blanks are fine (meaning \mbox{set-
% or} key-names consisting of spaces). The |\def\ekv@tmp| gobbles any \TeX\
% prefixes which would otherwise throw errors. This will, however, break the
% package if an |\outer| has been gobbled this way. I consider that good,
% because keys shouldn't be defined |\outer| anyways.
%    \begin{macrocode}
\edef\ekv@checkvalid
  {%
    \ekv@unexpanded\expandafter{\ekv@ifempty{#1}}%
    \ekv@unexpanded
      {{%
        \def\ekv@tmp{}%
        \ekv@errm{empty set name not allowed}%
      }}%
      {%
        \ekv@unexpanded\expandafter{\ekv@ifempty{#2}}%
        \ekv@unexpanded
          {%
            {%
              \def\ekv@tmp{}%
              \ekv@errm{empty key name not allowed}%
            }%
            \@secondoftwo
          }%
      }%
    \ekv@unexpanded{\@gobble}%
  }
\ekv@exparg{\protected\def\ekv@checkvalid#1#2}{\ekv@checkvalid}%
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvifdefined,\ekvifdefinedNoVal}
% And provide user-level macros to test whether a key is defined.
%    \begin{macrocode}
\ekv@expargtwice{\long\def\ekvifdefined#1#2}%
  {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}}}
\ekv@expargtwice{\long\def\ekvifdefinedNoVal#1#2}%
  {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}N}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,
%     \ekvdefunknown,\ekvdefunknownNoVal,\ekvletunknown,\ekvletunknownNoVal
%   }
% Set up the key defining macros |\ekvdef| etc. We use temporary macros to set
% these up with a few expansions already done.
%    \begin{macrocode}
\def\ekvdef#1#2#3#4#5#6%
  {%
    \protected\long\def\ekvdef##1##2##3%
      {#1{\expandafter\def\csname#2\endcsname####1{##3}#4}}%
    \protected\long\def\ekvdefNoVal##1##2##3%
      {#1{\expandafter\def\csname#2N\endcsname{##3}#4}}%
    \protected\long\def\ekvlet##1##2##3%
      {#1{\expandafter\let\csname#2\endcsname##3#4}}%
    \protected\long\def\ekvletNoVal##1##2##3%
      {#1{\expandafter\let\csname#2N\endcsname##3#4}}%
    \ekv@expargtwice{\protected\long\def\ekv@defunknown##1##2##3##4}%
      {%
        \romannumeral
        \ekv@exparg
          {\ekv@zero\ekv@checkvalid{##3}.}%
          {%
            \expandafter\expandafter\expandafter
            \def\expandafter\csname\ekv@name{##3}{}u##1\endcsname##2{##4}%
            #6%
          }%
      }%
    \ekv@expargtwice{\protected\long\def\ekv@letunknown##1##2##3}%
      {%
        \romannumeral
        \ekv@exparg
          {\ekv@zero\ekv@checkvalid{##2}.}%
          {%
            \expandafter\expandafter\expandafter
            \let\expandafter\csname\ekv@name{##2}{}u##1\endcsname##3%
            #5%
          }%
      }%
    \protected\long\def\ekvletkv##1##2##3##4%
      {%
        #1%
          {%
            \expandafter\let\csname#2\expandafter\endcsname
            \csname#3\endcsname
            #4%
          }%
      }%
    \protected\long\def\ekvletkvNoVal##1##2##3##4%
      {%
        #1%
          {%
            \expandafter\let\csname#2N\expandafter\endcsname
            \csname#3N\endcsname
            #4%
          }%
      }%
  }
\edef\ekvdefNoVal
  {%
    {\ekv@unexpanded\expandafter{\ekv@checkvalid{#1}{#2}}}%
    {\ekv@unexpanded\expandafter{\ekv@name{#1}{#2}}}%
    {\ekv@unexpanded\expandafter{\ekv@name{#3}{#4}}}%
    {%
      \ekv@unexpanded{\expandafter\ekv@defsetmacro\csname}%
      \ekv@unexpanded\expandafter{\ekv@undefined@set{#1}\endcsname{#1}}%
    }%
    {%
      \ekv@unexpanded{\expandafter\ekv@defsetmacro\csname}%
      \ekv@unexpanded\expandafter{\ekv@undefined@set{#2}\endcsname{#2}}%
    }%
    {%
      \ekv@unexpanded{\expandafter\ekv@defsetmacro\csname}%
      \ekv@unexpanded\expandafter{\ekv@undefined@set{#3}\endcsname{#3}}%
    }%
  }
\expandafter\ekvdef\ekvdefNoVal
\ekv@exparg{\protected\long\def\ekvdefunknown#1#2}%
  {\ekv@defunknown{}{##1##2##3}{#1}{#2}}
\ekv@exparg{\protected\long\def\ekvdefunknownNoVal#1#2}%
  {\ekv@defunknown{N}{##1##2}{#1}{#2}}
\ekv@exparg{\protected\long\def\ekvletunknown#1#2}%
  {\ekv@letunknown{}{#1}{#2}}
\ekv@exparg{\protected\long\def\ekvletunknownNoVal#1#2}%
  {\ekv@letunknown{N}{#1}{#2}}
\let\ekv@defunknown\ekv@undefined
\let\ekv@letunknown\ekv@undefined
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvredirectunknown,\ekvredirectunknownNoVal}
% \begin{macro}[internal]
%   {
%     \ekv@defredirectunknown,\ekv@redirectunknown@aux,
%     \ekv@redirectunknownNoVal@aux
%   }
%   The redirection macros prepare the unknown function by looping over the
%   provided list of sets and leaving a |\ekv@redirect@kv| or |\ekv@redirect@k|
%   for each set. Only the first of these internals will receive the \key\ and
%   \val\ as arguments.
%    \begin{macrocode}
\protected\def\ekv@defredirectunknown#1#2#3#4#5#6%
  {%
    \begingroup
    \edef\ekv@tmp
      {%
        \ekvcsvloop#1{#6}%
        \ekv@unexpanded{#2}%
        {\ekvcsvloop{}{#5,#6}}%
      }%
    \ekv@expargtwice
      {\endgroup\long#3{#5}}%
      {\expandafter#4\ekv@tmp\ekv@stop}%
  }
\ekv@exparg{\protected\def\ekvredirectunknown#1#2}%
  {%
    \ekv@defredirectunknown
      \ekv@redirect@kv
      \ekv@err@redirect@kv@notfound
      \ekvdefunknown
      \ekv@redirectunknown@aux
      {#1}{#2}%
  }
\ekv@exparg{\protected\def\ekvredirectunknownNoVal#1#2}%
  {%
    \ekv@defredirectunknown
      \ekv@redirect@k
      \ekv@err@redirect@k@notfound
      \ekvdefunknownNoVal
      \ekv@redirectunknownNoVal@aux
      {#1}{#2}%
  }
\def\ekv@redirectunknown@aux#1{#1{##1}{##2}}
\def\ekv@redirectunknownNoVal@aux#1{#1{##1}}
\let\ekv@defredirectunknown\ekv@undefined
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \ekv@redirect@k,\ekv@redirect@k@a,\ekv@redirect@k@a@,
%     \ekv@redirect@k@b,\ekv@redirect@k@c,\ekv@redirect@k@d,
%     \ekv@redirect@kv,\ekv@redirect@kv@a,\ekv@redirect@kv@a@,
%     \ekv@redirect@kv@b,\ekv@redirect@kv@c,\ekv@redirect@kv@d
%   }
%   The redirect code works by some simple loop over all the sets, which we
%   already preprocessed in |\ekv@defredirectunknown|. For some optimisation we
%   blow this up a bit code wise, essentially, all this does is |\ekvifdefined|
%   or |\ekvifdefinedNoVal| in each set, if there is a match gobble the
%   remainder of the specified sets and execute the key macro, else go on with
%   the next set (to which the \key\ and \val\ are forwarded).
%
%   First we set up some code which is different depending on |\lastnamedcs|
%   being available or not. All this is stored in a temporary macro to have
%   pre-expanded |\ekv@name| constellations ready.
%    \begin{macrocode}
\def\ekv@redirect@k#1#2#3#4%
  {%
    \ekv@if@lastnamedcs
      {%
        \def\ekv@redirect@k##1##2##3%
          {%
            \ifcsname#1\endcsname\ekv@redirect@k@a\fi
            ##3{##1}%
          }%
        \def\ekv@redirect@k@a\fi{\fi\expandafter\ekv@redirect@k@b\lastnamedcs}%
        \long\def\ekv@redirect@kv##1##2##3##4%
          {%
            \ifcsname#2\endcsname\ekv@redirect@kv@a\fi\@gobble{##1}%
            ##4{##1}{##2}%
          }%
        \def\ekv@redirect@kv@a\fi\@gobble
          {\fi\expandafter\ekv@redirect@kv@b\lastnamedcs}%
      }
      {%
        \def\ekv@redirect@k##1##2##3%
          {%
            \ifcsname#1\endcsname\ekv@redirect@k@a\fi\ekv@redirect@k@a@
              #1\endcsname
            ##3{##1}%
          }%
        \def\ekv@redirect@k@a@#3\endcsname{}%
        \def\ekv@redirect@k@a\fi\ekv@redirect@k@a@
          {\fi\expandafter\ekv@redirect@k@b\csname}%
        \long\def\ekv@redirect@kv##1##2##3##4%
          {%
            \ifcsname#2\endcsname\ekv@redirect@kv@a\fi\ekv@redirect@kv@a@
              #2\endcsname{##1}%
            ##4{##1}{##2}%
          }%
        \long\def\ekv@redirect@kv@a@#4\endcsname##3{}%
        \def\ekv@redirect@kv@a\fi\ekv@redirect@kv@a@
          {\fi\expandafter\ekv@redirect@kv@b\csname}%
      }%
  }
%    \end{macrocode}
%   The key name given to this loop will already be |\detokenize|d by |\ekvset|,
%   so we can safely remove the |\detokenize| here for some performance gain.
%    \begin{macrocode}
\def\ekv@redirect@kv#1\detokenize#2#3\ekv@stop{\ekv@unexpanded{#1#2#3}}
\edef\ekv@redirect@kv
  {%
    {\expandafter\ekv@redirect@kv\ekv@name{#2}{#1}N\ekv@stop}%
    {\expandafter\ekv@redirect@kv\ekv@name{#3}{#2}\ekv@stop}%
    {\expandafter\ekv@redirect@kv\ekv@name{#1}{#2}N\ekv@stop}%
    {\expandafter\ekv@redirect@kv\ekv@name{#1}{#2}\ekv@stop}%
  }
%    \end{macrocode}
%   Everything is ready to make the real definitions.
%    \begin{macrocode}
\expandafter\ekv@redirect@k\ekv@redirect@kv
%    \end{macrocode}
%   The remaining macros here are independent on |\lastnamedcs|, starting from
%   the |@b| we know that there is a hash table entry, and get the macro as a
%   parameter. We still have to test whether the macro is |\relax|, depending on
%   the result of that test we have to either remove the remainder of the
%   current test, or the remainder of the set list and invoke the macro.
%    \begin{macrocode}
\def\ekv@redirect@k@b#1%
  {\ifx\relax#1\ekv@redirect@k@c\fi\ekv@redirect@k@d#1}
\def\ekv@redirect@k@c\fi\ekv@redirect@k@d#1{\fi}
\def\ekv@redirect@k@d#1#2\ekv@stop{#1}
\def\ekv@redirect@kv@b#1%
  {\ifx\relax#1\ekv@redirect@kv@c\fi\ekv@redirect@kv@d#1}
\long\def\ekv@redirect@kv@c\fi\ekv@redirect@kv@d#1#2{\fi}
\long\def\ekv@redirect@kv@d#1#2#3\ekv@stop{#1{#2}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@defsetmacro}
%   In order to enhance the speed the set name given to |\ekvset| will be turned
%   into a control sequence pretty early, so we have to define that control
%   sequence.
%    \begin{macrocode}
\edef\ekv@defsetmacro
  {%
    \ekv@unexpanded{\ifx#1\relax\edef#1##1}%
      {%
        \ekv@unexpanded\expandafter{\ekv@name@set{#2}}%
        \ekv@unexpanded\expandafter{\ekv@name@key{##1}}%
      }%
    \ekv@unexpanded{\fi}%
  }
\ekv@exparg{\protected\def\ekv@defsetmacro#1#2}{\ekv@defsetmacro}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvifdefinedset}
%    \begin{macrocode}
\ekv@expargtwice{\def\ekvifdefinedset#1}%
  {\expandafter\ekv@ifdefined\expandafter{\ekv@undefined@set{#1}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@ifexp}
%   We want to be able to include expansion control. This is started by a
%   specific structure, namely if the stuff to the left of the equals sign
%   contains a colon followed by a space followed by at least one non-space
%   token. There is an additional rule namely the contents in front of the
%   \verb*|: | marker mustn't contain spaces outside of braces, but
%   unfortunately we can test this only after we did the real split and not as
%   part of a fast test. The temporary meaning we set up here will get
%   \tkn{:}{13}\vissp{ } and \tkn{:}{11}\vissp{ } as |#1| and |#2|.
%
%   The real definition will take three arguments (two curried), namely the
%   un-|\detokenize|d name as |#1|, what should be done if the \expnotation\
%   should start as |#2|, and what should be done if no \expnotation\ is found
%   as |#3|.
%    \begin{macrocode}
\def\ekv@ifexp#1#2%
  {%
%    \end{macrocode}
%   In the following explanations I use \tkn{:}{12}, \tkn{:}{13}, and
%   \tkn{:}{11}, but I always mean that token followed by a space.
% \begin{macro}[internal]{\ekv@ifexp@split@o@or@other}
%   \tkn{:}{12} splitter also used to test for \tkn{:}{13} and \tkn{:}{11}
%    \begin{macrocode}
    \long\def\ekv@ifexp@split@o@or@other
        ##1: ##2\ekv@stop##3%
        ##4#1##5\ekv@stop##6%
        ##7#2##8\ekv@stop##9%
      {##9##6##3##1\ekv@stop##2}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]{\ekv@ifexp@split@a@or@l}
%   \tkn{:}{13} splitter also used to test for \tkn{:}{11}
%    \begin{macrocode}
    \long\def\ekv@ifexp@split@a@or@l
        ##1#1##2\ekv@stop##3%
        ##4#2##5\ekv@stop##6%
      {##6##3##1\ekv@stop##2}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {\ekv@ifexp@split@a,\ekv@ifexp@split@l}
%   \tkn{:}{13} splitter
%    \begin{macrocode}
    \long\def\ekv@ifexp@split@a##1#1##2\ekv@stop##3%
      {##3##1\ekv@stop##2}%
%    \end{macrocode}
%   \tkn{:}{11} splitter
%    \begin{macrocode}
    \long\def\ekv@ifexp@split@l##1#2##2\ekv@stop##3%
      {##3##1\ekv@stop##2}%
%    \end{macrocode}
% \end{macro}
%   To get good performance in the most common case (standard category codes
%   apply) we try to split on \tkn{:}{12}, due to the way this split works there
%   are a few possible outcomes:
%   \begin{enumerate}
%     \item |\ekv@ifexp@none| is the first token if no colon was
%       found at all
%     \item |\ekv@ifexp@o| is the first token if only \tkn{:}{12}
%       were part of \key
%     \item |\ekv@ifexp@a| is put in front of either of the two
%       aforementioned cases if there was at least one \tkn{:}{13} (in that case
%       we don't yet know which was the first colon)
%     \item |\ekv@ifexp@o| is put in front of any of the
%       aforementioned cases if there was at least one \tkn{:}{11} (in which
%       case we also don't know yet which was the first colon)
%   \end{enumerate}
%    \begin{macrocode}
    \long\def\ekv@ifexp##1%
      {%
        \ekv@ifexp@split@o@or@other
          ##1\ekv@nil\ekv@stop\ekv@ifexp@o
          : \ekv@stop\ekv@ifexp@none
          ##1\ekv@stop\ekv@ifexp@a#1\ekv@stop{}%
          ##1\ekv@stop\ekv@ifexp@l#2\ekv@stop{}%
      }%
%    \end{macrocode}
% \begin{macro}[internal]
%   {\ekv@ifexp@o,\ekv@ifexp@none}
%   If any of the next two are called we already know the outcome and can
%   directly expand to it.
%    \begin{macrocode}
    \long\def\ekv@ifexp@o##1\ekv@stop
      {\ekv@ifexp@done{##1}\ekv@mark}%
    \long\def\ekv@ifexp@none
        ##1\ekv@nil\ekv@stop\ekv@ifexp@o\ekv@stop
        ##2##3%
      {##3}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {\ekv@ifexp@a,\ekv@ifexp@a@i,\ekv@ifexp@a@ii}
%   If this is called we know that there was no \tkn{:}{13}, if the first token
%   now is |\ekv@ifexp@none| there was no \tkn{:}{12} as well
%    \begin{macrocode}
    \def\ekv@ifexp@a##1%
      {%
        \ekv@ifexp@a@i
          ##1\ekv@ifexp@a@ii
          \ekv@ifexp@none\ekv@ifexp@a@or@o
      }%
    \def\ekv@ifexp@a@i##1\ekv@ifexp@none{}%
%    \end{macrocode}
%   Easy route, no \tkn{:}{12}, simply grab and pack
%    \begin{macrocode}
    \long\def\ekv@ifexp@a@ii
        \ekv@ifexp@none\ekv@ifexp@a@or@o
        ##1#1##2\ekv@stop\ekv@ifexp@o\ekv@stop
      {\ekv@ifexp@done{##1}\ekv@mark##2}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {
%     \ekv@ifexp@a@or@o,
%     \ekv@ifexp@a@not@o,\ekv@ifexp@a@not@o@,
%     \ekv@ifexp@o@not@a
%   }
%   other route, there is a \tkn{:}{12}, re-split at \tkn{:}{13}
%    \begin{macrocode}
    \long\def\ekv@ifexp@a@or@o##1\ekv@stop
      {%
        \ekv@ifexp@split@a
          ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@o
          #1\ekv@stop\ekv@ifexp@o@not@a
      }%
%    \end{macrocode}
%   \tkn{:}{13} came earlier than \tkn{:}{12}
%    \begin{macrocode}
    \long\def\ekv@ifexp@a@not@o##1\ekv@stop
      {\ekv@ifexp@a@not@o@{##1}\ekv@mark}
    \long\def\ekv@ifexp@a@not@o@
        ##1##2\ekv@nil#1\ekv@stop\ekv@ifexp@o@not@a
      {\ekv@ifexp@done{##1}##2: }%
%    \end{macrocode}
%   \tkn{:}{12} came earlier than \tkn{:}{13}
%    \begin{macrocode}
    \long\def\ekv@ifexp@o@not@a
        ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@o\ekv@stop
      {\ekv@ifexp@done{##1}\ekv@mark}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]{\ekv@ifexp@l,\ekv@ifexp@l@i,\ekv@ifexp@l@ii}
%   Now this is the most complicated case, if |\ekv@ifexp@l| is
%   called there are a few possibilities:
%   \begin{enumerate}
%     \item |#1| is |\ekv@ifexp@none|: easiest route, only
%       \tkn{:}{11} was there
%     \item |#1| is |\ekv@ifexp@o|: complicated route, there was a
%      \tkn{:}{11} and a \tkn{:}{12}
%     \item |#1| is |\ekv@ifexp@a| and after that comes
%      |\ekv@ifexp@none|: more complicated, there was a
%      \tkn{:}{11} and a \tkn{:}{13}
%     \item |#1| is |\ekv@ifexp@a| and after that comes
%      |\ekv@ifexp@o|: cursed route, there were \tkn{:}{11},
%      \tkn{:}{12}, and \tkn{:}{13}
%   \end{enumerate}
%    \begin{macrocode}
    \def\ekv@ifexp@l##1%
      {%
        \ekv@ifexp@l@i
          ##1\ekv@ifexp@l@ii
          \ekv@ifexp@none{}%
          ##1\ekv@ifexp@l@or@o
          \ekv@ifexp@o
        \ekv@ifexp@l@or@a
      }%
    \def\ekv@ifexp@l@i
        ##1\ekv@ifexp@none##2%
        ##3\ekv@ifexp@o
      {##2}%
%    \end{macrocode}
%   easiest route, just \tkn{:}{11}
%    \begin{macrocode}
    \long\def\ekv@ifexp@l@ii
        \ekv@ifexp@l@or@a##1#2##2\ekv@stop
        \ekv@ifexp@o\ekv@stop#2\ekv@stop##3%
      {\ekv@ifexp@done{##1}\ekv@mark##2}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {
%     \ekv@ifexp@l@or@o,
%     \ekv@ifexp@l@not@o,\ekv@ifexp@l@not@o@,
%     \ekv@ifexp@o@not@l
%   }
%   slightly harder, \tkn{:}{11} or \tkn{:}{12}, re-split at \tkn{:}{11}
%    \begin{macrocode}
    \long\def\ekv@ifexp@l@or@o
        \ekv@ifexp@o\ekv@ifexp@l@or@a
        ##1\ekv@stop
      {%
        \ekv@ifexp@split@l
          ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@o
          #2\ekv@stop\ekv@ifexp@o@not@l
      }%
%    \end{macrocode}
%   \tkn{:}{11} came earlier than \tkn{:}{12}
%    \begin{macrocode}
    \long\def\ekv@ifexp@l@not@o##1\ekv@stop
      {\ekv@ifexp@l@not@o@{##1}\ekv@mark}
    \long\def\ekv@ifexp@l@not@o@
        ##1##2\ekv@nil#2\ekv@stop\ekv@ifexp@o@not@l
        ##3#2\ekv@stop##4%
      {\ekv@ifexp@done{##1}##2: ##3}%
%    \end{macrocode}
%   \tkn{:}{12} came earlier than \tkn{:}{11}
%    \begin{macrocode}
    \long\def\ekv@ifexp@o@not@l
        ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@o\ekv@stop
        ##2#2\ekv@stop##3%
      {\ekv@ifexp@done{##1}\ekv@mark##2}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {
%     \ekv@ifexp@l@or@a,
%     \ekv@ifexp@l@or@a@not@o,
%     \ekv@ifexp@l@not@a,\ekv@ifexp@l@not@a@,
%     \ekv@ifexp@a@not@l
%   }
%   \tkn{:}{13} was in the mix with \tkn{:}{11}, we need to see whether there
%   was a \tkn{:}{12} as well
%    \begin{macrocode}
    \def\ekv@ifexp@l@or@a##1%
      {%
%    \end{macrocode}
%   don't get confused by the name, this gobbles until |@none|
%    \begin{macrocode}
        \ekv@ifexp@a@i
          ##1\ekv@ifexp@l@or@a@not@o
          \ekv@ifexp@none
        \ekv@ifexp@l@or@a@or@o
      }%
%    \end{macrocode}
%   phew, no \tkn{:}{12} in the mix, we split at \tkn{:}{13} and see whether an
%   earlier \tkn{:}{11} is found
%    \begin{macrocode}
    \long\def\ekv@ifexp@l@or@a@not@o
        \ekv@ifexp@none\ekv@ifexp@l@or@a@or@o
        ##1#1%
      {%
        \ekv@ifexp@split@l
          ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@a
          #2\ekv@stop\ekv@ifexp@a@not@l
      }%
    \long\def\ekv@ifexp@l@not@a##1\ekv@stop
      {\ekv@ifexp@l@not@a@{##1}\ekv@mark}%
    \long\def\ekv@ifexp@l@not@a@
        ##1##2\ekv@nil#2\ekv@stop\ekv@ifexp@a@not@l
        ##3\ekv@stop\ekv@ifexp@o\ekv@stop#2\ekv@stop##4%
      {\ekv@ifexp@done{##1}##2#1##3}%
    \long\def\ekv@ifexp@a@not@l
        ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@a\ekv@stop
        ##2\ekv@stop\ekv@ifexp@o\ekv@stop#2\ekv@stop##3%
      {\ekv@ifexp@done{##1}\ekv@mark##2}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {
%     \ekv@ifexp@l@or@a@or@o,\ekv@ifexp@l@or@a@or@o@i,\ekv@ifexp@l@or@a@or@o@ii,
%     \ekv@ifexp@l@or@a@or@o@iii,\ekv@ifexp@l@or@a@or@o@iv,
%     \ekv@ifexp@o@not@l@or@a,
%     \ekv@ifexp@a@not@l@or@o,\ekv@ifexp@a@not@l@or@o@
%   }
%   ooh no, the ugliest path, we got ourself a \tkn{:}{11}, a \tkn{:}{12}, and a
%   \tkn{:}{13}, first grab everything left after splitting the first
%   \tkn{:}{12} and try a \tkn{:}{13} split
%    \begin{macrocode}
    \long\def\ekv@ifexp@l@or@a@or@o##1\ekv@stop
      {%
        \ekv@ifexp@split@a@or@l
          ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@l@or@o
          #1\ekv@stop\ekv@ifexp@o@not@l@or@a
          ##1\ekv@stop\ekv@ifexp@l@or@a@or@o@i#2\ekv@stop{}%
      }%
%    \end{macrocode}
%   \tkn{:}{12} splitting was correct
%    \begin{macrocode}
    \long\def\ekv@ifexp@o@not@l@or@a
        ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@l@or@o\ekv@stop
        ##2#2\ekv@stop##3%
      {\ekv@ifexp@done{##1}\ekv@mark##2}%
%    \end{macrocode}
%   \tkn{:}{13} split is correct, \tkn{:}{12} has to be reverted
%    \begin{macrocode}
    \long\def\ekv@ifexp@a@not@l@or@o##1\ekv@stop
      {\ekv@ifexp@a@not@l@or@o@{##1}\ekv@mark}
    \long\def\ekv@ifexp@a@not@l@or@o@
        ##1##2\ekv@nil##3#2\ekv@stop##4%
      {\ekv@ifexp@done{##1}##2: ##3}%
%    \end{macrocode}
%   there is still a \tkn{:}{11} left, we need to take care of \tkn{:}{13} as
%   well, but \tkn{:}{12} was wrong
%    \begin{macrocode}
    \def\ekv@ifexp@l@or@a@or@o@i##1%
      {%
        \ekv@ifexp@l@or@a@or@o@ii
          ##1\ekv@ifexp@l@or@a@or@o@iii
          \ekv@ifexp@o@not@l@or@a
        \ekv@ifexp@why
      }%
    \def\ekv@ifexp@l@or@a@or@o@ii
        ##1\ekv@ifexp@o@not@l@or@a
      {}%
%    \end{macrocode}
%   at least it's not absolutely the worst, \tkn{:}{11} is correct, revert the
%   \tkn{:}{12} split
%    \begin{macrocode}
    \long\def\ekv@ifexp@l@or@a@or@o@iii
        \ekv@ifexp@o@not@l@or@a\ekv@ifexp@why
        ##1#2%
      {\ekv@ifexp@l@or@a@or@o@iv{##1}\ekv@mark}%
    \long\def\ekv@ifexp@l@or@a@or@o@iv
        ##1##2\ekv@nil\ekv@stop\ekv@ifexp@a@not@l@or@o\ekv@stop
        #2\ekv@stop##3##4#2\ekv@stop##5%
      {\ekv@ifexp@done{##1}##2: ##4}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {
%     \ekv@ifexp@why,
%     \ekv@ifexp@why@l,\ekv@ifexp@why@l@i,\ekv@ifexp@why@l@ii,
%     \ekv@ifexp@why@a
%   }
%   why have you forsaken me? We know \tkn{:}{12} was wrong, but now we have
%   something that might be correctly split at \tkn{:}{13}, but might as well be
%   not
%    \begin{macrocode}
    \long\def\ekv@ifexp@why##1\ekv@stop
      {%
        \ekv@ifexp@split@l
          ##1\ekv@nil\ekv@stop\ekv@ifexp@why@l
          #2\ekv@stop\ekv@ifexp@why@a
      }%
%    \end{macrocode}
%   \tkn{:}{11} is correct, rebuild stuff undoing the wrong \tkn{:}{13} split
%    \begin{macrocode}
    \long\def\ekv@ifexp@why@l##1\ekv@stop
      {\ekv@ifexp@why@l@i{##1}\ekv@mark}
    \long\def\ekv@ifexp@why@l@i
        ##1##2\ekv@nil#2\ekv@stop\ekv@ifexp@why@a
      {\ekv@ifexp@why@l@ii{##1}##2#1}
%    \end{macrocode}
%   and undoing the wrong \tkn{:}{12} split
%    \begin{macrocode}
    \long\def\ekv@ifexp@why@l@ii
        ##1##2\ekv@nil#2\ekv@stop##3##4#2\ekv@stop##5%
      {\ekv@ifexp@done{##1}##2: ##4}%
%    \end{macrocode}
%   \tkn{:}{13} is correct, we know there is a \tkn{:}{11} hiding somewhere, so
%   we don't need to protect against brace strip using a two-step grab here,
%   just undoing the wrong \tkn{:}{12} split is enough
%    \begin{macrocode}
    \long\def\ekv@ifexp@why@a
        ##1\ekv@nil\ekv@stop\ekv@ifexp@why@l\ekv@stop
        ##2\ekv@nil#2\ekv@stop##3##4#2\ekv@stop##5%
      {\ekv@ifexp@done{##1}\ekv@mark##2: ##4}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {
%     \ekv@ifexp@done,\ekv@ifexp@done@,
%     \ekv@ifexp@done@test,
%     \ekv@ifexp@panic
%   }
%   once the colon split is done we need to check that there are no spaces in
%   the now split of part, if there are \emph{panic} (we did all of this for
%   nothing), else we're finally completely done with the splitting business.
%    \begin{macrocode}
    \ekv@exparg{\long\def\ekv@ifexp@done##1##2\ekv@nil}%
      {%
        \@firstofone
          {\ekv@ifexp@done@test##1\ekv@nil\ekv@ifexp@panic} \ekv@nil{}%
          ##2\ekv@stop\ekv@ifexp@done@{##1}{##2}\ekv@stop\@secondoftwo
      }
    \long\def\ekv@ifexp@done@test##1 ##2\ekv@nil##3##4##5##6\ekv@stop{##3}
    \ekv@exparg{\long\def\ekv@ifexp@done@##1##2\ekv@stop\@secondoftwo##3}%
      {\ekv@strip{##2}{##3{##1}}}%
%    \end{macrocode}
%   Panic in this case means give up on expansion parsing, instead the normal
%   action that would've been done if the expansion mark isn't found is
%   executed.
%    \begin{macrocode}
    \long\def\ekv@ifexp@panic##1\@secondoftwo##2##3{##3}
  }
%    \end{macrocode}
% \end{macro}
%   We set up the strange category codes for colons and do the real definition
%   after the temporary one.
%    \begin{macrocode}
\begingroup
  \catcode`\~=13
  \lccode`\~=`\:
  \catcode`\z=11
  \lccode`\z=`\:
\lowercase{\endgroup
\ekv@ifexp{~ }{z }}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvset}
% Set up |\ekvset|, which should not be affected by active commas and equal
% signs. The equal signs are a bit harder to cope with and we'll do that later,
% but the active commas can be handled by just doing two comma-splitting loops
% one at actives one at others. That's why we define |\ekvset| here with a
% temporary meaning just to set up the things with two different category codes.
% |#1| will be a \texttt{,\textsubscript{13}} and |#2| will be a
% \texttt{=\textsubscript{13}}.
%    \begin{macrocode}
\begingroup
\def\ekvset#1#2{%
\endgroup
\ekv@exparg{\long\def\ekvset##1##2}%
  {%
    \expandafter\expandafter\expandafter
    \ekv@set\expandafter\csname\ekv@undefined@set{##1}\endcsname
      \ekv@mark##2#1\ekv@stop#1{}%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@set}
% |\ekv@set| will split the \kv\ list at active commas. Then it has to check
% whether there were unprotected other commas and resplit there.
%    \begin{macrocode}
\long\def\ekv@set##1##2#1%
  {%
%    \end{macrocode}
% Test whether we're at the end, if so invoke |\ekv@endset|,
%    \begin{macrocode}
    \ekv@gobble@from@mark@to@stop##2\ekv@endset\ekv@stop
%    \end{macrocode}
% else go on with other commas.
%    \begin{macrocode}
    \ekv@set@other##1##2,\ekv@stop,%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@endset}
% |\ekv@endset| is a hungry little macro. It will eat everything that remains
% of |\ekv@set| and unbrace the sneaked stuff.
%    \begin{macrocode}
\long\def\ekv@endset\ekv@stop\ekv@set@other##1\ekv@mark\ekv@stop,\ekv@stop,##2%
  {##2}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@eq@other@or@active,\ekv@eq@active}
%   Splitting at equal signs will be done in a way that checks whether there is
%   an equal sign and splits at the same time. This gets quite messy and the
%   code might look complicated, but this is pretty fast (faster than first
%   checking for an equal sign and splitting if one is found). The splitting
%   code will be adapted for |\ekvset| and |\ekvparse| to get the most speed,
%   but some of these macros don't require such adaptions.
%   |\ekv@eq@other@or@active| and |\ekv@eq@active| will split the argument at
%   the first equal sign. |\ekv@eq@active| will insert the macro which comes
%   after the first following |\ekv@mark|, while |\ekv@eq@other@or@active| will
%   also check for an active equals sign or none.
%   Usage should look like this:
%   \begin{syntaxexample*}
%     |\ekv@eq@other@or@active|
%       \indent|#1\ekv@nil\ekv@mark|\meta{code for \tkn{=}{12}}
%       \indent\tkn{=}{12}|\ekv@mark|\meta{code for no equals sign}
%       \indent|#1\ekv@mark|\meta{code for \tkn{=}{13} or mixed}
%       \indent\tkn{=}{13}|\ekv@mark{}|
%     |\ekv@eq@active|
%       \indent|#1\ekv@nil\ekv@mark|\meta{code for \tkn{=}{13}}
%       \indent\tkn{=}{13}|\ekv@mark|\meta{code for no \tkn{=}{13}}
%   \end{syntaxexample*}
%   To prevent accidental brace stripping |#1| should be handed in with a
%   leading |\ekv@mark|, also that's what the |\ekv@nil| after the first |#1| is
%   used for. In |\ekv@eq@other@or@active| four cases are distinguished:
%   \begin{enumerate}
%     \item
%       Only equals signs of category 12 are found, then \meta{code for
%       \tkn{=}{12}} will be inserted.
%     \item
%       No equals sign is found, then \meta{code for no equals sign} will be
%       inserted.
%     \item
%       Only equals signs of category 13 are found, then \meta{code for
%       \tkn{=}{13} or mixed} will be inserted, directly followed by
%       \meta{code for no equals sign}.
%     \item
%       Equals signs of categories 12 and 13 are found, then \meta{code for
%       \tkn{=}{13} or mixed} directly followed by \meta{code for \tkn{=}{12}}
%       will be inserted.
%   \end{enumerate}
%   This allows for fast branching based on \TeX's argument grabbing rules and
%   we don't have to split after the branching if the equal sign was there.
%    \begin{macrocode}
\long\def\ekv@eq@other@or@active
    ##1=##2\ekv@mark##3%
    ##4#2##5\ekv@mark##6%
  {##6##3##1\ekv@stop\ekv@mark##2}
\long\def\ekv@eq@other##1=##2\ekv@mark##3{##3##1\ekv@stop\ekv@mark##2}
\long\def\ekv@eq@active##1#2##2\ekv@mark##3{##3##1\ekv@stop\ekv@mark##2}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@set@other,\ekv@set@next@other}
%   The macro |\ekv@set@other| is guaranteed to get only single \kv\ pairs.
%    \begin{macrocode}
\long\def\ekv@set@other##1##2,%
  {%
%    \end{macrocode}
%   First we test whether we're done.
%    \begin{macrocode}
    \ekv@gobble@from@mark@to@stop##2\ekv@endset@other\ekv@stop
%    \end{macrocode}
%   If not we split at the equal sign of category other.
%    \begin{macrocode}
    \ekv@eq@other@or@active
      ##2\ekv@nil\ekv@mark\ekv@set@eq@other
      =\ekv@mark\ekv@set@noeq
      ##2\ekv@mark\ekv@set@eq@active
      #2\ekv@mark{}%
%    \end{macrocode}
%   And put the set name after the splitting.
%    \begin{macrocode}
    ##1%
    \ekv@mark
  }
%    \end{macrocode}
%   The second macro is used as a shortcut to gobble two arguments and do the
%   same as a following |\ekv@set@other|.
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@set@next@other##1##2\ekv@set@other##3##4,}%
  {\ekv@set@other{##3}{##4},}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@endset@other}
%   Breaking the current inner loop for \tkn{,}{12} is done by gobbling all the
%   remaining tokens and grabbing the next split at an active comma
%   (incorporating the next |\ekv@set| call).
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@endset@other
    \ekv@stop\ekv@eq@other@or@active
    \ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@set@eq@other
    =\ekv@mark\ekv@set@noeq
    \ekv@mark\ekv@stop\ekv@mark\ekv@set@eq@active#2\ekv@mark##1%
    ##2##3#1}%
  {\ekv@set{##2}{##3}#1}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@set@eq@other}
%   If this gets called we know that there is no \tkn{=}{13}, hence are done
%   with the splitting business. This doesn't even need much clean up, we can
%   just strip the \key-name and forward it to |\ekv@set@pair|.
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@set@eq@other##1\ekv@stop}%
  {\ekv@strip@key{##1}\ekv@set@pair}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@set@if@noeq}
%   In the case that there was at least one \tkn{=}{13} we need a way to know
%   whether there also was a \tkn{=}{12}. This here can be used to check this by
%   only looking for |\ekv@set@noeq|.
%    \begin{macrocode}
\def\ekv@set@if@noeq##1\ekv@set@noeq{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@set@eq@active,\ekv@set@eq@active@}
%   The first token after this will either be |\ekv@set@noeq| or
%   |\ekv@set@eq@other|. We test this and branch accordingly.
%    \begin{macrocode}
\def\ekv@set@eq@active##1%
  {\ekv@set@if@noeq##1\ekv@set@eq@active@\ekv@set@noeq\ekv@set@eq@mixed}
%    \end{macrocode}
%   Since we know that there was no \tkn{=}{12} when the next macro is called we
%   can simply do the correct split without any checks and forward to
%   |\ekv@set@pair|.
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@set@eq@active@
    \ekv@set@noeq\ekv@set@eq@mixed
    ##1#2##2\ekv@mark
    \ekv@set@eq@other\ekv@stop\ekv@mark#2\ekv@mark##3}%
  {\ekv@strip@key{##1}\ekv@set@pair\ekv@mark##2}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {\ekv@set@eq@mixed,\ekv@set@eq@mixed@o,\ekv@set@mixed@a}
%   In the mixed case we grab until the first split of \tkn{=}{12} already done,
%   and resplit at \tkn{=}{13} using the conditonal splitter described earlier.
%    \begin{macrocode}
\long\def\ekv@set@eq@mixed##1\ekv@stop
  {%
    \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@mixed@a
      #2\ekv@mark\ekv@set@eq@mixed@o
  }
%    \end{macrocode}
%   If there actually was no \tkn{=}{13} before the first \tkn{=}{12} everything
%   was fine. We pick up our first split and remove the gibberish left by the
%   conditional splitter.
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@set@eq@mixed@o
    ##1\ekv@nil\ekv@mark\ekv@set@eq@mixed@a\ekv@stop\ekv@mark
    ##2\ekv@nil#2\ekv@mark##3}%
  {\ekv@strip@key{##1}\ekv@set@pair##2\ekv@nil}
%    \end{macrocode}
%   |\ekv@set@eq@mixed@a| will trigger if before the first \tkn{=}{12} there was
%   already a \tkn{=}{13}. So we use the new split and revert the erroneous
%   split at \tkn{=}{12}.
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@set@eq@mixed@a
    ##1\ekv@stop
    ##2\ekv@nil#2\ekv@mark\ekv@set@eq@mixed@o\ekv@mark
    ##3#2\ekv@mark##4}%
  {\ekv@strip@key{##1}\ekv@set@pair##2=##3}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@set@noeq,\ekv@set@was@blank}
%   If there was no equals sign the current element might in fact be blank.
%   Blank elements are ignored, hence we need to check for that, else we can
%   call |\ekv@set@key|.
%    \begin{macrocode}
\ekv@expandedarg
  {%
    \long\def\ekv@set@noeq
      ##1\ekv@nil\ekv@mark\ekv@set@eq@other\ekv@stop\ekv@mark
  }%
  {%
    \ekv@unexpanded
      {%
        \ekv@ifblank@##1\ekv@stop\ekv@ifblank@gobbletrue
          \ekv@stop\ekv@set@was@blank
      }%
    \ekv@unexpanded\expandafter{\ekv@strip@key{##1}\ekv@set@key}%
  }
%    \end{macrocode}
%   If in fact the element was blank we remove the |\ekv@set@key| call and
%   instead do the next iteration of |\ekv@set@other|.
%    \begin{macrocode}
\ekv@exparg{\long\expandafter\def\expandafter\ekv@set@was@blank
    \ekv@strip@key{\ekv@mark##1}\ekv@set@key
    ##2##3,}%
  {\ekv@set@other{##2}{##3},}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
% Provide macros that can completely stop the parsing of |\ekvset|, who knows
% what it'll be useful for.
%    \begin{macrocode}
\long\def\ekvbreak##1##2\ekv@stop#1##3{##1}
\long\def\ekvbreakPreSneak ##1##2\ekv@stop#1##3{##1##3}
\long\def\ekvbreakPostSneak##1##2\ekv@stop#1##3{##3##1}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvsneak,\ekvsneakPre}
% One last thing we want to do for |\ekvset| is to provide macros that just
% smuggle stuff after |\ekvset|'s effects.
%    \begin{macrocode}
\long\def\ekvsneak##1##2\ekv@stop#1##3{##2\ekv@stop#1{##3##1}}
\long\def\ekvsneakPre##1##2\ekv@stop#1##3{##2\ekv@stop#1{##1##3}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvparse}
% Additionally to the |\ekvset| macro we also want to provide an |\ekvparse|
% macro, that has the same scope as |\keyval_parse:NNn| from \pkg{expl3}.
% This is pretty analogue to the |\ekvset| implementation, we just put an
% |\unexpanded| here and there instead of other macros to stop the |\expanded|
% on our output. The |\unexpanded\expanded{{...}}| ensures that the material
% is in an alignment safe group at all time, and that it doesn't expand any
% further in an |\edef| or |\expanded| context.
%    \begin{macrocode}
\long\def\ekvparse##1##2##3%
  {%
    \ekv@unexpanded\ekv@expanded
      {{\ekv@parse{##1}{##2}\ekv@mark##3#1\ekv@stop#1}}%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse}
%    \begin{macrocode}
\long\def\ekv@parse##1##2##3#1%
  {%
    \ekv@gobble@from@mark@to@stop##3\ekv@endparse\ekv@stop
    \ekv@parse@other{##1}{##2}##3,\ekv@stop,%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@endparse}
%    \begin{macrocode}
\long\def\ekv@endparse\ekv@stop\ekv@parse@other##1\ekv@mark\ekv@stop,\ekv@stop,%
  {}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@other}
%    \begin{macrocode}
\long\def\ekv@parse@other##1##2##3,%
  {%
    \ekv@gobble@from@mark@to@stop##3\ekv@endparse@other\ekv@stop
    \ekv@eq@other@or@active
      ##3\ekv@nil\ekv@mark\ekv@parse@eq@other
      =\ekv@mark\ekv@parse@noeq
      ##3\ekv@mark\ekv@parse@eq@active#2\ekv@mark{}%
    {##1}{##2}%
    \ekv@mark
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@endparse@other}
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@endparse@other
    \ekv@stop\ekv@eq@other@or@active
    \ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@parse@eq@other
    =\ekv@mark\ekv@parse@noeq
    \ekv@mark\ekv@stop\ekv@mark\ekv@parse@eq@active#2\ekv@mark##1%
    ##2##3##4#1}%
  {\ekv@parse{##2}{##3}{##4}#1}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@eq@other}
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@parse@eq@other##1\ekv@stop}%
  {\ekv@strip{##1}\ekv@parse@pair}%
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@if@noeq}
%    \begin{macrocode}
\def\ekv@parse@if@noeq##1\ekv@parse@noeq{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@eq@active,\ekv@parse@eq@active@}
%    \begin{macrocode}
\def\ekv@parse@eq@active##1%
  {%
    \ekv@parse@if@noeq##1\ekv@parse@eq@active@\ekv@parse@noeq
    \ekv@parse@eq@mixed
  }
\ekv@exparg{\long\def\ekv@parse@eq@active@
    \ekv@parse@noeq\ekv@parse@eq@mixed
    ##1#2##2\ekv@mark
    \ekv@parse@eq@other\ekv@stop\ekv@mark#2\ekv@mark##3}%
  {\ekv@strip{##1}\ekv@parse@pair\ekv@mark##2}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {\ekv@parse@eq@mixed,\ekv@parse@eq@mixed@o,\ekv@parse@eq@mixed@a}
%    \begin{macrocode}
\long\def\ekv@parse@eq@mixed##1\ekv@stop
  {%
    \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@mixed@a
      #2\ekv@mark\ekv@parse@eq@mixed@o
  }
\ekv@exparg{\long\def\ekv@parse@eq@mixed@a
    ##1\ekv@stop
    ##2\ekv@nil#2\ekv@mark\ekv@parse@eq@mixed@o\ekv@mark
    ##3#2\ekv@mark##4}%
  {\ekv@strip{##1}\ekv@parse@pair##2=##3}
\ekv@exparg{\long\def\ekv@parse@eq@mixed@o
    ##1\ekv@nil\ekv@mark\ekv@parse@eq@mixed@a\ekv@stop\ekv@mark
    ##2\ekv@nil#2\ekv@mark##3}%
  {\ekv@strip{##1}\ekv@parse@pair##2\ekv@nil}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@noeq,\ekv@parse@was@blank}
%    \begin{macrocode}
\ekv@expandedarg
  {%
    \long\def\ekv@parse@noeq
      ##1\ekv@nil\ekv@mark\ekv@parse@eq@other\ekv@stop\ekv@mark
  }%
  {%
    \ekv@unexpanded
      {%
        \ekv@ifblank@##1\ekv@stop\ekv@ifblank@gobbletrue
          \ekv@stop\ekv@parse@was@blank
      }%
    \ekv@unexpanded\expandafter{\ekv@strip{##1}\ekv@parse@key}%
  }
\ekv@exparg{\long\expandafter\def\expandafter\ekv@parse@was@blank
    \ekv@strip{\ekv@mark##1}\ekv@parse@key
    ##2##3##4,}%
  {\ekv@parse@other{##2}{##3}{##4},}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@pair,\ekv@parse@pair@}
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@parse@pair##1##2\ekv@nil}%
  {\ekv@strip{##2}\ekv@parse@pair@{##1}}
\ekv@exparg{\long\def\ekv@parse@pair@##1##2##3##4}%
  {%
    \ekv@ifexp{##2}%
      {\ekv@expansion@parse@pair{##1}{##4}}%
      {\ekv@unexpanded{##4{##2}{##1}}}%
    \ekv@parse@other{##3}{##4}%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@key}
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@parse@key##1##2}%
  {%
    \ekv@ifexp{##1}%
      {\ekv@expansion@parse@key{##2}}%
      {\ekv@unexpanded{##2{##1}}}%
    \ekv@parse@other{##2}%
  }
%    \end{macrocode}
% \end{macro}
%
% Finally really setting things up with |\ekvset|'s temporary meaning:
%    \begin{macrocode}
}
\catcode`\,=13
\catcode`\==13
\ekvset,=
%    \end{macrocode}
%
% \begin{macro}{\ekvsetSneaked}
% This macro can be defined just by expanding |\ekvsneak| once after expanding
% |\ekvset|. To expand everything as much as possible early on we use a
% temporary definition.
%    \begin{macrocode}
\edef\ekvsetSneaked
  {%
    \ekv@unexpanded{\ekvsneak{#2}}%
    \ekv@unexpanded\expandafter{\ekvset{#1}{#3}}%
  }
\ekv@expargtwice{\long\def\ekvsetSneaked#1#2#3}{\ekvsetSneaked}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvchangeset}
% Provide a macro that is able to switch out the current \set\ in |\ekvset|.
% This operation allows something similar to \pkg{pgfkeys}'s
% \texttt{\meta{key}/.cd} mechanism. However this operation can be more
% expensive than |/.cd| as we can't just redefine some token to reflect this,
% but have to switch out the set expandably, so this works similar to the
% |\ekvsneak| macros reading and reinserting things, but it only has to read and
% reinsert the remainder of the current key's replacement code.
%    \begin{macrocode}
\ekv@exparg{\def\ekvchangeset#1}%
  {%
    \expandafter\expandafter\expandafter
    \ekv@changeset\expandafter\csname\ekv@undefined@set{#1}\endcsname\ekv@empty
  }
%    \end{macrocode}
% \begin{macro}[internal]{\ekv@changeset}
% This macro does the real change-out of |\ekvchangeset|. |#2| will have a
% leading |\ekv@empty| so that braces aren't stripped accidentally, but that
% will not hurt and just expand to nothing in one step.
%    \begin{macrocode}
\long\def\ekv@changeset#1#2\ekv@set@other#3{#2\ekv@set@other#1}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ekvmorekv}
%   |\ekvmorekv| injects additional keys for consideration without needing a
%   nested |\ekvset|. The issue we're facing here is that we can only inject
%   after the next |\ekv@set@other| to not destroy the order of things, but in
%   theory the argument to |\ekvmorekv| could contain an active comma. Now we
%   have two options:
%   \begin{enumerate}
%     \item reread all keys until the end of the current |\ekv@set@other| loop
%       to change the commas there to an active one and insert |\ekv@set|
%       instead
%     \item loop over the argument of |\ekvmorekv| to remove all top-level
%       active commas and replace them with ones of category 12.
%   \end{enumerate}
%   The following implements the second approach. We use a temporary definition
%   of |\ekvmorekv| to get us |#1| for active commas. For the comma replacement
%   we set up a small loop. The |\ekv@empty| at the end of |\ekvmorekv|'s
%   definition protects against accidental brace loss in user code.
%    \begin{macrocode}
\def\ekvmorekv#1%
  {%
    \long\def\ekvmorekv##1%
      {%
        \expandafter\ekv@morekv\ekv@expanded
          {{\ekv@morekv@loop\ekv@empty##1\ekv@stop\ekv@morekv@done#1}}%
        \ekv@empty
      }%
%    \end{macrocode}
% \begin{macro}[internal]{\ekv@parse@more,\ekv@parse@more@}
%   For the expansion control we also need a way to support reinsertion in
%   |\ekvparse|. Since there no user code is executed this is an internal macro.
%   It works in the same way but the argument order exchange is different. Also,
%   since this is only used internally, we know it is safe to omit the trailing
%   |\ekv@empty|.
%    \begin{macrocode}
    \long\def\ekv@parse@more##1\@gobble##2%
      {%
        \expandafter\ekv@parse@more@\ekv@expanded
          {{\ekv@morekv@loop\ekv@empty##1\ekv@stop\ekv@morekv@done#1}}%
      }%
    \long\def\ekv@parse@more@##1\ekv@parse@other##2##3\ekv@mark
      {\ekv@parse@other{##2}{##3}\ekv@mark##1,}%
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]{\ekv@morekv}
%   This is just a simple change of argument order, injecting the new comma
%   separated list after the current |\ekv@set@other| call.
%    \begin{macrocode}
    \long\def\ekv@morekv##1##2\ekv@set@other##3\ekv@mark
      {##2\ekv@set@other##3\ekv@mark##1,}
%    \end{macrocode}
% \end{macro}
% \begin{macro}[internal]
%   {\ekv@morekv@loop,\ekv@morekv@done,\ekv@morekv@wrap}
%   And here is the heavy lifting of the comma replacement. Each list element
%   until the next active comma is read and left as an argument for
%   |\ekv@morekv@wrap|, that will remove the leading |\ekv@empty|. The trick for
%   a fast end of the loop is that |\ekv@morekv@wrap| will read until the next
%   |\ekv@stop|, of which an additional one is put before |\ekv@morekv@done| so
%   that |wrap| will wrap the real end of the list and then |done| removes the
%   excess code.
%    \begin{macrocode}
    \long\def\ekv@morekv@loop##1#1%
      {\ekv@morekv@wrap##1\ekv@stop,\ekv@morekv@loop\ekv@empty}%
    \long\def\ekv@morekv@wrap##1\ekv@stop{\ekv@unexpanded\expandafter{##1}}%
    \def\ekv@morekv@done\ekv@stop,\ekv@morekv@loop\ekv@empty{}%
  }
\begingroup\catcode`\,=13 \@firstofone{\endgroup\ekvmorekv,}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}[internal]
%   {
%     \ekv@def@expansion@rule,\ekv@def@expansion@rule@ea,
%     \ekv@expansion@rule@,\ekv@expansion@csname
%   }
%   All expansion rules share the same basic structure, they do their expansion
%   step and then call |\ekv@expansion@rule@| (this could be done faster by
%   letting each rule build the macro for the next rule in |\csname|, but that
%   would require a more complex argument grabbing structure of the rules, and
%   we'd need to use |\expanded{\unexpanded{\csname ...\endcsname}\expandafter}|
%   or similar to not do the expansion steps of the \val\ inside of |\csname|).
%   As a result of this the \val\ needs to be grabbed twice per expansion step.
%    \begin{macrocode}
\protected\def\ekv@def@expansion@rule#1#2#3#4%
  {%
    \long\expandafter\def\csname ekv@expansion@rule@#1\endcsname##1#2%
      {#3\ekv@expansion@rule@#4}%
  }
\protected\def\ekv@def@expansion@rule@ea#1#2%
  {\ekv@def@expansion@rule{#1}{#2}\expandafter}
%    \end{macrocode}
%   Rules follow this naming scheme. Note that for an undefined rule an error is
%   thrown and the result of the |\csname| is |\ekv@expansion@rule@|.
%    \begin{macrocode}
\long\def\ekv@expansion@csname#1\ekv@stop
  {%
    ekv@expansion@rule@%
    \ifcsname ekv@expansion@rule@#1\endcsname
      #1%
    \else
      \ekv@err@undefined@expansion{#1}%
    \fi
  }
%    \end{macrocode}
%   This auxiliary macro simply builds the next rule, it is used to start an
%   expansion chain, as well as for each defined or undefined rule.
%    \begin{macrocode}
\long\def\ekv@expansion@rule@#1#2%
  {\csname\expandafter\ekv@expansion@csname\string#2\ekv@stop\endcsname{#1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@expansion@rule@\ekv@mark}
%   The expansion chain is ended by an internal rule that behaves very different
%   from the others. It'll test whether the |r|-rule was used (in which case the
%   third argument will not be empty, and also execute that reinsertion) or grab
%   the code for the next step after the expansion.
%    \begin{macrocode}
\ekv@exparg
  {%
    \long\expandafter
    \def\csname ekv@expansion@rule@\string\ekv@mark\endcsname
      #1\ekv@stop#2#3#4#5%
  }%
  {%
    \romannumeral\ekv@exparg{\expandafter\ekv@zero\ekv@ifempty{#3}{#5{#2}{#1}}}%
      {\ekv@ifempty{#2}{#4{#1}}{\ekv@err@val@no@reinsert{#2}}}%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \ekv@expansion@rule@o,\ekv@expansion@rule@e,\ekv@expansion@rule@c,
%     \ekv@expansion@rule@f,\ekv@expansion@rule@V,\ekv@expansion@rule@v,
%     \ekv@expansion@rule@s,\ekv@expansion@rule@b,\ekv@expansion@rule@\r,
%     \ekv@expansion@rule@g,\ekv@expansion@rule@p,\ekv@expansion@rule@P,
%     \ekv@expansion@rule@r,\ekv@expansion@rule@R
%   }
%   All the expansion rules are executed inside a |\csname| construct, so they
%   have to issue an |\endcsname| after the intended expansion took place. I
%   guess the code is pretty straight forward here.
%    \begin{macrocode}
\ekv@def@expansion@rule@ea{o}{}{\expandafter{#1}}
\ekv@def@expansion@rule@ea{e}{}{\ekv@expanded{{#1}}}
\ekv@def@expansion@rule@ea{c}{}{\csname#1\endcsname}
\ekv@def@expansion@rule@ea{f}{}{\expandafter{\romannumeral`\^^@#1}}
\ekv@exparg{\ekv@def@expansion@rule{s}{}}{\ekv@strip{\ekv@mark#1}}{}
\ekv@def@expansion@rule{b}{}{}{{{#1}}}
\ekv@def@expansion@rule{\string\r}{#2\ekv@stop#3#4}{}{{#1}#2\ekv@stop{#3}{#4r}}
\ekv@def@expansion@rule@ea{g}{}{\expandafter{\@gobble#1}}
\ekv@def@expansion@rule{p}{#2}{}{{#2#1}}
\ekv@def@expansion@rule{P}{#2}{}{{#1#2}}
%    \end{macrocode}
%   The |V| and |v| rules are a bit more complicated. They use some auxiliaries
%   but otherwise should be more or less obvious as well. The |v| one uses some
%   expansion to get a more meaningful error message in case the resulting
%   control sequence would be undefined (without actually using |\csname|, to
%   not accidentally define anything as |\relax|).
%    \begin{macrocode}
\long\def\ekv@expansion@rule@V#1%
  {%
    \ifx\relax#1\ekv@err@erroneous@variable{#1}\ekv@expansion@@clean@V\fi
    \ekv@expansion@@V{#1}%
  }
\ekv@expandedarg{\long\def\ekv@expansion@rule@v#1}%
  {%
    \ekv@unexpanded{\ekv@ifdefined{#1}%
      {\expandafter\ekv@expansion@@V\csname#1\endcsname}}%
      {%
        \ekv@unexpanded{\expandafter\ekv@err@erroneous@variable\ekv@expanded}%
          {{\expandafter\@gobble\string\\#1}}%
        \ekv@unexpanded{\ekv@expansion@rule@}{}%
      }%
  }
\ekv@exparg{\long\def\ekv@expansion@rule@r#1#2\ekv@stop#3#4}%
  {\ekv@expansion@rule@v{#1}#2\ekv@stop{#3}{#4r}}
\ekv@exparg{\long\def\ekv@expansion@rule@R#1#2\ekv@stop#3#4}%
  {\ekv@expansion@rule@V{#1}#2\ekv@stop{#3}{#4r}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@expansion@@V,\ekv@expansion@@clean@V}
%   The actual |V| evaluation is pretty much the same as in \pkg{expl3}, but we
%   need to put braces around the expansion result, hence branch slightly
%   differently. In general, a macro will temporarily have the meaning of
%   |\relax| if hit by |\noexpand| and hence the \cs[no-index]{ifx} test will
%   result in false (as the meaning isn't the same now), so we can tell
%   whether it would expand directly. Else we assume this is a register type and
%   use |\the|.
%    \begin{macrocode}
\long\def\ekv@expansion@@V#1%
  {%
    \expandafter\ifx\noexpand#1#1%
      \ekv@fi@firstoftwo
    \fi
    \@secondoftwo
    {\expandafter\ekv@expansion@rule@\expandafter{\the#1}}%
    {\expandafter\ekv@expansion@rule@\expandafter{#1}}%
  }
\long\def\ekv@expansion@@clean@V\fi\ekv@expansion@@V#1%
  {\fi\ekv@expansion@rule@{}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {\ekv@expansion@rule@\key,\ekv@expansion@rule@\ekv@key@after}
%   The |\key|-rule works by calling a nested expansion chain with swapped \key\
%   and \val. Instead of |\ekv@mark| marking the end of the expansion chain
%   we use a different final step called |\ekv@key@after|, that simply checks
%   whether an |r|-rule was executed (\emph{error}) and ends the current
%   expansion step in the outer chain.
%    \begin{macrocode}
\ekv@def@expansion@rule{\string\key}{#2#3\ekv@stop#4}%
  {}{{#4}#2\ekv@key@after\ekv@stop{#1}{}{#3}}
\ekv@exparg{\ekv@def@expansion@rule{\string\ekv@key@after}{\ekv@stop#2#3#4}}%
  {\ekv@ifempty{#3}{}\ekv@err@key@no@reinsert}
  {{#2}#4\ekv@stop{#1}}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}[internal]
%   {
%     \ekv@set@pair,\ekv@set@pair@,
%     \ekv@set@pair@relax,\ekv@set@pair@undefined,
%     \ekv@set@pair@u,\ekv@set@pair@u@relax,\ekv@set@pair@no@u
%   }
%   |\ekv@set@pair| gets invoked with the space and brace stripped key-name as
%   its first, the value as the second (delimited by |\ekv@nil|), and the set
%   name as the third argument. It provides tests for the key-macros and
%   everything to be able to throw meaningful error messages if it isn't
%   defined. We have two routes here, one if |\lastnamedcs| is defined and one
%   if it isn't. The big difference is that if it is we can omit a |\csname| and
%   instead just expand |\lastnamedcs| once to get the control sequence.
%   If the macro is defined the value will be space and brace stripped and the
%   key-macro called. Else branch into the error handling provided by
%   |\ekv@set@pair@undefined|.
%    \begin{macrocode}
\ekv@if@lastnamedcs
  {%
    \long\def\ekv@set@pair#1\ekv@mark#2#3\ekv@nil#4%
      {%
        \ifcsname#4{#1}\endcsname\expandafter\ekv@set@pair@\lastnamedcs\fi
        \ekv@set@pair@undefined{#3}{#1}{#2}%
        \ekv@set@other#4%
      }
    \ekv@exparg{\long\def\ekv@set@pair@undefined#1#2#3\ekv@set@other#4}%
      {%
        \romannumeral
        \ekv@exparg
          {\expandafter\ekv@zero\ekv@ifexp{#3}}%
          {\ekv@strip{#1}\ekv@expansion@set@pair}%
          {%
            \ifcsname#4{}u\endcsname\expandafter\ekv@set@pair@u\lastnamedcs\fi
            \ekv@set@pair@no@u{#1}{#2}{#3}%
          }%
        \ekv@set@other#4%
      }
  }
  {%
    \long\def\ekv@set@pair#1\ekv@mark#2#3\ekv@nil#4%
      {%
        \ifcsname#4{#1}\endcsname
          \expandafter\ekv@set@pair@\csname#4{#1}\endcsname
        \fi
        \ekv@set@pair@undefined{#3}{#1}{#2}%
        \ekv@set@other#4%
      }
    \ekv@exparg{\long\def\ekv@set@pair@undefined#1#2#3\ekv@set@other#4}%
      {%
        \romannumeral
        \ekv@exparg
          {\expandafter\ekv@zero\ekv@ifexp{#3}}%
          {\ekv@strip{#1}\ekv@expansion@set@pair}%
          {%
            \ifcsname#4{}u\endcsname
              \expandafter\ekv@set@pair@u\csname#4{}u\endcsname
            \fi
            \ekv@set@pair@no@u{#1}{#2}{#3}%
          }%
        \ekv@set@other#4%
      }
  }
\ekv@expandedarg{\long\def\ekv@set@pair@#1\fi\ekv@set@pair@undefined#2}%
  {%
    \ekv@unexpanded{\fi\ifx#1\relax\ekv@set@pair@relax\fi}%
    \ekv@unexpanded\expandafter{\ekv@strip{#2}#1\ekv@set@next@other}%
  }
\ekv@expandafter{\long\def\ekv@set@pair@relax\fi}%
    \ekv@strip{#1}#2\ekv@set@next@other
  {\fi\ekv@set@pair@undefined{#1}}
\ekv@expandedarg{\long\def\ekv@set@pair@u#1\fi\ekv@set@pair@no@u#2}%
  {%
    \ekv@unexpanded
      {%
        \fi
        \ifx\relax#1%
          \ekv@set@pair@u@relax
        \fi
      }%
    \ekv@unexpanded\expandafter{\ekv@strip{#2}#1}%
  }
\ekv@expandafter{\long\def\ekv@set@pair@u@relax\fi}\ekv@strip{\ekv@mark#1}#2%
  {\fi\ekv@set@pair@no@u.}
\long\def\ekv@set@pair@no@u#1#2#3\ekv@set@other#4%
  {%
    \ekv@ifdefined{#4{#2}N}%
      \ekv@err@noarg
      \ekv@err@unknown
        #4{#2}{#3}%
    \ekv@set@other#4%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \ekv@set@key,\ekv@set@key@,
%     \ekv@set@key@relax,\ekv@set@key@undefined,
%     \ekv@set@key@u,\ekv@set@key@u@relax,\ekv@set@key@no@u
%   }
% Analogous to |\ekv@set@pair|, |\ekv@set@key| builds the \Nkey-macro and
% provides an error-branch. It'll test whether the key-macro is defined and if
% so call it, else there might be some \expnotation, or errors are thrown.
%    \begin{macrocode}
\ekv@if@lastnamedcs
  {%
    \long\def\ekv@set@key#1\ekv@mark#2#3%
      {%
        \ifcsname#3{#1}N\endcsname\expandafter\ekv@set@key@\lastnamedcs\fi
        \ekv@set@key@undefined{#1}{#2}%
        \ekv@set@other#3%
      }
    \ekv@exparg{\long\def\ekv@set@key@undefined#1#2\ekv@set@other#3}%
      {%
        \ekv@ifexp{#2}%
          \ekv@expansion@set@key
          {%
            \ifcsname#3{}uN\endcsname\expandafter\ekv@set@key@u\lastnamedcs\fi
            \ekv@set@key@no@u{#1}{#2}%
          }%
        \ekv@set@other#3%
      }
  }
  {%
    \long\def\ekv@set@key#1\ekv@mark#2#3%
      {%
        \ifcsname#3{#1}N\endcsname
          \expandafter\ekv@set@key@\csname#3{#1}N\endcsname
        \fi
        \ekv@set@key@undefined{#1}{#2}%
        \ekv@set@other#3%
      }
    \ekv@exparg{\long\def\ekv@set@key@undefined#1#2\ekv@set@other#3}%
      {%
        \ekv@ifexp{#2}%
          \ekv@expansion@set@key
          {%
            \ifcsname#3{}uN\endcsname
              \expandafter\ekv@set@key@u\csname#3{}uN\endcsname
            \fi
            \ekv@set@key@no@u{#1}{#2}%
          }%
        \ekv@set@other#3%
      }
  }
\long\def\ekv@set@key@#1\fi\ekv@set@key@undefined
  {\fi\ifx#1\relax\ekv@set@key@relax\fi#1\ekv@set@next@other}
\long\def\ekv@set@key@relax\fi#1\ekv@set@next@other{\fi\ekv@set@key@undefined}
\long\def\ekv@set@key@u#1\fi\ekv@set@key@no@u
  {\fi\ifx\relax#1\ekv@set@key@u@relax\fi#1}
\def\ekv@set@key@u@relax\fi#1{\fi\ekv@set@key@no@u}
\long\def\ekv@set@key@no@u#1#2\ekv@set@other#3%
  {%
    \ekv@ifdefined{#3{#1}}%
      \ekv@err@reqval
      \ekv@err@unknown
        #3{#1}{#2}%
    \ekv@set@other#3%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \ekv@expansion@set@key,\ekv@expansion@set@key@,
%     \ekv@expansion@set@pair,\ekv@expansion@set@pair@
%   }
%   These macros just pick up the pieces of the \expansion\ prefix as separate
%   arguments. The \val\ for the \expansion-rules is left empty. Once expansion
%   is done we loop back to |\ekv@set@key|, that'll pick up the processed \key\
%   and set it if it's now defined. The same trick is used for a \kv\ pair.
%    \begin{macrocode}
\long\def\ekv@expansion@set@key#1#2#3%
  {%
    \ekv@expansion@rule@{#2}#1\ekv@mark\ekv@stop{}{}\ekvmorekv
    \ekv@expansion@set@key@
  }
\long\def\ekv@expansion@set@key@#1#2\ekv@set@other#3%
  {\expandafter\ekv@set@key\detokenize{#2}\ekv@mark{#2}#3}
\long\def\ekv@expansion@set@pair#1#2#3#4%
  {%
    \ekv@expansion@rule@{#1}#2\ekv@mark\ekv@stop{#3}{}\ekvmorekv
    \ekv@expansion@set@pair@
  }
\long\def\ekv@expansion@set@pair@#1#2\ekv@set@other#3%
  {\expandafter\ekv@set@pair\detokenize{#1}\ekv@mark{#1}\ekv@mark{#2}\ekv@nil#3}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \ekv@expansion@parse@key,\ekv@expansion@parse@key@,
%     \ekv@expansion@parse@pair,\ekv@expansion@parse@pair@
%   }
%   In |\ekvparse| we don't need to resort to looping back into |\ekv@parse@key|
%   or the like, we can simply leave the result via |\ekv@unexpanded|.
%    \begin{macrocode}
\long\def\ekv@expansion@parse@key#1#2#3#4%
  {%
    \ekv@expansion@rule@{#3}#2\ekv@mark\ekv@stop{}{}\ekv@parse@more
    \ekv@expansion@parse@key@\@gobble{#1}%
  }
\long\def\ekv@expansion@parse@key@#1#2\@gobble#3{\ekv@unexpanded{#3{#2}}}
\long\def\ekv@expansion@parse@pair#1#2#3#4#5%
  {%
    \ekv@expansion@rule@{#1}#3\ekv@mark\ekv@stop{#4}{}\ekv@parse@more
    \ekv@expansion@parse@pair@\@gobble{#2}%
  }
\long\def\ekv@expansion@parse@pair@#1#2\@gobble#3{\ekv@unexpanded{#3{#1}{#2}}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvsetdef}
%   Provide a macro to define a shorthand to use |\ekvset| on a specified \set.
%   To gain the maximum speed |\ekvset| is expanded twice by
%   |\ekv@exparg| so that during runtime the macro storing the set name
%   is already built and one |\expandafter| doesn't have to be used.
%    \begin{macrocode}
\ekv@expargtwice{\protected\def\ekvsetdef#1#2}%
  {%
    \romannumeral
    \ekv@exparg{\ekv@zero\ekv@exparg{\def#1##1}}%
      {\ekvset{#2}{##1}}%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvsetSneakeddef,\ekvsetdefSneaked}
% And do the same for |\ekvsetSneaked| in the two possible ways, with a fixed
% sneaked argument and with a flexible one.
%    \begin{macrocode}
\ekv@expargtwice{\protected\def\ekvsetSneakeddef#1#2}%
  {%
    \romannumeral
    \ekv@exparg{\ekv@zero\ekv@exparg{\long\def#1##1##2}}%
      {\ekvsetSneaked{#2}{##1}{##2}}%
  }
\ekv@expargtwice{\protected\def\ekvsetdefSneaked#1#2#3}%
  {%
    \romannumeral
    \ekv@exparg{\ekv@zero\ekv@exparg{\long\def#1##1}}%
      {\ekvsetSneaked{#2}{#3}{##1}}%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@alignsafe,\ekv@endalignsafe}
%   These macros protect the usage of ampersands inside of alignment contexts.
%    \begin{macrocode}
\begingroup
\catcode`\^^@=2
\@firstofone{\endgroup
  \def\ekv@alignsafe{\romannumeral\iffalse{\fi`^^@ }
}
\def\ekv@endalignsafe{\ifnum`{=\ekv@zero}\fi}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvoptarg,\ekvoptargTF}
% Provide macros to expandably collect an optional argument in brackets. The
% macros here are pretty simple in nature compared to \pkg{xparse}'s
% possibilities (they don't care for nested bracket levels).
%
% We start with a temporary definition to pre-expand |\ekv@alignsafe| (will be
% |#1|) and |\ekv@endalignsafe| (will be |#2|). As |\ekv@alignsafe| starts with
% a |\romannumeral| we use that to also control the number of steps needed
% instead of adding another |\romannumeral|. For this we have to remove the
% space token from the end of |\ekv@alignsafe|'s definition.
%    \begin{macrocode}
\begingroup
\def\ekvoptarg#1#2{%
\endgroup
%    \end{macrocode}
% The real definition starts an expansion context and afterwards grabs the
% arguments. |#1| will be the next step, |#2| the default value, and |#3| might
% be an opening bracket, or the mandatory argument. We check for the opening
% bracket, if it is found grab the optional argument, else leave |#1{#2}| in the
% input stream after ending the expansion context.
%    \begin{macrocode}
\def\ekvoptarg{#1\ekv@optarg@a}
\long\def\ekv@optarg@a##1##2##3%
  {%
    \ekv@optarg@if\ekv@mark##3\ekv@mark\ekv@optarg@b\ekv@mark[\ekv@mark
    #2%
    \@firstofone{ ##1}{##2}{##3}%
  }%
%    \end{macrocode}
% The other variant of this will do roughly the same. Here, |#1| will be the
% next step if an optional argument is found, |#2| the next step else, and |#3|
% might be the opening bracket or mandatory argument.
%    \begin{macrocode}
\def\ekvoptargTF{#1\ekv@optargTF@a}
\long\def\ekv@optargTF@a##1##2##3%
  {%
    \ekv@optarg@if\ekv@mark##3\ekv@mark\ekv@optargTF@b{##1}\ekv@mark[\ekv@mark
    #2%
    \@firstofone{ ##2}{##3}%
  }
%    \end{macrocode}
% The two macros to grab the optional argument have to remove the remainder of
% the test and the wrong next step as well as grabbing the argument.
%    \begin{macrocode}
\long\def\ekv@optarg@b\ekv@mark[\ekv@mark\ifnum`##1\fi\@firstofone##2##3##4##5]%
  {#2##2{##5}}
\long\def\ekv@optargTF@b
    ##1\ekv@mark[\ekv@mark\ifnum`##2\fi\@firstofone##3##4##5]%
  {#2 ##1{##5}}
}
%    \end{macrocode}
% Do the definitions and add the test macro. We use |\ekv@strip| to remove the
% trailing space from the definition of |\ekv@alignsafe|.
%    \begin{macrocode}
\ekv@exparg
  {%
    \expandafter\ekv@strip\expandafter
      {\expandafter\ekv@mark\ekv@alignsafe}%
      \ekvoptarg
  }%
  \ekv@endalignsafe
\long\def\ekv@optarg@if#1\ekv@mark[\ekv@mark{}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@ifstar}
%   Internal helper to get an expandable |ifstar| implementation. This is pretty
%   straight forward.
%    \begin{macrocode}
\long\def\ekv@ifstar#1#2#3%
  {%
    \if*\string#3%
      \ekv@fi@firstoftwo
    \fi
    \@secondoftwo
      {#1}%
      {#2{#3}}%
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvcompile}
%   The idea of key-compilation is to preparse some list into a form that sets
%   that list very fast (but is frozen), in our case this means we do everything
%   except expanding the key's code. There are two levels of expansion possible,
%   either expand until the key-macro or expand the key-macro once as well (the
%   latter might break if the key-macros take additional arguments). The
%   following supports both by using a starred form.
%    \begin{macrocode}
\protected\long\def\ekvcompile
  {%
    \ekv@alignsafe
    \ekv@ifstar{\ekv@compile{}}{\ekv@compile{\expandafter\expandafter}}%
  }
%    \end{macrocode}
% \begin{macro}[internal]
%   {\ekv@compile,\ekv@compile@,\ekv@compile@key,\ekv@compile@pair}
%   |\ekvparse| starts with an |\unexpanded| that we don't need. Hence we use a
%   temporary definition to remove that. Else this is pretty straight forward.
%   There is a minor indirection (the parsing step of |\ekv@compile|) which is
%   necessary to grab any argument specification.
%    \begin{macrocode}
\def\ekv@compile#1#2#3#{\ekv@compile@{#1}{#2#3}}
\def\ekv@compile@#1#2#3{#2#3}
\ekv@exparg{\protected\long\def\ekv@compile@#1#2#3#4}%
  {%
    \expandafter\ekv@expanded\expandafter
      {%
        \romannumeral\ekv@expargtwice{\ekv@zero\def\ekv@unexpanded{#2}}%
          {%
            \expandafter\ekv@compile@
            \ekvparse
              {\ekv@compile@key{#1}{#3}}%
              {\ekv@compile@pair{#1}{#3}}%
              {#4}%
          }%
      }%
    \ekv@endalignsafe
  }
%    \end{macrocode}
%   The compilation step just checks whether the keys are defined and leaves
%   their code (maybe expanded once).
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@compile@key#1#2#3}%
  {%
    \ekvifdefinedNoVal{#2}{#3}%
      {\ekv@unexpanded#1\expandafter{\csname\ekv@name{#2}{#3}N\endcsname}}%
      {%
        \ekv@ifdefined{\ekv@name{#2}{}uN}
          {%
            \ekv@unexpanded#1\expandafter
              {%
                \csname\ekv@name{#2}{}uN\expandafter\endcsname
                  \expandafter{\detokenize{#3}}{#3}%
              }%
          }%
          {%
            \ekvifdefined{#2}{#3}%
              {\ekv@err{missing value for `#3' in set `#2'}}%
              {\ekv@err{unknown key `#3' in set `#2'}}%
          }%
      }%
  }
\ekv@exparg{\long\def\ekv@compile@pair#1#2#3#4}%
  {%
    \ekvifdefined{#2}{#3}%
      {\ekv@unexpanded#1\expandafter{\csname\ekv@name{#2}{#3}\endcsname{#4}}}%
      {%
        \ekv@ifdefined{\ekv@name{#2}{}u}%
          {%
            \ekv@unexpanded#1\expandafter
              {%
                \csname\ekv@name{#2}{}u\ekv@expanded{\endcsname
                  {\ekv@unexpanded{#4}}{\detokenize{#3}}}{#3}%
              }%
          }%
          {%
            \ekvifdefinedNoVal{#2}{#3}%
              {\ekv@err{unwanted value for `#3' in set `#2'}}%
              {\ekv@err{unknown key `#3' in set `#2'}}%
          }%
      }%
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ekverr}
% \begin{macro}[internal]{\ekv@err@collect,\ekv@err@cleanup}
% Since |\ekvset| is fully expandable as long as the code of the keys is (which
% is unlikely) we want to somehow throw expandable errors, in our case via
% a runaway argument (to my knowledge the first version of this method was
% implemented by Jean-François Burnol, many thanks to him). The first step is to
% ensure that the second argument (which might contain user input) doesn't
% contain tokens we use as delimiters (in this case |\par|), this will be done
% by the front facing macro |\ekverr|. But first we set some other things up.
%
% We use a temporary definition for |\ekverr| to get multiple consecutive
% spaces. Then we set up the macro that will collect the error and the macro
% that will throw the error. The latter will have an unreasonable long name.
% This way we can convey more information. Though the information in the macro
% name is static and has to be somewhat general to fit every occurence. The
% important bit is that the long named macro has a delimited argument and is
% short which will throw the error at the |\par| at the end of
% |\ekv@err@collect|. This macro has the drawback that it will only print nicely
% if the |\newlinechar| is |^^J|.
%    \begin{macrocode}
\def\ekv@err@cleanup\par{}
\def\ekv@err@collect#1%
  {%
    \def\ekv@err@collect##1\par##2%
      {%
        \expandafter
        \ekv@err@cleanup
        #1! ##2 Error: ##1\par
      }%
    \def#1##1\thanks@jfbu{}%
  }
\def\ekverr{ }
\expandafter\ekv@err@collect\csname <an-expandable-macro>^^J%
  completed due to above exception. \ekverr If the error^^J%
  summary is \ekverr not comprehensible \ekverr see the package^^J%
  documentation.^^J%
  I will try to recover now. \ekverr If you're in inter-^^J%
  active mode hit <return> \ekverr at the ? prompt and I^^J%
  continue hoping recovery\endcsname
%    \end{macrocode}
%    \begin{macrocode}
\long\def\ekverr#1#2{\expandafter\ekv@err@collect\detokenize{#2}\par{#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@err,\ekv@errm}
% We define shorthands to throw errors in \expkv.
%    \begin{macrocode}
\ekv@exparg{\long\def\ekv@err#1}{\ekverr{expkv}{#1}}
\protected\long\def\ekv@errm#1{\errmessage{expkv Error: #1}}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]
%   {
%     \ekv@err@common,\ekv@err@common@,
%     \ekv@err@unknown,\ekv@err@noarg,\ekv@err@reqval,
%     \ekv@err@undefined@expansion
%   }
% Now we can use |\ekv@err| to set up some error messages so that we can later
% use those instead of the full strings.
%    \begin{macrocode}
\long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}}
\ekv@exparg{\long\def\ekv@err@common@#1`#2' #3.#4#5}%
  {\ekv@err{#4 `#5' in set `#2'}}
\ekv@exparg{\long\def\ekv@err@unknown#1#2}{\ekv@err@common{unknown key}{#1}}
\ekv@exparg{\long\def\ekv@err@noarg#1#2}
  {\ekv@err@common{unwanted value for}{#1}}
\ekv@exparg{\long\def\ekv@err@reqval#1#2}%
  {\ekv@err@common{missing value for}{#1}}
\ekv@exparg{\long\def\ekv@err@redirect@kv@notfound#1#2#3\ekv@stop}%
  {\ekv@err{no key `#2' in sets #3}}
\ekv@exparg{\def\ekv@err@redirect@k@notfound#1#2\ekv@stop}%
  {\ekv@err{no NoVal key `#1' in sets #2}}
\ekv@exparg{\def\ekv@err@undefined@expansion#1\fi}%
  {\expandafter\fi\ekv@err{Undefined expansion rule `#1'}}%
\ekv@exparg{\def\ekv@err@erroneous@variable#1}%
  {\ekv@err{Erroneous variable `#1' used}}
\ekv@exparg{\def\ekv@err@key@no@reinsert}%
  {\ekv@err{Reinsertion in \key expansion forbidden}}
\ekv@exparg{\def\ekv@err@val@no@reinsert#1}%
  {\ekv@err{Reinsertion with key `#1' forbidden}}
%    \end{macrocode}
% \end{macro}
%
% Now everything that's left is to reset the category code of |@|.
%    \begin{macrocode}
\catcode`\@=\ekv@tmp
%    \end{macrocode}
%
% \gobbledocstriptag
%</tex>
%^^A=<<
