summaryrefslogtreecommitdiff
path: root/macros/generic/expkv-bundle/expkv-def.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/generic/expkv-bundle/expkv-def.dtx')
-rw-r--r--macros/generic/expkv-bundle/expkv-def.dtx1369
1 files changed, 1369 insertions, 0 deletions
diff --git a/macros/generic/expkv-bundle/expkv-def.dtx b/macros/generic/expkv-bundle/expkv-def.dtx
new file mode 100644
index 0000000000..33933425e6
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-def.dtx
@@ -0,0 +1,1369 @@
+% \iffalse meta-comment
+%
+% File: expkv-def.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-def.sty}{\from{expkv-def.dtx}{pkg}}}
+\generate{\file{expkv-def.tex}{\from{expkv-def.dtx}{tex}}}
+\generate{\file{t-expkv-def.tex}{\from{expkv-def.dtx}{ctx}}}
+\endbatchfile
+%</driver>^^A=<<
+% \fi
+%
+% \section{\expkvd}
+%^^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\ekvd@tmp
+ {%
+ \ProvidesFile{expkv-def.tex}%
+ [\ekvdDate\space v\ekvdVersion\space a key-defining frontend for expkv]%
+ }
+\input{expkv-def.tex}
+\ProvidesPackage{expkv-def}%
+ [\ekvdDate\space v\ekvdVersion\space a key-defining frontend for expkv]
+% \end{macrocode}
+% \gobbledocstriptag
+%</pkg>
+%^^A=<<
+%^^A the ConTeXt module >>=
+% \subsection{The \ConTeXt\ module}
+% \gobbledocstriptag
+%<*ctx>
+% \begin{macrocode}
+\writestatus{loading}{ConTeXt User Module / expkv-def}
+\usemodule[expkv-pop]
+\unprotect
+\input expkv-def.tex
+\writestatus{loading}
+ {ConTeXt User Module / expkv-def / Version \ekvdVersion\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. Additionally load \expkvp, which aids in defining the type
+% system (and \expkvp\ will actually do the \expkv\ loading).
+% \begin{macrocode}
+\input expkv-pop
+% \end{macrocode}
+%
+% We make sure that \file{expkv-def.tex} is only input once:
+% \begin{macrocode}
+\expandafter\ifx\csname ekvdVersion\endcsname\relax
+\else
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% \begin{macro}{\ekvdVersion,\ekvdDate}
+% We're on our first input, so lets store the version and date in a macro.
+% \begin{macrocode}
+\def\ekvdVersion{1.0}
+\def\ekvdDate{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 |\ekvd@tmp| to use
+% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
+% \begin{macrocode}
+\csname ekvd@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 ekvd@tmp\endcsname=\catcode`\@
+\catcode`\@=11
+% \end{macrocode}
+% |\ekvd@tmp| will be reused later to handle expansion during the key
+% defining. But we don't need it to ever store information long-term after
+% \expkvd\ was initialized.
+%
+% \begin{macro}[internal]{\ekvd@ifprimitive}
+% \begin{macrocode}
+\protected\long\def\ekvd@ifprimitive#1%
+ {%
+ \begingroup
+ \edef\ekvd@tmpa{\string #1}%
+ \edef\ekvd@tmpb{\meaning#1}%
+ \expandafter
+ \endgroup
+ \ifx\ekvd@tmpa\ekvd@tmpb
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvd@long,\ekvd@prot,\ekvd@clear@prefixes,\ekvd@ifalso}
+% \expkvd\ will use |\ekvd@long|, |\ekvd@prot|, and |\ekvd@ifalso| to store
+% whether a key should be defined as |\long| or |\protected| or adds an action
+% to an existing key, and we have to clear them for every new key. By default
+% |long| and |protected| will just be empty, |ifalso| will be
+% |\@secondoftwo|, and |ifnew| will just use its third argument.
+% \begin{macrocode}
+\protected\def\ekvd@clear@prefixes
+ {%
+ \let\ekvd@long\ekv@empty
+ \let\ekvd@prot\ekv@empty
+ \let\ekvd@ifalso\@secondoftwo
+ \let\ekvd@do@new\@gobbletwo
+ }
+\ekvd@clear@prefixes
+% \end{macrocode}
+% \end{macro}
+%
+% We define the parser for our front-facing macro and its \prefix{}es here:
+% \begin{macrocode}
+\ekvpNewParser{ekvd@definekeys}
+\ekvpDefNoValuePrefix{ekvd@definekeys}
+ {\let\ekvd@ifnoarg\@firstoftwo}
+ {\let\ekvd@ifnoarg\@secondoftwo}
+\ekvpDefPrefixLet{ekvd@definekeys}{long} \ekvd@long\long \ekv@empty
+\ekvpDefPrefixLet{ekvd@definekeys}{protected}\ekvd@prot\protected\ekv@empty
+\ekvpDefPrefixLet{ekvd@definekeys}{protect} \ekvd@prot\protected\ekv@empty
+\ekvpDefPrefixLet{ekvd@definekeys}{also}\ekvd@ifalso\@firstoftwo\@secondoftwo
+\ekvpDefPrefixLet{ekvd@definekeys}{new}\ekvd@do@new\ekvd@assert@new\@gobbletwo
+% \end{macrocode}
+% We ease the process of error throwing a bit for now by using our own macro
+% instead of relying on \expkvp's argument forwarding.
+% \begin{macrocode}
+\ekvpDefAutoPrefix{ekvd@definekeys}{\edef\ekvd@cur{\detokenize{#3}}}{}
+% \end{macrocode}
+%
+% \begin{macro}{\ekvdefinekeys}
+% This is the one front-facing macro which provides the interface to define
+% keys. It stores the \set\ for which the keys should be defined in
+% |\ekvd@set| and calls a parser defined with \expkvp.
+% \begin{macrocode}
+\protected\edef\ekvdefinekeys#1%
+ {%
+ \ekv@unexpanded{\def\ekvd@set}{#1}%
+ \ekv@unexpanded{\ekvpParse@unsafe@auto\ekvp@@p@ekvd@definekeys}%
+ \ekv@unexpanded\expandafter{\csname\ekvp@@p@ekvd@definekeys{ppa}\endcsname}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Key Types}
+%
+% \begin{macro}[internal]{\ekvd@def@type,\ekvd@def@type@fwd}
+% To reduce some typing the following is a shortcut to |\ekvpDefType|. The
+% |@fwd| variant will forward the key name and value and remove the
+% unprocessed key. The other variant automatically sets up a helper macro,
+% unfortunately this is necessary due to the design decision of \expkvp\ to
+% not |\detokenize| the key names while \expkvd\ used to do this very early.
+% \begin{macrocode}
+\protected\def\ekvd@def@type#1#2%
+ {%
+ \ekv@exparg{\ekvpDefType{ekvd@definekeys}{#1}}
+ {%
+ \expandafter\expandafter\csname ekvd@th@#1\endcsname
+ \detokenize{##1}\ekv@stop{##2}{##3}%
+ }%
+ \long\expandafter\def\csname ekvd@th@#1\endcsname##1\ekv@stop##2##3{#2}%
+ }
+\protected\long\def\ekvd@def@type@fwd#1#2%
+ {\ekvpDefType{ekvd@definekeys}{#1}{\ekv@exparg{#2}{\detokenize{##1}}{##3}}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set}
+% \begin{macro}[internal]{\ekvd@type@set}
+% \begin{macrocode}
+\ekvd@def@type{set}
+ {\ekvd@ifnoarg{\ekvd@type@set{#1}{#1}}{\ekvd@type@set{#1}{#3}}}
+\protected\def\ekvd@type@set#1#2%
+ {%
+ \ekvd@assert@not@long
+ \ekvd@assert@not@protected
+ \ekvd@do@new{NoVal}{#1}%
+ \ekv@ifempty{#2}%
+ {\ekvd@err@missing@definition}%
+ {%
+ \ekvd@ifalso
+ {%
+ \ekv@expargtwice{\ekvd@add@noval{#1}}%
+ {\ekvchangeset{#2}}%
+ \ekvd@assert@not@protected@also
+ }%
+ {\ekv@expargtwice{\ekvdefNoVal\ekvd@set{#1}}{\ekvchangeset{#2}}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{noval,enoval}
+% \begin{macro}[internal]{\ekvd@type@noval}
+% Another pretty simple type, |noval| just needs to assert that there is a
+% definition and that |long| wasn't specified.
+% There are types where the difference in the variants is so small, that we
+% define a common handler for them, those common handlers are named with
+% |@type@|. |noval| and |enoval| are so similar that we can use such a |@type@|
+% macro, even if we could've done |noval| in a slightly faster way without it.
+% \begin{macrocode}
+\ekvd@def@type@fwd{noval}{\ekvd@type@noval\def}
+\ekvd@def@type@fwd{enoval}{\ekvd@type@noval\edef}
+\protected\long\def\ekvd@type@noval#1#2#3%
+ {%
+ \ekvd@do@new{NoVal}{#2}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@long
+ \ekvd@prot#1\ekvd@tmp{#3}%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@noval{#2}}\ekvd@tmp{}}%
+ {\ekvletNoVal\ekvd@set{#2}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{code,ecode}
+% \begin{macro}[internal]{\ekvd@type@code}
+% |code| is simple as well, |ecode| has to use |\edef| on a temporary macro,
+% since \expkv\ doesn't provide an |\ekvedef|.
+% \begin{macrocode}
+\ekvd@def@type@fwd{code}{\ekvd@type@code\def}
+\ekvd@def@type@fwd{ecode}{\ekvd@type@code\edef}
+\protected\long\def\ekvd@type@code#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@arg
+ \ekvd@prot\ekvd@long#1\ekvd@tmp##1{#3}%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@val{#2}}{\ekvd@tmp{##1}}{}}%
+ {\ekvlet\ekvd@set{#2}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{default,qdefault,odefault,fdefault,edefault}
+% \begin{macro}[internal]
+% {
+% \ekvd@type@default,\ekvd@t@default,\ekvd@t@qdefault,\ekvd@t@odefault,
+% \ekvd@t@fdefault
+% }
+% |\ekvd@type@default| asserts there was an argument, also the key for which one
+% wants to set a default has to be already defined (this is not so important for
+% |default|, but |qdefault| requires it). If everything is good, |\edef| a
+% temporary macro that expands |\ekvd@set| and the |\csname| for the key.
+% The different expansion variants are implemented via |\ekv@unexpanded| and
+% some |\expandafter|s.
+% \begin{macrocode}
+\ekvd@def@type@fwd{default}{\ekvd@type@default{\ekv@unexpanded\expandafter}{}}
+\ekvd@def@type@fwd{odefault}
+ {\ekvd@type@default{\ekv@unexpanded\expandafter\expandafter\expandafter}{}}
+\ekvpLet{ekvd@definekeys}{type}{qdefault}{odefault}
+\ekvd@def@type@fwd{fdefault}
+ {\ekvd@type@default{\ekv@unexpanded\expandafter}{\romannumeral`\^^@}}
+\protected\long\def\ekvd@type@default#1#2#3#4%
+ {%
+ \ekvd@assert@arg
+ \ekvd@do@new{NoVal}{#3}%
+ \ekvd@assert@not@long
+ \ekvifdefined\ekvd@set{#3}%
+ {%
+ \ekvd@prot\edef\ekvd@tmp
+ {#1{#2\csname\ekv@name\ekvd@set{#3}\endcsname{#4}}}%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@noval{#3}}\ekvd@tmp{}}%
+ {\ekvletNoVal\ekvd@set{#3}\ekvd@tmp}%
+ }%
+ {\ekvd@err@undefined@key{#3}}%
+ }
+\ekvd@def@type{edefault}
+ {%
+ \ekvd@assert@arg
+ \ekvd@do@new{NoVal}{#1}%
+ \ekvd@assert@not@long
+ \ekvifdefined\ekvd@set{#1}%
+ {%
+ \ekvd@prot\edef\ekvd@tmp
+ {%
+ \ekv@unexpanded\ekv@expanded
+ {{\csname\ekv@name\ekvd@set{#1}\endcsname{#3}}}%
+ }%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@noval{#1}}\ekvd@tmp{}}%
+ {\ekvletNoVal\ekvd@set{#1}\ekvd@tmp}%
+ }%
+ {\ekvd@err@undefined@key{#1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{initial,oinitial,finitial,einitial}
+% \begin{macro}[internal]{\ekvd@type@initial}
+% \begin{macrocode}
+\ekvd@def@type@fwd{initial}{\ekvd@type@initial\@firstofone}
+\ekvd@def@type@fwd{oinitial}{\ekvd@type@initial\ekv@exparg}
+\ekvd@def@type@fwd{einitial}{\ekvd@type@initial\ekv@expandedarg}
+\ekvd@def@type@fwd{finitial}{\ekvd@type@initial\ekv@fexparg}
+\long\def\ekvd@type@initial#1#2#3%
+ {%
+ \ekvd@assert@not@new
+ \ekvd@assert@not@also
+ \ekvd@assert@not@long
+ \ekvd@assert@not@protected
+ \ekvd@ifnoarg
+ {%
+ \ekvifdefinedNoVal\ekvd@set{#2}%
+ {\csname\ekv@name\ekvd@set{#2}N\endcsname}%
+ {\ekvd@err@undefined@noval{#2}}%
+ }%
+ {%
+ \ekvifdefined\ekvd@set{#2}%
+ {#1{\csname\ekv@name\ekvd@set{#2}\endcsname}{#3}}%
+ {\ekvd@err@undefined@key{#2}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{bool,gbool,boolTF,gboolTF,invbool,ginvbool,invboolTF,ginvboolTF}
+% \begin{macro}[internal]{\ekvd@type@bool}
+% The boolean types are a quicker version of a |choice| that accept |true| and
+% |false|, and set up the |NoVal| action to be identical to \texttt{\key=true}.
+% The |true| and |false| actions are always just |\let|ting the macro in |#7| to
+% some other macro (\emph{e.g.}, \cs[no-index]{iftrue}).
+% \begin{macrocode}
+\ekvd@def@type@fwd{bool}{\ekvd@type@bool{}\iftrue\iffalse}
+\ekvd@def@type@fwd{gbool}{\ekvd@type@bool\global\iftrue\iffalse}
+\ekvd@def@type@fwd{boolTF}{\ekvd@type@bool{}\@firstoftwo\@secondoftwo}
+\ekvd@def@type@fwd{gboolTF}{\ekvd@type@bool\global\@firstoftwo\@secondoftwo}
+\ekvd@def@type@fwd{invbool}{\ekvd@type@bool{}\iffalse\iftrue}
+\ekvd@def@type@fwd{ginvbool}{\ekvd@type@bool\global\iffalse\iftrue}
+\ekvd@def@type@fwd{invboolTF}{\ekvd@type@bool{}\@secondoftwo\@firstoftwo}
+\ekvd@def@type@fwd{ginvboolTF}{\ekvd@type@bool\global\@secondoftwo\@firstoftwo}
+\protected\def\ekvd@type@bool#1#2#3#4#5%
+ {%
+ \ekvd@do@new{}{#4}%
+ \ekvd@do@new{NoVal}{#4}%
+ \ekvd@assert@filledarg{#5}%
+ \ekvd@newlet#5#3%
+ \ekvd@type@choice{#4}%
+ \protected\ekvdefNoVal\ekvd@set{#4}{#1\let#5#2}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{true}\endcsname
+ {#1\let#5#2}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{false}\endcsname
+ {#1\let#5#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{boolpair,gboolpair,boolpairTF,gboolpairTF}
+% \begin{macro}[internal]{\ekvd@type@boolpair}
+% The boolean pair types are essentially the same as the boolean types, but set
+% two macros instead of one.
+% \begin{macrocode}
+\ekvd@def@type{boolpair}
+ {\ekvd@assert@twoargs{#3}\ekvd@type@boolpair{}\iftrue\iffalse{#1}#3}
+\ekvd@def@type{gboolpair}
+ {\ekvd@assert@twoargs{#3}\ekvd@type@boolpair\global\iftrue\iffalse{#1}#3}
+\ekvd@def@type{boolpairTF}
+ {\ekvd@assert@twoargs{#3}\ekvd@type@boolpair{}\@firstoftwo\@secondoftwo{#1}#3}
+\ekvd@def@type{gboolpairTF}
+ {%
+ \ekvd@assert@twoargs{#3}%
+ \ekvd@type@boolpair\global\@firstoftwo\@secondoftwo{#1}#3%
+ }
+\protected\def\ekvd@type@boolpair#1#2#3#4#5#6%
+ {%
+ \ekvd@do@new{}{#4}%
+ \ekvd@do@new{NoVal}{#4}%
+ \ekvd@newlet#5#3%
+ \ekvd@newlet#6#2%
+ \ekvd@type@choice{#4}%
+ \protected\ekvdefNoVal\ekvd@set{#4}{#1\let#5#2#1\let#6#3}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{true}\endcsname
+ {#1\let#5#2#1\let#6#3}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{false}\endcsname
+ {#1\let#5#3#1\let#6#2}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{data,gdata,dataT,gdataT}
+% \begin{macro}[internal]{\ekvd@type@data}
+% \begin{macrocode}
+\ekvd@def@type@fwd{data}
+ {\ekvd@type@data\@secondoftwo\edef{####2}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{edata}
+ {%
+ \ekvd@type@data\@secondoftwo\edef
+ {####2}{\ekv@unexpanded\ekv@expanded{{##1}}}%
+ }
+\ekvd@def@type@fwd{gdata}
+ {\ekvd@type@data\@secondoftwo\xdef{####2}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{xdata}
+ {%
+ \ekvd@type@data\@secondoftwo\xdef
+ {####2}{\ekv@unexpanded\ekv@expanded{{##1}}}%
+ }
+\ekvd@def@type@fwd{dataT}{\ekvd@type@data\@gobble\edef{}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{edataT}
+ {\ekvd@type@data\@gobble\edef{}{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\ekvd@def@type@fwd{gdataT}{\ekvd@type@data\@gobble\xdef{}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{xdataT}
+ {\ekvd@type@data\@gobble\xdef{}{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\protected\def\ekvd@type@data#1#2#3#4#5#6%
+ {%
+ \ekvd@do@new{}{#5}%
+ \ekvd@assert@filledarg{#6}%
+ \ekvd@newlet#6#1%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#5}{\long#2#6####1#3{####1{#4}}}{}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#5}%
+ {\long#2#6####1#3{####1{#4}}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{box,gbox}
+% \begin{macro}[internal]{\ekvd@type@box}
+% Set up our boxes. Though we're a generic package we want to be colour safe, so
+% we put an additional grouping level inside the box contents, for the case that
+% someone uses \pkg{color}. |\ekvd@newreg| is a small wrapper which tests
+% whether the first argument is defined and if not does
+% |\csname new#2\endcsname#1|.
+% \begin{macrocode}
+\ekvd@def@type@fwd{box}{\ekvd@type@box{}}
+\ekvd@def@type@fwd{gbox}{\ekvd@type@box\global}
+\protected\def\ekvd@type@box#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{box}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1\setbox#3=\hbox{\begingroup##1\endgroup}}{}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#2}%
+ {#1\setbox#3=\hbox{\begingroup##1\endgroup}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{toks,gtoks}
+% \begin{macro}[internal]{\ekvd@type@toks}
+% Similar to |box|, but set the |toks|.
+% \begin{macrocode}
+\ekvd@def@type@fwd{toks}{\ekvd@type@toks{}}
+\ekvd@def@type@fwd{gtoks}{\ekvd@type@toks\global}
+\protected\def\ekvd@type@toks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1#3={##1}}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#2}{#1#3={##1}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@type@preapptoks,\ekvd@t@apptoks,\ekvd@t@gapptoks}
+% Just like |toks|, but expand the current contents of the |toks| register to
+% append the new contents.
+% \begin{macrocode}
+\ekvd@ifprimitive\toksapp
+ {%
+ \ekvd@def@type@fwd{apptoks}{\ekvd@type@preapptoks\toksapp}
+ \ekvd@def@type@fwd{gapptoks}{\ekvd@type@preapptoks\gtoksapp}
+ \ekvd@def@type@fwd{pretoks}{\ekvd@type@preapptoks\tokspre}
+ \ekvd@def@type@fwd{gpretoks}{\ekvd@type@preapptoks\gtokspre}
+ \protected\def\ekvd@type@preapptoks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1#3{##1}}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#2}{#1#3{##1}}}%
+ }
+ }
+ {%
+ \ekvd@def@type@fwd{apptoks}{\ekvd@type@apptoks{}}
+ \ekvd@def@type@fwd{gapptoks}{\ekvd@type@apptoks\global}
+ \protected\def\ekvd@type@apptoks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1#3=\expandafter{\the#3##1}}{}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#2}%
+ {#1#3=\expandafter{\the#3##1}}%
+ }%
+ }
+ \ekvd@def@type@fwd{pretoks}{\ekvd@type@pretoks{}}
+ \ekvd@def@type@fwd{gpretoks}{\ekvd@type@pretoks\global}
+ \newtoks\ekvd@toks
+ \protected\def\ekvd@type@pretoks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}%
+ {#1#3=\ekv@expanded{{\ekv@unexpanded{##1}\the#3}}}%
+ {}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#2}%
+ {#1#3=\ekv@expanded{{\ekv@unexpanded{##1}\the#3}}}%
+ }%
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {int,eint,gint,xint,dimen,edimen,gdimen,xdimen,skip,eskip,gskip,xskip}
+% \begin{macro}[internal]{\ekvd@type@register}
+% The |\ekvd@type@register| can handle all the types for which the assignment will
+% just be \texttt{\meta{register}=\meta{value}}.
+% \begin{macrocode}
+\ekvd@def@type@fwd {int}{\ekvd@type@register{count}{}{}}
+\ekvd@def@type@fwd{eint}{\ekvd@type@register{count}{}\numexpr}
+\ekvd@def@type@fwd{gint}{\ekvd@type@register{count}\global{}}
+\ekvd@def@type@fwd{xint}{\ekvd@type@register{count}\global\numexpr}
+\ekvd@def@type@fwd {dimen}{\ekvd@type@register{dimen}{}{}}
+\ekvd@def@type@fwd{edimen}{\ekvd@type@register{dimen}{}\dimexpr}
+\ekvd@def@type@fwd{gdimen}{\ekvd@type@register{dimen}\global{}}
+\ekvd@def@type@fwd{xdimen}{\ekvd@type@register{dimen}\global\dimexpr}
+\ekvd@def@type@fwd {skip}{\ekvd@type@register{skip}{}{}}
+\ekvd@def@type@fwd{eskip}{\ekvd@type@register{skip}{}\glueexpr}
+\ekvd@def@type@fwd{gskip}{\ekvd@type@register{skip}\global{}}
+\ekvd@def@type@fwd{xskip}{\ekvd@type@register{skip}\global\glueexpr}
+\protected\def\ekvd@type@register#1#2#3#4#5%
+ {%
+ \ekvd@do@new{}{#4}%
+ \ekvd@assert@filledarg{#5}%
+ \ekvd@newreg#5{#1}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#4}{#2#5=#3##1\relax}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#4}{#2#5=#3##1\relax}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{store,gstore,estore,xstore}
+% \begin{macro}[internal]{\ekvd@type@store}
+% The none-expanding |store| types use an |\edef| or |\xdef| and |\unexpanded|
+% to be able to also store |#| easily.
+% \begin{macrocode}
+\ekvd@def@type@fwd{store}{\ekvd@type@store\edef{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{gstore}{\ekvd@type@store\xdef{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{estore}
+ {\ekvd@type@store\edef{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\ekvd@def@type@fwd{xstore}
+ {\ekvd@type@store\xdef{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\protected\def\ekvd@type@store#1#2#3#4%
+ {%
+ \ekvd@do@new{}{#3}%
+ \ekvd@assert@filledarg{#4}%
+ \ekvd@newlet#4\ekv@empty
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#3}{#1#4{#2}}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#3}{#1#4{#2}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{meta,nmeta}
+% \begin{macro}[internal]{\ekvd@type@meta}
+% |meta| sets up things such that another instance of |\ekvset| will be run on
+% the argument, with the same \set.
+% \begin{macrocode}
+\ekvd@def@type@fwd{meta}
+ {\ekvd@type@meta{}{##1}\ekvd@add@val{{##1}}{}\ekv@exparg}
+\ekvd@def@type@fwd{nmeta}
+ {%
+ \ekvd@assert@not@long
+ \ekvd@type@meta
+ {NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also\ekv@expargtwice
+ }
+\protected\long\def\ekvd@type@meta#1#2#3#4#5#6#7#8%
+ {%
+ \ekvd@do@new{#1}{#7}%
+ \ekvd@assert@filledarg{#8}%
+ #6{\ekvd@prot\ekvd@long\def\ekvd@tmp#2}{\ekvmorekv{#8}}%
+ \ekvd@ifalso
+ {\ekv@exparg{#3{#7}}{\ekvd@tmp#4}{#5}}%
+ {\csname ekvlet#1\endcsname\ekvd@set{#7}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{smeta,snmeta}
+% \begin{macro}[internal]
+% {\ekvd@type@smeta,\ekvd@type@smeta@}
+% |smeta| is pretty similar to |meta|, but needs two arguments inside of \val,
+% such that the first is the \set\ for which the sub-|\ekvset| and the second is
+% the \kv\ list.
+% \begin{macrocode}
+\ekvd@def@type@fwd{smeta}{\ekvd@type@smeta{}{##1}\ekvd@add@val{{##1}}{}}
+\ekvd@def@type@fwd{snmeta}
+ {%
+ \ekvd@assert@not@long
+ \ekvd@type@smeta{NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also
+ }
+\protected\long\def\ekvd@type@smeta#1#2#3#4#5#6#7%
+ {%
+ \ekvd@do@new{#1}{#6}%
+ \ekvd@assert@twoargs{#7}%
+ \ekvd@type@smeta@#7{#2}%
+ \ekvd@ifalso
+ {\ekv@exparg{#3{#6}}{\ekvd@tmp#4}{#5}}%
+ {\csname ekvlet#1\endcsname\ekvd@set{#6}\ekvd@tmp}%
+ }
+\protected\long\def\ekvd@type@smeta@#1#2#3%
+ {\ekvd@prot\ekvd@long\ekv@expargtwice{\def\ekvd@tmp#3}{\ekvset{#1}{#2}}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{choice}
+% \begin{macro}[internal]{\ekvd@type@choice,\ekvd@populate@choice}
+% The real key definition of a |choice| type is pretty simple, the heavy
+% lifting is done by a helper macro at run time. Though setting up the choices
+% needs a bit of work. First the key macro definition.
+% \begin{macrocode}
+\protected\def\ekvd@type@choice#1%
+ {%
+ \ekvd@assert@not@long
+ \ekv@expargtwice{\ekvd@prot\def\ekvd@tmp##1}%
+ {%
+ \expandafter\expandafter\expandafter
+ \ekvd@h@choice
+ \expandafter\expandafter\expandafter
+ {\expandafter\ekvd@choice@name\expandafter{\ekvd@set}{#1}{##1}}%
+ }%
+ \ekvd@ifalso
+ {%
+ \ekvd@assert@val{#1}%
+ \ekvd@if@not@already@choice{#1}%
+ {%
+ \ekv@exparg
+ {%
+ \expandafter\ekvd@add@aux
+ \csname\ekv@name\ekvd@set{#1}\endcsname{{##1}}{#1}%
+ }%
+ {\ekvd@tmp{##1}}%
+ {\ekvd@long\ekvdef}\ekvd@assert@not@long@also
+ }%
+ }%
+ {\ekvlet\ekvd@set{#1}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% The set up of different choices is done through another parser, that one
+% needs relatively few types though.
+% \begin{macrocode}
+\ekvpNewParser{ekvd@populate@choice}
+\ekvpValueAlwaysRequired{ekvd@populate@choice}
+\ekvpDefType{ekvd@populate@choice}{protect}
+ {\ekvd@populate@choice\protected{#1}{#3}}
+\ekvpDefType{ekvd@populate@choice}{unprotect}{\ekvd@populate@choice{}{#1}{#3}}
+\ekvpDefNoType{ekvd@populate@choice} {\ekvd@populate@choice{}{#1}{#3}}
+\ekvpLet{ekvd@populate@choice}{type}{protected}{protect}
+\ekvpLet{ekvd@populate@choice}{type}{unprotected}{unprotect}
+% \end{macrocode}
+% The choice definition is done by the following little helper:
+% \begin{macrocode}
+\protected\long\def\ekvd@populate@choice#1#2#3%
+ {%
+ #1\expandafter\edef
+ \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
+ {\ekv@unexpanded{#3}}%
+ }
+% \end{macrocode}
+% And we define the real type:
+% \begin{macrocode}
+\ekvd@def@type{choice}
+ {%
+ \ekvd@do@new{}{#1}%
+ \ekvd@assert@arg
+ \ekvd@type@choice{#1}%
+ \def\ekvd@set@choice{#1}%
+ \ekvpParse@unsafe\ekvp@@p@ekvd@populate@choice{#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{choice-store,choice-enum}
+% These two types define a special kind of |choice| key and are quite similar,
+% the only difference is what the different choices do (hence they use a
+% shared initialisation which differs in the chosen |populate| step).
+% \begin{macrocode}
+\ekvd@def@type@fwd{choice-store}
+ {\ekvd@type@choicespecial\ekvd@populate@choicestore}
+\ekvd@def@type@fwd{choice-enum}
+ {\ekvd@type@choicespecial\ekvd@populate@choiceenum}
+% \end{macrocode}
+% \begin{macro}[internal]{\ekvd@type@choicespecial}
+% Initialise similar to a |choice| key. The difference is that we require two
+% arguments (which we assert), a macro to store things in, and a |csv|-list
+% containing the allowed values. |#1| is the |populate| macro according to the
+% type used.
+% \begin{macrocode}
+\protected\long\def\ekvd@type@choicespecial#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@twoargs{#3}%
+ \ekvd@type@choice{#2}%
+ \def\ekvd@set@choice{#2}%
+ #1#3%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {\ekvd@populate@choicestore,\ekvd@populate@choicestore@}
+% We initialise the storing macro if it doesn't yet exist, and then we loop
+% over the value list. The |\edef|s with |\unexpanded| are both necessary to
+% be able to store macro parameter tokens (the outer protects at define time,
+% the inner at use time).
+% \begin{macrocode}
+\protected\long\def\ekvd@populate@choicestore#1%
+ {%
+ \ekvd@newlet#1\ekv@empty
+ \ekvparse{\ekvd@populate@choicestore@k#1}{\ekvd@populate@choicestore@kv#1}%
+ }
+\protected\long\def\ekvd@populate@choicestore@kv#1#2#3%
+ {%
+ \protected\expandafter\edef
+ \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
+ {\ekv@unexpanded{\edef#1{\ekv@unexpanded{#3}}}}%
+ }
+\ekv@exparg{\protected\long\def\ekvd@populate@choicestore@k#1#2}%
+ {\ekvd@populate@choicestore@kv{#1}{#2}{#2}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {\ekvd@populate@choiceenum,\ekvd@populate@choiceenum@}
+% This is similar to the population of a |choice-store| type, but instead of
+% storing the values in a macro this initialises a count and stores the
+% position of the value in the list inside that count (zero-indexed). The
+% space is necessary to terminate the number scanning, which is the reason we
+% use |\@firstofone| (so that the space after the macro name isn't gobbled by
+% \TeX).
+% \begin{macrocode}
+\protected\long\def\ekvd@populate@choiceenum#1%
+ {%
+ \ekvd@newreg#1{count}%
+ \def\ekvd@tmp{0}%
+ \ekvcsvloop{\ekvd@populate@choiceenum@#1}%
+ }
+\protected\long\def\ekvd@populate@choiceenum@#1#2%
+ {%
+ \protected\expandafter\edef
+ \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
+ {#1=\@firstofone{\ekvd@tmp} }%
+ \edef\ekvd@tmp{\the\numexpr\ekvd@tmp+1\relax}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{unknown-choice}
+% \begin{macrocode}
+\ekvd@def@type{unknown-choice}
+ {%
+ \ekvd@do@new@for@name{\ekvd@unknown@choice@name\ekvd@set{#1}}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@long
+ \ekvd@assert@not@also
+ \ekvd@prot\expandafter
+ \def\csname\ekvd@unknown@choice@name\ekvd@set{#1}\endcsname##1{#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{unknown}
+% \begin{macro}[internal]{\ekvd@type@unknown@code,\ekvd@type@unknown@noval}
+% The |unknown| type has different subtypes which would be the key names for
+% other types. It is first checked whether that subtype is defined, if it
+% isn't throw an error, else use that subtype.
+% \begin{macrocode}
+\ekvd@def@type{unknown}
+ {%
+ \ekv@ifdefined{ekvd@type@unknown@\detokenize{#1}}%
+ {\csname ekvd@type@unknown@\detokenize{#1}\endcsname{#3}}%
+ \ekvd@err@misused@unknown
+ }
+% \end{macrocode}
+% The |unknown noval| type can use |\ekvdefunknownNoVal| directly (after
+% asserting some prefixes).
+% \begin{macrocode}
+\protected\long\def\ekvd@type@unknown@noval#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}uN}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \ekvd@prot\ekvd@long\ekvdefunknownNoVal\ekvd@set{#1}%
+ }
+% \end{macrocode}
+% The |unknown code| type uses some trickery during the definition in order to
+% swap out |#1| and |#2| in the user supplied definition. This is done via a
+% temporary macro that stores the definition but gets the parameter numbers
+% reversed while the real definition is done.
+% \begin{macrocode}
+\protected\long\def\ekvd@type@unknown@code#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}u}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \begingroup
+ \def\ekvd@tmp##1##2##3{#1}%
+ \ekv@exparg
+ {%
+ \endgroup
+ \ekvd@prot\ekvd@long\ekvdefunknown\ekvd@set
+ }%
+ {\ekvd@tmp{##2}{##1}{##3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@type@unknown@redirect,
+% \ekvd@type@unknown@redirect-code,
+% \ekvd@type@unknown@redirect-noval
+% }
+% The |unknown redirect| types also just forward to |\ekvredirectunknown|
+% after asserting some prefixes.
+% \begin{macrocode}
+\protected\edef\ekvd@type@unknown@redirect#1%
+ {%
+ \expandafter\noexpand\csname ekvd@type@unknown@redirect-code\endcsname{#1}%
+ \expandafter\noexpand\csname ekvd@type@unknown@redirect-noval\endcsname{#1}%
+ }
+\protected\expandafter\def\csname ekvd@type@unknown@redirect-code\endcsname#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}u}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \ekvd@assert@not@protected
+ \expandafter\ekvredirectunknown\expandafter{\ekvd@set}{#1}%
+ }
+\protected\expandafter\def\csname ekvd@type@unknown@redirect-noval\endcsname#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}uN}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \ekvd@assert@not@protected
+ \expandafter\ekvredirectunknownNoVal\expandafter{\ekvd@set}{#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Key Type Helpers}
+% There are some keys that might need helpers during their execution (not during
+% their definition, which are gathered as |@type@| macros). These helpers are
+% named |@h@|.
+%
+% \begin{macro}[internal]{\ekvd@h@choice,\ekvd@h@choice@}
+% The |choice| helper will just test whether the given choice was defined, if
+% not throw an error expandably, else call the macro which stores the code for
+% this choice.
+% \begin{macrocode}
+\def\ekvd@h@choice#1%
+ {%
+ \expandafter\ekvd@h@choice@
+ \csname\ifcsname#1\endcsname#1\else relax\fi\endcsname
+ {#1}%
+ }
+\def\ekvd@h@choice@#1#2%
+ {%
+ \ifx#1\relax
+ \ekvd@err@choice@invalid{#2}%
+ \expandafter\@gobble
+ \fi
+ #1%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Handling \texttt{also}}
+%
+% \begin{macro}[internal]
+% {\ekvd@add@val,\ekvd@add@noval,\ekvd@add@aux,\ekvd@add@aux@}
+% \begin{macrocode}
+\protected\long\def\ekvd@add@val#1#2#3%
+ {%
+ \ekvd@assert@val{#1}%
+ \expandafter\ekvd@add@aux\csname\ekv@name\ekvd@set{#1}\endcsname{{##1}}%
+ {#1}{#2}{\ekvd@long\ekvdef}{#3}%
+ }
+\protected\long\def\ekvd@add@noval#1#2#3%
+ {%
+ \ekvd@assert@noval{#1}%
+ \expandafter\ekvd@add@aux\csname\ekv@name\ekvd@set{#1}N\endcsname{}%
+ {#1}{#2}\ekvdefNoVal{#3}%
+ }
+\protected\long\def\ekvd@add@aux#1#2%
+ {%
+ \ekvd@extract@prefixes#1%
+ \expandafter\ekvd@add@aux@\expandafter{#1#2}%
+ }
+% \end{macrocode}
+% Once we're done with adding something to the definition of a key we need to
+% clear the prefixes. Maybe it would be better to only restore them if they
+% were changed by the |\ekvd@extract@prefixes| mechanism, but I think this is
+% fine with just resetting all (there should be no code dependent on any of
+% the prefix storing macros after this was run).
+% \begin{macrocode}
+\protected\long\def\ekvd@add@aux@#1#2#3#4#5%
+ {%
+ #5%
+ \ekvd@prot#4\ekvd@set{#2}{#1#3}%
+ \ekvd@clear@prefixes
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@extract@prefixes,\ekvd@extract@prefixes@,
+% \ekvd@extract@prefixes@long,\ekvd@extract@prefixes@prot
+% }
+% This macro checks which prefixes were used for the definition of a macro and
+% sets |\ekvd@long| and |\ekvd@prot| accordingly.
+% \begin{macrocode}
+\protected\def\ekvd@extract@prefixes#1%
+ {%
+ \expandafter\ekvd@extract@prefixes@\meaning#1\ekvd@stop
+ }
+% \end{macrocode}
+% In the following definition |#1| will get replaced by |macro:|, |#2| by
+% |\long| and |#3| by |\protected| (in each, all tokens will have category
+% other). This allows us to parse the |\meaning| of a macro for those strings.
+% \begin{macrocode}
+\protected\def\ekvd@extract@prefixes@#1#2#3%
+ {%
+ \protected\def\ekvd@extract@prefixes@##1#1##2\ekvd@stop
+ {%
+ \ekvd@extract@prefixes@long
+ ##1\ekvd@mark\@firstofone#2\ekvd@mark\@gobble\ekvd@stop
+ {\let\ekvd@long\long}%
+ \ekvd@extract@prefixes@prot
+ ##1\ekvd@mark\@firstofone#3\ekvd@mark\@gobble\ekvd@stop
+ {\let\ekvd@prot\protected}%
+ }%
+ \protected\def\ekvd@extract@prefixes@long##1#2##2\ekvd@mark##3##4\ekvd@stop
+ {##3}%
+ \protected\def\ekvd@extract@prefixes@prot##1#3##2\ekvd@mark##3##4\ekvd@stop
+ {##3}%
+ }
+% \end{macrocode}
+% We use a temporary macro to expand the three arguments of
+% |\ekvd@extract@prefixes@|, which will set up the real meaning of itself and
+% the parsing for |\long| and |\protected|.
+% \begin{macrocode}
+\begingroup
+\edef\ekvd@tmp
+ {%
+ \endgroup
+ \ekvd@extract@prefixes@
+ {\detokenize{macro:}}%
+ {\string\long}%
+ {\string\protected}%
+ }
+\ekvd@tmp
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Tests}
+%
+% \begin{macro}[internal]{\ekvd@newlet,\ekvd@newreg}
+% These macros test whether a control sequence is defined, if it isn't they
+% define it, either via |\let| or via the correct \cs[no-index]{new\meta{reg}}.
+% \begin{macrocode}
+\protected\def\ekvd@newlet#1#2%
+ {%
+ \ifdefined#1%
+ \ifx#1\relax\ekv@fi@gobble\fi\@firstofone
+ \ekv@fi@gobble
+ \fi
+ \@firstofone{\let#1#2}%
+ }
+\protected\def\ekvd@newreg#1#2%
+ {%
+ \ifdefined#1%
+ \ifx#1\relax\ekv@fi@gobble\fi\@firstofone
+ \ekv@fi@gobble
+ \fi
+ \@firstofone{\csname new#2\endcsname#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvd@assert@twoargs,\ekvd@ifnottwoargs,\ekvd@ifempty@gtwo}
+% A test for exactly two tokens can be reduced for an empty-test after gobbling
+% two tokens, in the case that there are fewer tokens than two in the argument,
+% only macros will be gobbled that are needed for the true branch, which doesn't
+% hurt, and if there are more this will not be empty.
+% \begin{macrocode}
+\long\def\ekvd@assert@twoargs#1%
+ {\ekvd@ifnottwoargs{#1}{\ekvd@err@missing@definition\ekvpGobbleT}{}}
+\long\def\ekvd@ifnottwoargs#1%
+ {%
+ \ekvd@ifempty@gtwo#1\ekv@ifempty@B
+ \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ }
+\long\def\ekvd@ifempty@gtwo#1#2{\ekv@ifempty@\ekv@ifempty@A}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@assert@val,\ekvd@assert@val@,\ekvd@assert@noval,\ekvd@assert@noval@,
+% \ekvd@extract@args,\ekvd@extracted@args,\ekvd@one@arg@string
+% }
+% Assert that a given key is defined as a value taking key or a |NoVal| key with
+% the correct argument structure, respectively.
+% \begin{macrocode}
+\protected\def\ekvd@assert@val#1%
+ {%
+ \ekvifdefined\ekvd@set{#1}%
+ {\expandafter\ekvd@assert@val@\csname\ekv@name\ekvd@set{#1}\endcsname}%
+ {%
+ \ekvifdefinedNoVal\ekvd@set{#1}%
+ \ekvd@err@add@val@on@noval
+ {\ekvd@err@undefined@key{#1}}%
+ \ekvpGobbleT
+ }%
+ }
+\protected\def\ekvd@assert@val@#1%
+ {%
+ \expandafter\ekvd@extract@args\meaning#1\ekvd@stop
+ \unless\ifx\ekvd@extracted@args\ekvd@one@arg@string
+ \ekvd@err@unsupported@arg
+ \expandafter\ekvpGobbleT
+ \fi
+ }%
+\protected\def\ekvd@assert@noval#1%
+ {%
+ \ekvifdefinedNoVal\ekvd@set{#1}%
+ {\expandafter\ekvd@assert@noval@\csname\ekv@name\ekvd@set{#1}N\endcsname}%
+ {%
+ \ekvifdefined\ekvd@set{#1}%
+ \ekvd@err@add@noval@on@val
+ {\ekvd@err@undefined@key{#1}}%
+ \ekvpGobbleT
+ }%
+ }
+\protected\def\ekvd@assert@noval@#1%
+ {%
+ \expandafter\ekvd@extract@args\meaning#1\ekvd@stop
+ \unless\ifx\ekvd@extracted@args\ekv@empty
+ \ekvd@err@unsupported@arg
+ \expandafter\ekvpGobbleT
+ \fi
+ }
+\protected\def\ekvd@extract@args#1%
+ {%
+ \protected\def\ekvd@extract@args##1#1##2->##3\ekvd@stop
+ {\def\ekvd@extracted@args{##2}}%
+ }
+\expandafter\ekvd@extract@args\expandafter{\detokenize{macro:}}
+\edef\ekvd@one@arg@string{\string#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@assert@arg,\ekvd@ifnoarg}
+% The |\ekvd@ifnoarg| macro is initialised as |\@secondoftwo|. Each time a key
+% without an argument is encountered it will be set to |\@firstoftwo| for the
+% scope of that key's parsing.
+% \begin{macrocode}
+\def\ekvd@assert@arg{\ekvd@ifnoarg{\ekvd@err@missing@definition\ekvpGobbleT}{}}
+\let\ekvd@ifnoarg\@secondoftwo
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@assert@filledarg,\ekvd@ifnoarg@or@empty}
+% \begin{macrocode}
+\long\def\ekvd@assert@filledarg#1%
+ {\ekvd@ifnoarg@or@empty{#1}{\ekvd@err@missing@definition\ekvpGobbleT}{}}
+\long\def\ekvd@ifnoarg@or@empty#1%
+ {%
+ \ekvd@ifnoarg
+ \@firstoftwo
+ {\ekv@ifempty{#1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@assert@not@long,\ekvd@assert@not@protected,\ekvd@assert@not@also,
+% \ekvd@assert@not@long@also,\ekvd@assert@not@protected@also,
+% \ekvd@assert@new,\ekvd@assert@not@new
+% }
+% Some key-types don't want to be |also|, |\long| or |\protected|, so we provide
+% macros to test this and throw an error, this could be silently ignored but now
+% users will learn to not use unnecessary stuff which slows the compilation
+% down.
+% \begin{macrocode}
+\def\ekvd@assert@not@long{\ifx\ekvd@long\long\ekvd@err@no@prefix{long}\fi}
+\def\ekvd@assert@not@protected
+ {\ifx\ekvd@prot\protected\ekvd@err@no@prefix{protected}\fi}
+\def\ekvd@assert@not@also{\ekvd@ifalso{\ekvd@err@no@prefix{also}}{}}
+\def\ekvd@assert@not@long@also
+ {\ifx\ekvd@long\long\ekvd@err@no@prefix@also{long}\fi}
+\def\ekvd@assert@not@protected@also
+ {\ifx\ekvd@prot\protected\ekvd@err@no@prefix@also{protected}\fi}
+\def\ekvd@assert@new#1#2%
+ {%
+ \csname ekvifdefined#1\endcsname\ekvd@set{#2}%
+ {\ekvd@err@not@new\ekvpGobbleT}%
+ {}%
+ }
+\def\ekvd@assert@not@new
+ {\ifx\ekvd@do@new\ekvd@assert@new\ekvd@err@no@prefix{new}\fi}
+\def\ekvd@do@new@for@name#1%
+ {%
+ \ifx\ekvd@do@new\ekvd@assert@new
+ \ekv@fi@firstofone
+ \fi
+ \@gobble{\ekv@ifdefined{#1}{\ekvd@err@not@new\ekvpGobbleT}{}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@if@not@already@choice, \ekvd@if@not@already@choice@a,
+% \ekvd@if@not@already@choice@b
+% }
+% It is bad to use |also| on a key that already contains a |choice|, as both
+% choices would share the same valid values and thus lead to each callback being
+% used twice. The following is a rudimentary test against this.
+% \begin{macrocode}
+\protected\def\ekvd@if@not@already@choice#1%
+ {%
+ \expandafter\ekvd@if@not@already@choice@a
+ \csname\ekv@name\ekvd@set{#1}\endcsname
+ {}\ekvd@h@choice\ekvd@stop
+ }
+\protected\def\ekvd@if@not@already@choice@a
+ {%
+ \expandafter\ekvd@if@not@already@choice@b
+ }
+\long\protected\def\ekvd@if@not@already@choice@b#1\ekvd@h@choice#2\ekvd@stop
+ {%
+ \ekv@ifempty{#2}\@firstofone\@gobble
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@ifspace,\ekvd@ifspace@}
+% Yet another test which can be reduced to an if-empty, this time by gobbling
+% everything up to the first space.
+% \begin{macrocode}
+\long\def\ekvd@ifspace#1%
+ {%
+ \ekvd@ifspace@#1 \ekv@ifempty@B
+ \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ }
+\long\def\ekvd@ifspace@#1 % keep this space
+ {%
+ \ekv@ifempty@\ekv@ifempty@A
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Messages}
+%
+% Most messages of \expkvd\ are not expandable, since they only appear during
+% key-definition, which is not expandable anyway.
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@errm,\ekvd@err@missing@definition,
+% \ekvd@err@missing@type,\ekvd@err@undefined@prefix,\ekvd@err@undefined@key,
+% \ekvd@err@no@prefix,\ekvd@err@no@prefix@also,
+% \ekvd@err@add@val@on@noval,\ekvd@err@add@noval@on@val,
+% \ekvd@err@unsupported@arg,\ekvd@err@not@new
+% }
+% The non-expandable error messages are boring, so here they are:
+% \begin{macrocode}
+\protected\long\def\ekvd@errm#1{\errmessage{expkv-def Error: #1}}
+\protected\def\ekvd@err@missing@definition
+ {\ekvd@errm{Missing definition for key `\ekvd@cur'}}
+\protected\def\ekvd@err@missing@type
+ {\ekvd@errm{Missing type prefix for key `\ekvd@cur'}}
+\protected\def\ekvd@err@undefined@prefix#1%
+ {%
+ \ekvd@errm
+ {%
+ Undefined prefix `\ekv@unexpanded{#1}' found while processing
+ `\ekvd@cur'%
+ }%
+ }
+\protected\def\ekvd@err@undefined@key#1%
+ {%
+ \ekvd@errm
+ {Undefined key `\ekv@unexpanded{#1}' found while processing `\ekvd@cur'}%
+ }
+\protected\def\ekvd@err@undefined@noval#1%
+ {%
+ \ekvd@errm
+ {%
+ Undefined noval key `\ekv@unexpanded{#1}' found while processing
+ `\ekvd@cur'%
+ }%
+ }
+\protected\def\ekvd@err@no@prefix#1%
+ {\ekvd@errm{prefix `#1' not accepted in `\ekvd@cur'}}
+\protected\def\ekvd@err@no@prefix@also#1%
+ {\ekvd@errm{`\ekvd@cur' not allowed with a `#1' key}}
+\protected\def\ekvd@err@add@val@on@noval
+ {\ekvd@errm{`\ekvd@cur' not allowed with a NoVal key}}
+\protected\def\ekvd@err@add@noval@on@val
+ {\ekvd@errm{`\ekvd@cur' not allowed with a value taking key}}
+\protected\def\ekvd@err@unsupported@arg
+ {%
+ \ekvd@errm
+ {%
+ Existing key-macro has the unsupported argument string
+ `\ekvd@extracted@args' for key `\ekvd@cur'%
+ }%
+ }
+\protected\def\ekvd@err@not@new
+ {\ekvd@errm{The key for `\ekvd@cur' is already defined}}
+\protected\long\def\ekvd@err@misused@unknown
+ {\ekvd@errm{Misuse of the unknown type found while processing `\ekvd@cur'}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@err@choice@invalid,\ekvd@err@choice@invalid@,\ekvd@choice@name,
+% \ekvd@unknown@choice@name
+% }
+% |\ekvd@err@choice@invalid| will have to use this mechanism to throw its
+% message. Also we have to retrieve the name parts of the choice in an easy way,
+% so we use parentheses of catcode 8 here, which should suffice in most cases to
+% allow for a correct separation.
+% \begin{macrocode}
+\def\ekvd@err@choice@invalid#1%
+ {%
+ \ekvd@err@choice@invalid@#1%
+ }
+\begingroup
+\catcode40=8
+\catcode41=8
+\@firstofone{\endgroup
+\def\ekvd@choice@name#1#2#3%
+ {%
+ ekvd#1(#2)\detokenize{#3}%
+ }
+\def\ekvd@unknown@choice@name#1#2%
+ {%
+ ekvd:u:#1(#2)%
+ }
+\def\ekvd@err@choice@invalid@ ekvd#1(#2)\detokenize#3%
+ {%
+ \ekv@ifdefined{\ekvd@unknown@choice@name{#1}{#2}}%
+ {\csname\ekvd@unknown@choice@name{#1}{#2}\endcsname{#3}}%
+ {\ekvd@err{invalid choice `#3' for `#2' in set `#1'}}%
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@err}
+% The expandable error messages use |\ekvd@err|, which is just like |\ekv@err|
+% from \expkv. It uses a runaway argument to start the error message.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekvd@err#1}{\ekverr{expkv-def}{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% Now everything that's left is to reset the category code of |@|.
+% \begin{macrocode}
+\catcode`\@=\ekvd@tmp
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</tex>
+%^^A=<<