summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2020-10-11 20:49:36 +0000
committerKarl Berry <karl@freefriends.org>2020-10-11 20:49:36 +0000
commit594d9d83472299aca8bfbe9f123b418cbc40d4ca (patch)
tree55fdc6e1bd56082bdbed20db8da98f1ef3d9382f
parent2579db312dc508bbbe9e4ba31a8a510545f69503 (diff)
expkv (11oct20)
git-svn-id: svn://tug.org/texlive/trunk@56634 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/latex/expkv/README.md2
-rw-r--r--Master/texmf-dist/doc/latex/expkv/expkv.pdfbin397919 -> 410888 bytes
-rw-r--r--Master/texmf-dist/source/latex/expkv/expkv.dtx961
-rw-r--r--Master/texmf-dist/tex/generic/expkv/expkv.tex592
4 files changed, 953 insertions, 602 deletions
diff --git a/Master/texmf-dist/doc/latex/expkv/README.md b/Master/texmf-dist/doc/latex/expkv/README.md
index c885f8a0d06..730b302b5a4 100644
--- a/Master/texmf-dist/doc/latex/expkv/README.md
+++ b/Master/texmf-dist/doc/latex/expkv/README.md
@@ -1,7 +1,7 @@
-------------------------------------------------------------------------------
# expkv -- an expandable key=val implementation
-Version 2020-07-04 v1.4
+Version 2020-10-10 v1.5
Released under the LaTeX Project Public License v1.3c or later
See http://www.latex-project.org/lppl.txt
diff --git a/Master/texmf-dist/doc/latex/expkv/expkv.pdf b/Master/texmf-dist/doc/latex/expkv/expkv.pdf
index 627341a78ff..4396ddfee2f 100644
--- a/Master/texmf-dist/doc/latex/expkv/expkv.pdf
+++ b/Master/texmf-dist/doc/latex/expkv/expkv.pdf
Binary files differ
diff --git a/Master/texmf-dist/source/latex/expkv/expkv.dtx b/Master/texmf-dist/source/latex/expkv/expkv.dtx
index f804e6ee0fe..3cd8479be56 100644
--- a/Master/texmf-dist/source/latex/expkv/expkv.dtx
+++ b/Master/texmf-dist/source/latex/expkv/expkv.dtx
@@ -70,6 +70,7 @@ and the derived files expkv.pdf
\RequirePackage{array}
\RequirePackage{collcell}
\RequirePackage{siunitx}
+\DeclareSIUnit\ops{ops}
\RequirePackage{xcolor}
\RequirePackage{caption}
\RequirePackage{microtype}
@@ -102,6 +103,19 @@ and the derived files expkv.pdf
\definecolor{expkvred}{HTML}{9F393D}
\colorlet{expkvgrey}{black!75}
\makeatletter
+\newcommand*\expFormat
+ {^^A
+ {^^A
+ \rmfamily
+ \bfseries
+ {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A
+ \lower.493ex\hbox{{\color{expkvgrey}P}}^^A
+ }^^A
+ }
+\newcommand*\kvstyle
+ {^^A
+ \normalfont\rmfamily\bfseries\color{expkvred}^^A
+ }
\newcommand*\expkv
{^^A
\texorpdfstring
@@ -158,7 +172,7 @@ and the derived files expkv.pdf
\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,\detokenize}
+\DoNotIndex{\@,\unexpanded,\string,\expanded,\detokenize,\meaning,\lastnamedcs}
\DoNotIndex{\ifcsname}
\DoNotIndex{\ifx}
\DoNotIndex{\else}
@@ -182,7 +196,10 @@ and the derived files expkv.pdf
{^^A
\huge\expkv
\\[\medskipamount]
- \Large an expandable \kv\ implementation^^A
+ \Large an {\expFormat}andable
+ \meta{{\kvstyle k}\kern-.05em ey}=^^A
+ \meta{{\kvstyle v}\kern-.05em alue}
+ implementation^^A
}{expkv - an expandable <key>=<value> implementation}^^A
}
\date{\ekvDate\space v\ekvVersion}
@@ -198,10 +215,10 @@ and the derived files expkv.pdf
% \begin{abstract}
% \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} is one and a
-% half times as fast, but not expandable and it might strip braces it shouldn't
-% have stripped).
+% \emph{fully expandable}, the \meta{code} of your keys might be not. \expkv\ is
+% \emph{swift}, close to the fastest \kv\ implementation. However it is the
+% fastest which copes with active commas and equal signs and doesn't strip
+% braces accidentally.
% \end{abstract}
%
% \tableofcontents
@@ -259,7 +276,7 @@ and the derived files expkv.pdf
% 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.
% \set\ will be used as is inside of |\csname ...\endcsname| and \key\ will get
-% \cs[no-index]{detokenize}d.
+% |\detokenize|d.
%
% \begin{function}{\ekvdef}
% \begin{syntax}
@@ -297,7 +314,8 @@ and the derived files expkv.pdf
% \cs{ekvletkv}\marg{set}\marg{key}\marg{set2}\marg{key2}
% \end{syntax}
% Let the \key\ in \set\ to \meta{key2} in \meta{set2}, it is not checked
-% whether that second key exists.
+% whether that second key exists (but take a look at
+% \cs[no-index]{ekvifdefined}).
% \end{function}
%
% \begin{function}{\ekvletkvNoVal}
@@ -305,7 +323,8 @@ and the derived files expkv.pdf
% \cs{ekvletkvNoVal}\marg{set}\marg{key}\marg{set2}\marg{key2}
% \end{syntax}
% Let the \key\ in \set\ to \meta{key2} in \meta{set2}, it is not checked
-% whether that second key exists.
+% whether that second key exists (but take a look at
+% \cs[no-index]{ekvifdefinedNoVal}).
% \end{function}
%
% \begin{function}{\ekvdefunknown}
@@ -349,18 +368,59 @@ and the derived files expkv.pdf
% |\ekvset| should be nestable.
% \end{function}
%
+% \begin{function}{\ekvsetSneaked}
+% \begin{syntax}
+% \cs{ekvsetSneaked}\marg{set}\marg{sneak}\{\kv,\ldots\}
+% \end{syntax}
+% Just like \cs[no-index]{ekvset}, this macro parses the \kv\ pairs within the
+% given \set. But \cs[no-index]{ekvsetSneaked} will behave as if
+% \cs[no-index]{ekvsneak} has been called with \meta{sneak} as its argument as
+% the first action.
+% \end{function}
+%
% \begin{function}{\ekvsetdef}
% \begin{syntax}
% \cs{ekvsetdef}\meta{cs}\marg{set}
% \end{syntax}
% With this function you can define a shorthand macro \meta{cs} to parse keys
% of a specified \set. It is always defined |\long|, but if you need to you
-% can also prefix it with |\global|. The resulting macro is a bit faster than
-% the idiomatic definition:\par
+% can also prefix it with |\global|. The resulting macro is faster than but
+% else equivalent to the idiomatic definition:\par
% \texttt
% {\string\long\string\def\meta{cs}\#1\{\string\ekvset\marg{set}\{\#1\}\}}
% \end{function}
%
+% \begin{function}{\ekvsetSneakeddef}
+% \begin{syntax}
+% \cs{ekvsetSneakeddef}\meta{cs}\marg{set}
+% \end{syntax}
+% Just like \cs[no-index]{ekvsetdef} this defines a shorthand macro \meta{cs},
+% but this macro will make it a shorthand for \cs[no-index]{ekvsetSneaked},
+% meaning that \meta{cs} will take two arguments, the first being stuff that
+% should be given to \cs[no-index]{ekvsneak} and the second the \kv\ list. The
+% resulting macro is faster than but else equivalent to the idiomatic
+% definition:\par
+% \texttt
+% {%
+% \string\long\string\def\meta{cs}\#1\#2\{^^A
+% \string\ekvsetSneaked\marg{set}\{\#1\}\{\#2\}\}^^A
+% }
+% \end{function}
+%
+% \begin{function}{\ekvsetdefSneaked}
+% \begin{syntax}
+% \cs{ekvsetSneakeddef}\meta{cs}\marg{set}\marg{sneaked}
+% \end{syntax}
+% And this one behaves like \cs[no-index]{ekvsetSneakeddef} but with a fixed
+% \meta{sneaked} argument. So the resulting macro is faster than but else
+% equivalent to the idiomatic definition:\par
+% \texttt
+% {%
+% \string\long\string\def\meta{cs}\#1\{^^A
+% \string\ekvsetSneaked\marg{set}\marg{sneaked}\{\#1\}\}^^A
+% }
+% \end{function}
+%
% \begin{function}{\ekvparse}
% \begin{syntax}
% \cs{ekvparse}\meta{cs1}\meta{cs2}\{\kv,\ldots\}
@@ -457,8 +517,9 @@ and the derived files expkv.pdf
% \meta{after} after any other tokens which might have been sneaked before,
% while |\ekvsneakPre| will put \meta{after} before other smuggled stuff.
% This reads and reinserts the remainder of the current |\ekvset| macro and
-% its argument list to do its job. A small usage example is shown in
-% \autoref{sec:sneakex}.
+% its argument list to do its job. After |\ekvset| has parsed the entire \kv\
+% list everything that has been |\ekvsneak|ed will be left in the input
+% stream. A small usage example is shown in \autoref{sec:sneakex}.
% \end{function}
%
% \begin{function}{\ekvchangeset}
@@ -481,20 +542,17 @@ and the derived files expkv.pdf
% \cs{ekv@name@key}\marg{key}
% \end{syntax}
% The names of the macros that correspond to a key in a set are build with
-% these macros. The default definition of |\ekv@name@set| is
-% ``\texttt{\csname ekv@name@set\endcsname{\set}}'' and the default of
-% |\ekv@name@key| is ``\texttt{\csname ekv@name@key\endcsname{\key}}''.
-% The complete name is build using |\ekv@name| which is equivalent to
-% \texttt
-% {^^A
-% \cs[no-index]{ekv@name@set}\marg{set}\cs{ekv@name@key}^^A
-% \{\cs[no-index]{detokenize}\marg{key}\}^^A
-% }.
+% these macros. The name is built from two blocks, one that is formatting the
+% \set\ name (|\ekv@name@set|) and one for formatting the \key\ name
+% (|\ekv@name@key|). To get the actual name the argument to |\ekv@name@key|
+% must be |\detokenize|d. Both blocks are put together (with the necessary
+% |\detokenize|) by |\ekv@name|.
% For |NoVal| keys an additional |N| gets appended irrespective of these
% macros' definition, so their name is
-% \cs[no-index]{\csname ekv@name\endcsname{\set}{\key}N}. You might redefine
-% |\ekv@name@set| and |\ekv@name@key| locally but \emph{don't redefine}
-% |\ekv@name|!
+% \texttt{\cs[no-index]{ekv@name}\marg{set}\marg{key}N}.\par
+% You can use these macros to implement additional functionality or access key
+% macros outside of \expkv, but \emph{don't} change them! \expkv\ relies on
+% their exact definitions internally.
% \end{function}
%
% \subsubsection{Bugs}
@@ -510,7 +568,8 @@ and the derived files expkv.pdf
% \pkg{l3benchmark} package. The key and its usage should be equivalent to
% \begin{lstlisting}
% \protected\ekvdef{test}{height}{\def\myheight{#1}}
-% \ekvset{test}{ height = 6 }
+% \ekvsetdef\expkvtest{test}
+% \expkvtest{ height = 6 }
% \end{lstlisting}
% and only the usage of the key, not its definition, is benchmarked. For the
% impatient, the essence of these comparisons regarding speed and buggy
@@ -527,14 +586,17 @@ and the derived files expkv.pdf
% contained, as most other packages don't provide equivalent features to my
% knowledge. |\ekvparse| is slightly faster than |\ekvset|, but keep in mind
% 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 $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
-% someone loads \pkg{xkeyval} the performance of \pkg{keyval} gets replaced by
-% \pkg{xkeyval}'s.
+% |\keys_set:nn| of \pkg{expl3} (where the difference is much bigger). Comparing
+% just the two, |\ekvparse| is a tad faster than |\keyval_parse:NNn| because of
+% the two tests (for empty key names and only a single equal sign) which are
+% omitted.
+%
+% \paragraph{\pkg{keyval}} is about \SIrange{30}{40}{\percent} 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 someone loads \pkg{xkeyval} the performance of
+% \pkg{keyval} gets replaced by \pkg{xkeyval}'s.
%
% Also \pkg{keyval} has a bug, which unfortunately can't really be resolved
% without breaking backwards compatibility for \emph{many} documents, namely it
@@ -545,49 +607,58 @@ and the derived files expkv.pdf
% \begin{lstlisting}[belowskip=0pt]
% \setkeys{foo}{bar=baz}
% \setkeys{foo}{bar= {baz}}
-% \setkeys{foo}{bar={ baz}}
-% \setkeys{foo}{bar={{baz}}}
+% \setkeys{foo}{bar={ baz}} % should be ` baz'
+% \setkeys{foo}{bar={{baz}}} % should be `{baz}'
% \end{lstlisting}
%
-% \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 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
+% \paragraph{\pkg{xkeyval}} is roughly twenty 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 no longer compatible with the \LaTeX\ kernel
+% starting with the release 2020-10-01. It is over 380 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 five 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. 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 around $2.7$ times slower for one key,
-% but has an \emph{enormous} feature set.
+% \url{https://tex.stackexchange.com/questions/461783}). Because it is no longer
+% compatible with the kernel, I stop benchmarking it (so the numbers listed here
+% and in \autoref{tab:comp} regarding \pkg{ltxkeys} were last updated on
+% 2020-10-05).
+%
+% \paragraph{\pkg{l3keys}} is around four and a half 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.
+%
+% \paragraph{\pkg{pgfkeys}} is around \num{2.7} times slower for one key if one
+% uses the |/|\meta{path}|/.cd| syntax and almost \SI{20}{\percent} slower if
+% one uses |\pgfqkeys|, but has an \emph{enormous} feature set.
+% To get the best performance |\pgfqkeys| was used in the benchmark. This
+% reduces the overhead for setting the base directory of the benchmark keys by
+% about \SI{43}{\ops} (so both $p_0$ and $T_0$ would be about \SI{43}{\ops}
+% bigger if |\pgfkeys{|\meta{path}|/.cd,|\meta{keys}|}| was used instead).
% 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.
+% was last updated in 2012 and it slows down |\pgfkeys| by factor~\num{8}. Also
+% \pkg{pgfkeyx} is no longer compatible with versions of \pkg{pgfkeys} newer
+% than 2020-05-25.
%
-% \paragraph{\pkg{kvsetkeys} with \pkg{kvdefinekeys}} is about $3.7$ times
+% \paragraph{\pkg{kvsetkeys} with \pkg{kvdefinekeys}} is about \num{4.4} 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 $1.5$ times slower for only a single value. It
-% has a much bigger feature set. Unfortunately it also suffers from the
+% \paragraph{\pkg{options}} is \num{1.7} 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
@@ -597,10 +668,11 @@ and the derived files expkv.pdf
% packages. It has problems with stripping braces and spaces in a hard to
% predict manner just like \pkg{keyval}. Also, while it tries to be robust
% against category code changes of commas and equal signs, the used mechanism
-% fails if the \kv\ list already got tokenized. Regarding unknown keys it got a
+% fails if the \kv\ list already got tokenised. Regarding unknown keys it got a
% very interesting behaviour. It doesn't throw an error, but stores the \val\ in
% a new entry accessible with \cs[no-index]{useKV}. Also if you omit \val\ it
-% stores |true| for that \key. It is around $10\,\%$ faster than \expkv.
+% stores |true| for that \key. For up to three keys, \expkv\ is a bit faster,
+% for more keys \pkg{simplekv} takes the lead.
%
% \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
@@ -640,16 +712,16 @@ and the derived files expkv.pdf
% \toprule
% \rmfamily Package & {$p_1$} & {$p_0$} & {$T_0$}& BB & CF & Date \\
% \midrule
-% keyval & 13.694 & 1.504 & 7.008 & \yes & \yes & 2014-10-28 \\
-% simplekv & 18.739 & 5.325 & 17.68 & \yes & \yes & 2020-04-27 \\
-% \expkv & 22.007 & 3.100 & 10.095 & \no & \no & 2020-06-21 \\
-% options & 24.351 & 12.010 & 20.38 & \yes & \yes & 2015-03-01 \\
-% pgfkeys & 24.621 & 45.474 & 53.25 & \yes & \yes & 2020-06-17 \\
-% kvsetkeys & {\fnsym} & {\fnsym} & 40.0 & \no & \no & 2019-12-15 \\
-% l3keys & 92.103 & 32.724 & 38.05 & \no & \no & 2020-06-18 \\
-% xkeyval & 257.125 & 173.704 & 164.5 & \yes & \yes & 2014-12-03 \\
-% yax & 440.234 & 76.276 & 113.9 & \yes & \yes & 2010-01-22 \\
-% ltxkeys & 3448.339 & 4470.031 & 5241.0 & \no & \no & 2012-11-17 \\
+% keyval & 13.742 & 1.486 & 7.254 & \yes & \yes & 2014-10-28 \\
+% \expkv & 19.701 & 2.169 & 6.592 & \no & \no & 2020-10-10 \\
+% simplekv & 18.334 & 6.971 & 17.710 & \yes & \yes & 2020-04-27 \\
+% pgfkeys & 24.274 & 1.725 & 10.650 & \yes & \yes & 2020-09-05 \\
+% options & 23.600 & 15.638 & 20.830 & \yes & \yes & 2015-03-01 \\
+% kvsetkeys & {\fnsym} & {\fnsym} & 40.290 & \no & \no & 2019-12-15 \\
+% l3keys & 71.309 & 33.131 & 31.590 & \no & \no & 2020-09-24 \\
+% xkeyval & 253.563 & 202.246 & 168.300 & \yes & \yes & 2014-12-03 \\
+% yax & 421.853 & 157.003 & 114.700 & \yes & \yes & 2010-01-22 \\
+% ltxkeys & 3400.142 & 4737.958 & 5368.000 & \no & \no & 2012-11-17 \\
% \bottomrule
% \end{tabular}
% \par
@@ -658,12 +730,12 @@ 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{8.811}$, $p_1=\num{36.015}$, and $p_0=\num{81.792}$. Of course the
+% $p_2=\num{8.240}$, $p_1=\num{44.862}$, and $p_0=\num{60.793}$. 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. 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{29.496}$, $p_1=\num{2828.933}$, and $p_0=\num{6741.189}$.
+% $p_2=\num{23.500}$, $p_1=\num{2906.634}$, and $p_0=\num{6547.489}$.
% \end{table}
%
% \subsection{Examples}
@@ -672,7 +744,7 @@ and the derived files expkv.pdf
%
% Say we have a macro for which we want to create a \kv\ interface. The macro
% has a parameter, which is stored in the dimension |\ourdim| having a default
-% value from its initialization. Now we want to be able to change that dimension
+% value from its initialisation. Now we want to be able to change that dimension
% with the |width| key to some specified value. For that we'd do
% \begin{lstlisting}
% \newdimen\ourdim
@@ -1010,8 +1082,8 @@ and the derived files expkv.pdf
% \begin{macro}{\ekvVersion,\ekvDate}
% We're on our first input, so lets store the version and date in a macro.
% \begin{macrocode}
-\def\ekvVersion{1.4}
-\def\ekvDate{2020-07-04}
+\def\ekvVersion{1.5}
+\def\ekvDate{2020-10-10}
% \end{macrocode}
% \end{macro}
%
@@ -1034,6 +1106,34 @@ and the derived files expkv.pdf
% restore it at the end of the file, we never care for the actual definition of
% it.
%
+% \begin{macro}[internal]{\ekv@if@lastnamedcs}
+% If the primitive |\lastnamedcs| is available, we can be a bit faster than
+% without it. So we test for this and save the test's result in this macro.
+% \begin{macrocode}
+\begingroup
+ \edef\ekv@tmpa{\string \lastnamedcs}
+ \edef\ekv@tmpb{\meaning\lastnamedcs}
+ \ifx\ekv@tmpa\ekv@tmpb
+ \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##1}}
+ \else
+ \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##2}}
+ \fi
+ \expandafter
+\endgroup
+\ekv@if@lastnamedcs
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@empty}
+% Sometimes we have to introduce a token to prevent accidental brace stripping.
+% This token would then need to be removed by |\@gobble| or similar. Instead we
+% can use |\ekv@empty| which will just expand to nothing, that is faster than
+% gobbling an argument.
+% \begin{macrocode}
+\def\ekv@empty{}
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[internal]
% {
% \@gobble,\@firstofone,\@firstoftwo,\@secondoftwo,
@@ -1112,28 +1212,89 @@ and the derived files expkv.pdf
%
% \begin{macro}[internal]{\ekv@ifdefined}
% We'll need to check whether something is defined quite frequently, so why not
-% define a macro that does this. The following test is expandable, slower than
-% the typical expandable test for undefined control sequences, but faster for
-% defined ones. Since we want to be as fast as possible for correct input, this
-% is to be preferred.
+% define a macro that does this. The following test is expandable and pretty
+% fast. The version with |\lastnamedcs| is the fastest version to test for an
+% undefined macro I know of (that considers both undefined macros and those with
+% the meaning |\relax|).
% \begin{macrocode}
-\def\ekv@ifdefined#1%
+\ekv@if@lastnamedcs
{%
- \expandafter
- \ifx\csname\ifcsname #1\endcsname #1\else relax\fi\endcsname\relax
- \ekv@fi@secondoftwo
- \fi
- \@firstoftwo
+ \def\ekv@ifdefined#1{\ifcsname#1\endcsname\ekv@ifdef@\fi\@secondoftwo}
+ \def\ekv@ifdef@\fi\@secondoftwo
+ {%
+ \fi
+ \expandafter\ifx\lastnamedcs\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ }
+ }
+ {%
+ \def\ekv@ifdefined#1%
+ {%
+ \ifcsname#1\endcsname\ekv@ifdef@\fi\ekv@ifdef@false#1\endcsname\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ }
+ \def\ekv@ifdef@\fi\ekv@ifdef@false{\fi\expandafter\ifx\csname}
+ \long\def\ekv@ifdef@false
+ #1\endcsname\relax\ekv@fi@secondoftwo\fi\@firstoftwo#2#3%
+ {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@strip,\ekv@strip@a,\ekv@strip@b,\ekv@strip@c}
+% We borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
+% from keys and values. This |\ekv@strip| also strips one level of outer braces
+% \emph{after} stripping spaces, so an input of | {abc} | becomes |abc| after
+% stripping. It should be used with |#1| prefixed by |\ekv@mark|. Also this
+% implementation at most strips \emph{one} space from both sides (which should
+% be fine most of the time, since \TeX\ reads consecutive spaces as a single one
+% during tokenisation).
+% \begin{macrocode}
+\def\ekv@strip#1%
+ {%
+ \long\def\ekv@strip##1%
+ {%
+ \ekv@strip@a
+ ##1\ekv@nil
+ \ekv@mark#1%
+ #1\ekv@nil
+ \ekv@stop
+ }%
+ \long\def\ekv@strip@a##1\ekv@mark#1{\ekv@strip@b##1\ekv@mark}%
+ \long\def\ekv@strip@b##1#1\ekv@nil {\ekv@strip@c##1\ekv@nil}%
+ }
+\ekv@strip{ }
+\long\def\ekv@strip@c\ekv@mark#1\ekv@nil\ekv@mark#2\ekv@nil\ekv@stop#3{#3{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@expB@unbraceA,\ekv@expB@unbraceA@}
+% To reduce some code doublets while gaining some speed, it is often useful to
+% expand the first token in a definition once. Let's define a wrapper for this.
+% \begin{macrocode}
+\long\def\ekv@expB@unbraceA#1#2%
+ {%
+ \expandafter\ekv@expB@unbraceA@\expandafter{#2}{#1}%
}
+\long\def\ekv@expB@unbraceA@#1#2{#2{#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.
% \begin{macrocode}
-\def\ekv@name#1#2{\ekv@name@set{#1}\ekv@name@key{\detokenize{#2}}}
\def\ekv@name@set#1{ekv#1(}
\def\ekv@name@key#1{#1)}
+\edef\ekv@name
+ {%
+ \unexpanded\expandafter{\ekv@name@set{#1}}%
+ \unexpanded\expandafter{\ekv@name@key{\detokenize{#2}}}%
+ }
+\ekv@expB@unbraceA{\def\ekv@name#1#2}{\ekv@name}
% \end{macrocode}
% \end{macro}
%
@@ -1158,31 +1319,38 @@ and the derived files expkv.pdf
% 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%
+\edef\ekv@checkvalid
{%
- \ekv@ifempty{#1}%
- {%
+ \unexpanded\expandafter{\ekv@ifempty{#1}}%
+ \unexpanded
+ {{%
\def\ekv@tmp{}%
\errmessage{expkv Error: empty set name not allowed}%
- }%
+ }}%
{%
- \ekv@ifempty{#2}%
+ \unexpanded\expandafter{\ekv@ifempty{#2}}%
+ \unexpanded
{%
- \def\ekv@tmp{}%
- \errmessage{expkv Error: empty key name not allowed}%
+ {%
+ \def\ekv@tmp{}%
+ \errmessage{expkv Error: empty key name not allowed}%
+ }%
+ \@secondoftwo
}%
- \@secondoftwo
}%
- \@gobble
+ \unexpanded{\@gobble}%
}
+\ekv@expB@unbraceA{\protected\def\ekv@checkvalid#1#2}{\ekv@checkvalid}%
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvifdefined,\ekvifdefinedNoVal}
% And provide user-level macros to test whether a key is defined.
% \begin{macrocode}
-\def\ekvifdefined#1#2{\ekv@ifdefined{\ekv@name{#1}{#2}}}
-\def\ekvifdefinedNoVal#1#2{\ekv@ifdefined{\ekv@name{#1}{#2}N}}
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\def\ekvifdefined#1#2}}%
+ {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}}}
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\def\ekvifdefinedNoVal#1#2}}%
+ {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}N}}
% \end{macrocode}
% \end{macro}
%
@@ -1191,74 +1359,71 @@ and the derived files expkv.pdf
% \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,
% \ekvdefunknown,\ekvdefunknownNoVal
% }
-% Set up the key defining macros |\ekvdef| etc.
+% Set up the key defining macros |\ekvdef| etc. We use temporary macros to set
+% these up with a few expansions already done.
% \begin{macrocode}
-\protected\long\def\ekvdef#1#2#3%
+\def\ekvdef#1#2#3#4%
{%
- \ekv@checkvalid{#1}{#2}%
+ \protected\long\def\ekvdef##1##2##3%
+ {#1{\expandafter\def\csname#2\endcsname####1{##3}#3}}%
+ \protected\long\def\ekvdefNoVal##1##2##3%
+ {#1{\expandafter\def\csname#2N\endcsname{##3}#3}}%
+ \protected\def\ekvlet##1##2##3%
+ {#1{\expandafter\let\csname#2\endcsname##3#3}}%
+ \protected\def\ekvletNoVal##1##2##3%
+ {#1{\expandafter\let\csname#2N\endcsname##3#3}}%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+ \protected\long\def\ekvdefunknown##1##2}}}%
{%
- \expandafter\def\csname\ekv@name{#1}{#2}\endcsname##1{#3}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
- }%
- }
-\protected\long\def\ekvdefNoVal#1#2#3%
- {%
- \ekv@checkvalid{#1}{#2}%
- {%
- \expandafter\def\csname\ekv@name{#1}{#2}N\endcsname{#3}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
- }%
- }
-\protected\def\ekvlet#1#2#3%
- {%
- \ekv@checkvalid{#1}{#2}%
- {%
- \expandafter\let\csname\ekv@name{#1}{#2}\endcsname#3%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
- }%
- }
-\protected\def\ekvletNoVal#1#2#3%
- {%
- \ekv@checkvalid{#1}{#2}%
- {%
- \expandafter\let\csname\ekv@name{#1}{#2}N\endcsname#3%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ \expandafter\ekv@expB@unbraceA@\expandafter
+ {%
+ \expandafter\expandafter\expandafter
+ \def\expandafter\csname\ekv@name{##1}{}u\endcsname####1####2{##2}%
+ #3%
+ }%
+ {\ekv@checkvalid{##1}.}%
}%
- }
-\protected\def\ekvletkv#1#2#3#4%
- {%
- \ekv@checkvalid{#1}{#2}%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+ \protected\long\def\ekvdefunknownNoVal##1##2}}}%
{%
- \expandafter\let\csname\ekv@name{#1}{#2}\expandafter\endcsname
- \csname\ekv@name{#3}{#4}\endcsname
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ \expandafter\ekv@expB@unbraceA@\expandafter
+ {%
+ \expandafter\expandafter\expandafter
+ \def\expandafter\csname\ekv@name{##1}{}uN\endcsname####1{##2}%
+ #3%
+ }%
+ {\ekv@checkvalid{##1}.}%
}%
- }
-\protected\def\ekvletkvNoVal#1#2#3#4%
- {%
- \ekv@checkvalid{#1}{#2}%
+ \protected\def\ekvletkv##1##2##3##4%
{%
- \expandafter\let\csname\ekv@name{#1}{#2}N\expandafter\endcsname
- \csname\ekv@name{#3}{#4}N\endcsname
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ #1%
+ {%
+ \expandafter\let\csname#2\expandafter\endcsname
+ \csname#4\endcsname
+ #3%
+ }%
}%
- }
-\protected\def\ekvdefunknown#1#2%
- {%
- \ekv@checkvalid{#1}{.}%
+ \protected\def\ekvletkvNoVal##1##2##3##4%
{%
- \expandafter\def\csname\ekv@name{#1}{}u\endcsname##1##2{#2}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ #1%
+ {%
+ \expandafter\let\csname#2N\expandafter\endcsname
+ \csname#4N\endcsname
+ #3%
+ }%
}%
}
-\protected\def\ekvdefunknownNoVal#1#2%
+\edef\ekvdefNoVal
{%
- \ekv@checkvalid{#1}{.}%
- {%
- \expandafter\def\csname\ekv@name{#1}{}uN\endcsname##1{#2}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
- }%
- }
+ {\unexpanded\expandafter{\ekv@checkvalid{#1}{#2}}}%
+ {\unexpanded\expandafter{\ekv@name{#1}{#2}}}%
+ {%
+ \unexpanded{\expandafter\ekv@defsetmacro\csname}%
+ \unexpanded\expandafter{\ekv@undefined@set{#1}\endcsname{#1}}%
+ }%
+ {\unexpanded\expandafter{\ekv@name{#3}{#4}}}%
+ }%
+\expandafter\ekvdef\ekvdefNoVal
% \end{macrocode}
% \end{macro}
%
@@ -1267,20 +1432,24 @@ and the derived files expkv.pdf
% into a control sequence pretty early, so we have to define that control
% sequence.
% \begin{macrocode}
-\protected\def\ekv@defsetmacro#1#2%
+\edef\ekv@defsetmacro
{%
- \ifx#1\relax
- \edef#1##1{\ekv@name@set{#2}\ekv@name@key{\noexpand\detokenize{##1}}}%
- \fi
+ \unexpanded{\ifx#1\relax\edef#1##1}%
+ {%
+ \unexpanded\expandafter{\ekv@name@set{#2}}%
+ \unexpanded\expandafter{\ekv@name@key{##1}}%
+ }%
+ \unexpanded{\fi}%
}
+\ekv@expB@unbraceA{\protected\def\ekv@defsetmacro#1#2}{\ekv@defsetmacro}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ekvifdefinedset}
% \begin{macrocode}
-\def\ekvifdefinedset#1%
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\def\ekvifdefinedset#1}}%
{%
- \ekv@ifdefined{\ekv@undefined@set{#1}}%
+ \expandafter\ekv@ifdefined\expandafter{\ekv@undefined@set{#1}}%
}
% \end{macrocode}
% \end{macro}
@@ -1294,11 +1463,13 @@ and the derived files expkv.pdf
% |#1| will be a \texttt{,\textsubscript{13}} and |#2| will be a
% \texttt{=\textsubscript{13}}.
% \begin{macrocode}
+\begingroup
\def\ekvset#1#2{%
\endgroup
-\long\def\ekvset##1##2%
+\ekv@expB@unbraceA{\long\def\ekvset##1##2}%
{%
- \expandafter\ekv@set\csname\ekv@undefined@set{##1}\endcsname
+ \expandafter\expandafter\expandafter
+ \ekv@set\expandafter\csname\ekv@undefined@set{##1}\endcsname
\ekv@mark##2#1\ekv@stop#1{}%
}
% \end{macrocode}
@@ -1315,13 +1486,9 @@ and the derived files expkv.pdf
% \begin{macrocode}
\ekv@gobble@from@mark@to@stop##2\ekv@endset\ekv@stop
% \end{macrocode}
-% else go on with other commas,
+% else go on with other commas.
% \begin{macrocode}
\ekv@set@other##1##2,\ekv@stop,%
-% \end{macrocode}
-% and get the next active comma delimited \kv\ pair.
-% \begin{macrocode}
- \ekv@set##1\ekv@mark
}
% \end{macrocode}
% \end{macro}
@@ -1331,9 +1498,8 @@ and the derived files expkv.pdf
% of |\ekv@set| and unbrace the sneaked stuff.
% \begin{macrocode}
\long\def\ekv@endset
- \ekv@stop\ekv@set@other##1,\ekv@stop,\ekv@set##2\ekv@mark
- ##3%
- {##3}
+ \ekv@stop\ekv@set@other##1\ekv@mark\ekv@stop,\ekv@stop,##2%
+ {##2}
% \end{macrocode}
% \end{macro}
%
@@ -1349,11 +1515,11 @@ and the derived files expkv.pdf
% 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
+\long\def\ekv@eq@other##1=##2\ekv@mark##3%
{%
##3##1\ekv@stop\ekv@mark##2%
}
-\long\def\ekv@eq@active##1#2##2\ekv@mark##3##4\ekv@stop
+\long\def\ekv@eq@active##1#2##2\ekv@mark##3%
{%
##3##1\ekv@stop\ekv@mark##2%
}
@@ -1373,12 +1539,12 @@ and the derived files expkv.pdf
% 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
+ =\ekv@mark\ekv@set@eq@active
% \end{macrocode}
-% And insert the set name and the next recursion step of |\ekv@set@other|.
+% And insert the set name for the next recursion step of |\ekv@set@other|.
% \begin{macrocode}
##1%
- \ekv@set@other##1\ekv@mark
+ \ekv@mark
}
% \end{macrocode}
% \end{macro}
@@ -1391,39 +1557,41 @@ and the derived files expkv.pdf
% \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
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@other@active
+ #2\ekv@mark\ekv@set@eq@other@b
}
% \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|.
+% test and forward the \kv\ pair to |\ekv@set@pair|. Normally we would have to
+% also gobble an additional |\ekv@mark| after |\ekv@stop|, but this mark is
+% needed to delimit |\ekv@set@pair|'s argument anyway, so we just leave it
+% there.
% \begin{macrocode}
-\long\def\ekv@set@eq@other@b
- ##1\ekv@nil\ekv@mark\ekv@set@eq@other@active@a\ekv@stop\ekv@mark
+\ekv@expB@unbraceA
{%
- \ekv@strip{##1}\ekv@set@pair
- }
+ \long\def\ekv@set@eq@other@b
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@other@active\ekv@stop\ekv@mark
+ ##2\ekv@nil=\ekv@mark\ekv@set@eq@active
+ }%
+ {\ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2\ekv@nil}
% \end{macrocode}
% \end{macro}
%
-% \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
+% \begin{macro}[internal]{\ekv@set@eq@other@active}
+% |\ekv@set@eq@other@active| 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.
+% to reinsert the equal sign and forward things to |\ekv@set@pair|.
% \begin{macrocode}
-\long\def\ekv@set@eq@other@active@a##1\ekv@stop##2\ekv@nil\ekv@mark
+\ekv@expB@unbraceA
{%
- \ekv@set@eq@other@active@b{##1}##2=%
- }
-\long\def\ekv@set@eq@other@active@b##1%
- {%
- \ekv@strip{##1}\ekv@set@pair
- }
+ \long\def\ekv@set@eq@other@active
+ ##1\ekv@stop##2\ekv@nil#2\ekv@mark
+ \ekv@set@eq@other@b\ekv@mark##3=\ekv@mark\ekv@set@eq@active
+ }%
+ {\ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2=##3}
% \end{macrocode}
% \end{macro}
%
@@ -1436,15 +1604,16 @@ and the derived files expkv.pdf
##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
+ #2\ekv@mark\ekv@set@noeq
}
% \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@expB@unbraceA
+ {\long\def\ekv@set@eq@active@##1\ekv@stop##2\ekv@nil#2\ekv@mark\ekv@set@noeq}%
{%
- \ekv@strip{##1}\ekv@set@pair
+ \ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2\ekv@nil
}
% \end{macrocode}
% \end{macro}
@@ -1456,12 +1625,31 @@ and the derived files expkv.pdf
% 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
+\edef\ekv@set@noeq
+ {%
+ \unexpanded
+ {%
+ \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@set@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ }%
+ \unexpanded\expandafter
+ {\ekv@strip{##1}{\expandafter\ekv@set@key\detokenize}\ekv@mark}%
+ }
+\ekv@expB@unbraceA
+ {%
+ \long\def\ekv@set@noeq
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@active@\ekv@stop\ekv@mark
+ }%
+ {\ekv@set@noeq}
+\def\ekv@set@was@blank##1%
{%
- \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}%
+ \def\ekv@set@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ \ekv@strip@a\ekv@mark####1\ekv@nil\ekv@mark##1##1\ekv@nil\ekv@stop
+ ####2\ekv@mark
+ {\ekv@set@other}%
}
+\ekv@set@was@blank{ }
% \end{macrocode}
% \end{macro}
%
@@ -1471,11 +1659,9 @@ and the derived files expkv.pdf
% \begin{macrocode}
\long\def\ekv@endset@other
\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
- {}
+ \ekv@eq@other\ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@set@eq@other@a
+ =\ekv@mark\ekv@set@eq@active
+ {\ekv@set}
% \end{macrocode}
% \end{macro}
%
@@ -1524,7 +1710,6 @@ and the derived files expkv.pdf
{%
\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}
@@ -1532,7 +1717,7 @@ and the derived files expkv.pdf
% \begin{macro}[internal]{\ekv@endparse}
% \begin{macrocode}
\long\def\ekv@endparse
- \ekv@stop\ekv@parse@other##1,\ekv@stop,\ekv@parse##2\ekv@mark
+ \ekv@stop\ekv@parse@other##1\ekv@mark\ekv@stop,\ekv@stop,%
{}
% \end{macrocode}
% \end{macro}
@@ -1543,9 +1728,9 @@ and the derived files expkv.pdf
{%
\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
+ =\ekv@mark\ekv@parse@eq@active
##1##2%
- \ekv@parse@other##1##2\ekv@mark
+ \ekv@mark
}
% \end{macrocode}
% \end{macro}
@@ -1554,28 +1739,28 @@ and the derived files expkv.pdf
% \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
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active
+ #2\ekv@mark\ekv@parse@eq@other@b
}
-\long\def\ekv@parse@eq@other@b
- ##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active@a\ekv@stop\ekv@mark
+\ekv@expB@unbraceA
{%
- \ekv@strip{##1}\ekv@parse@pair
- }
+ \long\def\ekv@parse@eq@other@b
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active\ekv@stop\ekv@mark
+ ##2\ekv@nil=\ekv@mark\ekv@parse@eq@active
+ }%
+ {\ekv@strip{##1}\ekv@parse@pair##2\ekv@nil}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[internal]
-% {\ekv@parse@eq@other@active@a,\ekv@parse@eq@other@active@b}
+% \begin{macro}[internal]{\ekv@parse@eq@other@active}
% \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@expB@unbraceA
{%
- \ekv@strip{##1}\ekv@parse@pair
- }
+ \long\def\ekv@parse@eq@other@active
+ ##1\ekv@stop##2\ekv@nil#2\ekv@mark
+ \ekv@parse@eq@other@b\ekv@mark##3=\ekv@mark\ekv@parse@eq@active
+ }%
+ {\ekv@strip{##1}\ekv@parse@pair##2=##3}
% \end{macrocode}
% \end{macro}
%
@@ -1585,24 +1770,42 @@ and the derived files expkv.pdf
##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
+ #2\ekv@mark\ekv@parse@noeq
}
-\long\def\ekv@parse@eq@active@##1\ekv@stop
+\ekv@expB@unbraceA
+ {\long\def\ekv@parse@eq@active@##1\ekv@stop##2#2\ekv@mark\ekv@parse@noeq}%
{%
- \ekv@strip{##1}\ekv@parse@pair
+ \ekv@strip{##1}\ekv@parse@pair##2%
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@noeq}
% \begin{macrocode}
-\long\def\ekv@parse@noeq
- ##1\ekv@nil\ekv@mark\ekv@parse@eq@active@\ekv@stop\ekv@mark
+\edef\ekv@parse@noeq
+ {%
+ \unexpanded
+ {%
+ \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@parse@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ }%
+ \unexpanded\expandafter{\ekv@strip{##1}\ekv@parse@key}%
+ }
+\ekv@expB@unbraceA
+ {%
+ \long\def\ekv@parse@noeq
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@active@\ekv@stop\ekv@mark
+ }%
+ {\ekv@parse@noeq}
+\def\ekv@parse@was@blank##1%
{%
- \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}%
+ \def\ekv@parse@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ \ekv@strip@a\ekv@mark####1\ekv@nil\ekv@mark##1##1\ekv@nil\ekv@stop
+ \ekv@parse@key
+ {\ekv@parse@other}%
}
+\ekv@parse@was@blank{ }
% \end{macrocode}
% \end{macro}
%
@@ -1610,23 +1813,22 @@ and the derived files expkv.pdf
% \begin{macrocode}
\long\def\ekv@endparse@other
\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
- {}
+ \ekv@eq@other\ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@parse@eq@other@a
+ =\ekv@mark\ekv@parse@eq@active
+ {\ekv@parse}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[internal]{\ekv@parse@pair,\ekv@parse@pair@}
% \begin{macrocode}
-\long\def\ekv@parse@pair##1##2\ekv@nil
+\ekv@expB@unbraceA{\long\def\ekv@parse@pair##1##2\ekv@nil}%
{%
\ekv@strip{##2}\ekv@parse@pair@{##1}%
}
\long\def\ekv@parse@pair@##1##2##3##4%
{%
\unexpanded{##4{##2}{##1}}%
+ \ekv@parse@other##3##4%
}
% \end{macrocode}
% \end{macro}
@@ -1636,6 +1838,7 @@ and the derived files expkv.pdf
\long\def\ekv@parse@key##1##2##3%
{%
\unexpanded{##2{##1}}%
+ \ekv@parse@other##2##3%
}
% \end{macrocode}
% \end{macro}
@@ -1643,12 +1846,26 @@ and the derived files expkv.pdf
% Finally really setting things up with |\ekvset|'s temporary meaning:
% \begin{macrocode}
}
-\begingroup
\catcode`\,=13
\catcode`\==13
\ekvset,=
% \end{macrocode}
%
+% \begin{macro}{\ekvsetSneaked}
+% This macro can be defined just by expanding |\ekvsneak| once after expanding
+% |\ekvset|. To expand everything as much as possible early on we use a
+% temporary definition.
+% \begin{macrocode}
+\edef\ekvsetSneaked
+ {%
+ \unexpanded{\ekvsneak{#2}}%
+ \unexpanded\expandafter{\ekvset{#1}{#3}}%
+ }
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def\ekvsetSneaked#1#2#3}}%
+ {\ekvsetSneaked}
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\ekvchangeset}
% Provide a macro that is able to switch out the current \set\ in |\ekvset|.
% This operation is slow (by comparison, it should be slightly faster than
@@ -1658,111 +1875,147 @@ and the derived files expkv.pdf
% switch out the set expandably, so this works similar to the |\ekvsneak| macros
% reading and reinserting the remainder of the \kv\ list.
% \begin{macrocode}
-\def\ekvchangeset#1%
+\ekv@expB@unbraceA{\def\ekvchangeset#1}%
{%
- \expandafter\ekv@changeset\csname\ekv@undefined@set{#1}\endcsname\ekv@mark
+ \expandafter\expandafter\expandafter
+ \ekv@changeset\expandafter\csname\ekv@undefined@set{#1}\endcsname\ekv@empty
}
% \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
-% again.
+% This macro does the real change-out of |\ekvchangeset|. |#2| will have a
+% leading |\ekv@empty| so that braces aren't stripped accidentally, but that
+% will not hurt and just expand to nothing in one step.
% \begin{macrocode}
-\long\def\ekv@changeset#1#2\ekv@set@other#3#4\ekv@set#5%
+\long\def\ekv@changeset#1#2\ekv@set@other#3%
{%
- \ekv@gobble@mark#2\ekv@set@other#1#4\ekv@set#1%
+ #2\ekv@set@other#1%
}
% \end{macrocode}
% \end{macro}
%
%
-% \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 check whether an
-% unknown key handler is defined for this set and that one will branch into
-% the error messages provided by |\ekv@set@pair| if it isn't.
+% \begin{macro}[internal]
+% {
+% \ekv@set@pair,\ekv@set@pair@a,\ekv@set@pair@b,\ekv@set@pair@c,
+% \ekv@set@pair@d,\ekv@set@pair@e
+% }
+% |\ekv@set@pair| gets invoked with the space and brace stripped and
+% |\detokenize|d key-name as its first, the value as the second, and the set
+% name as the third argument. It provides tests for the key-macros and
+% everything to be able to throw meaningful error messages if it isn't
+% defined. We have two routes here, one if |\lastnamedcs| is defined and one
+% if it isn't. The big difference is that if it is we can omit a |\csname| and
+% instead just expand |\lastnamedcs| once to get the control sequence.
+% If the macro is defined the value will be space and brace stripped and the
+% key-macro called. Else branch into the error handling provided by
+% |\ekv@set@pair|.
% \begin{macrocode}
-\long\def\ekv@set@pair#1#2\ekv@nil#3%
+\ekv@if@lastnamedcs
{%
- \expandafter\ekv@set@pair@
- \csname
- \ifcsname #3{#1}\endcsname
- #3{#1}%
- \else
- relax%
- \fi
- \endcsname
- {#2}%
+ \long\def\ekv@set@pair#1\ekv@mark#2\ekv@nil#3%
{%
- \expandafter\ekv@set@pair@
- \csname
- \ifcsname #3{}u\endcsname
- #3{}u%
- \else
- relax%
- \fi
- \endcsname
+ \ifcsname #3{#1}\endcsname\ekv@set@pair@a\fi\@secondoftwo
{#2}%
{%
- \ekv@ifdefined{#3{#1}N}%
- \ekv@err@noarg
- \ekv@err@unknown
- #3%
+ \ifcsname #3{}u\endcsname\ekv@set@pair@a\fi\@secondoftwo
+ {#2}%
+ {%
+ \ekv@ifdefined{#3{#1}N}%
+ \ekv@err@noarg
+ \ekv@err@unknown
+ #3%
+ }%
+ {#1}%
}%
- {#1}%
- }%
+ \ekv@set@other#3%
+ }
+ \def\ekv@set@pair@a\fi\@secondoftwo
+ {\fi\expandafter\ekv@set@pair@b\lastnamedcs}
+ }
+ {%
+ \long\def\ekv@set@pair#1\ekv@mark#2\ekv@nil#3%
+ {%
+ \ifcsname #3{#1}\endcsname
+ \ekv@set@pair@a\fi\ekv@set@pair@c#3{#1}\endcsname
+ {#2}%
+ {%
+ \ifcsname #3{}u\endcsname
+ \ekv@set@pair@a\fi\ekv@set@pair@c#3{}u\endcsname
+ {#2}%
+ {%
+ \ekv@ifdefined{#3{#1}N}%
+ \ekv@err@noarg
+ \ekv@err@unknown
+ #3%
+ }%
+ {#1}%
+ }%
+ \ekv@set@other#3%
+ }
+ \def\ekv@set@pair@a\fi\ekv@set@pair@c{\fi\expandafter\ekv@set@pair@b\csname}
+ \long\def\ekv@set@pair@c#1\endcsname#2#3{#3}
}
-\long\def\ekv@set@pair@#1#2%
+\long\def\ekv@set@pair@b#1%
{%
\ifx#1\relax
- \ekv@fi@secondoftwo
+ \ekv@set@pair@e
\fi
- \@firstoftwo
- {\ekv@strip{#2}#1}%
+ \ekv@set@pair@d#1%
}
+\ekv@expB@unbraceA{\long\def\ekv@set@pair@d#1#2#3}{\ekv@strip{#2}#1}
+\long\def\ekv@set@pair@e\fi\ekv@set@pair@d#1#2#3{\fi#3}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[internal]{\ekv@set@key}
+% \begin{macro}[internal]
+% {\ekv@set@key,\ekv@set@key@a,\ekv@set@key@b,\ekv@set@key@c}
% 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@if@lastnamedcs
{%
- \expandafter\ekv@set@key@
- \csname
- \ifcsname #2{#1}N\endcsname
- #2{#1}N%
- \else
- relax%
- \fi
- \endcsname
+ \long\def\ekv@set@key#1\ekv@mark#2%
{%
- \expandafter\ekv@set@key@
- \csname
- \ifcsname #2{}uN\endcsname
- #2{}uN%
- \else
- relax%
- \fi
- \endcsname
+ \ifcsname #2{#1}N\endcsname\ekv@set@key@a\fi\@firstofone
{%
- \ekv@ifdefined{#2{#1}}%
- \ekv@err@reqval
- \ekv@err@unknown
- #2%
+ \ifcsname #2{}uN\endcsname\ekv@set@key@a\fi\@firstofone
+ {%
+ \ekv@ifdefined{#2{#1}}%
+ \ekv@err@reqval
+ \ekv@err@unknown
+ #2%
+ }%
+ {#1}%
}%
- {#1}%
- }%
+ \ekv@set@other#2%
+ }
+ \def\ekv@set@key@a\fi\@firstofone{\fi\expandafter\ekv@set@key@b\lastnamedcs}
+ }
+ {%
+ \long\def\ekv@set@key#1\ekv@mark#2%
+ {%
+ \ifcsname #2{#1}N\endcsname
+ \ekv@set@key@a\fi\ekv@set@key@c#2{#1}N\endcsname
+ {%
+ \ifcsname #2{}uN\endcsname
+ \ekv@set@key@a\fi\ekv@set@key@c#2{}uN\endcsname
+ {%
+ \ekv@ifdefined{#2{#1}}%
+ \ekv@err@reqval
+ \ekv@err@unknown
+ #2%
+ }%
+ {#1}%
+ }%
+ \ekv@set@other#2%
+ }
+ \def\ekv@set@key@a\fi\ekv@set@key@c{\fi\expandafter\ekv@set@key@b\csname}
+ \long\def\ekv@set@key@c#1N\endcsname#2{#2}
}
-\def\ekv@set@key@#1%
+\long\def\ekv@set@key@b#1%
{%
\ifx#1\relax
\ekv@fi@secondoftwo
@@ -1774,24 +2027,34 @@ and the derived files expkv.pdf
%
% \begin{macro}{\ekvsetdef}
% Provide a macro to define a shorthand to use |\ekvset| on a specified \set.
-% The first macro expands |\ekvset| twice, such that everything which can be
-% done up to this point is done.
+% To gain the maximum speed |\ekvset| is expanded twice by
+% |\ekv@expB@unbraceA| so that during runtime the macro storing the set name
+% is already built and one |\expandafter| doesn't have to be used.
% \begin{macrocode}
-\protected\def\ekvsetdef#1#2%
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+\protected\def\ekvsetdef#1#2}}}}%
{%
- \expandafter\expandafter\expandafter
- \ekv@setdef\expandafter\expandafter\expandafter{\ekvset{#2}{##1}}#1%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def#1##1}}%
+ {\ekvset{#2}{##1}}%
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[internal]{\ekv@setdef}
-% This auxiliary macro defines the shorthand macro after |\ekvset| got
-% expanded as far as possible.
+% \begin{macro}{\ekvsetSneakeddef,\ekvsetdefSneaked}
+% And do the same for |\ekvsetSneaked| in the two possible ways, with a fixed
+% sneaked argument and with a flexible one.
% \begin{macrocode}
-\protected\def\ekv@setdef#1#2%
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+\protected\def\ekvsetSneakeddef#1#2}}}}%
+ {%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def#1##1##2}}%
+ {\ekvsetSneaked{#2}{##1}{##2}}%
+ }
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+\protected\def\ekvsetdefSneaked#1#2#3}}}}%
{%
- \long\def#2##1{#1}%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def#1##1}}%
+ {\ekvsetSneaked{#2}{#3}{##1}}%
}
% \end{macrocode}
% \end{macro}
@@ -1827,44 +2090,12 @@ and the derived files expkv.pdf
% \begin{macrocode}
\long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}}
\long\def\ekv@err@common@#1`#2' #3.#4#5{\ekv@err{#4 (`#5', set `#2')}}
-\long\def\ekv@err@unknown#1#2{\ekv@err@common{unknown key}#1{#2}}
-\long\def\ekv@err@noarg #1#2{\ekv@err@common{value forbidden}#1{#2}}
-\long\def\ekv@err@reqval #1#2{\ekv@err@common{value required}#1{#2}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@strip,\ekv@strip@a,\ekv@strip@b,\ekv@strip@c}
-% Finally we borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
-% from keys and values. This |\ekv@strip| also strips one level of outer braces
-% \emph{after} stripping spaces, so an input of | {abc} | becomes |abc| after
-% stripping. It should be used with |#1| prefixed by |\ekv@mark|. Also this
-% implementation at most strips \emph{one} space from both sides.
-% \begin{macrocode}
-\def\ekv@strip#1%
- {%
- \long\def\ekv@strip##1%
- {%
- \ekv@strip@a
- ##1%
- \ekv@nil
- \ekv@mark#1%
- #1\ekv@nil{}%
- \ekv@stop
- }%
- \long\def\ekv@strip@a##1\ekv@mark#1##2\ekv@nil##3%
- {%
- \ekv@strip@b##3##1##2\ekv@nil
- }%
- \long\def\ekv@strip@b##1#1\ekv@nil
- {%
- \ekv@strip@c##1\ekv@nil
- }%
- \long\def\ekv@strip@c\ekv@mark##1\ekv@nil##2\ekv@stop##3%
- {%
- ##3{##1}%
- }%
- }
-\ekv@strip{ }
+\ekv@expB@unbraceA{\long\def\ekv@err@unknown#1}%
+ {\ekv@err@common{unknown key}{#1}}
+\ekv@expB@unbraceA{\long\def\ekv@err@noarg #1}%
+ {\ekv@err@common{value forbidden}{#1}}
+\ekv@expB@unbraceA{\long\def\ekv@err@reqval #1}%
+ {\ekv@err@common{value required}{#1}}
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/tex/generic/expkv/expkv.tex b/Master/texmf-dist/tex/generic/expkv/expkv.tex
index 84898302138..5897ca8c924 100644
--- a/Master/texmf-dist/tex/generic/expkv/expkv.tex
+++ b/Master/texmf-dist/tex/generic/expkv/expkv.tex
@@ -39,11 +39,23 @@
\errmessage{expkv requires e-TeX}
\expandafter\endinput
\fi
-\def\ekvVersion{1.4}
-\def\ekvDate{2020-07-04}
+\def\ekvVersion{1.5}
+\def\ekvDate{2020-10-10}
\csname ekv@tmp\endcsname
\expandafter\chardef\csname ekv@tmp\endcsname=\catcode`\@
\catcode`\@=11
+\begingroup
+ \edef\ekv@tmpa{\string \lastnamedcs}
+ \edef\ekv@tmpb{\meaning\lastnamedcs}
+ \ifx\ekv@tmpa\ekv@tmpb
+ \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##1}}
+ \else
+ \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##2}}
+ \fi
+ \expandafter
+\endgroup
+\ekv@if@lastnamedcs
+\def\ekv@empty{}
\long\def\@gobble#1{}
\long\def\@firstofone#1{#1}
\long\def\@firstoftwo#1#2{#1}
@@ -74,135 +86,184 @@
\ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
}
\long\def\ekv@ifblank@\ekv@mark#1{\ekv@ifempty@\ekv@ifempty@A}
-\def\ekv@ifdefined#1%
+\ekv@if@lastnamedcs
{%
- \expandafter
- \ifx\csname\ifcsname #1\endcsname #1\else relax\fi\endcsname\relax
- \ekv@fi@secondoftwo
- \fi
- \@firstoftwo
+ \def\ekv@ifdefined#1{\ifcsname#1\endcsname\ekv@ifdef@\fi\@secondoftwo}
+ \def\ekv@ifdef@\fi\@secondoftwo
+ {%
+ \fi
+ \expandafter\ifx\lastnamedcs\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ }
}
-\def\ekv@name#1#2{\ekv@name@set{#1}\ekv@name@key{\detokenize{#2}}}
-\def\ekv@name@set#1{ekv#1(}
-\def\ekv@name@key#1{#1)}
-\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.}
-\protected\def\ekv@checkvalid#1#2%
{%
- \ekv@ifempty{#1}%
- {%
- \def\ekv@tmp{}%
- \errmessage{expkv Error: empty set name not allowed}%
- }%
+ \def\ekv@ifdefined#1%
{%
- \ekv@ifempty{#2}%
- {%
- \def\ekv@tmp{}%
- \errmessage{expkv Error: empty key name not allowed}%
- }%
- \@secondoftwo
- }%
- \@gobble
+ \ifcsname#1\endcsname\ekv@ifdef@\fi\ekv@ifdef@false#1\endcsname\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ }
+ \def\ekv@ifdef@\fi\ekv@ifdef@false{\fi\expandafter\ifx\csname}
+ \long\def\ekv@ifdef@false
+ #1\endcsname\relax\ekv@fi@secondoftwo\fi\@firstoftwo#2#3%
+ {#3}
}
-\def\ekvifdefined#1#2{\ekv@ifdefined{\ekv@name{#1}{#2}}}
-\def\ekvifdefinedNoVal#1#2{\ekv@ifdefined{\ekv@name{#1}{#2}N}}
-\protected\long\def\ekvdef#1#2#3%
+\def\ekv@strip#1%
{%
- \ekv@checkvalid{#1}{#2}%
+ \long\def\ekv@strip##1%
{%
- \expandafter\def\csname\ekv@name{#1}{#2}\endcsname##1{#3}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ \ekv@strip@a
+ ##1\ekv@nil
+ \ekv@mark#1%
+ #1\ekv@nil
+ \ekv@stop
}%
+ \long\def\ekv@strip@a##1\ekv@mark#1{\ekv@strip@b##1\ekv@mark}%
+ \long\def\ekv@strip@b##1#1\ekv@nil {\ekv@strip@c##1\ekv@nil}%
}
-\protected\long\def\ekvdefNoVal#1#2#3%
+\ekv@strip{ }
+\long\def\ekv@strip@c\ekv@mark#1\ekv@nil\ekv@mark#2\ekv@nil\ekv@stop#3{#3{#1}}
+\long\def\ekv@expB@unbraceA#1#2%
{%
- \ekv@checkvalid{#1}{#2}%
- {%
- \expandafter\def\csname\ekv@name{#1}{#2}N\endcsname{#3}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
- }%
+ \expandafter\ekv@expB@unbraceA@\expandafter{#2}{#1}%
}
-\protected\def\ekvlet#1#2#3%
+\long\def\ekv@expB@unbraceA@#1#2{#2{#1}}%
+\def\ekv@name@set#1{ekv#1(}
+\def\ekv@name@key#1{#1)}
+\edef\ekv@name
{%
- \ekv@checkvalid{#1}{#2}%
- {%
- \expandafter\let\csname\ekv@name{#1}{#2}\endcsname#3%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
- }%
+ \unexpanded\expandafter{\ekv@name@set{#1}}%
+ \unexpanded\expandafter{\ekv@name@key{\detokenize{#2}}}%
}
-\protected\def\ekvletNoVal#1#2#3%
+\ekv@expB@unbraceA{\def\ekv@name#1#2}{\ekv@name}
+\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.}
+\edef\ekv@checkvalid
{%
- \ekv@checkvalid{#1}{#2}%
+ \unexpanded\expandafter{\ekv@ifempty{#1}}%
+ \unexpanded
+ {{%
+ \def\ekv@tmp{}%
+ \errmessage{expkv Error: empty set name not allowed}%
+ }}%
{%
- \expandafter\let\csname\ekv@name{#1}{#2}N\endcsname#3%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ \unexpanded\expandafter{\ekv@ifempty{#2}}%
+ \unexpanded
+ {%
+ {%
+ \def\ekv@tmp{}%
+ \errmessage{expkv Error: empty key name not allowed}%
+ }%
+ \@secondoftwo
+ }%
}%
- }
-\protected\def\ekvletkv#1#2#3#4%
- {%
- \ekv@checkvalid{#1}{#2}%
+ \unexpanded{\@gobble}%
+ }
+\ekv@expB@unbraceA{\protected\def\ekv@checkvalid#1#2}{\ekv@checkvalid}%
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\def\ekvifdefined#1#2}}%
+ {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}}}
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\def\ekvifdefinedNoVal#1#2}}%
+ {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}N}}
+\def\ekvdef#1#2#3#4%
+ {%
+ \protected\long\def\ekvdef##1##2##3%
+ {#1{\expandafter\def\csname#2\endcsname####1{##3}#3}}%
+ \protected\long\def\ekvdefNoVal##1##2##3%
+ {#1{\expandafter\def\csname#2N\endcsname{##3}#3}}%
+ \protected\def\ekvlet##1##2##3%
+ {#1{\expandafter\let\csname#2\endcsname##3#3}}%
+ \protected\def\ekvletNoVal##1##2##3%
+ {#1{\expandafter\let\csname#2N\endcsname##3#3}}%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+ \protected\long\def\ekvdefunknown##1##2}}}%
{%
- \expandafter\let\csname\ekv@name{#1}{#2}\expandafter\endcsname
- \csname\ekv@name{#3}{#4}\endcsname
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ \expandafter\ekv@expB@unbraceA@\expandafter
+ {%
+ \expandafter\expandafter\expandafter
+ \def\expandafter\csname\ekv@name{##1}{}u\endcsname####1####2{##2}%
+ #3%
+ }%
+ {\ekv@checkvalid{##1}.}%
}%
- }
-\protected\def\ekvletkvNoVal#1#2#3#4%
- {%
- \ekv@checkvalid{#1}{#2}%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+ \protected\long\def\ekvdefunknownNoVal##1##2}}}%
{%
- \expandafter\let\csname\ekv@name{#1}{#2}N\expandafter\endcsname
- \csname\ekv@name{#3}{#4}N\endcsname
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ \expandafter\ekv@expB@unbraceA@\expandafter
+ {%
+ \expandafter\expandafter\expandafter
+ \def\expandafter\csname\ekv@name{##1}{}uN\endcsname####1{##2}%
+ #3%
+ }%
+ {\ekv@checkvalid{##1}.}%
}%
- }
-\protected\def\ekvdefunknown#1#2%
- {%
- \ekv@checkvalid{#1}{.}%
+ \protected\def\ekvletkv##1##2##3##4%
{%
- \expandafter\def\csname\ekv@name{#1}{}u\endcsname##1##2{#2}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ #1%
+ {%
+ \expandafter\let\csname#2\expandafter\endcsname
+ \csname#4\endcsname
+ #3%
+ }%
}%
- }
-\protected\def\ekvdefunknownNoVal#1#2%
- {%
- \ekv@checkvalid{#1}{.}%
+ \protected\def\ekvletkvNoVal##1##2##3##4%
{%
- \expandafter\def\csname\ekv@name{#1}{}uN\endcsname##1{#2}%
- \expandafter\ekv@defsetmacro\csname\ekv@undefined@set{#1}\endcsname{#1}%
+ #1%
+ {%
+ \expandafter\let\csname#2N\expandafter\endcsname
+ \csname#4N\endcsname
+ #3%
+ }%
}%
}
-\protected\def\ekv@defsetmacro#1#2%
+\edef\ekvdefNoVal
{%
- \ifx#1\relax
- \edef#1##1{\ekv@name@set{#2}\ekv@name@key{\noexpand\detokenize{##1}}}%
- \fi
+ {\unexpanded\expandafter{\ekv@checkvalid{#1}{#2}}}%
+ {\unexpanded\expandafter{\ekv@name{#1}{#2}}}%
+ {%
+ \unexpanded{\expandafter\ekv@defsetmacro\csname}%
+ \unexpanded\expandafter{\ekv@undefined@set{#1}\endcsname{#1}}%
+ }%
+ {\unexpanded\expandafter{\ekv@name{#3}{#4}}}%
+ }%
+\expandafter\ekvdef\ekvdefNoVal
+\edef\ekv@defsetmacro
+ {%
+ \unexpanded{\ifx#1\relax\edef#1##1}%
+ {%
+ \unexpanded\expandafter{\ekv@name@set{#2}}%
+ \unexpanded\expandafter{\ekv@name@key{##1}}%
+ }%
+ \unexpanded{\fi}%
}
-\def\ekvifdefinedset#1%
+\ekv@expB@unbraceA{\protected\def\ekv@defsetmacro#1#2}{\ekv@defsetmacro}
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\def\ekvifdefinedset#1}}%
{%
- \ekv@ifdefined{\ekv@undefined@set{#1}}%
+ \expandafter\ekv@ifdefined\expandafter{\ekv@undefined@set{#1}}%
}
+\begingroup
\def\ekvset#1#2{%
\endgroup
-\long\def\ekvset##1##2%
+\ekv@expB@unbraceA{\long\def\ekvset##1##2}%
{%
- \expandafter\ekv@set\csname\ekv@undefined@set{##1}\endcsname
+ \expandafter\expandafter\expandafter
+ \ekv@set\expandafter\csname\ekv@undefined@set{##1}\endcsname
\ekv@mark##2#1\ekv@stop#1{}%
}
\long\def\ekv@set##1##2#1%
{%
\ekv@gobble@from@mark@to@stop##2\ekv@endset\ekv@stop
\ekv@set@other##1##2,\ekv@stop,%
- \ekv@set##1\ekv@mark
}
\long\def\ekv@endset
- \ekv@stop\ekv@set@other##1,\ekv@stop,\ekv@set##2\ekv@mark
- ##3%
- {##3}
-\long\def\ekv@eq@other##1=##2\ekv@mark##3##4\ekv@stop
+ \ekv@stop\ekv@set@other##1\ekv@mark\ekv@stop,\ekv@stop,##2%
+ {##2}
+\long\def\ekv@eq@other##1=##2\ekv@mark##3%
{%
##3##1\ekv@stop\ekv@mark##2%
}
-\long\def\ekv@eq@active##1#2##2\ekv@mark##3##4\ekv@stop
+\long\def\ekv@eq@active##1#2##2\ekv@mark##3%
{%
##3##1\ekv@stop\ekv@mark##2%
}
@@ -210,51 +271,70 @@
{%
\ekv@gobble@from@mark@to@stop##2\ekv@endset@other\ekv@stop
\ekv@eq@other##2\ekv@nil\ekv@mark\ekv@set@eq@other@a
- =\ekv@mark\ekv@set@eq@active\ekv@stop
+ =\ekv@mark\ekv@set@eq@active
##1%
- \ekv@set@other##1\ekv@mark
+ \ekv@mark
}
\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
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@other@active
+ #2\ekv@mark\ekv@set@eq@other@b
}
-\long\def\ekv@set@eq@other@b
- ##1\ekv@nil\ekv@mark\ekv@set@eq@other@active@a\ekv@stop\ekv@mark
+\ekv@expB@unbraceA
{%
- \ekv@strip{##1}\ekv@set@pair
- }
-\long\def\ekv@set@eq@other@active@a##1\ekv@stop##2\ekv@nil\ekv@mark
+ \long\def\ekv@set@eq@other@b
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@other@active\ekv@stop\ekv@mark
+ ##2\ekv@nil=\ekv@mark\ekv@set@eq@active
+ }%
+ {\ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2\ekv@nil}
+\ekv@expB@unbraceA
{%
- \ekv@set@eq@other@active@b{##1}##2=%
- }
-\long\def\ekv@set@eq@other@active@b##1%
- {%
- \ekv@strip{##1}\ekv@set@pair
- }
+ \long\def\ekv@set@eq@other@active
+ ##1\ekv@stop##2\ekv@nil#2\ekv@mark
+ \ekv@set@eq@other@b\ekv@mark##3=\ekv@mark\ekv@set@eq@active
+ }%
+ {\ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2=##3}
\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
+ #2\ekv@mark\ekv@set@noeq
}
-\long\def\ekv@set@eq@active@##1\ekv@stop
+\ekv@expB@unbraceA
+ {\long\def\ekv@set@eq@active@##1\ekv@stop##2\ekv@nil#2\ekv@mark\ekv@set@noeq}%
{%
- \ekv@strip{##1}\ekv@set@pair
+ \ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2\ekv@nil
}
-\long\def\ekv@set@noeq##1\ekv@nil\ekv@mark\ekv@set@eq@active@\ekv@stop\ekv@mark
+\edef\ekv@set@noeq
{%
- \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}%
+ \unexpanded
+ {%
+ \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@set@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ }%
+ \unexpanded\expandafter
+ {\ekv@strip{##1}{\expandafter\ekv@set@key\detokenize}\ekv@mark}%
+ }
+\ekv@expB@unbraceA
+ {%
+ \long\def\ekv@set@noeq
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@active@\ekv@stop\ekv@mark
+ }%
+ {\ekv@set@noeq}
+\def\ekv@set@was@blank##1%
+ {%
+ \def\ekv@set@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ \ekv@strip@a\ekv@mark####1\ekv@nil\ekv@mark##1##1\ekv@nil\ekv@stop
+ ####2\ekv@mark
+ {\ekv@set@other}%
}
+\ekv@set@was@blank{ }
\long\def\ekv@endset@other
\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
- {}
+ \ekv@eq@other\ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@set@eq@other@a
+ =\ekv@mark\ekv@set@eq@active
+ {\ekv@set}
\long\def\ekvbreak##1##2\ekv@stop#1##3{##1}
\long\def\ekvbreakPreSneak ##1##2\ekv@stop#1##3{##1##3}
\long\def\ekvbreakPostSneak##1##2\ekv@stop#1##3{##3##1}
@@ -274,167 +354,229 @@
{%
\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
}
\long\def\ekv@endparse
- \ekv@stop\ekv@parse@other##1,\ekv@stop,\ekv@parse##2\ekv@mark
+ \ekv@stop\ekv@parse@other##1\ekv@mark\ekv@stop,\ekv@stop,%
{}
\long\def\ekv@parse@other##1##2##3,%
{%
\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
+ =\ekv@mark\ekv@parse@eq@active
##1##2%
- \ekv@parse@other##1##2\ekv@mark
+ \ekv@mark
}
\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
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active
+ #2\ekv@mark\ekv@parse@eq@other@b
}
-\long\def\ekv@parse@eq@other@active@a##1\ekv@stop##2\ekv@nil\ekv@mark
+\ekv@expB@unbraceA
{%
- \ekv@parse@eq@other@active@b{##1}##2=%
- }
-\long\def\ekv@parse@eq@other@active@b##1%
+ \long\def\ekv@parse@eq@other@b
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active\ekv@stop\ekv@mark
+ ##2\ekv@nil=\ekv@mark\ekv@parse@eq@active
+ }%
+ {\ekv@strip{##1}\ekv@parse@pair##2\ekv@nil}
+\ekv@expB@unbraceA
{%
- \ekv@strip{##1}\ekv@parse@pair
- }
+ \long\def\ekv@parse@eq@other@active
+ ##1\ekv@stop##2\ekv@nil#2\ekv@mark
+ \ekv@parse@eq@other@b\ekv@mark##3=\ekv@mark\ekv@parse@eq@active
+ }%
+ {\ekv@strip{##1}\ekv@parse@pair##2=##3}
\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
+ #2\ekv@mark\ekv@parse@noeq
+ }
+\ekv@expB@unbraceA
+ {\long\def\ekv@parse@eq@active@##1\ekv@stop##2#2\ekv@mark\ekv@parse@noeq}%
+ {%
+ \ekv@strip{##1}\ekv@parse@pair##2%
}
-\long\def\ekv@parse@eq@active@##1\ekv@stop
+\edef\ekv@parse@noeq
{%
- \ekv@strip{##1}\ekv@parse@pair
+ \unexpanded
+ {%
+ \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@parse@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ }%
+ \unexpanded\expandafter{\ekv@strip{##1}\ekv@parse@key}%
}
-\long\def\ekv@parse@noeq
- ##1\ekv@nil\ekv@mark\ekv@parse@eq@active@\ekv@stop\ekv@mark
+\ekv@expB@unbraceA
+ {%
+ \long\def\ekv@parse@noeq
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@active@\ekv@stop\ekv@mark
+ }%
+ {\ekv@parse@noeq}
+\def\ekv@parse@was@blank##1%
{%
- \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}%
+ \def\ekv@parse@was@blank
+ \ekv@ifempty@A\ekv@ifempty@B
+ \ekv@strip@a\ekv@mark####1\ekv@nil\ekv@mark##1##1\ekv@nil\ekv@stop
+ \ekv@parse@key
+ {\ekv@parse@other}%
}
+\ekv@parse@was@blank{ }
\long\def\ekv@endparse@other
\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
- {}
-\long\def\ekv@parse@pair##1##2\ekv@nil
+ \ekv@eq@other\ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@parse@eq@other@a
+ =\ekv@mark\ekv@parse@eq@active
+ {\ekv@parse}
+\ekv@expB@unbraceA{\long\def\ekv@parse@pair##1##2\ekv@nil}%
{%
\ekv@strip{##2}\ekv@parse@pair@{##1}%
}
\long\def\ekv@parse@pair@##1##2##3##4%
{%
\unexpanded{##4{##2}{##1}}%
+ \ekv@parse@other##3##4%
}
\long\def\ekv@parse@key##1##2##3%
{%
\unexpanded{##2{##1}}%
+ \ekv@parse@other##2##3%
}
}
-\begingroup
\catcode`\,=13
\catcode`\==13
\ekvset,=
-\def\ekvchangeset#1%
+\edef\ekvsetSneaked
{%
- \expandafter\ekv@changeset\csname\ekv@undefined@set{#1}\endcsname\ekv@mark
+ \unexpanded{\ekvsneak{#2}}%
+ \unexpanded\expandafter{\ekvset{#1}{#3}}%
}
-\long\def\ekv@changeset#1#2\ekv@set@other#3#4\ekv@set#5%
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def\ekvsetSneaked#1#2#3}}%
+ {\ekvsetSneaked}
+\ekv@expB@unbraceA{\def\ekvchangeset#1}%
{%
- \ekv@gobble@mark#2\ekv@set@other#1#4\ekv@set#1%
+ \expandafter\expandafter\expandafter
+ \ekv@changeset\expandafter\csname\ekv@undefined@set{#1}\endcsname\ekv@empty
}
-\long\def\ekv@set@pair#1#2\ekv@nil#3%
+\long\def\ekv@changeset#1#2\ekv@set@other#3%
{%
- \expandafter\ekv@set@pair@
- \csname
- \ifcsname #3{#1}\endcsname
- #3{#1}%
- \else
- relax%
- \fi
- \endcsname
- {#2}%
+ #2\ekv@set@other#1%
+ }
+\ekv@if@lastnamedcs
+ {%
+ \long\def\ekv@set@pair#1\ekv@mark#2\ekv@nil#3%
{%
- \expandafter\ekv@set@pair@
- \csname
- \ifcsname #3{}u\endcsname
- #3{}u%
- \else
- relax%
- \fi
- \endcsname
+ \ifcsname #3{#1}\endcsname\ekv@set@pair@a\fi\@secondoftwo
{#2}%
{%
- \ekv@ifdefined{#3{#1}N}%
- \ekv@err@noarg
- \ekv@err@unknown
- #3%
+ \ifcsname #3{}u\endcsname\ekv@set@pair@a\fi\@secondoftwo
+ {#2}%
+ {%
+ \ekv@ifdefined{#3{#1}N}%
+ \ekv@err@noarg
+ \ekv@err@unknown
+ #3%
+ }%
+ {#1}%
}%
- {#1}%
- }%
+ \ekv@set@other#3%
+ }
+ \def\ekv@set@pair@a\fi\@secondoftwo
+ {\fi\expandafter\ekv@set@pair@b\lastnamedcs}
+ }
+ {%
+ \long\def\ekv@set@pair#1\ekv@mark#2\ekv@nil#3%
+ {%
+ \ifcsname #3{#1}\endcsname
+ \ekv@set@pair@a\fi\ekv@set@pair@c#3{#1}\endcsname
+ {#2}%
+ {%
+ \ifcsname #3{}u\endcsname
+ \ekv@set@pair@a\fi\ekv@set@pair@c#3{}u\endcsname
+ {#2}%
+ {%
+ \ekv@ifdefined{#3{#1}N}%
+ \ekv@err@noarg
+ \ekv@err@unknown
+ #3%
+ }%
+ {#1}%
+ }%
+ \ekv@set@other#3%
+ }
+ \def\ekv@set@pair@a\fi\ekv@set@pair@c{\fi\expandafter\ekv@set@pair@b\csname}
+ \long\def\ekv@set@pair@c#1\endcsname#2#3{#3}
}
-\long\def\ekv@set@pair@#1#2%
+\long\def\ekv@set@pair@b#1%
{%
\ifx#1\relax
- \ekv@fi@secondoftwo
+ \ekv@set@pair@e
\fi
- \@firstoftwo
- {\ekv@strip{#2}#1}%
+ \ekv@set@pair@d#1%
}
-\long\def\ekv@set@key#1#2%
+\ekv@expB@unbraceA{\long\def\ekv@set@pair@d#1#2#3}{\ekv@strip{#2}#1}
+\long\def\ekv@set@pair@e\fi\ekv@set@pair@d#1#2#3{\fi#3}
+\ekv@if@lastnamedcs
{%
- \expandafter\ekv@set@key@
- \csname
- \ifcsname #2{#1}N\endcsname
- #2{#1}N%
- \else
- relax%
- \fi
- \endcsname
+ \long\def\ekv@set@key#1\ekv@mark#2%
{%
- \expandafter\ekv@set@key@
- \csname
- \ifcsname #2{}uN\endcsname
- #2{}uN%
- \else
- relax%
- \fi
- \endcsname
+ \ifcsname #2{#1}N\endcsname\ekv@set@key@a\fi\@firstofone
{%
- \ekv@ifdefined{#2{#1}}%
- \ekv@err@reqval
- \ekv@err@unknown
- #2%
+ \ifcsname #2{}uN\endcsname\ekv@set@key@a\fi\@firstofone
+ {%
+ \ekv@ifdefined{#2{#1}}%
+ \ekv@err@reqval
+ \ekv@err@unknown
+ #2%
+ }%
+ {#1}%
}%
- {#1}%
- }%
+ \ekv@set@other#2%
+ }
+ \def\ekv@set@key@a\fi\@firstofone{\fi\expandafter\ekv@set@key@b\lastnamedcs}
+ }
+ {%
+ \long\def\ekv@set@key#1\ekv@mark#2%
+ {%
+ \ifcsname #2{#1}N\endcsname
+ \ekv@set@key@a\fi\ekv@set@key@c#2{#1}N\endcsname
+ {%
+ \ifcsname #2{}uN\endcsname
+ \ekv@set@key@a\fi\ekv@set@key@c#2{}uN\endcsname
+ {%
+ \ekv@ifdefined{#2{#1}}%
+ \ekv@err@reqval
+ \ekv@err@unknown
+ #2%
+ }%
+ {#1}%
+ }%
+ \ekv@set@other#2%
+ }
+ \def\ekv@set@key@a\fi\ekv@set@key@c{\fi\expandafter\ekv@set@key@b\csname}
+ \long\def\ekv@set@key@c#1N\endcsname#2{#2}
}
-\def\ekv@set@key@#1%
+\long\def\ekv@set@key@b#1%
{%
\ifx#1\relax
\ekv@fi@secondoftwo
\fi
\@firstoftwo#1%
}
-\protected\def\ekvsetdef#1#2%
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+\protected\def\ekvsetdef#1#2}}}}%
{%
- \expandafter\expandafter\expandafter
- \ekv@setdef\expandafter\expandafter\expandafter{\ekvset{#2}{##1}}#1%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def#1##1}}%
+ {\ekvset{#2}{##1}}%
+ }
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+\protected\def\ekvsetSneakeddef#1#2}}}}%
+ {%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def#1##1##2}}%
+ {\ekvsetSneaked{#2}{##1}{##2}}%
}
-\protected\def\ekv@setdef#1#2%
+\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{\ekv@expB@unbraceA{%
+\protected\def\ekvsetdefSneaked#1#2#3}}}}%
{%
- \long\def#2##1{#1}%
+ \ekv@expB@unbraceA{\ekv@expB@unbraceA{\long\def#1##1}}%
+ {\ekvsetSneaked{#2}{#3}{##1}}%
}
\begingroup
\edef\ekv@err
@@ -451,34 +593,12 @@
\def\ekv@err@{\expandafter\ekv@gobbleto@stop}
\long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}}
\long\def\ekv@err@common@#1`#2' #3.#4#5{\ekv@err{#4 (`#5', set `#2')}}
-\long\def\ekv@err@unknown#1#2{\ekv@err@common{unknown key}#1{#2}}
-\long\def\ekv@err@noarg #1#2{\ekv@err@common{value forbidden}#1{#2}}
-\long\def\ekv@err@reqval #1#2{\ekv@err@common{value required}#1{#2}}
-\def\ekv@strip#1%
- {%
- \long\def\ekv@strip##1%
- {%
- \ekv@strip@a
- ##1%
- \ekv@nil
- \ekv@mark#1%
- #1\ekv@nil{}%
- \ekv@stop
- }%
- \long\def\ekv@strip@a##1\ekv@mark#1##2\ekv@nil##3%
- {%
- \ekv@strip@b##3##1##2\ekv@nil
- }%
- \long\def\ekv@strip@b##1#1\ekv@nil
- {%
- \ekv@strip@c##1\ekv@nil
- }%
- \long\def\ekv@strip@c\ekv@mark##1\ekv@nil##2\ekv@stop##3%
- {%
- ##3{##1}%
- }%
- }
-\ekv@strip{ }
+\ekv@expB@unbraceA{\long\def\ekv@err@unknown#1}%
+ {\ekv@err@common{unknown key}{#1}}
+\ekv@expB@unbraceA{\long\def\ekv@err@noarg #1}%
+ {\ekv@err@common{value forbidden}{#1}}
+\ekv@expB@unbraceA{\long\def\ekv@err@reqval #1}%
+ {\ekv@err@common{value required}{#1}}
\catcode`\@=\ekv@tmp
%%
%%