diff options
Diffstat (limited to 'macros/generic/expkv-def')
-rw-r--r-- | macros/generic/expkv-def/README.md | 32 | ||||
-rw-r--r-- | macros/generic/expkv-def/expkv-def.dtx | 1383 | ||||
-rw-r--r-- | macros/generic/expkv-def/expkv-def.pdf | bin | 0 -> 294005 bytes |
3 files changed, 1415 insertions, 0 deletions
diff --git a/macros/generic/expkv-def/README.md b/macros/generic/expkv-def/README.md new file mode 100644 index 0000000000..4026585657 --- /dev/null +++ b/macros/generic/expkv-def/README.md @@ -0,0 +1,32 @@ +------------------------------------------------------------------------------- +# expkv-def -- a key-defining frontend for expkv + +Version 2020-02-27 v0.1 + +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt + +Hosted at https://github.com/Skillmon/tex_expkv-def + +------------------------------------------------------------------------------- + +Copyright (C) 2020 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 provides a key=val frontend to define keys for +[`expkv`](https://github.com/Skillmon/tex_expkv). It is generic code and only +requires `expkv` for its parsing. There is a LaTeX package `expkv-def.sty` +included to play nice on LaTeX's package loading system, but that package is not +needed and does not provide more functionality than the generic code in +`expkv-def.tex`. diff --git a/macros/generic/expkv-def/expkv-def.dtx b/macros/generic/expkv-def/expkv-def.dtx new file mode 100644 index 0000000000..33bcf27157 --- /dev/null +++ b/macros/generic/expkv-def/expkv-def.dtx @@ -0,0 +1,1383 @@ +% \iffalse meta-comment +% +% File: expkv-def.dtx Copyright (C) 2020 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 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 + +\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}}} +\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{listings} +\RequirePackage{booktabs} +\RequirePackage{array} +\RequirePackage{collcell} +\RequirePackage{siunitx} +\RequirePackage{xcolor} +\RequirePackage{caption} +\RequirePackage{microtype} +\RequirePackage{accsupp} +\lstset + { + ,flexiblecolumns=false + ,basewidth=.53em + ,gobble=2 + ,basicstyle=\fontfamily{jkp}\itshape + ,morekeywords=^^A + {^^A + \ekvdefinekeys + } + ,morecomment=[l]\% + ,commentstyle=\color[gray]{0.4} + ,literate={\{}{{\CodeSymbol\{}}{1} + {\}}{{\CodeSymbol\}}}{1} + ^^A,literate=*{<key>}{\key}{4}{<set>}{\set}{4} + } +\newcommand*\CodeSymbol[1]{\textbf{#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\enfprot{\textcolor{black}{protected}} +\newcommand\allprot{\textcolor{gray}{protected}} +\newcommand\notprot{\textcolor{red!80!black}{protected}} +\newcommand\enflong{\textcolor{black}{long}} +\newcommand\alllong{\textcolor{gray}{long}} +\newcommand\notlong{\textcolor{red!80!black}{long}} +\newcommand\prefixes[2] + {^^A + \hfill + \ifcase\numexpr#1\relax\or + \enfprot\or + \allprot\or + \notprot\fi\space + \ifcase\numexpr#2\relax\or + \enflong\or + \alllong\or + \notlong\fi + } +\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{\noexpand,\protected,\ProvidesFile,\ProvidesPackage,\relax,\space} +\DoNotIndex{\@,\unexpanded,\string,\expanded,\dimexpr,\global,\glueexpr,\hbox} +\DoNotIndex{\numexpr,\RequirePackage,\setbox,\the,\unless,\xdef} +\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 and as a \LaTeX\ package. It'll +% automatically load \expkv\ in the same mode as well. To use it, just use one +% of +% \begin{lstlisting} +% \usepackage{expkv-def} % LaTeX +% \input expkv-def % plainTeX +% \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 |p|-type prefixes 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. +% \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} +% +% \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{\enfprot}), allowed prefixes will be grey (\texttt{\allprot}), and +% disallowed prefixes will be red (\texttt{\notprot}). This will be put +% flush-right in the syntax showing line. +% +% \begin{function}{code,ecode} +% \begin{syntax} +% code \key\ = \marg{definition} \prefixes22 +% \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} \prefixes23 +% \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,edefault} +% \begin{syntax} +% default \key\ = \marg{definition} \prefixes23 +% \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. The |edefault| on the other hand fully expands the +% \key-code with \meta{definition} as its argument inside of an |\edef|. +% \end{function} +% +% \begin{function}{initial} +% \begin{syntax} +% initial \key\ = \{\val\} \prefixes33 +% \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. +% \end{function} +% +% \begin{function}{bool,gbool,boolTF,gboolTF} +% \begin{syntax} +% bool \key\ = \meta{cs} \prefixes23 +% \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). +% \end{function} +% +% \begin{function}{store,estore,gstore,xstore} +% \begin{syntax} +% store \key\ = \meta{cs} \prefixes12 +% \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}{int,eint,gint,xint} +% \begin{syntax} +% int \key\ = \meta{cs} \prefixes12 +% \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} \prefixes12 +% \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} +% dimen \key\ = \meta{cs} \prefixes12 +% \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} +% \begin{syntax} +% dimen \key\ = \meta{cs} \prefixes12 +% \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. 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} \prefixes12 +% \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\} \prefixes22 +% \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|. +% \end{function} +% +% \begin{function}{nmeta} +% \begin{syntax} +% nmeta \key\ = \{\kv, \ldots\} \prefixes23 +% \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\} \prefixes22 +% \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\} \prefixes23 +% \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} \prefixes33 +% \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\} \prefixes23 +% \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{dafinition} 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. +% \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 +% ,int keyE = \keyE +% ,dimen keyF = \keyF +% ,skip keyG = \keyG +% ,toks keyH = \keyH +% ,default keyH = \empty test +% ,box keyI = \keyI +% ,qdefault keyI = text +% ,choice keyJ = +% { +% ,protected 1 = \texttt{a} +% ,2 = b +% ,3 = c +% ,4 = d +% ,5 = e +% } +% ,edefault keyJ = 2 +% ,meta keyK = {keyA={#1},keyB=false} +% ,set setB = B +% } +% \end{lstlisting} +% +% \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 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.1} +\def\ekvdDate{2020-02-27} +% \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@long,\ekvd@prot,\ekvd@clear@prefixes,\ekvd@empty} +% \expkvd\ will use |\ekvd@long| and |\ekvd@prot| to store whether a key should +% be defined an |\long| or |\protected|, and we have to clear them for every new +% key. By default they'll just be empty. +% \begin{macrocode} +\def\ekvd@empty{} +\protected\def\ekvd@clear@prefixes + {% + \let\ekvd@long\ekvd@empty + \let\ekvd@prot\ekvd@empty + } +\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@ + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@noarg,\ekvd@} +% |\ekvd@noarg| just places a special marker and gives control to |\ekvd@|. +% |\ekvd@| 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\def\ekvd@noarg#1{\ekvd@{#1}\ekvd@noarg@mark} +\protected\def\ekvd@#1#2% + {% + \ekvd@clear@prefixes + \ekvd@ifspace{#1}% + {\ekvd@prefix\ekv@mark#1\ekv@stop{#2}}% + {\ekvd@missing@prefix{#1}}% + } +% \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{#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}% + {% + \expandafter\ekvd@err@missing@prefix\expandafter{\ekv@gobble@mark#1}% + \@gobble + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@p@long,\ekvd@p@protected,\ekvd@p@protect} +% Define the |@p@| type prefixes, they all just store some information in a +% temporary macro and call |\ekvd@prefix@after@p|. +% \begin{macrocode} +\protected\def\ekvd@p@long{\let\ekvd@long\long\ekvd@prefix@after@p} +\protected\def\ekvd@p@protected{\let\ekvd@prot\protected\ekvd@prefix@after@p} +\let\ekvd@p@protect\ekvd@p@protected +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Key Types} +% +% \begin{macro}[internal]{\ekvd@t@set} +% The |set| type is quite straight forward, just define a |NoVal| key to call +% |\ekvchangeset|. +% \begin{macrocode} +\protected\def\ekvd@t@set#1#2% + {% + \ekvd@assert@not@long{set #1}% + \ekvd@assert@not@protected{set #1}% + \ekvd@ifnoarg{#2}% + {\ekvdefNoVal\ekvd@set{#1}{\ekvchangeset{#1}}}% + {% + \ekv@ifempty{#2}% + {\ekvd@err@missing@definition{set #1}}% + {\ekvdefNoVal\ekvd@set{#1}{\ekvchangeset{#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#4% + {% + \ekvd@assert@arg{#1noval #3}{#4}% + {% + \ekvd@assert@not@long{#1noval #3}% + \ekvd@prot#2\ekvd@tmp{#4}% + \ekvletNoVal\ekvd@set{#3}\ekvd@tmp + }% + } +\protected\def\ekvd@t@noval{\ekvd@type@noval{}\def} +\protected\def\ekvd@t@enoval{\ekvd@type@noval e\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#4% + {% + \ekvd@assert@arg{#1code #3}{#4} + {% + \ekvd@prot\ekvd@long#2\ekvd@tmp##1{#4}% + \ekvlet\ekvd@set{#3}\ekvd@tmp + }% + } +\protected\def\ekvd@t@code{\ekvd@type@code{}\def} +\protected\def\ekvd@t@ecode{\ekvd@type@code e\edef} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@default,\ekvd@t@default,\ekvd@t@qdefault} +% |\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{#1default #3}{#4}% + {% + \ekvifdefined\ekvd@set{#3}% + {% + \ekvd@assert@not@long{#1default #3}% + \ekvd@prot\edef\ekvd@tmp + {% + \unexpanded\expandafter#2% + {\csname\ekv@name\ekvd@set{#3}\endcsname{#4}}% + }% + \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 q{\expandafter\expandafter}} +% \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{edefault #1}{#2}% + {% + \ekvifdefined\ekvd@set{#1}% + {% + \ekvd@assert@not@long{edefault #1}% + \ekvd@prot\edef\ekvd@tmp + {\csname\ekv@name\ekvd@set{#1}\endcsname{#2}}% + \ekvletNoVal\ekvd@set{#1}\ekvd@tmp + }% + {\ekvd@err@undefined@key{#1}}% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@t@initial} +% \begin{macrocode} +\long\def\ekvd@t@initial#1#2% + {% + \ekvd@assert@arg{initial #1}{#2}% + {% + \ekvifdefined\ekvd@set{#1}% + {% + \ekvd@assert@not@long{initial #1}% + \ekvd@assert@not@protected{initial #1}% + \csname\ekv@name\ekvd@set{#1}\endcsname{#2}% + }% + {\ekvd@err@undefined@key{#1}}% + }% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\ekvd@type@bool,\ekvd@t@bool,\ekvd@t@gbool,\ekvd@t@boolTF,\ekvd@t@gboolTF} +% 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#6#7% + {% + \ekvd@assert@filledarg{#1bool#2 #6}{#7}% + {% + \ekvd@newlet#7#5% + \ekvd@type@choice{#1bool#2}{#6}% + \protected\ekvdefNoVal\ekvd@set{#6}{#3\let#7#4}% + \protected\expandafter\def + \csname\ekvd@choice@name\ekvd@set{#6}{true}\endcsname + {#3\let#7#4}% + \protected\expandafter\def + \csname\ekvd@choice@name\ekvd@set{#6}{false}\endcsname + {#3\let#7#5}% + }% + } +\protected\def\ekvd@t@bool{\ekvd@type@bool{}{}{}\iftrue\iffalse} +\protected\def\ekvd@t@gbool{\ekvd@type@bool g{}\global\iftrue\iffalse} +\protected\def\ekvd@t@boolTF{\ekvd@type@bool{}{TF}{}\@firstoftwo\@secondoftwo} +\protected\def\ekvd@t@gboolTF + {\ekvd@type@bool g{TF}\global\@firstoftwo\@secondoftwo} +% \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#4% + {% + \ekvd@assert@filledarg{#1box #3}{#4}% + {% + \ekvd@newreg#4{box}% + \protected\ekvd@long\ekvdef\ekvd@set{#3}% + {#2\setbox#4\hbox{\begingroup##1\endgroup}}% + }% + } +\protected\def\ekvd@t@box{\ekvd@type@box{}{}} +\protected\def\ekvd@t@gbox{\ekvd@type@box g\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#4% + {% + \ekvd@assert@filledarg{#1toks #3}{#4}% + {% + \ekvd@newreg#4{toks}% + \protected\ekvd@long\ekvdef\ekvd@set{#3}{#2#4{##1}}% + }% + } +\protected\def\ekvd@t@toks{\ekvd@type@toks{}{}} +\protected\def\ekvd@t@gtoks{\ekvd@type@toks{g}\global} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@apptoks,\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} +\protected\def\ekvd@type@apptoks#1#2#3#4% + {% + \ekvd@assert@filledarg{#1apptoks #3}{#4}% + {% + \ekvd@newreg#4{toks}% + \protected\ekvd@long\ekvdef\ekvd@set{#3}{#2#4\expandafter{\the#4##1}}% + }% + } +\protected\def\ekvd@t@apptoks{\ekvd@type@apptoks{}{}} +\protected\def\ekvd@t@gapptoks{\ekvd@type@apptoks{g}\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#7% + {% + \ekvd@assert@filledarg{#1 #6}{#7}% + {% + \ekvd@newreg#7{#2}% + \protected\ekvd@long\ekvdef\ekvd@set{#6}{#3#7=#4##1#5\relax}% + }% + } +\protected\def\ekvd@t@int{\ekvd@type@reg{int}{count}{}{}{}} +\protected\def\ekvd@t@eint{\ekvd@type@reg{eint}{count}{}\numexpr\relax} +\protected\def\ekvd@t@gint{\ekvd@type@reg{gint}{count}\global{}{}} +\protected\def\ekvd@t@xint{\ekvd@type@reg{xint}{count}\global\numexpr\relax} +\protected\def\ekvd@t@dimen{\ekvd@type@reg{dimen}{dimen}{}{}{}} +\protected\def\ekvd@t@edimen{\ekvd@type@reg{edimen}{dimen}{}\dimexpr\relax} +\protected\def\ekvd@t@gdimen{\ekvd@type@reg{gdimen}{dimen}\global{}{}} +\protected\def\ekvd@t@xdimen{\ekvd@type@reg{xdimen}{dimen}\global\dimexpr\relax} +\protected\def\ekvd@t@skip{\ekvd@type@reg{skip}{skip}{}{}{}} +\protected\def\ekvd@t@eskip{\ekvd@type@reg{eskip}{skip}{}\glueexpr\relax} +\protected\def\ekvd@t@gskip{\ekvd@type@reg{gskip}{skip}\global{}{}} +\protected\def\ekvd@t@xskip{\ekvd@type@reg{xskip}{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@assert@filledarg{#1store #3}{#4}% + {% + \unless\ifdefined#4\let#4\ekvd@empty\fi + \protected\ekvd@long\ekvdef\ekvd@set{#3}{#2#4{\unexpanded{##1}}}% + }% + } +\protected\def\ekvd@t@store{\ekvd@type@store{}\edef} +\protected\def\ekvd@t@gstore{\ekvd@type@store{g}\xdef} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@type@estore,\ekvd@t@estore,\ekvd@t@xstore} +% And the straight forward |estore| types. +% \begin{macrocode} +\protected\def\ekvd@type@estore#1#2#3#4% + {% + \ekvd@assert@filledarg{#1store #3}{#4}% + {% + \ekvd@newlet#4\ekvd@empty + \protected\ekvd@long\ekvdef\ekvd@set{#3}{#2#4{##1}}% + }% + } +\protected\def\ekvd@t@estore{\ekvd@type@estore{e}\edef} +\protected\def\ekvd@t@xstore{\ekvd@type@estore{x}\xdef} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% {\ekvd@type@meta,\ekvd@type@meta@,\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% + {% + \ekvd@assert@filledarg{#1meta #4}{#5}% + {% + \edef\ekvd@tmp{\ekvd@set}% + \expandafter\ekvd@type@meta@\expandafter{\ekvd@tmp}{#3}{#5}% + #2\ekvd@set{#4}\ekvd@tmp + }% + } +\protected\long\def\ekvd@type@meta@#1#2#3% + {% + \ekvd@prot\ekvd@long\def\ekvd@tmp#2{\ekvset{#1}{#3}}% + } +\protected\def\ekvd@t@meta{\ekvd@type@meta{}\ekvlet{##1}} +\protected\def\ekvd@t@nmeta#1#2% + {% + \ekvd@assert@not@long{nmeta #1}% + \ekvd@type@meta n\ekvletNoVal{}{#1}{#2}% + } +% \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% + {% + \ekvd@assert@twoargs{s#1meta #4}{#5}% + {% + \expandafter\ekvd@type@smeta@\expandafter{\@secondoftwo#5}{#5}{#3} + #2\ekvd@set{#4}\ekvd@tmp + }% + } +\protected\long\def\ekvd@type@smeta@#1#2#3% + {% + \expandafter\ekvd@type@meta@\expandafter{\@firstoftwo#2}{#3}{#1}% + } +\protected\def\ekvd@t@smeta{\ekvd@type@smeta{}\ekvlet{##1}} +\protected\def\ekvd@t@snmeta#1#2% + {% + \ekvd@assert@not@long{snmeta #1}% + \ekvd@type@smeta n\ekvletNoVal{}{#1}{#2}% + } +% \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@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#2% + {% + \ekvd@assert@not@long{#1 #2}% + \ekvd@prot\edef\ekvd@tmp##1% + {% + \unexpanded{\ekvd@h@choice}{\ekvd@choice@name\ekvd@set{#2}{##1}}% + }% + \ekvlet\ekvd@set{#2}\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\def\ekvd@populate@choice@noarg#1% + {% + \expandafter\ekvd@err@missing@definition\expandafter{\ekvd@set@choice : #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 + \expandafter\ekvd@assert@arg\expandafter{\ekvd@set@choice : #1}{#2}% + {% + \ekvd@ifspace{#1}% + {\ekvd@choice@prefix\ekv@mark#1\ekv@stop}% + {% + \expandafter\def + \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#1}\endcsname + }% + {#2}% + }% + } +\protected\def\ekvd@choice@prefix#1 + {% + \ekv@strip{#1}\ekvd@choice@prefix@\ekv@mark + } +\protected\def\ekvd@choice@prefix@#1#2\ekv@stop + {% + \ekv@ifdefined{ekvd@choice@p@#1}% + {% + \csname ekvd@choice@p@#1\endcsname + \ekvd@ifspace{#2}% + {\ekvd@choice@prefix#2\ekv@stop}% + {% + \ekvd@prot\expandafter\def + \csname + \ekv@strip{#2}{\ekvd@choice@name\ekvd@set\ekvd@set@choice}% + \endcsname + }% + }% + {\ekvd@err@undefined@prefix{#1}\@gobble}% + } +\protected\def\ekvd@choice@p@protected{\let\ekvd@prot\protected} +\let\ekvd@choice@p@protect\ekvd@choice@p@protected +\protected\def\ekvd@choice@p@long\ekvd@ifspace#1% + {% + \expandafter\ekvd@choice@p@long@\expandafter{\ekv@gobble@mark#1}% + \ekvd@ifspace{#1}% + } +\protected\def\ekvd@choice@p@long@#1% + {% + \expandafter\ekvd@err@no@long\expandafter + {\ekvd@set@choice : long #1}% + } +% \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@assert@arg{choice #1}{#2}% + {% + \ekvd@type@choice{choice}{#1}% + \def\ekvd@set@choice{#1}% + \ekvd@populate@choice{#2}% + }% + } +% \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{Tests} +% +% \begin{macro}[internal]{\ekvd@noarg@mark} +% This macro serves as a flag for the case that no \val\ was specified for a +% key. As such it is not a test, but exists only for some tests. +% \begin{macrocode} +\def\ekvd@noarg@mark{\ekvd@noarg@mark} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@fi@firstoftwo} +% While we can reuse many of the internals of \expkv\ the specific case for this +% branch wasn't needed by \expkv\ and hence isn't defined. We'll need it, so we +% define it. +% \begin{macrocode} +\long\def\ekvd@fi@firstoftwo\fi\@secondoftwo#1#2{\fi#1} +% \end{macrocode} +% \end{macro} +% +% \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% + {% + \unless\ifdefined#1\let#1#2\fi + } +\protected\def\ekvd@newreg#1#2% + {% + \unless\ifdefined#1\csname new#2\endcsname#1\fi + } +% \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#2% + {% + \ekvd@ifnottwoargs{#2}% + {\ekvd@err@missing@definition{#1}}% + } +\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@arg,\ekvd@ifnoarg} +% The test for an argument is just an |\ifx| comparison with our |noarg@mark|. +% \begin{macrocode} +\long\def\ekvd@assert@arg#1#2% + {% + \ekvd@ifnoarg{#2}% + {\ekvd@err@missing@definition{#1}}% + } +\long\def\ekvd@ifnoarg#1% + {% + \ifx\ekvd@noarg@mark#1% + \ekvd@fi@firstoftwo + \fi + \@secondoftwo + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@assert@filledarg,\ekvd@ifnoarg@or@empty} +% \begin{macrocode} +\long\def\ekvd@assert@filledarg#1#2% + {% + \ekvd@ifnoarg@or@empty{#2}% + {\ekvd@err@missing@definition{#1}}% + } +\long\def\ekvd@ifnoarg@or@empty#1% + {% + \ekvd@ifnoarg{#1}% + \@firstoftwo + {\ekv@ifempty{#1}}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal]{\ekvd@assert@not@long,\ekvd@assert@not@protected} +% Some key-types don't want to be |\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} +\long\def\ekvd@assert@not@long#1% + {% + \ifx\ekvd@long\long\ekvd@err@no@long{#1}\fi + } +\long\def\ekvd@assert@not@protected#1% + {% + \ifx\ekvd@prot\protected\ekvd@err@no@protected{#1}\fi + } +% \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@err@missing@definition,\ekvd@err@missing@prefix, +% \ekvd@err@undefined@prefix,\ekvd@err@undefined@key,\ekvd@err@no@protected, +% \ekvd@err@no@long +% } +% The non-expandable error messages are boring, so here they are: +% \begin{macrocode} +\protected\def\ekvd@err@missing@definition#1% + {\errmessage{expkv-def Error: Missing definition for key `\unexpanded{#1}'}} +\protected\def\ekvd@err@missing@prefix#1% + {\errmessage{expkv-def Error: Missing prefix for key `\unexpanded{#1}'}} +\protected\def\ekvd@err@undefined@prefix#1% + {\errmessage{expkv-def Error: Undefined prefix `\unexpanded{#1}'}} +\protected\def\ekvd@err@undefined@key#1% + {\errmessage{expkv-def Error: Undefined key `\unexpanded{#1}'}} +\protected\def\ekvd@err@no@protected#1% + {% + \errmessage + {expkv-def Error: prefix `protected' not accepted for `\unexpanded{#1}'}% + } +\protected\def\ekvd@err@no@long#1% + {% + \errmessage + {expkv-def Error: prefix `long' not accepted for `\unexpanded{#1}'}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[internal] +% { +% \ekvd@err@choice@invalid,\ekvd@err@choice@invalid@,\ekvd@choice@name, +% \ekvd@err +% } +% The expandable error messages use |\ekvd@err|, which is just like |\ekv@err| +% from \expkv\ or the way \pkg{expl3} throws expandable error messages. It uses +% an undefined control sequence to start the error message. +% |\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\ekv@stop + } +\begingroup +\catcode40=8 +\catcode41=8 +\@firstofone{\endgroup +\def\ekvd@choice@name#1#2#3% + {% + ekvd#1(#2)#3% + } +\def\ekvd@err@choice@invalid@ ekvd#1(#2)#3\ekv@stop% + {% + \ekvd@err{invalid choice `#3' (`#2', set `#1')}% + } +} +\begingroup +\edef\ekvd@err + {% + \endgroup + \unexpanded{\long\def\ekvd@err}##1% + {% + \unexpanded{\expandafter\ekv@err@\@firstofone}% + {\expandafter\noexpand\csname ! expkv-def Error:\endcsname ##1.}% + \unexpanded{\ekv@stop}% + }% + } +\ekvd@err +% \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=>>=,=<< diff --git a/macros/generic/expkv-def/expkv-def.pdf b/macros/generic/expkv-def/expkv-def.pdf Binary files differnew file mode 100644 index 0000000000..a4c589c83f --- /dev/null +++ b/macros/generic/expkv-def/expkv-def.pdf |