summaryrefslogtreecommitdiff
path: root/macros/generic/expkv-bundle/expkv-cs.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/generic/expkv-bundle/expkv-cs.dtx')
-rw-r--r--macros/generic/expkv-bundle/expkv-cs.dtx1748
1 files changed, 1748 insertions, 0 deletions
diff --git a/macros/generic/expkv-bundle/expkv-cs.dtx b/macros/generic/expkv-bundle/expkv-cs.dtx
new file mode 100644
index 0000000000..4cf7946a87
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-cs.dtx
@@ -0,0 +1,1748 @@
+% \iffalse meta-comment
+%
+% File: expkv-cs.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-cs.sty}{\from{expkv-cs.dtx}{pkg}}}
+\generate{\file{expkv-cs.tex}{\from{expkv-cs.dtx}{tex}}}
+\generate{\file{t-expkv-cs.tex}{\from{expkv-cs.dtx}{ctx}}}
+\endbatchfile
+%</driver>^^A=<<
+% \fi
+%
+% \section{\expkvc}
+%^^A the LaTeX package >>=
+% \subsection{The \LaTeX\ Package}
+% Just like for \expkv\ we provide a small \LaTeX\ package that sets up things
+% such that we behave nicely on \LaTeX\ packages and files system. It'll
+% |\input| the generic code which implements the functionality.
+% \gobbledocstriptag
+%<*pkg>
+% \begin{macrocode}
+\RequirePackage{expkv-pop}
+\def\ekvc@tmp
+ {%
+ \ProvidesFile{expkv-cs.tex}%
+ [%
+ \ekvcDate\space v\ekvcVersion\space
+ define expandable key=val macros using expkv%
+ ]%
+ }
+\input{expkv-cs.tex}
+\ProvidesPackage{expkv-cs}%
+ [%
+ \ekvcDate\space v\ekvcVersion\space
+ define expandable key=val macros using expkv%
+ ]
+% \end{macrocode}
+% \gobbledocstriptag
+%</pkg>
+%^^A=<<
+%^^A the ConTeXt module >>=
+% \subsection{The \ConTeXt\ module}
+% \gobbledocstriptag
+%<*ctx>
+% \begin{macrocode}
+\writestatus{loading}{ConTeXt User Module / expkv-cs}
+\usemodule[expkv-pop]
+\unprotect
+\input expkv-cs.tex
+\writestatus{loading}
+ {ConTeXt User Module / expkv-cs / Version \ekvcVersion\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>
+%
+% Load \expkv\ if the package didn't already do so -- since \expkv\ has
+% safeguards against being loaded twice this does no harm and the overhead
+% isn't that big. Also we reuse some of the internals of \expkv\ to save us from
+% retyping them.
+% \begin{macrocode}
+\input expkv-pop
+% \end{macrocode}
+%
+% We make sure that \file{expkv-cs.tex} is only input once:
+% \begin{macrocode}
+\expandafter\ifx\csname ekvcVersion\endcsname\relax
+\else
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% \begin{macro}{\ekvcVersion,\ekvcDate}
+% We're on our first input, so lets store the version and date in a macro.
+% \begin{macrocode}
+\def\ekvcVersion{1.3}
+\def\ekvcDate{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 |\ekvc@tmp| to use
+% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
+% \begin{macrocode}
+\csname ekvc@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 ekvc@tmp\endcsname=\catcode`\@
+\catcode`\@=11
+% \end{macrocode}
+% |\ekvc@tmp| will be reused later, but we don't need it to ever store
+% information long-term after \expkvc\ was initialized.
+%
+% \begin{macro}[internal]{\ekvc@tripledots}
+% This macro just serves as a marker for a comparison to allow the syntax
+% for the unknown key handlers.
+% \begin{macrocode}
+\edef\ekvc@tripledots{\detokenize{...}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@keycount}
+% We'll need to keep count how many keys must be defined for each macro in the
+% |split| variants.
+% \begin{macrocode}
+\newcount\ekvc@keycount
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@long,\ekvc@any@long}
+% Some macros will have to be defined long. These two will be let to |\long|
+% when this should be the case.
+% \begin{macrocode}
+\let\ekvc@long\ekv@empty
+\let\ekvc@any@long\ekv@empty
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@ifdefined}
+% We want to test whether a macro is already defined. This test checks for a
+% defined macro that isn't |\relax|.
+% \begin{macrocode}
+\long\def\ekvc@ifdefined#1%
+ {%
+ \ifdefined#1%
+ \ifx\relax#1%
+ \ekv@fi@gobble
+ \fi
+ \@firstofone
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@ekvset@pre@expander,
+% \ekvc@ekvset@pre@expander@a,
+% \ekvc@ekvset@pre@expander@b
+% }
+% This macro expands |\ekvset| twice so that the first two steps of expansion
+% don't have to be made every time the \expkvc\ macros are used. We have to do
+% a little magic trick to get the macro parameter |#1| for the macro
+% definition this is used in, even though we're calling |\unexpanded|. We do
+% that by splitting the expanded |\ekvset| at some marks and place |##1| in
+% between. At this spot we also add |\ekv@alignsafe| and |\ekv@endalignsafe|
+% to ensure that macros created with \expkvc\ are alignment safe.
+% \begin{macrocode}
+\def\ekvc@ekvset@pre@expander#1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander@a\ekvset{#1}\ekvc@stop\ekvc@stop
+ }
+\def\ekvc@ekvset@pre@expander@a
+ {%
+ \expandafter\ekvc@ekvset@pre@expander@b
+ }
+\def\ekvc@ekvset@pre@expander@b#1\ekvc@stop#2\ekvc@stop
+ {%
+ \ekv@unexpanded\expandafter{\ekv@alignsafe}%
+ \ekv@unexpanded{#1}##1\ekv@unexpanded{#2}%
+ \ekv@unexpanded\expandafter{\ekv@endalignsafe}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcSplitAndUse}
+% The first user macro we want to set up can be reused for
+% \cs[no-index]{ekvcSplitAndForward} and \cs[no-index]{ekvcSplit}. We'll split
+% this one up so that the test whether the macro is already defined doesn't
+% run twice.
+% \begin{macrocode}
+\protected\long\def\ekvcSplitAndUse#1#2%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcSplitAndUse@#1{}{#2}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvcSplitAndUse@}
+% The actual macro setting up things. We need to set some variables, forward
+% the key list to |\ekvc@SetupSplitKeys|, and afterwards define the front
+% facing macro to call |\ekvset| and put the initials and the argument sorting
+% macro behind it. The internals |\ekvc@any@long|, |\ekvc@initials| and
+% |\ekvc@keycount| will be set correctly by |\ekvc@SetupSplitKeys|.
+% \begin{macrocode}
+\protected\long\def\ekvcSplitAndUse@#1#2#3%
+ {%
+ \edef\ekvc@set{\string#1}%
+ \ekvc@SetupSplitKeys{#3}%
+ \ekvc@helpers@needed
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@split@\the\ekvc@keycount\endcsname}%
+ \ekv@unexpanded\expandafter{\ekvc@initials{}#2}%
+ }%
+ }%
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded{#2}%
+ \ekv@unexpanded\expandafter{\ekvc@initials}%
+ }%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\ekvcSplitAndForward}
+% This just reuses |\ekvcSplitAndUse@| with a non-empty second argument,
+% resulting in that argument to be called after the splitting.
+% \begin{macrocode}
+\protected\long\def\ekvcSplitAndForward#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcSplitAndUse@#1{{#2}}{#3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcSplit}
+% The first half is just |\ekvcSplitAndForward| then we define the macro to
+% which the parsed key list is forwarded. There we need to allow for up to
+% nine arguments.
+% \begin{macrocode}
+\protected\long\def\ekvcSplit#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@secondoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {%
+ \expandafter
+ \ekvcSplitAndUse@\expandafter#1\csname ekvc@\string#1\endcsname{#2}%
+ \ifnum\ekvc@keycount<1
+ \ekvc@any@long\expandafter\def\csname ekvc@\string#1\endcsname{#3}%
+ \else
+ \ifnum\ekvc@keycount>9
+ \ekvc@err@toomany{#1}%
+ \let#1\ekvc@undefined
+ \else
+ \ekvcSplit@build@argspec
+ \ekvc@any@long\expandafter
+ \def\csname ekvc@\string#1\expandafter\endcsname\ekvc@tmp{#3}%
+ \fi
+ \fi
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvcSplit@build@argspec,\ekvcSplit@build@argspec@}
+% \begin{macrocode}
+\protected\def\ekvcSplit@build@argspec
+ {%
+ \begingroup
+ \edef\ekvc@tmp
+ {\endgroup\def\ekv@unexpanded{\ekvc@tmp}{\ekvcSplit@build@argspec@{1}}}%
+ \ekvc@tmp
+ }
+\def\ekvcSplit@build@argspec@#1%
+ {%
+ \ifnum#1>\ekvc@keycount
+ \ekv@fi@gobble
+ \fi
+ \@firstofone
+ {%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@#1\endcsname####}#1%
+ \expandafter\ekvcSplit@build@argspec@\expandafter{\the\numexpr#1+1}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@SetupSplitKeys, \ekvc@SetupSplitKeys@a, \ekvc@SetupSplitKeys@b,
+% \ekvc@SetupSplitKeys@unknown
+% }
+% These macros parse the list of keys and set up the key macros. First we need
+% to initialise some macros and start an \expkvp\ parser.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupSplitKeys
+ {%
+ \ekvc@keycount=\ekv@zero
+ \let\ekvc@any@long\ekv@empty
+ \let\ekvc@initials\ekv@empty
+ \ekvpParse@unsafe\ekvp@@p@ekvc@setup@splitkeys
+ }
+% \end{macrocode}
+% We're calling a parser here without the safety nets testing for parser
+% existence, so better define it now.
+% \begin{macrocode}
+\ekvpNewParser{ekvc@setup@splitkeys}
+\ekvpDefType{ekvc@setup@splitkeys}{short}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupSplitKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefType{ekvc@setup@splitkeys}{long}
+ {%
+ \let\ekvc@long\long
+ \let\ekvc@any@long\long
+ \expandafter\ekvc@SetupSplitKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefNoType{ekvc@setup@splitkeys}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupSplitKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+% \end{macrocode}
+% If no value was provided this could either be an error, or the unknown key
+% forwarding. We have to check this (comparing against |...| inside
+% |\ekvc@tripledots|) and if this is the unknown key list type, set it up
+% accordingly (advancing the key count and setting up the unknown handlers of
+% \expkv). Else we simply throw an error and ignore the incident.
+% \begin{macrocode}
+\ekvpDefNoValue{ekvc@setup@splitkeys}
+ {%
+ \begingroup
+ \edef\ekvc@tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc@tripledots\ekvc@tmp
+ \advance\ekvc@keycount1
+% \end{macrocode}
+% The |\begingroup\expandafter\endgroup| ensures that the split mark isn't
+% actually defined (even if it just were with meaning |\relax|).
+% \begin{macrocode}
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@SetupSplitKeys@unknown
+ \csname ekvc@splitmark@\the\ekvc@keycount\endcsname
+ \let\ekvc@any@long\long
+ \else
+ \ekvc@err@value@required{#1}%
+ \fi
+ }
+% \end{macrocode}
+%
+% Now everything is parsed down to the point that we got the key name and its
+% value. We step the key counter and build the mark within a group to not
+% accidentally define the |\csname|.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupSplitKeys@a
+ {%
+ \advance\ekvc@keycount1
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@SetupSplitKeys@b
+ \csname ekvc@splitmark@\the\ekvc@keycount\endcsname
+ }
+\protected\long\def\ekvc@SetupSplitKeys@b#1#2\ekv@stop#3%
+ {%
+ \long\def\ekvc@tmp##1##2#1##3{##2#1{##1}}%
+% \end{macrocode}
+% The short variant needs a bit of special treatment. The key macro will be
+% short to throw the correct error, but since there might be long macros
+% somewhere the reordering of arguments needs to be long, so for short keys we
+% use a two step approach, first grabbing only the short argument, then
+% reordering.
+% \begin{macrocode}
+ \ifx\ekvc@long\long
+ \else
+ \expandafter\let\csname ekvc@\ekvc@set(#2)\endcsname\ekvc@tmp
+ \edef\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded\expandafter{\csname ekvc@\ekvc@set(#2)\endcsname}%
+ {##1}%
+ }%
+ \fi
+ \ekvlet\ekvc@set{#2}\ekvc@tmp
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{#3}}}%
+ \ekvc@helpers@needed
+ {\expandafter\ekvc@setup@splitmacro\expandafter{\the\ekvc@keycount}}%
+ {}%
+ }
+% \end{macrocode}
+%
+% Here we get everything readily set up, |#1| contains the mark for unknown
+% keys and they only have to do some reordering.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupSplitKeys@unknown#1%
+ {%
+ \long\def\ekvc@tmp##1##2##3##4#1##5{##4#1{##5, {##3} = {##1} }}%
+ \ekvletunknown\ekvc@set\ekvc@tmp
+ \long\def\ekvc@tmp##1##2##3#1##4{##3#1{##4, {##2} }}%
+ \ekvletunknownNoVal\ekvc@set\ekvc@tmp
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{}}}%
+ \ekvc@helpers@needed
+ {\expandafter\ekvc@setup@splitmacro\expandafter{\the\ekvc@keycount}}%
+ {}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@defarggobbler}
+% This is needed to define a macro with 1-9 parameters programmatically.
+% \LaTeX's \cs[no-index]{newcommand} does something similar for example.
+% \begin{macrocode}
+\protected\def\ekvc@defarggobbler#1{\def\ekvc@tmp##1#1##2##{##1#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@setup@splitmacro,
+% \ekvc@split@1, \ekvc@split@2, \ekvc@split@3,
+% \ekvc@split@4, \ekvc@split@5, \ekvc@split@6,
+% \ekvc@split@7
+% }
+% Since the first few split macros are different from the others we manually
+% set those up now. All the others will be defined as needed (always
+% globally). The split macros just read up until the correct split mark, move
+% that argument into a list and reinsert the rest, calling the next split
+% macro afterwards.
+% \begin{macrocode}
+\begingroup
+\edef\ekvc@tmp
+ {%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@1\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ ##2##3%
+ {##3{##1}##2}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@2\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ ##3##4%
+ {##4{##1}{##2}##3}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@3\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ ##4##5%
+ {##5{##1}{##2}{##3}##4}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@4\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ ##5##6%
+ {##6{##1}{##2}{##3}{##4}##5}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@5\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
+ ##6##7%
+ {##7{##1}{##2}{##3}{##4}{##5}##6}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@6\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@6\endcsname}##6%
+ ##7##8%
+ {##8{##1}{##2}{##3}{##4}{##5}{##6}##7}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@7\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@6\endcsname}##6%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@7\endcsname}##7%
+ ##8##9%
+ {##9{##1}{##2}{##3}{##4}{##5}{##6}{##7}##8}%
+ }
+\ekvc@tmp
+\endgroup
+\protected\def\ekvc@setup@splitmacro#1%
+ {%
+ \ekv@ifdefined{ekvc@split@#1}{}%
+ {%
+ \begingroup
+ \def\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@splitmark@\the\numexpr#1-##1\relax\endcsname}%
+ }%
+ \edef\ekvc@tmp
+ {%
+ \long\gdef
+ \ekv@unexpanded\expandafter{\csname ekvc@split@#1\endcsname}%
+ ####1%
+ \ekvc@tmp{6}####2%
+ \ekvc@tmp{5}####3%
+ \ekvc@tmp{4}####4%
+ \ekvc@tmp{3}####5%
+ \ekvc@tmp{2}####6%
+ \ekvc@tmp{1}####7%
+ \ekvc@tmp{0}####8%
+ ####9%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@split@\the\numexpr#1-7\relax\endcsname}%
+ ####1{{####2}{####3}{####4}{####5}{####6}{####7}{####8}####9}%
+ }%
+ }%
+ \ekvc@tmp
+ \endgroup
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcHashAndUse}
+% |\ekvcHashAndUse| works just like |\ekvcSplitAndUse|.
+% \begin{macrocode}
+\protected\long\def\ekvcHashAndUse#1#2%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcHashAndUse@#1{}{#2}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvcHashAndUse@}
+% This is more or less the same as |\ekvcSplitAndUse@|. Instead of an empty
+% group we place a marker after the initials, we don't use the sorting macros
+% of |split|, but instead pack all the values in one argument.
+% \begin{macrocode}
+\protected\long\def\ekvcHashAndUse@#1#2#3%
+ {%
+ \edef\ekvc@set{\string#1}%
+ \ekvc@SetupHashKeys{#3}%
+ \ekvc@helpers@needed
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded{\ekvc@hash@pack@argument}%
+ \ekv@unexpanded\expandafter{\ekvc@initials\ekvc@stop#2}%
+ }%
+ }%
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded{#2}%
+ \ekv@unexpanded\expandafter{\ekvc@initials\ekvc@stop}%
+ }%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcHashAndForward}
+% |\ekvcHashAndForward| works just like |\ekvcSplitAndForward|.
+% \begin{macrocode}
+\protected\long\def\ekvcHashAndForward#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcHashAndUse@#1{{#2}}{#3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcHash}
+% |\ekvcHash| does the same as |\ekvcSplit|, but has the advantage of not
+% needing to count arguments, so the definition of the internal macro is a bit
+% more straight forward.
+% \begin{macrocode}
+\protected\long\def\ekvcHash#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@secondoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {%
+ \expandafter
+ \ekvcHashAndUse@\expandafter#1\csname ekvc@\string#1\endcsname{#2}%
+ \ekvc@any@long\expandafter\def\csname ekvc@\string#1\endcsname
+ ##1\ekvc@stop
+ {#3}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@hash@pack@argument}
+% All this macro does is pack the values into one argument and forward that to
+% the next macro.
+% \begin{macrocode}
+\long\def\ekvc@hash@pack@argument#1\ekvc@stop#2{#2{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@SetupHashKeys,\ekvc@SetupHashKeys@a,\ekvc@SetupHashKeys@b,
+% \ekvc@SetupHashKeys@unknown
+% }
+% This should look awfully familiar as well, since it's just the same as for
+% the split keys with a few other names here and there.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupHashKeys
+ {%
+ \let\ekvc@any@long\ekv@empty
+ \let\ekvc@initials\ekv@empty
+ \ekvpParse@unsafe\ekvp@@p@ekvc@setup@hashkeys
+ }
+\ekvpNewParser{ekvc@setup@hashkeys}
+\ekvpDefType{ekvc@setup@hashkeys}{short}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupHashKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefType{ekvc@setup@hashkeys}{long}
+ {%
+ \let\ekvc@long\long
+ \let\ekvc@any@long\long
+ \expandafter\ekvc@SetupHashKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefNoType{ekvc@setup@hashkeys}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupHashKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefNoValue{ekvc@setup@hashkeys}
+ {%
+ \begingroup
+ \edef\ekvc@tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc@tripledots\ekvc@tmp
+ \ekvc@SetupHashKeys@unknown
+ \let\ekvc@any@long\long
+ \else
+ \ekvc@err@value@required{#1}%
+ \fi
+ }
+% \end{macrocode}
+% Again we build the marker, this time instead of a numbered one a named
+% hashmark, inside a group to not actually define the macro used as a marker.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupHashKeys@a#1\ekv@stop
+ {%
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@SetupHashKeys@b\csname ekvc@hashmark@#1\endcsname{#1}%
+ }
+% \end{macrocode}
+% Yes, even the defining macro looks awfully familiar. Instead of numbered we
+% have named marks. Still the key macros grab everything up to their
+% respective mark and reorder the arguments. The same quirk is applied for
+% short keys. And instead of the |\ekvc@setup@splitmacro| we use
+% |\ekvc@setup@hashmacro|.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupHashKeys@b#1#2#3%
+ {%
+ \long\def\ekvc@tmp##1##2#1##3{##2#1{##1}}%
+ \ifx\ekvc@long\long
+ \else
+ \expandafter\let\csname ekvc@\ekvc@set(#2)\endcsname\ekvc@tmp
+ \edef\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded\expandafter{\csname ekvc@\ekvc@set(#2)\endcsname}%
+ {##1}%
+ }%
+ \fi
+ \ekvlet\ekvc@set{#2}\ekvc@tmp
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{#3}}}%
+ \ekvc@setup@hashmacro{#2}%
+ }
+% \end{macrocode}
+% Another temporary definition, this time to get the hashmarks for the unknown
+% handler without defining them.
+% \begin{macrocode}
+\def\ekvc@SetupHashKeys@unknown#1%
+ {%
+ \protected\def\ekvc@SetupHashKeys@unknown
+ {%
+ \ekvletunknown\ekvc@set\ekvc@hash@unknown@kv
+ \ekvletunknownNoVal\ekvc@set\ekvc@hash@unknown@k
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{}}}%
+ \ekvc@setup@hashmacro{...}%
+ }%
+ \long\def\ekvc@hash@unknown@kv##1##2##3##4#1##5{##4#1{##5, {##3} = {##1} }}%
+ \long\def\ekvc@hash@unknown@k##1##2##3#1##4{##3#1{##4, {##2} }}%
+ }
+\begingroup\expandafter\endgroup
+\expandafter\ekvc@SetupHashKeys@unknown
+ \csname ekvc@hashmark@\ekvc@tripledots\endcsname
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@setup@hashmacro}
+% The safe hash macros will be executed inside of an |\unexpanded| expansion
+% context, so they have to insert braces for that once they are done.
+% Most of the tests which have to be executed will already be done, but we
+% have to play safe if the hash doesn't show up in the hash list. Therefore we
+% use some |\ekvc@mark|s and |\ekvc@stop| to throw errors if the hash isn't
+% found in the right place. The fast variants have an easier life and just
+% return the correct value.
+% \begin{macrocode}
+\protected\def\ekvc@setup@hashmacro#1%
+ {%
+ \ekv@ifdefined{ekvc@fasthash@#1}{}%
+ {%
+ \begingroup
+ \edef\ekvc@tmp
+ {%
+ \long\gdef
+ \ekv@unexpanded\expandafter{\csname ekvc@fasthash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@stop}%
+ {####2}%
+ \long\gdef
+ \ekv@unexpanded\expandafter{\csname ekvc@safehash@#1\endcsname}%
+ ####1%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@@safehash@#1\endcsname}%
+ ####1\ekv@unexpanded{\ekvc@mark}{}%
+ \ekv@unexpanded\expandafter
+ {%
+ \csname ekvc@hashmark@#1\endcsname{}%
+ \ekvc@mark{\ekvc@err@missing@hash{#1}}\ekvc@stop
+ }%
+ }%
+ \long\gdef
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@@safehash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@mark}####4####5%
+ \ekv@unexpanded{\ekvc@stop}%
+ {%
+ ####4{####2}%
+ }%
+ \long\gdef\ekv@unexpanded\expandafter
+ {\csname ekvc@fastsplithash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@stop}####4%
+ {%
+ ####4{####2}%
+ }%
+ \long\gdef\ekv@unexpanded\expandafter
+ {\csname ekvc@safesplithash@#1\endcsname}####1%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@@safesplithash@#1\endcsname}%
+ ####1\ekv@unexpanded{\ekvc@mark\ekvc@safe@after@hash}%
+ \ekv@unexpanded\expandafter
+ {%
+ \csname ekvc@hashmark@#1\endcsname{}%
+ \ekvc@mark
+ {\ekvc@err@missing@hash{#1}\ekvc@safe@after@hash}%
+ \ekvc@stop
+ }%
+ }%
+ \long\gdef\ekv@unexpanded\expandafter
+ {\csname ekvc@@safesplithash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@mark}####4####5%
+ \ekv@unexpanded{\ekvc@stop}%
+ {%
+ ####4{####2}%
+ }%
+ }%
+ \ekvc@tmp
+ \endgroup
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValue}
+% \begin{macro}[internal]{\ekvcValue@}
+% All this does is a few consistency checks on the first argument (not empty,
+% hash macro exists) and then call that hash-grabbing macro that will also
+% test whether the hash is inside of |#2| or not.
+% \begin{macrocode}
+\long\def\ekvcValue#1%
+ {%
+ \ekv@unexpanded
+ \expandafter\ekvcValue@\detokenize{#1}\ekvc@stop
+ }
+\def\ekvcValue@#1\ekvc@stop
+ {%
+ \ekv@ifdefined{ekvc@safehash@#1}%
+ {\csname ekvc@safehash@#1\endcsname}%
+ {\ekvc@err@unknown@hash{#1}\@firstoftwo{{}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValueFast}
+% To be as fast as possible, this doesn't test for anything, assuming the user
+% knows best.
+% \begin{macrocode}
+\long\def\ekvcValueFast#1#2%
+ {\csname ekvc@fasthash@\detokenize{#1}\endcsname#2\ekvc@stop}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValueSplit}
+% \begin{macro}[internal]{\ekvcValueSplit@,\ekvcValueSplit@recover}
+% This splits off a single value.
+% \begin{macrocode}
+\long\def\ekvcValueSplit#1%
+ {\expandafter\ekvcValueSplit@\detokenize{#1}\ekvc@stop}
+\def\ekvcValueSplit@#1\ekvc@stop
+ {%
+ \ekv@ifdefined{ekvc@safesplithash@#1}%
+ {\csname ekvc@safesplithash@#1\endcsname}%
+ {\ekvc@err@unknown@hash{#1}\ekvcValueSplit@recover}%
+ }
+\long\def\ekvcValueSplit@recover#1#2{#2{}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@safe@after@hash}
+% \begin{macrocode}
+\long\def\ekvc@safe@after@hash#1#2%
+ {%
+ #2{#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValueSplitFast}
+% Again a fast approach which doesn't provide too many safety measurements.
+% This needs to build the hash function and expand it before passing the
+% results to the next control sequence. The first step only builds the control
+% sequence.
+% \begin{macrocode}
+\long\def\ekvcValueSplitFast#1#2%
+ {\csname ekvc@fastsplithash@\detokenize{#1}\endcsname#2\ekvc@stop}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@safehash@,\ekvc@fasthash@,
+% \ekvc@safesplithash@,\ekvc@fastsplithash@
+% }
+% At least in the empty hash case we can provide a meaningful error message
+% without affecting performance by just defining the macro that would be build
+% in that case. There is of course a downside to this, the error will not be
+% thrown by |\ekvcValueFast| in three expansion steps. The safe hash variant
+% has to also stop the |\unexpanded| expansion.
+% \begin{macrocode}
+\long\def\ekvc@safehash@#1{\ekvc@err@empty@hash{}}
+\long\def\ekvc@fasthash@#1\ekvc@stop{\ekvc@err@empty@hash}
+\long\def\ekvc@safesplithash@#1#2{\ekvc@err@empty@hash#2{}}
+\long\def\ekvc@fastsplithash@#1\ekvc@stop#2{\ekvc@err@empty@hash#2{}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcSecondaryKeys}
+% \begin{macro}[internal]
+% {\ekvcSecondaryKeys@a,\ekvcSecondaryKeys@b,\ekvcSecondaryKeys@c}
+% Secondary keys use yet another \expkvp\ parser, keys will be set up further
+% down in their own subsection.
+% \begin{macrocode}
+\ekvpNewParser{ekvc@setup@secondary}
+\ekvpValueAlwaysRequired{ekvc@setup@secondary}
+\protected\long\def\ekvcSecondaryKeys#1%
+ {%
+ \edef\ekvc@set{\string#1}%
+ \let\ekvc@long\ekv@empty
+ \ekvpParse@unsafe\ekvp@@p@ekvc@setup@secondary
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcChange}
+% This can be used to change the defaults of an \expkvc\ defined macro. It
+% checks whether there is a set with the correct name and that the macro is
+% defined. If both is true the real work is done by |\ekvc@change|.
+% \begin{macrocode}
+\protected\long\def\ekvcChange#1%
+ {%
+ \ekvifdefinedset{\string#1}%
+ {%
+ \ekvc@ifdefined#1%
+ {\ekvc@change#1}%
+ {\ekvc@err@no@key@macro#1\@gobble}%
+ }%
+ {\ekvc@err@no@key@macro#1\@gobble}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@change ,\ekvc@change@a,\ekvc@change@b,
+% \ekvc@change@c,\ekvc@change@d,\ekvc@change@e
+% }
+% First we need to see whether the macro is currently |\long|. For this we get
+% the meaning and will parse it. |#1| is the macro name in which we want to
+% change the defaults.
+% \begin{macrocode}
+\protected\def\ekvc@change#1%
+ {\expandafter\ekvc@change@a\meaning#1\ekv@stop#1}
+% \end{macrocode}
+% A temporary definition to get the stringified |macro:|. |##1| will be the
+% list of prefixes, we don't care for the exact contents of |##2| and |##3|.
+% \begin{macrocode}
+\def\ekvc@change@a#1%
+ {%
+ \protected\def\ekvc@change@a##1#1##2->##3\ekv@stop
+ {%
+ \ekvc@change@iflong{##1}%
+ {\ekvc@change@b{}}%
+ {\ekvc@change@b{\long}}%
+ }%
+ }
+\expandafter\ekvc@change@a\expandafter{\detokenize{macro:}}
+% \end{macrocode}
+% Next we expand the macro once to get its contents (including the current
+% default values with their markers) and place |\ekvc@stop| instead of an
+% argument as a marker for the last step. |#1| is either |\long| or empty,
+% |#2| is the macro.
+% \begin{macrocode}
+\protected\def\ekvc@change@b#1#2%
+ {\expandafter\ekvc@change@c\expandafter{#2\ekvc@stop}{#1}#2}
+% \end{macrocode}
+% Here we place an unbalanced closing brace after the expansion of the macro.
+% Then we just parse the \kv-list with |\ekvset|, that will exchange the
+% values behind the markers. Once those are changed we give control to
+% |\ekvc@change@d|. The |\ekvset| step might horribly fail if the user defined
+% some keys that don't behave nice. |#1| is the expansion of the macro, |#2|
+% is either |\long| or empty, |#3| is the macro, and |#4| is the \kv-list
+% containing the new defaults.
+% \begin{macrocode}
+\ekv@exparg{\protected\long\def\ekvc@change@c#1#2#3#4}%
+ {%
+ \expandafter\iffalse\expandafter{\expandafter{\expandafter\fi
+ \ekvset{\string#3}{#4}%
+ \ekvc@change@d{#2}{#3}%
+ #1%
+ }}%
+ }
+% \end{macrocode}
+% The final step needs to put an unbalanced opening brace after |\edef|. Also
+% we have to protect everything from further expanding with the exception of
+% the redefined macro's argument, which is why we placed the |\ekvc@stop|
+% earlier. Then we need to also protect the rest of the contents from further
+% expanding using |\unexpanded| with another unbalanced opening brace.
+% |#1| will be either empty or |\long| and |#2| is the macro.
+% \begin{macrocode}
+\protected\def\ekvc@change@d#1#2%
+ {#1\edef#2##1{\expandafter\ekvc@change@e\iffalse}\fi}
+\long\def\ekvc@change@e#1\ekvc@stop
+ {\ekv@unexpanded{#1}##1\ekv@unexpanded\expandafter{\iffalse}\fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@change@iflong,\ekvc@change@iflong@}
+% Checking whether a string contains the string representation of |\long| can
+% be done by gobbling everything up to the first |\long| and checking whether
+% the result is completely empty. We need a temporary macro to get the result
+% of |\string\long| inside the definitions.
+% \begin{macrocode}
+\def\ekvc@change@iflong#1%
+ {%
+ \protected\def\ekvc@change@iflong##1%
+ {\expandafter\ekv@ifempty\expandafter{\ekvc@change@iflong@##1#1}}%
+ \def\ekvc@change@iflong@##1#1{}
+ }
+\expandafter\ekvc@change@iflong\expandafter{\string\long}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcPass}
+% This macro can be used to pass a value to a key of some macro (this way
+% more complicated key codes are possible that in the end pass processed
+% values on to some macro). The implemantation is pretty straight forward.
+% \begin{macrocode}
+\long\def\ekvcPass#1#2%
+ {%
+ \ekvifdefined{\string#1}{#2}%
+ {\csname\ekv@name{\string#1}{#2}\endcsname}%
+ {\ekvc@err@unknown@key@or@macro{#1}{#2}\@gobble}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Secondary Key Types}
+%
+% There is a single prefix named |long| and set up pretty simple.
+% \begin{macrocode}
+\ekvpDefPrefixLet{ekvc@setup@secondary}{long}\ekvc@long\long\ekv@empty
+% \end{macrocode}
+%
+% \begin{macro}[internal]
+% {
+% meta, nmeta,
+% \ekvc@type@meta, \ekvc@type@meta@
+% }
+% The |meta| and |nmeta| key types use |\ekvmorekv| to set other keys in
+% the same macro's \set. If the \kv\ list ist fixed (|nmeta|) we can expand
+% |\ekvmorekv| as far as possible (twice), else we expand it only once. This
+% makes a difference only if the \val\ of the |meta| key isn't forwarded in
+% braces and commas are active at the time of usage, in which case expanding
+% |\ekvmorekv| twice would result in wrong behaviour.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{meta}
+ {\ekvc@type@meta\ekv@exparg\ekvc@long{##1}\ekvlet{#1}{#3}}
+\ekvpDefType{ekvc@setup@secondary}{nmeta}
+ {\ekvc@assert@not@long\ekvc@type@meta\ekv@expargtwice{}{}\ekvletNoVal{#1}{#3}}
+\protected\long\def\ekvc@type@meta#1#2#3#4#5#6%
+ {%
+ #1\ekvc@type@meta@{\ekvmorekv{#6}}{#2}{#3}%
+ #4\ekvc@set{#5}\ekvc@tmp
+ }
+\protected\long\def\ekvc@type@meta@#1#2#3{#2\def\ekvc@tmp#3{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{alias}
+% |alias| just checks whether there is a key and/or |NoVal| key defined with
+% the target name and |\let| the key to those.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{alias}
+ {%
+ \ekvc@assert@not@long
+ \ekvc@assert@k@or@p@defined{#3}%
+ \ekvifdefined\ekvc@set{#3}{\ekvletkv\ekvc@set{#1}\ekvc@set{#3}}{}%
+ \ekvifdefinedNoVal\ekvc@set{#3}{\ekvletkvNoVal\ekvc@set{#1}\ekvc@set{#3}}{}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{default}
+% The |default| key can be used to set a \Nkey\ for an existing \Vkey. It
+% will just pass the \val\ to the key macro of that other key.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{default}
+ {%
+ \ekvc@assert@defined{#1}%
+ \ekvc@assert@not@long
+ \edef\ekvc@tmp
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname\ekv@name\ekvc@set{#1}\endcsname{#3}}%
+ }%
+ \ekvletNoVal\ekvc@set{#1}\ekvc@tmp
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{enum,choice}
+% \begin{macro}[internal]
+% {
+% \ekvc@type@enum,\ekvc@h@enum,\ekvc@h@enum@,\ekvc@enum@name,
+% \ekvc@type@choice@
+% }
+% Enums don't need to apply special trickery to make the parts of the names
+% retrievable, so unlike in \expkvd\ we don't need catcode juggling.
+% The setup of an |enum| requires unpacking the value in two different
+% arguments so we need an auxiliary here.
+% \begin{macrocode}
+\def\ekvc@enum@name#1#2#3{ekvc#1(#2)#3}
+\ekvpDefType{ekvc@setup@secondary}{enum}
+ {\ekvpAssertTwoValues{#3}\ekvc@type@enum\ekvc@type@enum@{#1}#3}
+\ekvpDefType{ekvc@setup@secondary}{choice}
+ {\ekvpAssertTwoValues{#3}\ekvc@type@enum\ekvc@type@choice@{#1}#3}
+\protected\long\def\ekvc@type@enum#1#2#3%
+ {%
+ \ekvc@assert@defined{#3}%
+% \end{macrocode}
+% At run time we need another helper and we need to expand the current
+% |\ekvc@set| now. The helper will build a control sequence from each given
+% value, those will be set up in the |\ekvcsvloop|.
+% \begin{macrocode}
+ \ekvc@long\edef\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded{\expandafter\ekvc@h@enum\detokenize}{##1}%
+ \ekv@unexpanded{\ekvc@stop}%
+ {\ekvc@set}{#2}%
+ }%
+ \ekvlet\ekvc@set{#2}\ekvc@tmp
+ \def\ekvc@tmp{0}%
+ \expandafter\ekvcsvloop\expandafter
+ {\expandafter#1\csname\ekv@name\ekvc@set{#3}\endcsname{#2}}%
+ }
+% \end{macrocode}
+% Here |#1| will be the key-macro of the underlying primary or secondary key,
+% |#2| is the |enum| key's name, and |#3| will be the choice. The rest is
+% pretty obvious.
+% \begin{macrocode}
+\ekv@exparg{\protected\long\def\ekvc@type@enum@#1#2#3}%
+ {%
+ \expandafter\expandafter\expandafter\edef\expandafter
+ \csname\ekvc@enum@name\ekvc@set{#2}{\detokenize{#3}}\endcsname
+ {\ekv@unexpanded{#1}{\ekvc@tmp}}%
+ \edef\ekvc@tmp{\the\numexpr\ekvc@tmp+1\relax}%
+ }
+\ekv@exparg{\protected\long\def\ekvc@type@choice@#1#2#3}%
+ {%
+ \expandafter\expandafter\expandafter\edef\expandafter
+ \csname\ekvc@enum@name\ekvc@set{#2}{\detokenize{#3}}\endcsname
+ {\ekv@unexpanded{#1{#3}}}%
+ }
+% \end{macrocode}
+% The use-time helper will check if the macro for the passed in choice exists,
+% if it doesn't throws an error, else calls that macro which will set the
+% correct value.
+% \begin{macrocode}
+\ekv@if@lastnamedcs
+ {%
+ \ekv@exparg{\def\ekvc@h@enum#1\ekvc@stop#2#3}%
+ {%
+ \expandafter\ifcsname\ekvc@enum@name{#2}{#3}{#1}\endcsname
+ \expandafter\ekvc@h@enum@\lastnamedcs
+ \fi
+ \ekvc@err@unknown@enum{#2}{#3}{#1}%
+ }
+ \def\ekvc@h@enum@#1\fi\ekvc@err@unknown@enum#2#3#4%
+ {%
+ \fi
+ \ifx#1\relax
+ \ekvc@err@unknown@enum{#2}{#3}{#4}%
+ \expandafter\@gobble
+ \fi
+ #1%
+ }
+ }
+ {%
+ \def\ekvc@h@enum#1%
+ {%
+ \def\ekvc@h@enum##1\ekvc@stop##2##3%
+ {%
+ \expandafter\ekvc@h@enum@
+ \csname\ifcsname#1\endcsname#1\else relax\fi\endcsname
+ {##2}{##3}{##1}%
+ }%
+ }
+ \expandafter\ekvc@h@enum\expandafter{\ekvc@enum@name{#2}{#3}{#1}}
+ \def\ekvc@h@enum@#1#2#3#4%
+ {%
+ \ifx#1\relax
+ \ekvc@err@unknown@enum{#2}{#3}{#4}%
+ \expandafter\@gobble
+ \fi
+ #1%
+ }
+ }
+% \end{macrocode}
+% We don't need |\ekvc@enum@name| anymore, so let's undefine it.
+% \begin{macrocode}
+\let\ekvc@enum@name\ekvc@undefined
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{aggregate,e-aggregate}
+% Aggregating isn't easy to define. We'll have to extract the correct mark for
+% the specified key, branch correctly for short and long keys, and use a small
+% hack to have the correct arguments on the user interface (|#1| as the
+% current contents, |#2| as the new value). This is split into a few steps
+% here.
+%
+% First, assert that the user input is well-behaved.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{aggregate}
+ {%
+ \let\ekvc@type@aggregate@ifexpanded\@secondoftwo
+ \ekvc@type@aggregate{#1}{#3}%
+ }
+\ekvpDefType{ekvc@setup@secondary}{e-aggregate}
+ {%
+ \let\ekvc@type@aggregate@ifexpanded\@firstoftwo
+ \ekvc@type@aggregate{#1}{#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvc@type@aggregate,\ekvc@type@aggregate@a,\ekvc@type@aggregate@b}
+% The next step stores the user defined processing in a temporary macro that's
+% used to do the parameter number swapping later. It also builds the names of
+% the key macro and the helper which would be used for processing a short key.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate#1#2%
+ {%
+ \ekvc@assert@not@long
+ \ekvpAssertTwoValues{#2}%
+ \ekvc@type@aggregate@a
+ \ekvc@type@aggregate@long\ekvc@type@aggregate@short
+ {#1}#2%
+ }
+\protected\long\def\ekvc@type@aggregate@a#1#2#3#4#5%
+ {%
+ \ekvc@assert@defined{#4}%
+ \def\ekvc@type@aggregate@tmp##1##2{#5}%
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@type@aggregate@b
+ \csname\ekv@name\ekvc@set{#4}\expandafter\endcsname
+ \csname ekvc@\ekvc@set(#4)\endcsname
+ #1#2%
+ {#3}%
+ }
+\protected\long\def\ekvc@type@aggregate@b#1#2#3#4%
+ {%
+ \ekvc@type@aggregate@check@long#1#2%
+ {#3#1}%
+ {#4#2}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@type@aggregate@check@long,
+% \ekvc@type@aggregate@check@long@a,\ekvc@type@aggregate@check@long@b
+% }
+% To check whether the primary key is long we see whether its |\meaning|
+% contains the helper which would only be there for short keys. For this we
+% have to get the stringified name of the internal (using |\detokenize|),
+% and afterwards get the |\meaning| of the macro. A temporary helper does the
+% real test by gobbling and forwarding the result to |\ekv@ifempty|.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate@check@long#1#2%
+ {\expandafter\ekvc@type@aggregate@check@long@a\detokenize{#2}\ekv@stop#1}
+\protected\long\def\ekvc@type@aggregate@check@long@a#1\ekv@stop#2%
+ {%
+ \def\ekvc@type@aggregate@check@long@@##1#1{}%
+ \expandafter\ekvc@type@aggregate@check@long@b\meaning#2\ekv@stop{#1}%
+ }
+\protected\def\ekvc@type@aggregate@check@long@b#1\ekv@stop#2%
+ {\expandafter\ekv@ifempty\expandafter{\ekvc@type@aggregate@check@long@@#1#2}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@type@aggregate@long,\ekvc@type@aggregate@long@}
+% The long variant just builds the split mark we extract, uses the hack to
+% swap argument order, and then does the definition via |\ekvlet| and a
+% temporary macro.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate@long#1%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@aggregate@long@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ }
+\protected\long\def\ekvc@type@aggregate@long@#1#2#3%
+ {%
+ \ekvc@type@aggregate@ifexpanded
+ {%
+ \long\def\ekvc@type@aggregate@tmp##1##2#1##3%
+ {\ekv@expanded{\ekv@unexpanded{##2#1}{#2}}}%
+ }%
+ {\long\def\ekvc@type@aggregate@tmp##1##2#1##3{##2#1{#2}}}%
+ \ekvlet\ekvc@set{#3}\ekvc@type@aggregate@tmp
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvc@type@aggregate@short,\ekvc@type@aggregate@short@}
+% The short variant will have to build the marker and the name of the helper
+% function, and swap the user argument order. Hence here are a few more
+% |\expandafter|s involved. But afterwards we can do the definition of the key
+% and the helper macro directly.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate@short#1#2%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@aggregate@short@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \csname ekvc@\ekvc@set(#2)\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ {#2}%
+ }
+\protected\long\def\ekvc@type@aggregate@short@#1#2#3#4%
+ {%
+ \ekvdef\ekvc@set{#4}{#2{##1}}%
+ \ekvc@type@aggregate@ifexpanded
+ {\long\def#2##1##2#1##3{\ekv@expanded{\ekv@unexpanded{##2#1}{#3}}}}%
+ {\long\def#2##1##2#1##3{##2#1{#3}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{process}
+% The |process| type can reuse much of |aggregate|, just the last step of
+% definition differ.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{process}
+ {%
+ \ekvpAssertTwoValues{#3}%
+ \ifx\ekvc@long\long
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ {%
+ \ekvc@type@aggregate@a
+ \ekvc@type@process@long\ekvc@type@process@long
+ }%
+ {%
+ \ekvc@type@aggregate@a
+ \ekvc@type@process@short\ekvc@type@process@short
+ }%
+ {#1}#3%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@type@process@long,\ekvc@type@process@long@}
+% This defines a temporary macro to grab the current value (found after the
+% marker |#1|), executes the user code and puts everything back to where it
+% belongs. Then |\ekvlet| is used to assign that meaning to the key macro.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@process@long#1%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@process@long@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ }
+\protected\long\def\ekvc@type@process@long@#1#2#3%
+ {%
+ \long\def\ekvc@type@aggregate@tmp##1##2#1##3{#2##2#1{##3}}%
+ \ekvlet\ekvc@set{#3}\ekvc@type@aggregate@tmp
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@type@process@short,\ekvc@type@process@short@}
+% We define the key macro directly to just grab the argument once and forward
+% it to the auxiliary. That one does essentially the same as the long variant.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@process@short#1#2%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@process@short@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \csname ekvc@\ekvc@set(#2)\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ {#2}%
+ }
+\protected\long\def\ekvc@type@process@short@#1#2#3#4%
+ {%
+ \ekvdef\ekvc@set{#4}{#2{##1}}%
+ \long\def#2##1##2#1##3{#3##2#1{##3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{flag-bool}
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{flag-bool}
+ {%
+ \ekvc@assert@not@long
+ \ekvpAssertOneValue{#3}%
+ \ifdefined#3\else\ekvcFlagNew#3\fi
+ \ekvdef\ekvc@set{#1}%
+ {%
+ \ekv@ifdefined{ekvc@flag@set@##1}%
+ {%
+ \csname ekvc@flag@set@##1\expandafter\endcsname
+ \ekvcFlagHeight#3\ekv@stop#3%
+ }%
+ {\ekvc@err@invalid@bool{##1}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{flag-true,flag-false,flag-raise}
+% \begin{macro}[internal]{\ekvc@type@flag}
+% \begin{macrocode}
+\protected\def\ekvc@type@flag#1#2#3%
+ {%
+ \ekvc@assert@not@long
+ \ekvpAssertOneValue{#3}%
+ \ifdefined#3\else\ekvcFlagNew#3\fi
+ \ekv@exparg{\ekvdefNoVal\ekvc@set{#2}}{#1#3}%
+ }
+\ekvpDefType{ekvc@setup@secondary}{flag-true}
+ {\ekvc@type@flag\ekvcFlagSetTrue{#1}{#3}}
+\ekvpDefType{ekvc@setup@secondary}{flag-false}
+ {\ekvc@type@flag\ekvcFlagSetFalse{#1}{#3}}
+\ekvpDefType{ekvc@setup@secondary}{flag-raise}
+ {\ekvc@type@flag\ekvcFlagRaise{#1}{#3}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Flags}
+%
+% The basic idea of flags is to store information by the fact that \TeX\
+% expandably assigns the meaning |\relax| to undefined control sequences which
+% were built with |\csname|. This mechanism is borrowed from \pkg{expl3}.
+%
+% \begin{macro}[internal]{\ekvc@flag@name,\ekvc@flag@namescheme}
+% Flags follow a simple naming scheme which we define here. |\ekvc@flag@name|
+% will store the name of an internal function that is used to build names of
+% the second naming scheme defined by |\ekvc@flag@namescheme|.
+% \begin{macrocode}
+\def\ekvc@flag@name{ekvcf\string}
+\def\ekvc@flag@namescheme#1#2{ekvch#2#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagHeight}
+% For semantic reasons we use |\number| with another name.
+% \begin{macrocode}
+\let\ekvcFlagHeight\number
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagNew}
+% This macro defines a new flag. It stores the function build with the
+% |\ekvc@flag@name| naming scheme after the internal function
+% |\ekvc@flag@height| that'll determine the current flag height. It'll also
+% define the macro named via |\ekvc@flag@name| to build names according to
+% |\ekvc@flag@namescheme|.
+% \begin{macrocode}
+\protected\def\ekvcFlagNew#1%
+ {%
+ \edef#1%
+ {%
+ \ekv@unexpanded{\ekvc@flag@height}%
+ \ekv@unexpanded\expandafter{\csname\ekvc@flag@name#1\endcsname}%
+ }%
+ \ekv@expargtwice
+ {\expandafter\def\csname\ekvc@flag@name#1\endcsname##1}%
+ {\expandafter\ekvc@flag@namescheme\expandafter{\string#1}{##1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@flag@height,\ekvc@flag@height@}
+% This macro gets the height of a flag by a simple loop. The first loop
+% iteration differs a bit from the following in that it doesn't have to get
+% the current iteration count. The space at the end of |\ekvc@flag@height|
+% ends the |\number| evaluation.
+% \begin{macrocode}
+\def\ekvc@flag@height#1%
+ {%
+ \ifcsname#10\endcsname
+ \ekvc@flag@height@1\ekv@stop#1%
+ \fi
+ \@firstofone{0} % leave this space
+ }
+\def\ekvc@flag@height@#1\ekv@stop#2\fi\@firstofone#3%
+ {%
+ \fi
+ \ifcsname#2{#1}\endcsname
+ \expandafter\ekvc@flag@height@\the\numexpr#1+1\relax\ekv@stop#2%
+ \fi
+ \@firstofone{#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagRaise}
+% Raising a flag simply means letting the |\ekvc@flag@namescheme| macro for
+% the current height to relax. The result of raising a flag is that its height
+% is bigger by $1$.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvcFlagRaise#1}%
+ {%
+ \expandafter\expandafter\expandafter\@gobble\expandafter
+ \csname\ekvc@flag@namescheme{\string#1}{\ekvcFlagHeight#1}\endcsname
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagSetTrue,\ekvcFlagSetFalse}
+% \begin{macro}[internal]{\ekvc@flag@set@true,\ekvc@flag@set@false}
+% A flag is considered true if its current height is odd, and as false if it
+% is even. Therefore |\ekvcFlagSetTrue| and |\ekvcFlagSetFalse| only need to
+% raise the flag if the opposing boolean value is the current one.
+% \begin{macrocode}
+\def\ekvcFlagSetTrue#1%
+ {\expandafter\ekvc@flag@set@true\ekvcFlagHeight#1\ekv@stop#1}
+\def\ekvcFlagSetFalse#1%
+ {\expandafter\ekvc@flag@set@false\ekvcFlagHeight#1\ekv@stop#1}
+% \end{macrocode}
+% We can expand |\ekvc@flag@namescheme| at definition time here, which is why
+% we're using a temporary definition to set up |\ekvc@flag@set@true| and
+% |\ekvc@flag@set@false|.
+% \begin{macrocode}
+\def\ekvc@flag@set@true#1%
+ {%
+ \def\ekvc@flag@set@true##1\ekv@stop##2%
+ {%
+ \ifodd##1
+ \ekv@fi@gobble
+ \fi
+ \@firstofone{\expandafter\@gobble\csname#1\endcsname}%
+ }%
+ \def\ekvc@flag@set@false##1\ekv@stop##2%
+ {%
+ \ifodd##1
+ \ekv@fi@firstofone
+ \fi
+ \@gobble{\expandafter\@gobble\csname#1\endcsname}%
+ }%
+ }
+\expandafter\ekvc@flag@set@true\expandafter
+ {\ekvc@flag@namescheme{\string#2}{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagIf}
+% As already explained, truthiness is defined as a flag's height being odd, so
+% we just branch accordingly here.
+% \begin{macrocode}
+\def\ekvcFlagIf#1%
+ {%
+ \ifodd#1%
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagIfRaised}
+% This macro uses flags as a switch, if a flag's current height is bigger than
+% $0$ this test yields true.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvcFlagIfRaised#1}%
+ {%
+ \expandafter\ifcsname\ekvc@flag@namescheme{\string#1}0\endcsname
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagReset,\ekvcFlagResetGlobal}
+% \begin{macro}[internal]{\ekvc@flag@reset,\ekvc@flag@reset@}
+% Resetting works by locally letting all the defined internal macros named
+% after |\ekvc@flag@namescheme| to undefined.
+% \begin{macrocode}
+\protected\def\ekvcFlagReset#1%
+ {\expandafter\ekvc@flag@reset\csname\ekvc@flag@name#1\endcsname{}}
+\protected\def\ekvcFlagResetGlobal#1%
+ {\expandafter\ekvc@flag@reset\csname\ekvc@flag@name#1\endcsname\global}
+\protected\def\ekvc@flag@reset#1#2%
+ {%
+ \ifcsname#10\endcsname
+ #2\expandafter\let\csname#10\endcsname\ekvc@undefined
+ \ekvc@flag@reset@1\ekv@stop#1{#2}%
+ \fi
+ }
+\protected\def\ekvc@flag@reset@#1\ekv@stop#2#3\fi
+ {%
+ \fi
+ \ifcsname#2{#1}\endcsname
+ #3\expandafter\let\csname#2{#1}\endcsname\ekvc@undefined
+ \expandafter\ekvc@flag@reset@\the\numexpr#1+1\relax\ekv@stop#2{#3}%
+ \fi
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagGetHeight}
+% \begin{macro}[internal]{\ekvc@flag@get@height@single}
+% These are just small helpers, first getting the height of the flag and then
+% passing it on to the user supplied code.
+% \begin{macrocode}
+\def\ekvcFlagGetHeight#1%
+ {\expandafter\ekvc@flag@get@height@single\ekvcFlagHeight#1\ekv@stop}
+\long\def\ekvc@flag@get@height@single#1\ekv@stop#2{#2{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagGetHeights}
+% \begin{macro}[internal]
+% {\ekvc@flag@get@heights,\ekvc@flag@get@heights@,\ekvc@flag@get@heights@done}
+% This works by a simple loop that stops at |\ekv@stop|. As long as that
+% marker isn't hit, get the next flags height and put it into a list after
+% |\ekv@stop|. |\ekvc@flag@get@heights@| uses the same marker name for the
+% end of the height, which shouldn't clash in any case. Once we're done we
+% remove the remainder of the current iteration and leave the user supplied
+% code in the input stream with all the flags' heights as a single argument.
+% \begin{macrocode}
+\def\ekvcFlagGetHeights#1%
+ {%
+ \ekvc@flag@get@heights#1\ekv@stop{}%
+ }
+\def\ekvc@flag@get@heights#1%
+ {%
+ \ekv@gobbleto@stop#1\ekvc@flag@get@heights@done\ekv@stop
+ \expandafter\ekvc@flag@get@heights@\ekvcFlagHeight#1\ekv@stop
+ }
+\def\ekvc@flag@get@heights@#1\ekv@stop#2\ekv@stop#3%
+ {\ekvc@flag@get@heights#2\ekv@stop{#3{#1}}}
+\long\def\ekvc@flag@get@heights@done
+ \ekv@stop
+ \expandafter\ekvc@flag@get@heights@\ekvcFlagHeight\ekv@stop\ekv@stop#1#2%
+ {#2{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Helper Macros}
+%
+% \begin{macro}[internal]{\ekvc@extract@mark,\ekvc@extract@mark@}
+% This is used to extract the mark of a split or hash key from its definition.
+% This is kind of fragile, it assumes |#1| is always a macro used for hashing
+% or splitting. Also it assumes that the escape character is a backslash.
+% \begin{macrocode}
+\def\ekvc@extract@mark#1{\expandafter\ekvc@extract@mark@\meaning#1\ekv@stop}
+\begingroup
+\lccode`;=`#
+\lccode`/=`\\
+\lowercase{\endgroup
+\def\ekvc@extract@mark@#1:#2/#3 ;#4\ekv@stop{#3}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Assertions}
+%
+% \begin{macro}[internal]{\ekvc@assert@not@long}
+% Some keys don't want to be |long| and we have to educate the user, so let's
+% throw an error if someone wanted these to be long.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvc@assert@not@long}%
+ {\ekvpAssertIfNot{\ifx\ekvc@long\long}{`long' not accepted}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@assert@defined,\ekvc@assert@k@or@p@defined}
+% Since some keys interact with existing other keys we need to assert those
+% exist.
+% \begin{macrocode}
+\long\def\ekvc@assert@defined#1%
+ {\ekvpAssertTF{\ekvifdefined\ekvc@set{#1}}{undefined key `#1'}}
+\long\def\ekvc@assert@k@or@p@defined#1%
+ {%
+ \ekvpAssertTF
+ {\ekvifdefined\ekvc@set{#1}\@firstoftwo{\ekvifdefinedNoVal\ekvc@set{#1}}}%
+ {undefined key `#1'}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Messages}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@errm,
+% \ekvc@err@toomany,\ekvc@err@value@required,
+% \ekvc@err@already@defined,\ekvc@err@no@key@macro,
+% }
+% Boring unexpandable error messages.
+% \begin{macrocode}
+\protected\long\def\ekvc@errm#1{\errmessage{expkv-cs Error: #1}}
+\protected\long\def\ekvc@err@toomany#1%
+ {\ekvc@errm{Too many keys for macro `\string#1'}}
+\protected\long\def\ekvc@err@value@required#1%
+ {\ekvc@errm{Missing value for key `\ekv@unexpanded{#1}'}}
+\protected\long\def\ekvc@err@already@defined#1%
+ {\ekvc@errm{Macro `\string#1' already defined}}
+\protected\long\def\ekvc@err@no@key@macro#1%
+ {\ekvc@errm{\string#1 is no key=val macro}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@err}
+% We need a way to throw error messages expandably in some contexts.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekvc@err#1}{\ekverr{expkv-cs}{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@err@unknown@hash,\ekvc@err@empty@hash,\ekvc@err@missing@hash,
+% \ekvc@err@invalid@bool,\ekvc@err@unknown@key@or@macro,
+% \ekvc@err@unknown@enum
+% }
+% And here are the expandable error messages.
+% \begin{macrocode}
+\long\def\ekvc@err@unknown@hash#1{\ekvc@err{unknown hash `#1'}}
+\long\def\ekvc@err@missing@hash#1{\ekvc@err{hash `#1' not found}}
+\long\def\ekvc@err@empty@hash{\ekvc@err{empty hash}}
+\def\ekvc@err@invalid@bool#1{\ekvc@err{invalid boolean value `#1'}}
+\long\def\ekvc@err@unknown@key@or@macro#1#2%
+ {\ekvc@err{unknown key `#2' for #1}}
+\def\ekvc@err@unknown@enum#1#2#3%
+ {\ekvc@err{unknown choice `#3' for `#2' in #1}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% Now everything that's left is to reset the category code of |@|.
+% \begin{macrocode}
+\catcode`\@=\ekvc@tmp
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</tex>
+%^^A=<<