diff options
Diffstat (limited to 'macros/generic/expkv-bundle/expkv-def.dtx')
-rw-r--r-- | macros/generic/expkv-bundle/expkv-def.dtx | 1369 |
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=<< |