diff options
Diffstat (limited to 'obsolete/macros/generic/expkv-def/expkv-def.dtx')
-rw-r--r-- | obsolete/macros/generic/expkv-def/expkv-def.dtx | 2493 |
1 files changed, 2493 insertions, 0 deletions
diff --git a/obsolete/macros/generic/expkv-def/expkv-def.dtx b/obsolete/macros/generic/expkv-def/expkv-def.dtx new file mode 100644 index 0000000000..059c7dda01 --- /dev/null +++ b/obsolete/macros/generic/expkv-def/expkv-def.dtx @@ -0,0 +1,2493 @@ +% \iffalse meta-comment +% +% File: expkv-def.dtx Copyright (C) 2020-2022 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\nameofplainTeX{plain} +\ifx\fmtname\nameofplainTeX\else + \expandafter\begingroup +\fi +\input l3docstrip.tex +\askforoverwritefalse +\preamble + +-------------------------------------------------------------- +expkv-def -- a key-defining frontend for expkv +E-mail: jspratte@yahoo.de +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +-------------------------------------------------------------- + +Copyright (C) 2020-2022 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 + +This work is "maintained" (as per LPPL maintenance status) by + Jonathan P. Spratte. + +This work consists of the file expkv-def.dtx +and the derived files expkv-def.pdf + expkv-def.sty + expkv-def.tex + t-expkv-def.tex + +\endpreamble +% stop docstrip adding \endinput +\postamble +\endpostamble +\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}}} +\ifx\fmtname\nameofplainTeX + \expandafter\endbatchfile +\else + \expandafter\endgroup +\fi +% +\IfFileExists{expkv-def.tex}{\input{expkv-def.tex}}{} +\ProvidesFile{expkv-def.dtx} + [\csname ekvdDate\endcsname\ a key-defining frontend for expkv] +\PassOptionsToPackage{full}{textcomp} +\documentclass{l3doc} +\RequirePackage[oldstylenums,nott]{kpfonts} +\input{glyphtounicode} +\pdfgentounicode=1 +\RequirePackage{tcolorbox} +\newtcolorbox{exresult}[2][] + {colback=expkvgrey!10!white,colframe=expkvgrey,fontupper=\small,width={#2},#1} +\newtcbox\exres[1][] + { + colback=expkvgrey!10!white + ,colframe=expkvgrey + ,size=small + ,nobeforeafter + ,tcbox raise base + ,fontupper=\small + ,#1 + } +\RequirePackage{listings} +\RequirePackage{booktabs} +\RequirePackage{array} +\RequirePackage{collcell} +\RequirePackage{siunitx} +\RequirePackage{xcolor} +\RequirePackage{caption} +\RequirePackage{microtype} +\RequirePackage{accsupp} +\lstdefinelanguage{expkvd}[primitive]{TeX} + { + ,moretexcs=[4]^^A e-TeX + { + expanded, + numexpr, + protected, + } + ,moretexcs=[5]^^A plain/LaTeX + { + approx, + begin, + empty, + item, + LaTeX, + makeatletter,makeatother, + newcommand,newdimen, + RequirePackage, + rule, + TeX, + textit,texttt, + usepackage, + } + ,moretexcs=[6]^^A used packages + { + ^^A xfp + fpeval, + ^^A keyval + setkeys, + ^^A yax + defactiveparameter,storevalue,setparameterlist + } + ,moretexcs=[2]^^A expkv-def macros + { + ekvdefinekeys + } + ,moretexcs=[3]^^A expkv-pkg macros + { + ^^A expkv + ekvdef,ekvdefNoVal,^^A + ekvlet,ekvletNoVal,ekvletkv,ekvletkvNoVal,^^A + ekvdefunknown,ekvdefunknownNoVal,^^A + ekvredirectunknown,ekvredirectunknownNoVal,^^A + ekvset,ekvsetSneaked,^^A + ekvsetdef,ekvsetSneakeddef,ekvsetdefSneaked,^^A + ekvparse,^^A + ekvVersion,ekvDate,^^A + ekvifdefined,ekvifdefinedNoVal,ekvifdefinedset,^^A + ekvbreak,ekvbreakPreSneak,ekvbreakPostSneak,^^A + ekvsneak,ekvsneakPre,^^A + ekvchangeset,^^A + ekvoptarg,ekvoptargTF,^^A + ekverr, + ^^A expkv-cs + ekvcSecondaryKeys,ekvcSplitAndForward, + } + } +\colorlet{codeparam}{cyan!65!black} +\def\mylstwd{.55em} +\lstset + { + ,language=expkvd + ,flexiblecolumns=false + ,basewidth=\mylstwd + ,gobble=2 + ,basicstyle=\fontfamily{jkp}\itshape + ,texcsstyle=*[1]{\bfseries\color{expkvgrey}} ^^A primitives + ,texcsstyle=*[2]{\bfseries\color{expkvred}} ^^A expkv + ,texcsstyle=*[3]{\color{expkvred}} ^^A expkv-pkg + ,texcsstyle=*[4]{\bfseries\color{expkvgrey}} ^^A e-TeX + ,texcsstyle=*[5]{\bfseries\color{expkvgrey}} ^^A plain/LaTeX macros + ,texcsstyle=*[6]{} ^^A macros of other packages + ,commentstyle=\color[gray]{0.4} + ,literate= + {\{} {{\CodeUpBf\{}}{1} + {\}} {{\CodeUpBf\}}}{1} + {$} {{\CodeUpBf\$}}{1} + {[} {{\CodeUp[}}{1} + {]} {{\CodeUp]}}{1} + {(} {{\CodeUp(}}{1} + {)} {{\CodeUp)}}{1} + {*} {{$*$}}{1} + {1} {{\CodeUp{1}}}{1} + {2} {{\CodeUp{2}}}{1} + {3} {{\CodeUp{3}}}{1} + {4} {{\CodeUp{4}}}{1} + {5} {{\CodeUp{5}}}{1} + {6} {{\CodeUp{6}}}{1} + {7} {{\CodeUp{7}}}{1} + {8} {{\CodeUp{8}}}{1} + {9} {{\CodeUp{9}}}{1} + {0} {{\CodeUp{0}}}{1} + {##} {{\CodeColored{codeparam}{1}{\#}}}{1} + {##1}{{\CodeColored{codeparam}{2}{\#1}}}{2} + {##2}{{\CodeColored{codeparam}{2}{\#2}}}{2} + {##3}{{\CodeColored{codeparam}{2}{\#3}}}{2} + {##4}{{\CodeColored{codeparam}{2}{\#4}}}{2} + {##5}{{\CodeColored{codeparam}{2}{\#5}}}{2} + {##6}{{\CodeColored{codeparam}{2}{\#6}}}{2} + {##7}{{\CodeColored{codeparam}{2}{\#7}}}{2} + {##8}{{\CodeColored{codeparam}{2}{\#8}}}{2} + {##9}{{\CodeColored{codeparam}{2}{\#9}}}{2} + {<key>}{{$\langle$}key{$\rangle$}}{5} + {<set>}{{$\langle$}set{$\rangle$}}{5} + {<set1>}{{$\langle$}set1{$\rangle$}}{6} + {<set2>}{{$\langle$}set2{$\rangle$}}{6} + ^^A,literate=*{<key>}{\key}{4}{<set>}{\set}{4} + } +\newcommand*\CodeColored[3]{\textcolor{#1}{\makebox[\dimexpr\mylstwd*#2]{#3}}} +\newcommand*\CodeUpBf[1]{\makebox[\mylstwd]{\textup{\textbf{#1}}}} +\newcommand*\CodeUp[1]{\makebox[\mylstwd]{\textup{#1}}} +\RequirePackage{randtext} +\let\metaORIG\meta +\protected\def\meta #1{\texttt{\metaORIG{#1}}} +\renewcommand*\thefootnote{\fnsymbol{footnote}} +\definecolor{expkvred}{HTML}{9F393D} +\colorlet{expkvgrey}{black!75} +\makeatletter +\newcommand*\expkv + {^^A + \texorpdfstring + {^^A + \mbox + {^^A + \BeginAccSupp{ActualText=expkv}^^A + \href{https://github.com/Skillmon/tex_expkv} + {^^A + \rmfamily + \bfseries + {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A + \lower.493ex + \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A + \kern-.18em{\color{expkvred}v}^^A + }^^A + \EndAccSupp{}^^A + }^^A + } + {expkv}^^A + } +\newcommand*\expkvd + {^^A + \texorpdfstring + {^^A + \mbox + {^^A + \BeginAccSupp{ActualText=expkv-def}^^A + \href{https://github.com/Skillmon/tex_expkv-def} + {^^A + \rmfamily + \bfseries + {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A + \lower.493ex + \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A + \kern-.18em{\color{expkvred}v}^^A + {\color{expkvgrey}^^A + \kern.05em\rule[-.1ex]{.08em}{1.2ex}\kern.05em\textsc{def}^^A + }^^A + }^^A + \EndAccSupp{}^^A + }^^A + } + {expkv-def}^^A + } +\newcommand\kv{\meta{key}=\meta{value}} +\newcommand\key{\meta{key}} +\newcommand\val{\meta{value}} +\newcommand\set{\meta{set}} +\newcommand\enfprefix{\textcolor{black}} +\newcommand\allprefix{\textcolor{gray}} +\newcommand\notprefix{\textcolor{red!80!black}} +\newcommand\printprefix[2] + {^^A + \ifcase\numexpr#1\relax\or + \enfprefix{#2}\or + \allprefix{#2}\or + \notprefix{#2}\fi + } +\newcommand\prefixes[4] + {^^A + \hfill + \printprefix{#1}{new} + \printprefix{#2}{also} + \printprefix{#3}{protected} + \printprefix{#4}{long}^^A + } +\hypersetup{linkcolor=red!80!black,urlcolor=purple!80!black} +\DoNotIndex{\def,\edef,\,,\=,\begingroup,\catcode,\chardef,\csname,\endcsname} +\DoNotIndex{\endgroup,\endinput,\errmessage,\expandafter,\input,\let,\long} +\DoNotIndex{\protected,\ProvidesFile,\ProvidesPackage,\relax,\space} +\DoNotIndex{\@,\unexpanded,\string,\expanded,\dimexpr,\global,\glueexpr,\hbox} +\DoNotIndex{\numexpr,\RequirePackage,\setbox,\the,\unless,\xdef,\@firstofone} +\DoNotIndex{\@firstoftwo,\@gobble,\@secondoftwo,\meaning,\detokenize} +\DoNotIndex{\romannumeral,\^} +\DoNotIndex{\ifcsname} +\DoNotIndex{\ifx} +\DoNotIndex{\ifdefined} +\DoNotIndex{\iffalse} +\DoNotIndex{\iftrue} +\DoNotIndex{\else} +\DoNotIndex{\fi} +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}} +\makeatother +\begin{document} + \title + {^^A + \texorpdfstring + {^^A + \huge\expkvd + \\[\medskipamount] + \Large a key-defining frontend for \expkv + }{expkv-def - a key-defining frontend for expkv}^^A + } + \date{\ekvdDate\space v\ekvdVersion} + \author{Jonathan P. Spratte\thanks{\protect\randomize{jspratte@yahoo.de}}} + \DocInput{expkv-def.dtx} +\end{document} +%</driver>^^A=<< +% \fi +% +% \maketitle +% \renewcommand*\thefootnote{\arabic{footnote}} +% +% \begin{abstract} +% \noindent\parfillskip=0pt +% \expkvd\ provides a small \kv\ interface to define keys for \expkv. Key-types +% are declared using prefixes, similar to static typed languages. The stylised +% name is \expkvd\ but the files use \file{expkv-def}, this is due to CTAN-rules +% which don't allow \string| in package names since that is the pipe symbol in +% *nix shells. +% \end{abstract} +% +% \tableofcontents +% +% \begin{documentation}^^A>>= +% +% \section{Documentation} +% +% Since the trend for the last couple of years goes to defining keys for a \kv\ +% interface using a \kv\ interface, I thought that maybe providing such an +% interface for \expkv\ will make it more attractive for actual use, besides its +% unique selling points of being fully expandable, and fast and reliable. But at +% the same time I don't want to widen \expkv's initial scope. So here it is +% \expkvd, go define \kv\ interfaces with \kv\ interfaces. +% +% Unlike many of the other established \kv\ interfaces to define keys, \expkvd\ +% works using prefixes instead of suffixes (\emph{e.g.}, |.tl_set:N| of +% \pkg{l3keys}) or directory like handlers (\emph{e.g.}, |/.store in| of +% \pkg{pgfkeys}). This was decided as a personal preference, more over in \TeX\ +% parsing for the first space is way easier than parsing for the last one. +% \expkvd's prefixes are sorted into two categories: |p|-type, which are +% equivalent to \TeX's prefixes like |\long|, and |t|-type defining the type of +% the key. For a description of the available |p|-prefixes take a look at +% \autoref{sec:prefix:p}, the |t|-prefixes are described in +% \autoref{sec:prefix:t}. +% +% \expkvd\ is usable as generic code, as a \LaTeX\ package, and as a \ConTeXt\ +% module. It'll automatically load \expkv\ in the same mode as well. To use it, +% just use one of +% \begin{lstlisting} +% \input expkv-def % plainTeX +% \usepackage{expkv-def} % LaTeX +% \usemodule[expkv-def] % ConTeXt +% \end{lstlisting} +% +% \subsection{Macros} +% Apart from version and date containers there is only a single user-facing +% macro, and that should be used to define keys. +% +% \begin{function}{\ekvdefinekeys} +% \begin{syntax} +% \cs{ekvdefinekeys}\marg{set}\{\kv, \ldots\} +% \end{syntax} +% In \set, define \key\ to have definition \val. The general syntax for \key\ +% should be +% \begin{quote}\ttfamily\small +% \meta{prefix} \meta{name} +% \end{quote} +% Where \meta{prefix} is a space separated list of optional |p|-type prefixes +% followed by one |t|-type prefix. The syntax of \val\ is dependent on the +% used |t|-prefix. +% \end{function} +% +% \begin{function}{\ekvdDate,\ekvdVersion} +% These two macros store the version and date of the package. +% \end{function} +% +% \subsection{Prefixes} +% As already said there are |p|-prefixes and |t|-prefixes. Not every |p|-prefix +% is allowed for all |t|-prefixes. +% +% \subsubsection{\texttt{p}-Prefixes}\label{sec:prefix:p} +% The two |p|-type prefixes |long| and |protected| are pretty simple by nature, +% so their description is pretty simple. They affect the \key\ at use-time, so +% omitting |long| doesn't mean that a \meta{definition} can't contain a |\par| +% token, only that the \key\ will not accept a |\par| in \val. On the other +% hand |new| and |also| might be simple on first sight as well, but their rules +% are a bit more complicated. +% +% \begin{function}{also} +% The following key type will be \emph{added} to an existing \key's +% definition. You can't add a type taking an argument at use time to an +% existing key which doesn't take an argument and vice versa. Also you'll get +% an error if you try to add an action which isn't allowed to be either |long| +% or |protected| to a key which already is |long| or |protected| (the opposite +% order would be suboptimal as well, but can't be really captured with the +% current code). +% +% A key already defined as |long| or |protected| will stay |long| or +% |protected|, but you can as well add |long| or |protected| with the |also| +% definition. +% +% As a small example, suppose you want to create a boolean key, but +% additionally to setting a boolean value you want to execute some more code +% as well, you can use the following +% \begin{lstlisting} +% \ekvdefinekeys{also-example} +% { +% bool key = \ifmybool +% ,also code key = \domystuff{#1} +% } +% \end{lstlisting} +% +% If you use |also| on a |choice|, |bool|, |invbool|, or |boolpair| key it is +% tried to determine if the key already is of one of those types. If this test +% is true the declared choices will be added to the possible choices but the +% key's definition will not be changed other than that. If that wouldn't have +% been done, the callbacks of the different choices could get called multiple +% times. +% \end{function} +% +% \begin{function}{protected,protect} +% The following key will be defined |\protected|. Note that key-types which +% can't be defined expandable will always use |\protected|. +% \end{function} +% +% \begin{function}{long} +% The following key will be defined |\long|. +% \end{function} +% +% \begin{function}{new} +% The following key must be new (so previously undefined). An error is thrown +% if it is already defined and the new definition is ignored. |new| only +% asserts that there are no conflicts between |NoVal| keys and other |NoVal| +% keys or value taking keys and other value taking keys. For example you can +% use the following without an error: +% \begin{lstlisting} +% \ekvdefinekeys{new-example} +% { +% code key = \domystuffwitharg{#1} +% ,new noval key = \domystuffwithoutarg +% } +% \end{lstlisting} +% \end{function} +% +% \subsubsection{\texttt{t}-Prefixes}\label{sec:prefix:t} +% Since the |p|-type prefixes apply to some of the |t|-prefixes automatically +% but sometimes one might be disallowed we need some way to highlight this +% behaviour. In the following an enforced prefix will be printed black +% (\texttt{\enfprefix{protected}}), allowed prefixes will be grey +% (\texttt{\allprefix{protected}}), and disallowed prefixes will be red +% (\texttt{\notprefix{protected}}). This will be put flush-right in the syntax +% showing line. +% +% \begin{function}{code,ecode} +% \begin{syntax} +% code \key\ = \marg{definition} \prefixes2222 +% \end{syntax} +% Define \key\ to expand to \meta{definition}. The \key\ will require a \val\ +% for which you can use |#1| inside \meta{definition}. The |ecode| variant +% will fully expand \meta{definition} inside an |\edef|. +% \end{function} +% +% \begin{function}{noval,enoval} +% \begin{syntax} +% noval \key\ = \marg{definition} \prefixes2223 +% \end{syntax} +% The |noval| type defines \key\ to expand to \meta{definition}. The \key\ +% will not take a \val. |enoval| fully expands \meta{definition} inside an +% |\edef|. +% \end{function} +% +% \begin{function}{default,qdefault,odefault,fdefault,edefault} +% \begin{syntax} +% default \key\ = \marg{definition} \prefixes3223 +% \end{syntax} +% This serves to place a default \val\ for a \key\ that takes an argument, the +% \key\ can be of any argument-grabbing kind, and when used without a \val\ +% it will be passed \meta{definition} instead. The |qdefault| variant will +% expand the \key's code once, so will be slightly quicker, but not change if +% you redefine \key. |odefault| is just another name for |qdefault|. The +% |fdefault| version will expand the key code until a non-expandable token or +% a space is found, a space would be gobbled.\footnotemark{} The |edefault| on +% the other hand fully expands the \key-code with \meta{definition} as its +% argument inside of an |\edef|. +% \end{function} +% \footnotetext +% {^^A +% For those familiar with \TeX-coding: This uses a +% \cs[no-index]{romannumeral}-expansion. +% } +% +% \begin{function}{initial,oinitial,finitial,einitial} +% \begin{syntax} +% initial \key\ = \{\val\} \prefixes3333 +% initial \key +% \end{syntax} +% With |initial| you can set an initial \val\ for an already defined argument +% taking \key. It'll just call the key-macro of \key\ and pass it \val. The +% |einitial| variant will expand \val\ using an |\edef| expansion prior to +% passing it to the key-macro and the |oinitial| variant will expand the first +% token in \val\ once. |finitial| will expand \val\ until a non-expandable +% token or a space is found, a space would be +% gobbled.\footnotemark +% +% If you don't provide a value (and no equals sign) a |noval| \key\ of the +% same name is called once (or, if you specified a |default| for a value +% taking key that would be used). +% \end{function} +% \footnotetext{Again using \cs[no-index]{romannumeral}.} +% +% \begin{function}{bool,gbool,boolTF,gboolTF} +% \begin{syntax} +% bool \key\ = \meta{cs} \prefixes2223 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\iffoo|. +% This will define \key\ to be a boolean key, which only takes the values +% |true| or |false| and will throw an error for other values. If the key is +% used without a \val\ it'll have the same effect as if you use +% \texttt{\key=true}. |bool| and |gbool| will behave like \TeX-ifs so either +% be |\iftrue| or |\iffalse|. The |boolTF| and |gboolTF| variants will both +% take two arguments and if true the first will be used else the second, so +% they are always either |\@firstoftwo| or |\@secondoftwo|. The variants with +% a leading |g| will set the control sequence globally, the others locally. If +% \meta{cs} is not yet defined it'll be initialised as the |false| version. +% Note that the initialisation is \emph{not} done with |\newif|, so you will +% not be able to do |\footrue| outside of the \kv\ interface, but you could +% use |\newif| yourself. Even if the \key\ will not be |\protected| the +% commands which execute the |true| or |false| choice will be, so the usage +% should be safe in an expansion context (\emph{e.g.}, you can use +% \texttt{edefault \key\ = false} without an issue to change the default +% behaviour to execute the |false| choice). Internally a |bool| \key\ is the +% same as a |choice| key which is set up to handle |true| and |false| as +% choices. +% \end{function} +% +% \begin{function}{invbool,ginvbool,invboolTF,ginvboolTF} +% \begin{syntax} +% bool \key\ = \meta{cs} \prefixes2223 +% \end{syntax} +% These are inverse boolean keys, they behave like |bool| and friends but set +% the opposite meaning to the macro \meta{cs} in each case. So if +% \texttt{key=true} is used |invbool| will set \meta{cs} to |\iffalse| and +% vice versa. +% \end{function} +% +% \begin{function}{boolpair,gboolpair,boolpairTF,gboolpairTF} +% \begin{syntax} +% boolpair \key\ = \meta{cs_1}\meta{cs_2} \prefixes2223 +% \end{syntax} +% The |boolpair| key type behaves like both |bool| and |invbool|, the +% \meta{cs_1} will be set to the meaning according to the rules of |bool|, and +% \meta{cs_2} will be set to the opposite. +% \end{function} +% +% \begin{function}{store,estore,gstore,xstore} +% \begin{syntax} +% store \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\foo|. +% This will define \key\ to store \val\ inside of the control sequence. If +% \meta{cs} isn't yet defined it will be initialised as empty. The variants +% behave similarly to their |\def|, |\edef|, |\gdef|, and |\xdef| +% counterparts, but |store| and |gstore| will allow you to store macro +% parameters inside of them by using |\unexpanded|. +% \end{function} +% +% \begin{function}{data,edata,gdata,xdata} +% \begin{syntax} +% data \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\foo|. This will +% define \key\ to store \val\ inside of the control sequence. But unlike the +% |store| type, the macro \meta{cs} will be a switch at the same time, it'll +% take two arguments and if \key\ was used expands to the first argument +% followed by \val\ in braces, if \key\ was not used \meta{cs} will expand to +% the second argument (so behave like |\@secondoftwo|). The idea is that with +% this type you can define a key which should be typeset formatted. The +% |edata| and |xdata| variants will fully expand \val, the |gdata| and |xdata| +% variants will store \val\ inside \meta{cs} globally. The |p|-prefixes will +% only affect the key-macro, \meta{cs} will always be expandable and |\long|. +% \end{function} +% +% \begin{function}{dataT,edataT,gdataT,xdataT} +% \begin{syntax} +% dataT \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% Just like |data|, but instead of \meta{cs} grabbing two arguments it'll only +% grab one, so by default it'll behave like |\@gobble|, and if a \val\ was +% given to \key\ the \meta{cs} will behave like |\@firstofone| appended by +% \marg{value}. +% \end{function} +% +% \begin{function}{int,eint,gint,xint} +% \begin{syntax} +% int \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\foo|. +% An |int| key will be a \TeX-count register. If \meta{cs} isn't defined yet, +% |\newcount| will be used to initialise it. The |eint| and |xint| versions +% will use |\numexpr| to allow basic computations in their \val. The |gint| +% and |xint| variants set the register globally. +% \end{function} +% +% \begin{function}{dimen,edimen,gdimen,xdimen} +% \begin{syntax} +% dimen \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\foo|. +% This is just like |int| but uses a dimen register, |\newdimen| and +% |\dimexpr| instead. +% \end{function} +% +% \begin{function}{skip,eskip,gskip,xskip} +% \begin{syntax} +% skip \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\foo|. +% This is just like |int| but uses a skip register, |\newskip| and |\glueexpr| +% instead. +% \end{function} +% +% \begin{function}{toks,gtoks,apptoks,gapptoks,pretoks,gpretoks} +% \begin{syntax} +% toks \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\foo|. +% Store \val\ inside of a toks-register. The |g| variants use |\global|, the +% |app| variants append \val\ to the contents of that register, the |pre| +% variants will prepend \val. If \meta{cs} is not yet defined it will be +% initialised with |\newtoks|. +% \end{function} +% +% \begin{function}{box,gbox} +% \begin{syntax} +% box \key\ = \meta{cs} \prefixes2212 +% \end{syntax} +% The \meta{cs} should be a single control sequence, such as |\foo|. +% Typesets \val\ into a |\hbox| and stores the result in a box register. The +% boxes are colour safe. \expkvd\ doesn't provide a |vbox| type. +% \end{function} +% +% \begin{function}{meta} +% \begin{syntax} +% meta \key\ = \{\kv, \ldots\} \prefixes2222 +% \end{syntax} +% This key type can set other keys, you can access the \val\ which was passed +% to \key\ inside the \kv\ list with |#1|. It works by calling a sub-|\ekvset| +% on the \kv\ list, so a |set| key will only affect that \kv\ list and not the +% current |\ekvset|. Since it runs in a separate |\ekvset| you can't use +% |\ekvsneak| using keys or similar macros in the way you normally could. +% \end{function} +% +% \begin{function}{nmeta} +% \begin{syntax} +% nmeta \key\ = \{\kv, \ldots\} \prefixes2223 +% \end{syntax} +% This key type can set other keys, the difference to |meta| is, that this key +% doesn't take a value, so the \kv\ list is static. +% \end{function} +% +% \begin{function}{smeta} +% \begin{syntax} +% smeta \key\ = \marg{set}\{\kv, \ldots\} \prefixes2222 +% \end{syntax} +% Yet another |meta| variant. An |smeta| key will take a \val\ which you can +% access using |#1|, but it sets the \kv\ list inside of \set, so is equal to +% \texttt{\cs[no-index]{ekvset}\marg{set}\{\kv, \ldots\}}. +% \end{function} +% +% \begin{function}{snmeta} +% \begin{syntax} +% snmeta \key\ = \marg{set}\{\kv, \ldots\} \prefixes2223 +% \end{syntax} +% And the last |meta| variant. |snmeta| is a combination of |smeta| and +% |nmeta|. It doesn't take an argument and sets the \kv\ list inside of \set. +% \end{function} +% +% \begin{function}{set} +% \begin{syntax} +% set \key\ = \marg{set} \prefixes2233 +% \end{syntax} +% This will define \key\ to change the set of the current |\ekvset| +% invocation to \set. You can omit \set\ (including the equals sign), +% which is the same as using \texttt{set \key\ = \{\key\}}. The created |set| +% key will not take a \val. Note that just like in \expkv\ it'll not be +% checked whether \set\ is defined and you'll get a low-level \TeX\ error if +% you use an undefined \set. +% \end{function} +% +% \begin{function}{choice} +% \begin{syntax} +% choice \key\ = \{\val=\meta{definition}, \ldots\} \prefixes2223 +% \end{syntax} +% Defines \key\ to be a |choice| key, meaning it will only accept a limited +% set of values. You should define each possible \val\ inside of the +% \val=\meta{definition} list. If a defined \val\ is passed to \key\ the +% \meta{definition} will be left in the input stream. You can make +% individual values |protected| inside the \val=\meta{definition} list. By +% default a |choice| key is expandable, an undefined \val\ will throw an error +% in an expandable way (but see the |unknown-choice| prefix). You can add +% additional choices after the \key\ was created by using |choice| again for +% the same \key, redefining choices is possible the same way, but there is no +% interface to remove certain choices. +% \end{function} +% +% \begin{function}{choice-store} +% \begin{syntax} +% choice-store \key\ = \meta{cs}\{\val, \ldots\} \prefixes2223 +% \end{syntax} +% This is defines a special type of |choice| key that'll store the given +% choice inside the macro \meta{cs} (so \meta{cs} should be a single control +% sequence name such as |\foo|). Since storing inside a macro can't be done +% expandably every choice-code is |\protected|, you might define the +% |choice-store| key itself as |protected| as well if you want. Since the +% definition of each choice is predefined with this key type the choice list +% should just be a comma separated list of valid choices. +% \end{function} +% This means that the following |choice| and |choice-store| keys are equivalent +% at use time: +% \begin{lstlisting} +% \newcommand*\mya{} +% \ekvdefinekeys{example} +% { +% choice key1 = {a=\def\mya{a}, b=\def\mya{b}, c=\def\mya{c}} +% ,choice-store key2 = \mya{a,b,c} +% } +% \end{lstlisting} +% +% \begin{function}{choice-enum} +% \begin{syntax} +% choice-enum \key\ = \meta{cs}\{\val, \ldots\} \prefixes2223 +% \end{syntax} +% This is similar to |choice-store|, the differences are: \meta{cs} should be +% a count-register or is initialised as such if the \meta{cs} is undefined +% (via |\newcount|); instead of the value the position of the value in the +% given list is stored in this register (zero-based). +% \end{function} +% This means that the following |choice| and |choice-enum| keys are equivalent +% at use time: +% \begin{lstlisting} +% \newcount\myb +% \ekvdefinekeys{example} +% { +% choice key1 = {a={\myb=0 }, b={\myb=1 }, c={\myb=2 }} +% ,choice-enum key2 = \myb{a,b,c} +% } +% \end{lstlisting} +% +% \begin{function}{unknown-choice} +% \begin{syntax} +% unknown-choice \key\ = \marg{definition} \prefixes2323 +% \end{syntax} +% By default an unknown \val\ passed to a |choice| or |bool| key will throw an +% error. However, with this prefix you can define an alternative action which +% should be executed if \key\ received an unknown choice. In \meta{definition} +% you can refer to the choice which was passed in with |#1|. +% \end{function} +% +% \begin{function}{unknown code} +% \begin{syntax} +% unknown code = \marg{definition} \prefixes2322 +% \end{syntax} +% By default \expkv\ throws errors when it encounters unknown keys in a set. +% With the |unknown| prefix you can define handlers that deal with undefined +% keys, instead of a \key\ name you have to specify a subtype for this prefix, +% here the subtype is |code|.\par +% With |unknown code| the \meta{definition} is used for unknown keys which +% were provided a value (so corresponds to |\ekvdefunknown|), you can access +% the key name with |#1| and the value with |#2|.\footnotemark +% \end{function} +% \footnotetext +% {^^A +% There is some trickery involved to get this more intuitive argument order +% without any performance hit if you compare this to +% \cs[no-index]{ekvdefunknown} directly.^^A +% } +% +% \begin{function}{unknown noval} +% \begin{syntax} +% unknown noval = \marg{definition} \prefixes2323 +% \end{syntax} +% This is like |unknown code| but uses \meta{definition} for unknown keys to +% which no value was passed (so corresponds to |\ekvdefunknownNoVal|). You can +% access the key name with |#1|. +% \end{function} +% +% \begin{function}{unknown redirect-code} +% \begin{syntax} +% unknown redirect-code = \marg{set-list} \prefixes2331 +% \end{syntax} +% This uses a predefined action for |unknown code|. Instead of throwing an +% error, it is tried to find the \key\ in each \set\ in the comma separated +% \meta{set-list}. The first found match will be used and the remaining +% options from the list discarded. If the \key\ isn't found in any \set\ an +% expandable error will be thrown eventually. Internally \expkv's +% |\ekvredirectunknown| will be used. +% \end{function} +% +% \begin{function}{unknown redirect-noval} +% \begin{syntax} +% unknown redirect-noval = \marg{set-list} \prefixes2333 +% \end{syntax} +% This behaves just like |unknown redirect-code| but will set up means to +% forward keys for |unknown noval|. Internally \expkv's +% |\ekvredirectunknownNoVal| will be used. +% \end{function} +% +% \begin{function}{unknown redirect} +% \begin{syntax} +% unknown redirect = \marg{set-list} \prefixes2333 +% \end{syntax} +% This is a short cut to apply both, |unknown redirect-code| and +% |unknown redirect-noval|, as a result you might get doubled error messages, +% one from each. +% \end{function} +% +% \subsection{Bugs} +% I don't think there are any (but every developer says that), if you find some +% please let me know, either via the email address on the first page or on +% GitHub: +% \url{https://github.com/Skillmon/tex_expkv-def} +% +% \subsection{Example} +% The following is an example code defining each base key-type once. Please +% admire the very creative key-name examples. +% +% \begin{lstlisting} +% \ekvdefinekeys{example} +% { +% long code keyA = #1 +% ,noval keyA = NoVal given +% ,bool keyB = \keyB +% ,boolTF keyC = \keyC +% ,store keyD = \keyD +% ,data keyE = \keyE +% ,dataT keyF = \keyF +% ,int keyG = \keyG +% ,dimen keyH = \keyH +% ,skip keyI = \keyI +% ,toks keyJ = \keyJ +% ,default keyJ = \empty test +% ,new box keyK = \keyK +% ,qdefault keyK = K +% ,choice keyL = +% { +% protected 1 = \texttt{a} +% ,2 = b +% ,3 = c +% ,4 = d +% ,5 = e +% } +% ,edefault keyL = 2 +% ,meta keyM = {keyA={#1},keyB=false} +% ,invbool keyN = \keyN +% ,boolpair keyO = \keyOa\keyOb +% } +% \end{lstlisting} +% +% \bigskip +% Since the |data| type might be a bit strange, here is another usage example +% for it. +% \begin{lstlisting} +% \ekvdefinekeys{ex} +% { +% data name = \Pname +% ,data age = \Page +% ,dataT hobby = \Phobby +% } +% \newcommand\Person[1] +% {% +% \begingroup +% \ekvset{ex}{#1}% +% \begin{description} +% \item[\Pname{}{\errmessage{A person requires a name}}] +% \item[Age] \Page{\textit}{\errmessage{A person requires an age}} +% \Phobby{\item[Hobbies]} +% \end{description} +% \endgroup +% } +% \Person{name=Jonathan P. Spratte, age=young, hobby=\TeX\ coding} +% \Person{name=Some User, age=unknown, hobby=Reading Documentation} +% \Person{name=Anybody, age=any} +% \end{lstlisting} +% In this example a person should have a name and an age, but doesn't have to +% have hobbies. The name will be displayed as the description item and the age +% in Italics. If a person has no hobbies the description item will be silently +% left out. The result of the above code looks like this: +% +% \begin{exresult}{\linewidth} +% \ekvdefinekeys{ex} +% { +% data name = \Pname +% ,data age = \Page +% ,dataT hobby = \Phobby +% } +% \newcommand\Person[1] +% {% +% \begingroup +% \ekvset{ex}{#1}% +% \begin{description} +% \item[\Pname{}{\errmessage{A person requires a name}}] +% \item[Age] \Page{\textit}{\errmessage{A person requires an age}} +% \Phobby{\item[Hobbies]} +% \end{description} +% \endgroup +% } +% \Person{name=Jonathan P. Spratte, age=young, hobby=\TeX\ coding} +% \Person{name=Some User, age=unknown, hobby=Reading Documentation} +% \Person{name=Anybody, age=any} +% \end{exresult} +% +% \subsection{License} +% +% Copyright \textcopyright\ 2020\unless\ifnum\year=2020--\the\year\fi\ +% Jonathan P. Spratte +% +% \medskip\noindent +% 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: +% +% \url{http://www.latex-project.org/lppl.txt} +% +% \noindent +% This work is ``maintained'' (as per LPPL maintenance status) by +% +% \mbox{Jonathan P. Spratte}. +% +% \end{documentation}^^A=<< +% +% \begin{implementation}^^A>>= +% +% \clearpage +% +% \section{Implementation}^^A>>= +%^^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} +\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] +\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. +% \begin{macrocode} +\input expkv +% \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{0.9} +\def\ekvdDate{2022-01-29} +% \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 + \long\def\ekvd@ifnew##1##2##3{##3}% + } +\ekvd@clear@prefixes +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ekvdefinekeys} +% This is the one front-facing macro which provides the interface to define +% keys. It's using |\ekvparse| to handle the \kv\ list, the interpretation will +% be done by |\ekvd@noarg| and |\ekvd@|. The \set\ for which the keys should be +% defined is stored in |\ekvd@set|. +% \begin{macrocode} +\protected\def\ekvdefinekeys#1% + {% + \def\ekvd@set{#1}% + \ekvparse\ekvd@noarg\ekvd@arg + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@noarg,\ekvd@arg,\ekvd@handle} +% |\ekvd@noarg| and |\ekvd@arg| store whether there was a value in the \kv\ +% pair. |\ekvd@handle| has to test whether there is a space inside the key and +% if so calls the prefix grabbing routine, else we throw an error and ignore the +% key. +% \begin{macrocode} +\protected\long\def\ekvd@noarg#1% + {% + \let\ekvd@ifnoarg\@firstoftwo + \expandafter\ekvd@handle\detokenize{#1}\ekvd@stop{}% + } +\protected\long\def\ekvd@arg#1% + {% + \let\ekvd@ifnoarg\@secondoftwo + \expandafter\ekvd@handle\detokenize{#1}\ekvd@stop + } +\protected\long\def\ekvd@handle#1\ekvd@stop#2% + {% + \ekvd@clear@prefixes + \def\ekvd@cur{#1}% + \ekvd@ifspace{#1}% + {\ekvd@prefix\ekv@mark#1\ekv@stop{#2}}% + \ekvd@err@missing@type + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@prefix,\ekvd@prefix@} +% \expkvd\ separates prefixes into two groups, the first being prefixes in the +% \TeX\ sense (|long| and |protected|) which use |@p@| in their name, the other +% being key-types (|code|, |int|, \emph{etc.}) which use |@t@| instead. +% |\ekvd@prefix| splits at the first space and checks whether its a |@p@| +% or |@t@| type prefix. If it is neither throw an error and gobble the +% definition (the value). +% \begin{macrocode} +\protected\def\ekvd@prefix#1 {\ekv@strip{#1}\ekvd@prefix@\ekv@mark} +\protected\def\ekvd@prefix@#1#2\ekv@stop + {% + \ekv@ifdefined{ekvd@t@#1}% + {\ekv@strip{#2}{\csname ekvd@t@#1\endcsname}}% + {% + \ekv@ifdefined{ekvd@p@#1}% + {\csname ekvd@p@#1\endcsname\ekvd@prefix@after@p{#2}}% + {\ekvd@err@undefined@prefix{#1}\@gobble}% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@prefix@after@p} +% The |@p@| type prefixes are all just modifying a following |@t@| type, so they +% will need to search for another prefix. This is true for all of them, so we +% use a macro to handle this. It'll throw an error if there is no other prefix. +% \begin{macrocode} +\protected\def\ekvd@prefix@after@p#1% + {% + \ekvd@ifspace{#1}% + {\ekvd@prefix#1\ekv@stop}% + {\ekvd@err@missing@type\@gobble}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\ekvd@p@long,\ekvd@p@protected,\ekvd@p@protect,\ekvd@p@also,\ekvd@p@new} +% Define the |@p@| type prefixes, they all just store some information in a +% temporary macro. +% \begin{macrocode} +\protected\def\ekvd@p@long{\let\ekvd@long\long} +\protected\def\ekvd@p@protected{\let\ekvd@prot\protected} +\let\ekvd@p@protect\ekvd@p@protected +\protected\def\ekvd@p@also{\let\ekvd@ifalso\@firstoftwo} +\protected\def\ekvd@p@new{\let\ekvd@ifnew\ekvd@assert@new} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Key Types} +% +% \begin{macro}[internal]{\ekvd@type@set,\ekvd@t@set} +% The |set| type is quite straight forward, just define a |NoVal| key to call +% |\ekvchangeset|. +% \begin{macrocode} +\protected\def\ekvd@type@set#1#2% + {% + \ekvd@assert@not@long + \ekvd@assert@not@protected + \ekvd@ifnew{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}}}% + }% + }% + } +\protected\def\ekvd@t@set#1#2% + {% + \ekvd@ifnoarg + {\ekvd@type@set{#1}{#1}}% + {\ekvd@type@set{#1}{#2}}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@noval,\ekvd@t@noval,\ekvd@t@enoval} +% 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} +\protected\long\def\ekvd@type@noval#1#2#3% + {% + \ekvd@ifnew{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}% + }% + }% + } +\protected\def\ekvd@t@noval{\ekvd@type@noval\def} +\protected\def\ekvd@t@enoval{\ekvd@type@noval\edef} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@code,\ekvd@t@code,\ekvd@t@ecode} +% |code| is simple as well, |ecode| has to use |\edef| on a temporary macro, +% since \expkv\ doesn't provide an |\ekvedef|. +% \begin{macrocode} +\protected\long\def\ekvd@type@code#1#2#3% + {% + \ekvd@ifnew{}{#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}% + }% + }% + } +\protected\def\ekvd@t@code{\ekvd@type@code\def} +\protected\def\ekvd@t@ecode{\ekvd@type@code\edef} +% \end{macrocode} +% \end{macro} +% +% \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 is). If everything is good, |\edef| a +% temporary macro that expands |\ekvd@set| and the |\csname| for the key, and in +% the case of |qdefault| does the first expansion step of the key-macro. +% \begin{macrocode} +\protected\long\def\ekvd@type@default#1#2#3#4% + {% + \ekvd@assert@arg + {% + \ekvifdefined\ekvd@set{#3}% + {% + \ekvd@assert@not@new + \ekvd@assert@not@long + \ekvd@prot\edef\ekvd@tmp + {% + \ekv@unexpanded\expandafter#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}}% + }% + } +\protected\def\ekvd@t@default{\ekvd@type@default{}{}} +\protected\def\ekvd@t@qdefault{\ekvd@type@default{\expandafter\expandafter}{}} +\let\ekvd@t@odefault\ekvd@t@qdefault +\protected\def\ekvd@t@fdefault{\ekvd@type@default{}{\romannumeral`\^^@}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@t@edefault} +% |edefault| is too different from |default| and |qdefault| to reuse the +% |@type@| macro, as it doesn't need |\unexpanded| inside of |\edef|. +% \begin{macrocode} +\protected\long\def\ekvd@t@edefault#1#2% + {% + \ekvd@assert@arg + {% + \ekvifdefined\ekvd@set{#1}% + {% + \ekvd@assert@not@new + \ekvd@assert@not@long + \ekvd@prot\edef\ekvd@tmp + {\csname\ekv@name\ekvd@set{#1}\endcsname{#2}}% + \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} +% +% \begin{macro}[internal] +% {\ekvd@t@initial,\ekvd@t@oinitial,\ekvd@t@finitial,\ekvd@t@einitial} +% \begin{macrocode} +\long\def\ekvd@type@initial#1#2#3#4% + {% + \ekvd@assert@not@new + \ekvd@assert@not@also + \ekvd@assert@not@long + \ekvd@assert@not@protected + \ekvd@ifnoarg + {% + \ekvifdefinedNoVal\ekvd@set{#3}% + {\csname\ekv@name\ekvd@set{#3}N\endcsname}% + {\ekvd@err@undefined@noval{#3}}% + }% + {% + \ekvifdefined\ekvd@set{#3}% + {% + #1{#2#4}% + \csname\ekv@name\ekvd@set{#3}\expandafter\endcsname\expandafter + {\ekvd@tmp}% + }% + {\ekvd@err@undefined@key{#3}}% + }% + } +\def\ekvd@t@initial{\ekvd@type@initial{\def\ekvd@tmp}{}} +\def\ekvd@t@oinitial{\ekvd@type@initial{\ekv@exparg{\def\ekvd@tmp}}{}} +\def\ekvd@t@einitial{\ekvd@type@initial{\edef\ekvd@tmp}{}} +\def\ekvd@t@finitial + {\ekvd@type@initial{\ekv@exparg{\def\ekvd@tmp}}{\romannumeral`\^^@}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \ekvd@type@bool,\ekvd@t@bool,\ekvd@t@gbool,\ekvd@t@boolTF,\ekvd@t@gboolTF, +% \ekvd@t@invbool,\ekvd@t@ginvbool,\ekvd@t@invboolTF,\ekvd@t@ginvboolTF, +% } +% 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} +\protected\def\ekvd@type@bool#1#2#3#4#5% + {% + \ekvd@ifnew{}{#4}% + {% + \ekvd@ifnew{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}% + }% + }% + }% + } +\protected\def\ekvd@t@bool{\ekvd@type@bool{}\iftrue\iffalse} +\protected\def\ekvd@t@gbool{\ekvd@type@bool\global\iftrue\iffalse} +\protected\def\ekvd@t@boolTF{\ekvd@type@bool{}\@firstoftwo\@secondoftwo} +\protected\def\ekvd@t@gboolTF{\ekvd@type@bool\global\@firstoftwo\@secondoftwo} +\protected\def\ekvd@t@invbool{\ekvd@type@bool{}\iffalse\iftrue} +\protected\def\ekvd@t@ginvbool{\ekvd@type@bool\global\iffalse\iftrue} +\protected\def\ekvd@t@invboolTF{\ekvd@type@bool{}\@secondoftwo\@firstoftwo} +\protected\def\ekvd@t@ginvboolTF + {\ekvd@type@bool\global\@secondoftwo\@firstoftwo} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \ekvd@type@boolpair, +% \ekvd@t@boolpair,\ekvd@t@gboolpair,\ekvd@t@boolpairTF,\ekvd@t@gboolpairTF +% } +% The boolean pair types are essentially the same as the boolean types, but set +% two macros instead of one. +% \begin{macrocode} +\protected\def\ekvd@type@boolpair#1#2#3#4#5#6% + {% + \ekvd@ifnew{}{#4}% + {% + \ekvd@ifnew{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}% + }% + }% + } +\protected\def\ekvd@t@boolpair#1#2% + {\ekvd@assert@twoargs{#2}{\ekvd@type@boolpair{}\iftrue\iffalse{#1}#2}} +\protected\def\ekvd@t@gboolpair#1#2% + {\ekvd@assert@twoargs{#2}{\ekvd@type@boolpair\global\iftrue\iffalse{#1}#2}} +\protected\def\ekvd@t@boolpairTF#1#2% + {% + \ekvd@assert@twoargs{#2}% + {\ekvd@type@boolpair{}\@firstoftwo\@secondoftwo{#1}#2}% + } +\protected\def\ekvd@t@gboolpairTF#1#2% + {% + \ekvd@assert@twoargs{#2}% + {\ekvd@type@boolpair\global\@firstoftwo\@secondoftwo{#1}#2}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \ekvd@type@data,\ekvd@t@data,\ekvd@t@gdata,\ekvd@t@dataT,\ekvd@t@gdataT +% } +% \begin{macrocode} +\protected\def\ekvd@type@data#1#2#3#4#5#6% + {% + \ekvd@ifnew{}{#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}}}% + }% + }% + }% + } +\protected\def\ekvd@t@data + {\ekvd@type@data\@secondoftwo\edef{####2}{\ekv@unexpanded{##1}}} +\protected\def\ekvd@t@edata{\ekvd@type@data\@secondoftwo\edef{####2}{##1}} +\protected\def\ekvd@t@gdata + {\ekvd@type@data\@secondoftwo\xdef{####2}{\ekv@unexpanded{##1}}} +\protected\def\ekvd@t@xdata{\ekvd@type@data\@secondoftwo\xdef{####2}{##1}} +\protected\def\ekvd@t@dataT + {\ekvd@type@data\@gobble\edef{}{\ekv@unexpanded{##1}}} +\protected\def\ekvd@t@edataT{\ekvd@type@data\@gobble\edef{}{##1}} +\protected\def\ekvd@t@gdataT + {\ekvd@type@data\@gobble\xdef{}{\ekv@unexpanded{##1}}} +\protected\def\ekvd@t@xdataT{\ekvd@type@data\@gobble\xdef{}{##1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@box,\ekvd@t@box,\ekvd@t@gbox} +% 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} +\protected\def\ekvd@type@box#1#2#3% + {% + \ekvd@ifnew{}{#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}}% + }% + }% + }% + } +\protected\def\ekvd@t@box{\ekvd@type@box{}} +\protected\def\ekvd@t@gbox{\ekvd@type@box\global} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@toks,\ekvd@t@toks,\ekvd@t@gtoks} +% Similar to |box|, but set the |toks|. +% \begin{macrocode} +\protected\def\ekvd@type@toks#1#2#3% + {% + \ekvd@ifnew{}{#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}}}% + }% + }% + } +\protected\def\ekvd@t@toks{\ekvd@type@toks{}} +\protected\def\ekvd@t@gtoks{\ekvd@type@toks\global} +% \end{macrocode} +% \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 + {% + \protected\def\ekvd@type@preapptoks#1#2#3% + {% + \ekvd@ifnew{}{#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}}}% + }% + }% + } + \protected\def\ekvd@t@apptoks{\ekvd@type@preapptoks\toksapp} + \protected\def\ekvd@t@gapptoks{\ekvd@type@preapptoks\gtoksapp} + \protected\def\ekvd@t@pretoks{\ekvd@type@preapptoks\tokspre} + \protected\def\ekvd@t@gpretoks{\ekvd@type@preapptoks\gtokspre} + } + {% + \protected\def\ekvd@type@apptoks#1#2#3% + {% + \ekvd@ifnew{}{#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}}% + }% + }% + }% + } + \protected\def\ekvd@t@apptoks{\ekvd@type@apptoks{}} + \protected\def\ekvd@t@gapptoks{\ekvd@type@apptoks\global} + \newtoks\ekvd@toks + \protected\def\ekvd@type@pretoks#1#2#3% + {% + \ekvd@ifnew{}{#2}% + {% + \ekvd@assert@filledarg{#3}% + {% + \ekvd@newreg#3{toks}% + \ekvd@ifalso + {% + \let\ekvd@prot\protected + \ekvd@add@val{#2}% + {% + \ekvd@toks={##1}% + #1#3=\expandafter{\the\expandafter\ekvd@toks\the#3}% + }% + {}% + }% + {% + \protected\ekvd@long\ekvdef\ekvd@set{#2}% + {% + \ekvd@toks={##1}% + #1#3=\expandafter{\the\expandafter\ekvd@toks\the#3}% + }% + }% + }% + }% + } + \protected\def\ekvd@t@pretoks{\ekvd@type@pretoks{}} + \protected\def\ekvd@t@gpretoks{\ekvd@type@pretoks\global} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \ekvd@type@reg,\ekvd@t@int,\ekvd@t@eint,\ekvd@t@gint,\ekvd@t@xint, +% \ekvd@t@dimen,\ekvd@t@edimen,\ekvd@t@gdimen,\ekvd@t@xdimen, +% \ekvd@t@skip,\ekvd@t@eskip,\ekvd@t@gskip,\ekvd@t@xskip +% } +% The |\ekvd@type@reg| can handle all the types for which the assignment will +% just be \texttt{\meta{register}=\meta{value}}. +% \begin{macrocode} +\protected\def\ekvd@type@reg#1#2#3#4#5#6% + {% + \ekvd@ifnew{}{#5}% + {% + \ekvd@assert@filledarg{#6}% + {% + \ekvd@newreg#6{#1}% + \ekvd@ifalso + {% + \let\evkd@prot\protected + \ekvd@add@val{#5}{#2#6=#3##1#4\relax}{}% + }% + {\protected\ekvd@long\ekvdef\ekvd@set{#5}{#2#6=#3##1#4\relax}}% + }% + }% + } +\protected\def\ekvd@t@int{\ekvd@type@reg{count}{}{}{}} +\protected\def\ekvd@t@eint{\ekvd@type@reg{count}{}\numexpr\relax} +\protected\def\ekvd@t@gint{\ekvd@type@reg{count}\global{}{}} +\protected\def\ekvd@t@xint{\ekvd@type@reg{count}\global\numexpr\relax} +\protected\def\ekvd@t@dimen{\ekvd@type@reg{dimen}{}{}{}} +\protected\def\ekvd@t@edimen{\ekvd@type@reg{dimen}{}\dimexpr\relax} +\protected\def\ekvd@t@gdimen{\ekvd@type@reg{dimen}\global{}{}} +\protected\def\ekvd@t@xdimen{\ekvd@type@reg{dimen}\global\dimexpr\relax} +\protected\def\ekvd@t@skip{\ekvd@type@reg{skip}{}{}{}} +\protected\def\ekvd@t@eskip{\ekvd@type@reg{skip}{}\glueexpr\relax} +\protected\def\ekvd@t@gskip{\ekvd@type@reg{skip}\global{}{}} +\protected\def\ekvd@t@xskip{\ekvd@type@reg{skip}\global\glueexpr\relax} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@store,\ekvd@t@store,\ekvd@t@gstore} +% The none-expanding |store| types use an |\edef| or |\xdef| and |\unexpanded| +% to be able to also store |#| easily. +% \begin{macrocode} +\protected\def\ekvd@type@store#1#2#3#4% + {% + \ekvd@ifnew{}{#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}}}% + }% + }% + } +\protected\def\ekvd@t@store{\ekvd@type@store\edef{\ekv@unexpanded{##1}}} +\protected\def\ekvd@t@gstore{\ekvd@type@store\xdef{\ekv@unexpanded{##1}}} +\protected\def\ekvd@t@estore{\ekvd@type@store\edef{##1}} +\protected\def\ekvd@t@xstore{\ekvd@type@store\xdef{##1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \ekvd@type@meta,\ekvd@type@meta@a,\ekvd@type@meta@b,\ekvd@type@meta@c, +% \ekvd@t@meta,\ekvd@t@nmeta +% } +% |meta| sets up things such that another instance of |\ekvset| will be run on +% the argument, with the same \set. +% \begin{macrocode} +\protected\long\def\ekvd@type@meta#1#2#3#4#5#6#7% + {% + \ekvd@ifnew{#1}{#6}% + {% + \ekvd@assert@filledarg{#7}% + {% + \edef\ekvd@tmp{\ekvd@set}% + \expandafter\ekvd@type@meta@a\expandafter{\ekvd@tmp}{#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@meta@a#1#2% + {% + \expandafter\ekvd@type@meta@b\expandafter{\ekvset{#1}{#2}}% + } +\protected\def\ekvd@type@meta@b + {% + \expandafter\ekvd@type@meta@c\expandafter + } +\protected\long\def\ekvd@type@meta@c#1#2% + {% + \ekvd@prot\ekvd@long\def\ekvd@tmp#2{#1}% + } +\protected\def\ekvd@t@meta{\ekvd@type@meta{}{##1}\ekvd@add@val{{##1}}{}} +\protected\def\ekvd@t@nmeta + {% + \ekvd@assert@not@long + \ekvd@type@meta{NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\ekvd@type@smeta,\ekvd@type@smeta@,\ekvd@t@smeta,\ekvd@t@snmeta} +% |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} +\protected\long\def\ekvd@type@smeta#1#2#3#4#5#6#7% + {% + \ekvd@ifnew{#1}{#6}% + {% + \ekvd@assert@twoargs{#7}% + {% + \ekvd@type@meta@a#7{#2}% + \ekvd@ifalso + {\ekv@exparg{#3{#6}}{\ekvd@tmp#4}{#5}}% + {\csname ekvlet#1\endcsname\ekvd@set{#6}\ekvd@tmp}% + }% + }% + } +\protected\def\ekvd@t@smeta{\ekvd@type@smeta{}{##1}\ekvd@add@val{{##1}}{}} +\protected\def\ekvd@t@snmeta + {% + \ekvd@assert@not@long + \ekvd@type@smeta{NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \ekvd@type@choice, +% \ekvd@populate@choice,\ekvd@populate@choice@,\ekvd@populate@choice@noarg, +% \ekvd@choice@prefix,\ekvd@choice@prefix@,\ekvd@choice@prefix@done, +% \ekvd@choice@p@protected,\ekvd@choice@p@protect, +% \ekvd@choice@p@long,\ekvd@choice@p@long@, +% \ekvd@t@choice +% } +% The |choice| type is by far the most complex type, as we have to run a +% sub-parser on the choice-definition list, which should support the |@p@| type +% prefixes as well (but |long| will always throw an error, as they are not +% allowed to be long). |\ekvd@type@choice| will just define the choice-key, the +% handling of the choices definition will be done by |\ekvd@populate@choice|. +% \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} +% |\ekvd@populate@choice| just uses |\ekvparse| and then gives control to +% |\ekvd@populate@choice@noarg|, which throws an error, and +% |\ekvd@populate@choice@|. +% \begin{macrocode} +\protected\def\ekvd@populate@choice + {% + \ekvparse\ekvd@populate@choice@noarg\ekvd@populate@choice@ + } +\protected\long\def\ekvd@populate@choice@noarg#1% + {% + \expandafter\ekvd@err@missing@definition@msg\expandafter{\ekvd@cur : #1}% + } +% \end{macrocode} +% |\ekvd@populate@choice@| runs the prefix-test, if there is none we can +% directly define the choice, for that |\ekvd@set@choice| will expand to the +% current choice-key's name, which will have been defined by |\ekvd@t@choice|. +% If there is a prefix run the prefix grabbing routine, which was altered for +% |@type@choice|. +% \begin{macrocode} +\protected\long\def\ekvd@populate@choice@#1#2% + {% + \ekvd@clear@prefixes + \ekvd@ifspace{#1}% + {\ekvd@choice@prefix{\ekv@mark#1}\ekv@mark#1\ekv@stop}% + {% + \expandafter\edef + \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#1}\endcsname + }% + {\unexpanded{#2}}% + } +\protected\def\ekvd@choice@prefix#1#2 + {% + \ekv@strip{#2}{\ekvd@choice@prefix@{#1}}\ekv@mark + } +\protected\def\ekvd@choice@prefix@#1#2#3\ekv@stop + {% + \ekv@ifdefined{ekvd@choice@p@#2}% + {% + \csname ekvd@choice@p@#2\endcsname + \ekvd@ifspace{#3}% + {\ekvd@choice@prefix{#3}#3\ekv@stop}% + {\ekvd@choice@prefix@done{#3}}% + }% + {\ekvd@choice@prefix@done{#1}}% + } +\protected\def\ekvd@choice@prefix@done#1% + {% + \ekvd@prot\expandafter\edef + \csname + \ekv@strip{#1}{\ekvd@choice@name\ekvd@set\ekvd@set@choice}% + \endcsname + } +\protected\def\ekvd@choice@p@protected{\let\ekvd@prot\protected} +\let\ekvd@choice@p@protect\ekvd@choice@p@protected +\protected\def\ekvd@choice@invalid@p#1\ekvd@ifspace#2% + {% + \expandafter\ekvd@choice@invalid@p@\expandafter{\ekv@gobble@mark#2}{#1}% + \ekvd@ifspace{#2}% + } +\protected\def\ekvd@choice@invalid@p@#1#2% + {% + \expandafter\ekvd@err@no@prefix@msg\expandafter{\ekvd@cur : #2 #1}{#2}% + } +\protected\def\ekvd@choice@p@long{\ekvd@choice@invalid@p{long}}% +\protected\def\ekvd@choice@p@also{\ekvd@choice@invalid@p{also}}% +\protected\def\ekvd@choice@p@new{\ekvd@choice@invalid@p{new}}% +% \end{macrocode} +% Finally we're able to set up the |@t@choice| macro, which has to store the +% current choice-key's name, define the key, and parse the available choices. +% \begin{macrocode} +\protected\long\def\ekvd@t@choice#1#2% + {% + \ekvd@ifnew{}{#1}% + {% + \ekvd@assert@arg + {% + \ekvd@type@choice{#1}% + \def\ekvd@set@choice{#1}% + \ekvd@populate@choice{#2}% + }% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@t@choice-store,\ekvd@t@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} +\protected\long\expandafter\def\csname ekvd@t@choice-store\endcsname + {\ekvd@type@choicespecial\ekvd@populate@choicestore} +\protected\long\expandafter\def\csname ekvd@t@choice-enum\endcsname + {\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@ifnew{}{#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 + \ekvcsvloop{\ekvd@populate@choicestore@#1}% + } +\protected\long\def\ekvd@populate@choicestore@#1#2% + {% + \protected\expandafter\edef + \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname + {\unexpanded{\edef#1{\unexpanded{#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}[internal]{\ekvd@t@unknown-choice} +% \begin{macrocode} +\protected\long\expandafter\def\csname ekvd@t@unknown-choice\endcsname#1#2% + {% + \ekvd@assert@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{#2}% + }% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\ekvd@t@unknown,\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} +\protected\long\def\ekvd@t@unknown#1#2% + {% + \ekv@ifdefined{ekvd@type@unknown@\detokenize{#1}}% + {\csname ekvd@type@unknown@\detokenize{#1}\endcsname{#2}}% + \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@assert@new@for@name{\ekv@name\ekvd@set{}uN}% + {% + \ekvd@assert@arg + {% + \ekvd@assert@not@also + \ekvd@assert@not@long + \ekvd@prot\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@assert@new@for@name{\ekv@name\ekvd@set{}u}% + {% + \ekvd@assert@arg + {% + \ekvd@assert@not@also + \begingroup + \def\ekvd@tmp##1##2{#1}% + \ekv@exparg + {% + \endgroup + \ekvd@prot\ekvd@long\ekvdefunknown\ekvd@set + }% + {\ekvd@tmp{##2}{##1}}% + }% + }% + } +% \end{macrocode} +% \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@assert@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@assert@new@for@name{\ekv@name\ekvd@set{}uN}% + {% + \ekvd@assert@arg + {% + \ekvd@assert@not@also + \ekvd@assert@not@protected + \ekvd@assert@not@long + \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}% + } +\protected\long\def\ekvd@add@aux@#1#2#3#4#5% + {% + #5% + \ekvd@prot#4\ekvd@set{#2}{#1#3}% + } +% \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\ekv@fi@gobble\fi\@firstofone{\let#1#2}% + } +\protected\def\ekvd@newreg#1#2% + {% + \ifdefined#1\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}% + } +\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}}% + \@gobble + }% + } +\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 + \fi + \@firstofone + }% +\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}}% + \@gobble + }% + } +\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 + \fi + \@firstofone + } +\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@assert@arg@msg,\ekvd@ifnoarg} +% There is no need to actually define |\ekvd@ifnoarg| here, as it will be set by +% either |\ekvd@arg| or |\ekvd@noarg|. +% \begin{macrocode} +\def\ekvd@assert@arg{\ekvd@ifnoarg\ekvd@err@missing@definition} +\long\def\ekvd@assert@arg@msg#1% + {% + \ekvd@ifnoarg{\ekvd@err@missing@definition@msg{#1}}% + } +% \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 + } +\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}} +\def\ekvd@assert@not@new + {\ifx\ekvd@ifnew\ekvd@assert@new\ekvd@err@no@prefix{new}\fi} +\def\ekvd@assert@new@for@name#1% + {% + \ifx\ekvd@ifnew\ekvd@assert@new + \ekv@fi@firstoftwo + \fi + \@secondoftwo + {\ekv@ifdefined{#1}\ekvd@err@not@new}% + \@firstofone + } +% \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@definition@msg, +% \ekvd@err@missing@type,\ekvd@err@undefined@prefix,\ekvd@err@undefined@key, +% \ekvd@err@no@prefix,\ekvd@err@no@prefix@msg,\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\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@definition@msg#1% + {\ekvd@errm{Missing definition for key `\ekv@unexpanded{#1}'}} +\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 `\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@msg#1#2% + {\ekvd@errm{prefix `#2' not accepted in `\ekv@unexpanded{#1}'}} +\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\fi\@firstofone#1% + {% + \fi + \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=<< +% +%^^A=<< +% +% \end{implementation}^^A=<< +% +% \clearpage +% \PrintIndex +% +\endinput +% +^^A vim: ft=tex fdm=marker fmr=>>=,=<< |