summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expkv/expkv.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2020-04-11 22:21:50 +0000
committerKarl Berry <karl@freefriends.org>2020-04-11 22:21:50 +0000
commita028b56d2f5651b6aeefd34cc75b550617fa9989 (patch)
treed9cd6a7d466373dafb497b1f9c9e99cd7769b160 /Master/texmf-dist/source/latex/expkv/expkv.dtx
parent2ce8fab99cc0add24a98b8765b5324aa0fa3f573 (diff)
expkv (10apr20)
git-svn-id: svn://tug.org/texlive/trunk@54654 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/expkv/expkv.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expkv/expkv.dtx618
1 files changed, 375 insertions, 243 deletions
diff --git a/Master/texmf-dist/source/latex/expkv/expkv.dtx b/Master/texmf-dist/source/latex/expkv/expkv.dtx
index 0f0491164e6..3fae5459b08 100644
--- a/Master/texmf-dist/source/latex/expkv/expkv.dtx
+++ b/Master/texmf-dist/source/latex/expkv/expkv.dtx
@@ -74,6 +74,7 @@ and the derived files expkv.pdf
\RequirePackage{caption}
\RequirePackage{microtype}
\RequirePackage{accsupp}
+\RequirePackage{enumitem}
\lstset
{
,flexiblecolumns=false
@@ -122,27 +123,32 @@ and the derived files expkv.pdf
}
{expkv}^^A
}
-\newcommand*\expkvd
+\newcommand*\expkvpkg[1]
{^^A
\texorpdfstring
{^^A
\mbox
{^^A
- \BeginAccSupp{ActualText=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
+ \BeginAccSupp{ActualText=expkv-#1}^^A
+ \href{https://github.com/Skillmon/tex_expkv-#1}
+ {^^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{#1}^^A
+ }^^A
+ }^^A
\EndAccSupp{}^^A
}^^A
}
- {expkv-def}^^A
+ {expkv-#1}^^A
}
+\newcommand*\expkvd{\expkvpkg{def}}
+\newcommand*\expkvc{\expkvpkg{cs}}
\newcommand\kv{\meta{key}=\meta{value}}
\newcommand\key{\meta{key}}
\newcommand\val{\meta{value}}
@@ -150,7 +156,7 @@ and the derived files expkv.pdf
\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{\protected,\ProvidesFile,\ProvidesPackage,\relax,\space}
\DoNotIndex{\@,\unexpanded,\string,\expanded}
\DoNotIndex{\ifcsname}
\DoNotIndex{\ifx}
@@ -192,8 +198,8 @@ and the derived files expkv.pdf
% \noindent\parfillskip=0pt
% \expkv\ provides a small interface for \kv\ parsing. The parsing macro is
% fully expandable, the \meta{code} of your keys might be not. \expkv\ is pretty
-% fast, but not the fastest available \kv\ solution (\pkg{keyval} for instance
-% is thrice as fast, but not expandable and it might strip braces it shouldn't
+% fast, but not the fastest available \kv\ solution (\pkg{keyval} is one and a
+% half times as fast, but not expandable and it might strip braces it shouldn't
% have stripped).
% \end{abstract}
%
@@ -220,13 +226,22 @@ and the derived files expkv.pdf
% |\ProvidesPackage| and setting things up such that \file{expkv.tex} will use
% |\ProvidesFile|.
%
+% In the \expkv\ family are other packages contained which provide additional
+% functionality. Those packages currently are:
+% \begin{description}[format=\expkvpkg]
+% \item[def]
+% a key-defining frontend for \expkv\ using a \kv\ syntax
+% \item[cs]
+% define expandable \kv\ macros using \expkv
+% \end{description}
+% Note that while the package names are stylised with a vertical rule, their
+% names are all lower case with a hyphen (\emph{e.g.}, \file{expkv-def}).
+%
% \subsection{Setting up Keys}\label{sec:define}
% \expkv\ provides a rather simple approach to setting up keys, similar to
-% \pkg{keyval}. However there is an auxiliary package named
-% \href{https://github.com/Skillmon/tex_expkv-def}{\expkvd} (the files use
-% \file{expkv-def} instead because \string| isn't allowed in package names by
-% CTAN) which provides a more sophisticated interface, similar to well
-% established packages like \pkg{pgfkeys} or \pkg{l3keys}.
+% \pkg{keyval}. However there is an auxiliary package named \expkvd\ which
+% provides a more sophisticated interface, similar to well established packages
+% like \pkg{pgfkeys} or \pkg{l3keys}.
%
% Keys in \expkv\ (as in almost all other \kv\ implementations) belong to a
% \emph{set} such that different sets can contain keys of the same name. Unlike
@@ -236,7 +251,8 @@ and the derived files expkv.pdf
% user level).
%
% The following macros are available to define new keys. Those macros containing
-% ``|def|'' in their name can be prefixed by anything allowed to prefix |\def|,
+% ``|def|'' in their name can be prefixed by anything allowed to prefix |\def|
+% (but \emph{don't} use |\outer|, keys defined with it won't ever be usable),
% prefixes allowed for |\let| can prefix those with ``|let|'' in their name,
% accordingly. Neither \set\ nor \key\ are allowed to be empty for new keys and
% must not contain a |\par| or tokens that expand to it -- they must be legal
@@ -464,7 +480,7 @@ and the derived files expkv.pdf
% that it does less. The same is true for |\keyval_parse:NNn| compared to
% |\keys_set:nn| of \pkg{expl3} (where the difference is much bigger).
%
-% \paragraph{\pkg{keyval}} is about two times faster and has a comparable
+% \paragraph{\pkg{keyval}} is about $1.6$ times faster and has a comparable
% feature set just a slightly different way how it handles keys without values.
% That might be considered a drawback, as it limits the versatility, but also as
% an advantage, as it might reduce doubled code. Keep in mind that as soon as
@@ -484,52 +500,53 @@ and the derived files expkv.pdf
% \setkeys{foo}{bar={{baz}}}
% \end{lstlisting}
%
-% \paragraph{\pkg{xkeyval}} is roughly fourteen times slower, but it provides
+% \paragraph{\pkg{xkeyval}} is roughly seventeen times slower, but it provides
% more functionality, e.g., it has choice keys, boolean keys, and so on. It
% contains the same bug as \pkg{keyval} as it has to be compatible with it by
% design (it replaces \pkg{keyval}'s frontend), but also adds even more cases in
% which braces are stripped that shouldn't be stripped, worsening the situation.
%
-% \paragraph{\pkg{ltxkeys}} is over 300 times slower -- which is funny, because
-% it aims to be ``[\ldots] faster than these earlier packages [referring to
-% \pkg{keyval} and \pkg{xkeyval}].'' Since it aims to have a bigger feature set
-% than \pkg{xkeyval}, it most definitely also has a bigger feature set than
-% \expkv. Also, it can't parse |\long| input, so as soon as your values contain
-% a |\par|, it'll throw errors. Furthermore, \pkg{ltxkeys} doesn't strip outer
-% braces at all by design, which, imho, is a weird design choice. In addition
-% \pkg{ltxkeys} loads \pkg{catoptions} which is known to introduce bugs (e.g.,
-% see \url{https://tex.stackexchange.com/questions/461783}).
-%
-% \paragraph{\pkg{l3keys}} is almost five times slower, but has an, imho, great
+% \paragraph{\pkg{ltxkeys}} is over 370 times slower -- which is funny, because
+% it aims to be ``[\ldots] faster [\ldots] than these earlier packages
+% [referring to \pkg{keyval} and \pkg{xkeyval}].'' It needs more time to parse
+% zero keys than four of the packages in this comparison need to parse 100 keys.
+% Since it aims to have a bigger feature set than \pkg{xkeyval}, it most
+% definitely also has a bigger feature set than \expkv. Also, it can't parse
+% |\long| input, so as soon as your values contain a |\par|, it'll throw errors.
+% Furthermore, \pkg{ltxkeys} doesn't strip outer braces at all by design, which,
+% imho, is a weird design choice. In addition \pkg{ltxkeys} loads
+% \pkg{catoptions} which is known to introduce bugs (e.g., see
+% \url{https://tex.stackexchange.com/questions/461783}).
+%
+% \paragraph{\pkg{l3keys}} is around six times slower, but has an, imho, great
% interface to define keys. It strips \emph{all} outer spaces, even if somehow
% multiple spaces ended up on either end. It offers more features, but is pretty
-% much bound to \pkg{expl3} code. Whether that's a drawback is up to you.
+% much bound to \pkg{expl3} code. Whether that's a drawback is up to you. Note
+% that this comparison uses the version contained in \TeX Live 2019 (frozen)
+% which is a bit slower than versions starting with \TeX Live 2020.
%
-% \paragraph{\pkg{pgfkeys}} is a bit more than two times slower for one key,
-% but has an \emph{enormous} feature set. However, since adding additional keys
-% doesn't add as much needed time for \pkg{pgfkeys} compared to \expkv, it gets
-% faster than \expkv\ at around eight \kv\ pairs.
+% \paragraph{\pkg{pgfkeys}} is around $2.7$ times slower for one key,
+% but has an \emph{enormous} feature set.
% It has the same or a very similar bug \pkg{keyval} has. The brace bug (and
% also the category fragility) can be fixed by \pkg{pgfkeyx}, but this package
% was last updated in 2012 and it slows down |\pgfkeys| by factor~$8$. Also I
% don't know whether this might introduce new bugs.
%
-% \paragraph{\pkg{kvsetkeys} with \pkg{kvdefinekeys}} is about three times
+% \paragraph{\pkg{kvsetkeys} with \pkg{kvdefinekeys}} is about $3.7$ times
% slower, but it works even if commas and equals have category codes different
% from 12 (just as some other packages in this list). Else the features of the
% keys are equal to those of \pkg{keyval}, the parser has more features, though.
%
-% \paragraph{\pkg{options}} is a bit slower for only a single value, but gets a
-% tad faster than \expkv\ at around 10 \kv\ pairs. It has a much bigger feature
-% set. Unfortunately it also suffers from the premature unbracing bug
-% \pkg{keyval} has.
+% \paragraph{\pkg{options}} is $1.5$ times slower for only a single value. It
+% has a much bigger feature set. Unfortunately it also suffers from the
+% premature unbracing bug \pkg{keyval} has.
%
% \paragraph{\pkg{simplekv}} is hard to compare because I don't speak French (so
% I don't understand the documentation) and from what I can see, there is no
% direct way to define the equivalent test key. Nevertheless, I tested the
% closest possible equivalent of my test key while siding for \pkg{simplekv}'s
% design not forcing something into it it doesn't seem to be designed for. It is
-% more than five times slower and has hard to predict behaviour regarding brace
+% almost seven times slower and has hard to predict behaviour regarding brace
% and space stripping, similar to \pkg{keyval}. The tested definition was:
% \begin{lstlisting}[belowskip=0pt]
% \usepackage{simplekv}
@@ -537,7 +554,7 @@ and the derived files expkv.pdf
% \setKV[simplekv]{ height = 6 } % benchmarked
% \end{lstlisting}
%
-% \paragraph{\pkg{yax}} is over eighteen times slower. It has a pretty strange
+% \paragraph{\pkg{yax}} is over twenty times slower. It has a pretty strange
% syntax, imho, and again a direct equivalent is hard to define. It has the
% premature unbracing bug, too. Also somehow loading \pkg{yax} broke
% \pkg{options} for me. The tested definition was:
@@ -575,16 +592,16 @@ and the derived files expkv.pdf
% \toprule
% \rmfamily Package & {$p_1$} & {$p_0$} & {$T_0$}& BB & CF & Date \\
% \midrule
-% keyval & 13.539 & 1.844 & 6.969 & \yes & \yes & 2014-10-28 \\
-% \expkv & 26.411 & 2.391 & 12.610 & \no & \no & 2020-02-22 \\
-% options & 25.532 & 10.518 & 21.393 & \yes & \yes & 2015-03-01 \\
-% pgfkeys & 26.444 & 40.939 & 55.790 & \yes & \yes & 2020-01-08 \\
-% kvsetkeys & {\fnsym} & {\fnsym} & 41.620 & \no & \no & 2019-12-15 \\
-% l3keys & 114.456 & 35.357 & 52.667 & \no & \no & 2020-02-14 \\
-% simplekv & 160.523 & 10.809 & 8.698 & \yes & \yes & 2017-08-08 \\
-% xkeyval & 260.872 & 180.435 & 164.167 & \yes & \yes & 2014-12-03 \\
-% yax & 507.643 & 62.863 & 123.533 & \yes & \yes & 2010-01-22 \\
-% ltxkeys & 3932.759 & 4737.818 & 5883.000 & \no & \no & 2012-11-17 \\
+% keyval & 13.423 & 2.594 & 6.928 & \yes & \yes & 2014-10-28 \\
+% \expkv & 19.718 & 7.256 & 9.611 & \no & \no & 2020-04-07 \\
+% options & 23.436 & 15.618 & 19.920 & \yes & \yes & 2015-03-01 \\
+% pgfkeys & 24.577 & 46.244 & 52.770 & \yes & \yes & 2020-01-08 \\
+% kvsetkeys & {\fnsym} & {\fnsym} & 39.760 & \no & \no & 2019-12-15 \\
+% l3keys & 108.001 & 56.299 & 50.710 & \no & \no & 2020-02-25 \\
+% simplekv & 149.181 & 25.712 & 8.070 & \yes & \yes & 2017-08-08 \\
+% xkeyval & 248.777 & 234.420 & 161.900 & \yes & \yes & 2014-12-03 \\
+% yax & 443.584 & 170.471 & 115.700 & \yes & \yes & 2010-01-22 \\
+% ltxkeys & 3516.032 & 5254.811 & 5487.000 & \no & \no & 2012-11-17 \\
% \bottomrule
% \end{tabular}
% \par
@@ -593,13 +610,13 @@ and the derived files expkv.pdf
% \fnsym For \pkg{kvsetkeys} the linear model used for the other
% packages is a poor fit, \pkg{kvsetkeys} seems to have approximately
% quadratic run-time, the coefficients of the second degree polynomial fit are
-% $p_2=\num{9.911}$, $p_1=\num{40.523}$, and $p_0=\num{61.500}$. Of course the
+% $p_2=\num{7.473}$, $p_1=\num{51.276}$, and $p_0=\num{49.568}$. Of course the
% other packages might not really have linear run-time, but at least from 1~to
% 20~keys the fits don't seem too bad (the maximum ratio $p_2/p_1$
-% for the other packages is \num{9.697e-3}). If one extrapolates the fits
+% for the other packages is \num{3.478e-3}). If one extrapolates the fits
% for 100 \kv\ pairs one finds that most of them match pretty well, the
% exception being \pkg{ltxkeys}, which behaves quadratic as well with
-% $p_2=\num{31.685}$, $p_1=\num{3267.368}$, and $p_0=\num{7177.582}$.
+% $p_2=\num{11.396}$, $p_1=\num{3276.713}$, and $p_0=\num{6132.315}$.
% \end{table}
%
% \subsection{Examples}
@@ -683,7 +700,7 @@ and the derived files expkv.pdf
% To ignore duplicates will be easy if the value of the key used last will be
% put first in the list, so the following will use |\ekvsneakPre| for the
% user-level keys. If we wanted some key for which the first usage should be the
-% the binding one we would use |\ekvsneak| instead for that key.
+% binding one we would use |\ekvsneak| instead for that key.
%
% Providing default values can be done in different ways, we'll use a simple
% approach in which we'll just put the outcome of our keys if they were used
@@ -777,6 +794,30 @@ and the derived files expkv.pdf
% \edef\myval{\sine{f=tan}{1}}\texttt{\meaning\myval}
% \end{minipage}
%
+% \paragraph{The same macro using \protect\expkvc}
+% Using \expkvc\ we can set up something equivalent with a bit less code. The
+% implementation chosen in \expkvc\ is more efficient than the example above and
+% way easier to code.
+% \begin{lstlisting}
+% \makeatletter
+% \ekvcSplitAndForward\sine\sine@
+% {
+% f=sin,
+% unit=d,
+% round=3,
+% }
+% \ekvcSecondaryKeys\sine
+% {
+% nmeta degree={unit=d},
+% nmeta radian={unit={}},
+% }
+% \newcommand*\sine@[4]{\fpeval{round(#1#2(#4),#3)}}
+% \makeatother
+% \end{lstlisting}
+% The resulting macro will behave just like the one previously defined, but will
+% have an additional |unit| key, since in \expkvc\ every argument must have a
+% value taking key which defines it.
+%
%
% \subsection{Error Messages}
%
@@ -902,27 +943,28 @@ and the derived files expkv.pdf
% \gobbledocstriptag
%<*tex>
%
-% Check whether \eTeX\ is available -- \expkv\ requires \eTeX.
+% We make sure that it's only input once:
% \begin{macrocode}
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname numexpr\endcsname\relax
- \errmessage{expkv requires e-TeX}
+\expandafter\ifx\csname ekvVersion\endcsname\relax
+\else
\expandafter\endinput
\fi
% \end{macrocode}
%
-% We make sure that it's only input once:
+% Check whether \eTeX\ is available -- \expkv\ requires \eTeX.
% \begin{macrocode}
-\expandafter\ifx\csname ekvVersion\endcsname\relax
-\else
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname numexpr\endcsname\relax
+ \errmessage{expkv requires e-TeX}
\expandafter\endinput
\fi
% \end{macrocode}
+%
% \begin{macro}{\ekvVersion,\ekvDate}
% We're on our first input, so lets store the version and date in a macro.
% \begin{macrocode}
-\def\ekvVersion{0.5a}
-\def\ekvDate{2020-02-27}
+\def\ekvVersion{1.2}
+\def\ekvDate{2020-04-10}
% \end{macrocode}
% \end{macro}
%
@@ -948,7 +990,8 @@ and the derived files expkv.pdf
% \begin{macro}[internal]
% {
% \@gobble,\@firstofone,\@firstoftwo,\@secondoftwo,
-% \ekv@gobbleto@stop,\ekv@fi@secondoftwo,\ekv@gobble@mark
+% \ekv@gobbleto@stop,\ekv@fi@secondoftwo,\ekv@gobble@mark,
+% \ekv@gobble@from@mark@to@stop
% }
% Since branching tests are often more versatile than |\if...\else...\fi|
% constructs, we define helpers that are branching pretty fast. Also here are
@@ -962,6 +1005,7 @@ and the derived files expkv.pdf
\long\def\ekv@fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2}
\long\def\ekv@gobbleto@stop#1\ekv@stop{}
\def\ekv@gobble@mark\ekv@mark{}
+\long\def\ekv@gobble@from@mark@to@stop\ekv@mark#1\ekv@stop{}
% \end{macrocode}
% \end{macro}
% As you can see |\ekv@gobbleto@stop| uses a special marker |\ekv@stop|. The
@@ -974,7 +1018,8 @@ and the derived files expkv.pdf
% \begin{macro}[internal]
% {
% \ekv@ifempty,\ekv@ifempty@,\ekv@ifempty@true,\ekv@ifempty@false,
-% \ekv@ifempty@true@F
+% \ekv@ifempty@true@F,\ekv@ifempty@true@F@gobble,
+% \ekv@ifempty@true@F@gobbletwo
% }
% We can test for a lot of things building on an if-empty test, so lets define a
% really fast one. Since some tests might have reversed logic (true if something
@@ -989,6 +1034,11 @@ and the derived files expkv.pdf
\long\def\ekv@ifempty@true\ekv@ifempty@A\ekv@ifempty@B\@secondoftwo#1#2{#1}
\long\def\ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo#1#2{#2}
\long\def\ekv@ifempty@true@F\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1{}
+\long\def\ekv@ifempty@true@F@gobble\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2%
+ {}
+\long\def\ekv@ifempty@true@F@gobbletwo
+ \ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2#3%
+ {}
% \end{macrocode}
% \end{macro}
%
@@ -1019,54 +1069,6 @@ and the derived files expkv.pdf
}
% \end{macrocode}
% \end{macro}
- % \begin{macro}[internal]
-% {
-% \ekv@ifdefined@pair,\ekv@ifdefined@pair@,\ekv@ifdefined@key,
-% \ekv@ifdefined@key@
-% }
-% Since we can save some time if we only have to create the control sequence
-% once when we know beforehand how we want to use it, we build some other macros
-% for those cases (which we'll have quite often, once per key usage).
-% \begin{macrocode}
-\def\ekv@ifdefined@pair#1#2%
- {%
- \expandafter\ekv@ifdefined@pair@
- \csname
- \ifcsname #1{#2}\endcsname
- #1{#2}%
- \else
- relax%
- \fi
- \endcsname
- }
-\def\ekv@ifdefined@pair@#1%
- {%
- \ifx#1\relax
- \ekv@fi@secondoftwo
- \fi
- \@firstoftwo
- {\ekv@set@pair@#1\ekv@mark}%
- }
-\def\ekv@ifdefined@key#1#2%
- {%
- \expandafter\ekv@ifdefined@key@
- \csname
- \ifcsname #1{#2}N\endcsname
- #1{#2}N%
- \else
- relax%
- \fi
- \endcsname
- }
-\def\ekv@ifdefined@key@#1%
- {%
- \ifx#1\relax
- \ekv@fi@secondoftwo
- \fi
- \@firstoftwo#1%
- }
-% \end{macrocode}
-% \end{macro}
%
% \begin{macro}{\ekv@name,\ekv@name@set,\ekv@name@key}
% The keys will all follow the same naming scheme, so we define it here.
@@ -1076,6 +1078,7 @@ and the derived files expkv.pdf
\def\ekv@name@key#1{#1)}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@undefined@set}
% We can misuse the macro name we use to expandably store the set-name in a
% single token -- since this increases performance drastically, especially for
@@ -1088,10 +1091,14 @@ and the derived files expkv.pdf
\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@checkvalid}
% We place some restrictions on the allowed names, though, namely sets and
% keys are not allowed to be empty -- blanks are fine (meaning \mbox{set-
-% or} key-names consisting of spaces).
+% or} key-names consisting of spaces). The |\def\ekv@tmp| gobbles any \TeX\
+% prefixes which would otherwise throw errors. This will, however, break the
+% package if an |\outer| has been gobbled this way. I consider that good,
+% because keys shouldn't be defined |\outer| anyways.
% \begin{macrocode}
\protected\def\ekv@checkvalid#1#2%
{%
@@ -1112,6 +1119,7 @@ and the derived files expkv.pdf
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}{\ekvifdefined,\ekvifdefinedNoVal}
% And provide user-level macros to test whether a key is defined.
% \begin{macrocode}
@@ -1129,7 +1137,7 @@ and the derived files expkv.pdf
\ekv@checkvalid{#1}{#2}%
{%
\expandafter\def\csname\ekv@name{#1}{#2}\endcsname##1{#3}%
- \ekv@defset{#1}%
+ \expandafter\ekv@defset\csname\ekv@undefined@set{#1}\endcsname{#1}%
}%
}
\protected\long\def\ekvdefNoVal#1#2#3%
@@ -1137,7 +1145,7 @@ and the derived files expkv.pdf
\ekv@checkvalid{#1}{#2}%
{%
\expandafter\def\csname\ekv@name{#1}{#2}N\endcsname{#3}%
- \ekv@defset{#1}%
+ \expandafter\ekv@defset\csname\ekv@undefined@set{#1}\endcsname{#1}%
}%
}
\protected\def\ekvlet#1#2#3%
@@ -1145,7 +1153,7 @@ and the derived files expkv.pdf
\ekv@checkvalid{#1}{#2}%
{%
\expandafter\let\csname\ekv@name{#1}{#2}\endcsname#3%
- \ekv@defset{#1}%
+ \expandafter\ekv@defset\csname\ekv@undefined@set{#1}\endcsname{#1}%
}%
}
\protected\def\ekvletNoVal#1#2#3%
@@ -1153,7 +1161,7 @@ and the derived files expkv.pdf
\ekv@checkvalid{#1}{#2}%
{%
\expandafter\let\csname\ekv@name{#1}{#2}N\endcsname#3%
- \ekv@defset{#1}%
+ \expandafter\ekv@defset\csname\ekv@undefined@set{#1}\endcsname{#1}%
}%
}
\protected\def\ekvletkv#1#2#3#4%
@@ -1162,7 +1170,7 @@ and the derived files expkv.pdf
{%
\expandafter\let\csname\ekv@name{#1}{#2}\expandafter\endcsname
\csname\ekv@name{#3}{#4}\endcsname
- \ekv@defset{#1}%
+ \expandafter\ekv@defset\csname\ekv@undefined@set{#1}\endcsname{#1}%
}%
}
\protected\def\ekvletkvNoVal#1#2#3#4%
@@ -1171,20 +1179,22 @@ and the derived files expkv.pdf
{%
\expandafter\let\csname\ekv@name{#1}{#2}N\expandafter\endcsname
\csname\ekv@name{#3}{#4}N\endcsname
- \ekv@defset{#1}%
+ \expandafter\ekv@defset\csname\ekv@undefined@set{#1}\endcsname{#1}%
}%
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@defset}
% In order to enhance the speed the set name given to |\ekvset| will be turned
% into a control sequence pretty early, so we have to define that control
% sequence.
% \begin{macrocode}
-\protected\def\ekv@defset#1%
+\protected\def\ekv@defset#1#2%
{%
- \expandafter\edef\csname\ekv@undefined@set{#1}\endcsname##1%
- {\ekv@name@set{#1}\ekv@name@key{##1}}%
+ \ifx#1\relax
+ \edef#1##1{\ekv@name@set{#2}\ekv@name@key{##1}}%
+ \fi
}
% \end{macrocode}
% \end{macro}
@@ -1206,6 +1216,7 @@ and the derived files expkv.pdf
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@set}
% |\ekv@set| will split the \kv\ list at active commas. Then it has to check
% whether there were unprotected other commas and resplit there.
@@ -1215,7 +1226,7 @@ and the derived files expkv.pdf
% \end{macrocode}
% Test whether we're at the end, if so invoke |\ekv@endset|,
% \begin{macrocode}
- \ekv@gobbleto@markstop##2\ekv@endset\ekv@mark\ekv@stop
+ \ekv@gobble@from@mark@to@stop##2\ekv@endset\ekv@stop
% \end{macrocode}
% else go on with other commas,
% \begin{macrocode}
@@ -1227,83 +1238,160 @@ and the derived files expkv.pdf
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@endset}
% |\ekv@endset| is a hungry little macro. It will eat everything that remains
% of |\ekv@set| and unbrace the sneaked stuff.
% \begin{macrocode}
\long\def\ekv@endset
- \ekv@mark\ekv@stop\ekv@set@other##1,\ekv@stop,\ekv@set##2\ekv@mark
+ \ekv@stop\ekv@set@other##1,\ekv@stop,\ekv@set##2\ekv@mark
##3%
{##3}
% \end{macrocode}
% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@eq@other,\ekv@eq@active}
+% Splitting at equal signs will be done in a way that checks whether there is
+% an equal sign and splits at the same time. This gets quite messy and the
+% code might look complicated, but this is pretty fast (faster than first
+% checking for an equal sign and splitting if one is found). The splitting
+% code will be adapted for |\ekvset| and |\ekvparse| to get the most speed,
+% but some of these macros don't require such adaptions. |\ekv@eq@other| and
+% |\ekv@eq@active| will split the argument at the first equal sign and insert
+% the macro which comes after the first following |\ekv@mark|. This allows for
+% fast branching based on \TeX's argument grabbing rules and we don't have to
+% split after the branching if the equal sign was there.
+% \begin{macrocode}
+\long\def\ekv@eq@other##1=##2\ekv@mark##3##4\ekv@stop
+ {%
+ ##3##1\ekv@stop\ekv@mark##2%
+ }
+\long\def\ekv@eq@active##1#2##2\ekv@mark##3##4\ekv@stop
+ {%
+ ##3##1\ekv@stop\ekv@mark##2%
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[internal]{\ekv@set@other}
-% The macro |\ekv@set@other| is guaranteed to get only single \kv\ pairs.
-% First we test whether we're done, if not split at equal signs. It is faster to
-% first split at category 12 equal signs and only after that on actives.
-% If there is no equal sign, we need to test whether we got a blank argument and
-% if not this is a |NoVal| key.
+% The macro |\ekv@set@other| is guaranteed to get only single \kv\ pairs.
% \begin{macrocode}
\long\def\ekv@set@other##1##2,%
{%
- \ekv@gobbleto@markstop##2\ekv@endset@other\ekv@mark\ekv@stop
- \ekv@ifhas@eq@other##2=\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- {\ekv@set@eq@other##1##2\ekv@stop}%
- {%
- \ekv@ifhas@eq@active##2#2\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- {\ekv@set@eq@active##1##2\ekv@stop}%
- {%
- \ekv@ifblank@##2\ekv@nil\ekv@ifempty@B\ekv@ifempty@true@F
- \ekv@ifempty@A\ekv@ifempty@B\@firstofone
- {\ekv@strip{##2}\ekv@set@key##1}%
- }%
- }%
- \ekv@set@other##1\ekv@mark%
+% \end{macrocode}
+% First we test whether we're done.
+% \begin{macrocode}
+ \ekv@gobble@from@mark@to@stop##2\ekv@endset@other\ekv@stop
+% \end{macrocode}
+% If not we split at the equal sign of category other.
+% \begin{macrocode}
+ \ekv@eq@other##2\ekv@nil\ekv@mark\ekv@set@eq@other@a
+ =\ekv@mark\ekv@set@eq@active\ekv@stop
+% \end{macrocode}
+% And insert the set name and the next recursion step of |\ekv@set@other|.
+% \begin{macrocode}
+ ##1%
+ \ekv@set@other##1\ekv@mark
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}[internal]{\ekv@set@eq@other}
-% |\ekv@set@eq@other| might not be the correct break point, there might be an
-% active equal sign in the currently parsed key-name. If so, we have to resplit.
-% If the split is correct strip the key-name of outer spaces and braces and feed
-% it to |\ekv@set@pair|.
+%
+% \begin{macro}[internal]{\ekv@set@eq@other@a, \ekv@set@eq@other@b}
+% The first of these two macros runs the split-test for equal signs of
+% category active. It will only be inserted if the \kv\ pair contained at
+% least one equal sign of category other and |##1| will contain everything up
+% to that equal sign.
+% \begin{macrocode}
+\long\def\ekv@set@eq@other@a##1\ekv@stop
+ {%
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@other@active@a
+ #2\ekv@mark\ekv@set@eq@other@b\ekv@stop
+ }
+% \end{macrocode}
+% The second macro will have been called by |\ekv@eq@active| if no active
+% equal sign was found. All it does is remove the excess tokens of that
+% test and forward the \kv\ pair to |\ekv@set@pair|.
% \begin{macrocode}
-\long\def\ekv@set@eq@other##1##2=%
+\long\def\ekv@set@eq@other@b
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@other@active@a\ekv@stop\ekv@mark
{%
- \ekv@ifhas@eq@active##2#2\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- {\ekv@set@eq@active##1##2=}%
- {\ekv@strip{##2}\ekv@set@pair##1}%
+ \ekv@strip{##1}\ekv@set@pair
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}[internal]{\ekv@set@eq@active}
-% We need to handle the active equal signs.
+%
+% \begin{macro}[internal]{\ekv@set@eq@other@active@a,\ekv@set@eq@other@active@b}
+% |\ekv@set@eq@other@active@a| will be called if the \kv\ pair was wrongly
+% split on an equal sign of category other but has an earlier equal sign of
+% category active. |##1| will be the contents up to the active equal sign and
+% |##2| everything that remains until the first found other equal sign. It has
+% to reinsert the equal sign and passes things on to
+% |\ekv@set@eq@other@active@b| which calls |\ekv@set@pair| on the then
+% correctly split \kv\ pair.
% \begin{macrocode}
-\long\def\ekv@set@eq@active##1##2#2%
+\long\def\ekv@set@eq@other@active@a##1\ekv@stop##2\ekv@nil\ekv@mark
+ {%
+ \ekv@set@eq@other@active@b{##1}##2=%
+ }
+\long\def\ekv@set@eq@other@active@b##1%
{%
- \ekv@strip{##2}\ekv@set@pair##1%
+ \ekv@strip{##1}\ekv@set@pair
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}[internal]
-% {\ekv@ifhas@eq@other,\ekv@ifhas@eq@active,\ekv@endset@other}
-% And we have to set up the testing macros for our equal signs and
-% |\ekv@endset@other|.
+%
+% \begin{macro}[internal]{\ekv@set@eq@active, \ekv@set@eq@active@}
+% |\ekv@set@eq@active| will be called when there was no equal sign of category
+% other in the \kv\ pair. It removes the excess tokens of the prior test and
+% split-checks for an active equal sign.
+% \begin{macrocode}
+\long\def\ekv@set@eq@active
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@other@a\ekv@stop\ekv@mark
+ {%
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@active@
+ #2\ekv@mark\ekv@set@noeq\ekv@stop
+ }
+% \end{macrocode}
+% If an active equal sign was found in |\ekv@set@eq@active| we'll have to pass
+% the now split \kv\ pair on to |\ekv@set@pair|.
+% \begin{macrocode}
+\long\def\ekv@set@eq@active@##1\ekv@stop
+ {%
+ \ekv@strip{##1}\ekv@set@pair
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@set@noeq}
+% If no active equal sign was found by |\ekv@set@eq@active| there is no equal
+% sign contained in the parsed list entry. In that case we have to check
+% whether the entry is blank in order to ignore it (in which case we'll have
+% to gobble the set-name which was put after these tests by |\ekv@set@other|).
+% Else this is a |NoVal| key and the entry is passed on to |\ekv@set@key|.
+% \begin{macrocode}
+\long\def\ekv@set@noeq##1\ekv@nil\ekv@mark\ekv@set@eq@active@\ekv@stop\ekv@mark
+ {%
+ \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@ifempty@true@F@gobble
+ \ekv@ifempty@A\ekv@ifempty@B\@firstofone
+ {\ekv@strip{##1}\ekv@set@key}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@endset@other}
+% All that's left for |\ekv@set@other| is the macro which breaks the recursion
+% loop at the end. This is done by gobbling all the remaining tokens.
% \begin{macrocode}
-\long\def\ekv@ifhas@eq@other\ekv@mark##1={\ekv@ifempty@\ekv@ifempty@A}
-\long\def\ekv@ifhas@eq@active\ekv@mark##1#2{\ekv@ifempty@\ekv@ifempty@A}
\long\def\ekv@endset@other
- \ekv@mark\ekv@stop
- \ekv@ifhas@eq@other##1=\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ \ekv@stop
+ \ekv@eq@other##1\ekv@nil\ekv@mark\ekv@set@eq@other@a
+ =\ekv@mark\ekv@set@eq@active\ekv@stop
##2%
\ekv@set@other##3\ekv@mark
{}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
% Provide macros that can completely stop the parsing of |\ekvset|, who knows
% what it'll be useful for.
@@ -1313,6 +1401,7 @@ and the derived files expkv.pdf
\long\def\ekvbreakPostSneak##1##2\ekv@stop#1##3{##3##1}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}{\ekvsneak,\ekvsneakPre}
% One last thing we want to do for |\ekvset| is to provide macros that just
% smuggle stuff after |\ekvset|'s effects.
@@ -1341,90 +1430,123 @@ and the derived files expkv.pdf
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@parse}
% \begin{macrocode}
\long\def\ekv@parse##1##2##3#1%
{%
- \ekv@gobbleto@markstop##3\ekv@endparse\ekv@mark\ekv@stop
+ \ekv@gobble@from@mark@to@stop##3\ekv@endparse\ekv@stop
\ekv@parse@other##1##2##3,\ekv@stop,%
\ekv@parse##1##2\ekv@mark
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@endparse}
% \begin{macrocode}
\long\def\ekv@endparse
- \ekv@mark\ekv@stop\ekv@parse@other##1,\ekv@stop,\ekv@parse##2\ekv@mark
+ \ekv@stop\ekv@parse@other##1,\ekv@stop,\ekv@parse##2\ekv@mark
{}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@parse@other}
% \begin{macrocode}
\long\def\ekv@parse@other##1##2##3,%
{%
- \ekv@gobbleto@markstop##3\ekv@endparse@other\ekv@mark\ekv@stop
- \ekv@ifhas@eq@other##3=\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- {\ekv@parse@eq@other##3\ekv@stop##2}%
- {%
- \ekv@ifhas@eq@active##3#2\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- {\ekv@parse@eq@active##3\ekv@stop##2}%
- {%
- \ekv@ifblank@##3\ekv@nil\ekv@ifempty@B\ekv@ifempty@true@F
- \ekv@ifempty@A\ekv@ifempty@B\@firstofone
- {\ekv@strip{##3}\ekv@parse@key##1}%
- }%
- }%
+ \ekv@gobble@from@mark@to@stop##3\ekv@endparse@other\ekv@stop
+ \ekv@eq@other##3\ekv@nil\ekv@mark\ekv@parse@eq@other@a
+ =\ekv@mark\ekv@parse@eq@active\ekv@stop
+ ##1##2%
\ekv@parse@other##1##2\ekv@mark
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}[internal]{\ekv@parse@eq@other}
+%
+% \begin{macro}[internal]{\ekv@parse@eq@other@a,\ekv@parse@eq@other@b}
+% \begin{macrocode}
+\long\def\ekv@parse@eq@other@a##1\ekv@stop
+ {%
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active@a
+ #2\ekv@mark\ekv@parse@eq@other@b\ekv@stop
+ }
+\long\def\ekv@parse@eq@other@b
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active@a\ekv@stop\ekv@mark
+ {%
+ \ekv@strip{##1}\ekv@parse@pair
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekv@parse@eq@other@active@a,\ekv@parse@eq@other@active@b}
+% \begin{macrocode}
+\long\def\ekv@parse@eq@other@active@a##1\ekv@stop##2\ekv@nil\ekv@mark
+ {%
+ \ekv@parse@eq@other@active@b{##1}##2=%
+ }
+\long\def\ekv@parse@eq@other@active@b##1%
+ {%
+ \ekv@strip{##1}\ekv@parse@pair
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@eq@active,\ekv@parse@eq@active@}
% \begin{macrocode}
-\long\def\ekv@parse@eq@other##1=%
+\long\def\ekv@parse@eq@active
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@other@a\ekv@stop\ekv@mark
+ {%
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@active@
+ #2\ekv@mark\ekv@parse@noeq\ekv@stop
+ }
+\long\def\ekv@parse@eq@active@##1\ekv@stop
{%
- \ekv@ifhas@eq@active##1#2\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- {\ekv@parse@eq@active##1=}%
- {\ekv@strip{##1}\ekv@parse@pair\ekv@mark}%
+ \ekv@strip{##1}\ekv@parse@pair
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}[internal]{\ekv@parse@eq@active}
+%
+% \begin{macro}[internal]{\ekv@parse@noeq}
% \begin{macrocode}
-\long\def\ekv@parse@eq@active##1#2%
+\long\def\ekv@parse@noeq
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@active@\ekv@stop\ekv@mark
{%
- \ekv@strip{##1}\ekv@parse@pair\ekv@mark
+ \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@ifempty@true@F@gobbletwo
+ \ekv@ifempty@A\ekv@ifempty@B\@firstofone
+ {\ekv@strip{##1}\ekv@parse@key}%
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@endparse@other}
% \begin{macrocode}
\long\def\ekv@endparse@other
- \ekv@mark\ekv@stop
- \ekv@ifhas@eq@other##1=\ekv@ifempty@B\ekv@ifempty@false
- \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ \ekv@stop
+ \ekv@eq@other##1\ekv@nil\ekv@mark\ekv@parse@eq@other@a
+ =\ekv@mark\ekv@parse@eq@active\ekv@stop
##2%
\ekv@parse@other##3\ekv@mark
{}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@parse@pair,\ekv@parse@pair@}
% \begin{macrocode}
-\long\def\ekv@parse@pair##1##2\ekv@stop
+\long\def\ekv@parse@pair##1##2\ekv@nil
{%
\ekv@strip{##2}\ekv@parse@pair@{##1}%
}
-\long\def\ekv@parse@pair@##1##2##3%
+\long\def\ekv@parse@pair@##1##2##3##4%
{%
- \unexpanded{##3{##2}{##1}}%
+ \unexpanded{##4{##2}{##1}}%
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@parse@key}
% \begin{macrocode}
-\long\def\ekv@parse@key##1##2%
+\long\def\ekv@parse@key##1##2##3%
{%
\unexpanded{##2{##1}}%
}
@@ -1455,6 +1577,7 @@ and the derived files expkv.pdf
}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]{\ekv@changeset}
% This macro does the real change-out of |\ekvchangeset|. We introduced an
% |\ekv@mark| to not accidentally remove some braces which we have to remove
@@ -1468,58 +1591,59 @@ and the derived files expkv.pdf
% \end{macro}
%
%
-% \begin{macro}[internal]{\ekv@gobbleto@markstop}
-% The |\ekv@gobbleto@markstop| can be used to test for |\ekv@stop| similar to
-% our if-empty test, but instead of using tokens which are used nowhere else
-% (|\ekv@ifempty@A| and |\ekv@ifempty@B|) it uses |\ekv@mark| and |\ekv@stop|.
+% \begin{macro}[internal]{\ekv@set@pair}
+% |\ekv@set@pair| gets invoked with the space and brace stripped key-name as
+% its first argument, the value as the second argument, and the set name as
+% the third argument. It builds the key-macro name and provides everything to
+% be able to throw meaningful error messages if it isn't defined.
+% |\ekv@set@pair@| will space and brace strip the value if the macro is
+% defined and call the key-macro. Else it'll branch into the error messages
+% provided by |\ekv@set@pair|.
% \begin{macrocode}
-\long\def\ekv@gobbleto@markstop#1\ekv@mark\ekv@stop{}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@set@pair,\ekv@set@pair@}
-% |\ekv@set@pair| gets invoked with the space and brace stripped key-name as its
-% first argument, the set-macro as the second argument, and following that is
-% the key-value right delimited by an |\ekv@stop|.
-% \begin{macrocode}
-\long\def\ekv@set@pair#1#2%
+\long\def\ekv@set@pair#1#2\ekv@nil#3%
{%
- \ekv@ifdefined@pair#2{#1}%
+ \expandafter\ekv@set@pair@
+ \csname
+ \ifcsname #3{#1}\endcsname
+ #3{#1}%
+ \else
+ relax%
+ \fi
+ \endcsname
+ {#2}%
{%
-% \end{macrocode}
-% This branch will be executed if the key is not defined as an argument grabbing
-% one. If so test whether there is a |NoVal| key of the same name or whether the
-% key is unknown. Throw a meaningful error message and gobble the value.
-% \begin{macrocode}
- \ekv@ifdefined{#2{#1}N}%
+ \ekv@ifdefined{#3{#1}N}%
\ekv@err@noarg
\ekv@err@unknown
- #2{#1}%
- \ekv@gobbleto@stop
+ #3{#1}%
}%
}
-% \end{macrocode}
-% |\ekv@ifdefined@pair| will call |\ekv@set@pair@| if the key is correctly
-% defined. This will then grab the value, strip outer spaces and braces from it
-% and feed it to the key-macro. Afterwards |\ekv@set@other| will take control
-% again.
-% \begin{macrocode}
-\long\def\ekv@set@pair@#1#2\ekv@stop
+\long\def\ekv@set@pair@#1#2%
{%
- \ekv@strip{#2}#1%
+ \ifx#1\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ {\ekv@strip{#2}#1}%
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@set@key}
-% Analogous to |\ekv@set@pair|, |\ekv@set@key| lets |\ekv@ifdefined@key| test
-% whether a |NoVal| key is defined, else it'll throw a meaningful error message.
-% Since we don't have to grab any value |\ekv@ifdefined@key| will invoke the
-% key-macro and we're done here, |\ekv@set@other| will take over again.
+% Analogous to |\ekv@set@pair|, |\ekv@set@key| builds the |NoVal| key-macro and
+% provides an error-branch. |\ekv@set@key@| will test whether the key-macro is
+% defined and if so call it, else the errors are thrown.
% \begin{macrocode}
\long\def\ekv@set@key#1#2%
{%
- \ekv@ifdefined@key#2{#1}%
+ \expandafter\ekv@set@key@
+ \csname
+ \ifcsname #2{#1}N\endcsname
+ #2{#1}N%
+ \else
+ relax%
+ \fi
+ \endcsname
{%
\ekv@ifdefined{#2{#1}}%
\ekv@err@reqval
@@ -1527,6 +1651,13 @@ and the derived files expkv.pdf
#2{#1}%
}%
}
+\def\ekv@set@key@#1%
+ {%
+ \ifx#1\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo#1%
+ }
% \end{macrocode}
% \end{macro}
%
@@ -1542,7 +1673,7 @@ and the derived files expkv.pdf
\unexpanded{\long\def\ekv@err}##1%
{%
\unexpanded{\expandafter\ekv@err@\@firstofone}%
- {\expandafter\noexpand\csname ! expkv Error:\endcsname ##1.}%
+ {\unexpanded\expandafter{\csname ! expkv Error:\endcsname}##1.}%
\unexpanded{\ekv@stop}%
}%
}
@@ -1550,6 +1681,7 @@ and the derived files expkv.pdf
\def\ekv@err@{\expandafter\ekv@gobbleto@stop}
% \end{macrocode}
% \end{macro}
+%
% \begin{macro}[internal]
% {
% \ekv@err@common,\ekv@err@common@,