texlive[56634] Master/texmf-dist: expkv (11oct20)

commits+karl at tug.org commits+karl at tug.org
Sun Oct 11 22:49:37 CEST 2020


Revision: 56634
          http://tug.org/svn/texlive?view=revision&revision=56634
Author:   karl
Date:     2020-10-11 22:49:36 +0200 (Sun, 11 Oct 2020)
Log Message:
-----------
expkv (11oct20)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/expkv/README.md
    trunk/Master/texmf-dist/doc/latex/expkv/expkv.pdf
    trunk/Master/texmf-dist/source/latex/expkv/expkv.dtx
    trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex

Modified: trunk/Master/texmf-dist/doc/latex/expkv/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/expkv/README.md	2020-10-11 20:49:19 UTC (rev 56633)
+++ trunk/Master/texmf-dist/doc/latex/expkv/README.md	2020-10-11 20:49:36 UTC (rev 56634)
@@ -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

Modified: trunk/Master/texmf-dist/doc/latex/expkv/expkv.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/expkv/expkv.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/expkv/expkv.dtx	2020-10-11 20:49:19 UTC (rev 56633)
+++ trunk/Master/texmf-dist/source/latex/expkv/expkv.dtx	2020-10-11 20:49:36 UTC (rev 56634)
@@ -70,6 +70,7 @@
 \RequirePackage{array}
 \RequirePackage{collcell}
 \RequirePackage{siunitx}
+\DeclareSIUnit\ops{ops}
 \RequirePackage{xcolor}
 \RequirePackage{caption}
 \RequirePackage{microtype}
@@ -102,6 +103,19 @@
 \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 @@
 \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 @@
         {^^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 @@
 % \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 @@
 % 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 @@
 %     \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 @@
 %     \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,6 +368,16 @@
 %   |\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}
@@ -355,12 +384,43 @@
 %   \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 @@
 %   \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 @@
 %     \cs{ekv at 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 at name@set| is
-%   ``\texttt{\csname ekv at name@set\endcsname{\set}}'' and the default of
-%   |\ekv at name@key| is ``\texttt{\csname ekv at name@key\endcsname{\key}}''.
-%   The complete name is build using |\ekv at name| which is equivalent to
-%   \texttt
-%     {^^A
-%       \cs[no-index]{ekv at name@set}\marg{set}\cs{ekv at 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 at name@set|) and one for formatting the \key\ name
+%   (|\ekv at name@key|). To get the actual name the argument to |\ekv at name@key|
+%   must be |\detokenize|d. Both blocks are put together (with the necessary
+%   |\detokenize|) by |\ekv at name|.
 %   For |NoVal| keys an additional |N| gets appended irrespective of these
 %   macros' definition, so their name is
-%   \cs[no-index]{\csname ekv at name\endcsname{\set}{\key}N}. You might redefine
-%   |\ekv at name@set| and |\ekv at name@key| locally but \emph{don't redefine}
-%   |\ekv at name|!
+%   \texttt{\cs[no-index]{ekv at 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 @@
 % \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 @@
 % 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).
+% |\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 $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.
+% \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 @@
 % \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{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 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{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}).
+% \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 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{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 $2.7$ times slower for one key,
-% but has an \emph{enormous} feature set.
+% \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 @@
 % 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 @@
 %     \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 @@
 %   \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 @@
 %
 % 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 @@
 % \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 @@
 % restore it at the end of the file, we never care for the actual definition of
 % it.
 %
+% \begin{macro}[internal]{\ekv at 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 at tmpa{\string \lastnamedcs}
+  \edef\ekv at tmpb{\meaning\lastnamedcs}
+  \ifx\ekv at tmpa\ekv at tmpb
+    \def\ekv at if@lastnamedcs{\long\def\ekv at if@lastnamedcs##1##2{##1}}
+  \else
+    \def\ekv at if@lastnamedcs{\long\def\ekv at if@lastnamedcs##1##2{##2}}
+  \fi
+  \expandafter
+\endgroup
+\ekv at if@lastnamedcs
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv at 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 at empty| which will just expand to nothing, that is faster than
+% gobbling an argument.
+%    \begin{macrocode}
+\def\ekv at empty{}
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[internal]
 %   {
 %     \@gobble,\@firstofone,\@firstoftwo,\@secondoftwo,
@@ -1112,28 +1212,89 @@
 %
 % \begin{macro}[internal]{\ekv at 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 at ifdefined#1%
+\ekv at if@lastnamedcs
   {%
-    \expandafter
-    \ifx\csname\ifcsname #1\endcsname #1\else relax\fi\endcsname\relax
-      \ekv at fi@secondoftwo
-    \fi
-    \@firstoftwo
+    \def\ekv at ifdefined#1{\ifcsname#1\endcsname\ekv at ifdef@\fi\@secondoftwo}
+    \def\ekv at ifdef@\fi\@secondoftwo
+      {%
+        \fi
+        \expandafter\ifx\lastnamedcs\relax
+          \ekv at fi@secondoftwo
+        \fi
+        \@firstoftwo
+      }
   }
+  {%
+    \def\ekv at ifdefined#1%
+      {%
+        \ifcsname#1\endcsname\ekv at ifdef@\fi\ekv at ifdef@false#1\endcsname\relax
+          \ekv at fi@secondoftwo
+        \fi
+        \@firstoftwo
+      }
+    \def\ekv at ifdef@\fi\ekv at ifdef@false{\fi\expandafter\ifx\csname}
+    \long\def\ekv at ifdef@false
+        #1\endcsname\relax\ekv at fi@secondoftwo\fi\@firstoftwo#2#3%
+      {#3}
+  }
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{\ekv at strip,\ekv at strip@a,\ekv at strip@b,\ekv at strip@c}
+% We borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
+% from keys and values. This |\ekv at 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 at 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 at strip#1%
+  {%
+    \long\def\ekv at strip##1%
+      {%
+        \ekv at strip@a
+          ##1\ekv at nil
+          \ekv at mark#1%
+          #1\ekv at nil
+        \ekv at stop
+      }%
+    \long\def\ekv at strip@a##1\ekv at mark#1{\ekv at strip@b##1\ekv at mark}%
+    \long\def\ekv at strip@b##1#1\ekv at nil {\ekv at strip@c##1\ekv at nil}%
+  }
+\ekv at strip{ }
+\long\def\ekv at strip@c\ekv at mark#1\ekv at nil\ekv at mark#2\ekv at nil\ekv at stop#3{#3{#1}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv at expB@unbraceA,\ekv at 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 at expB@unbraceA#1#2%
+  {%
+    \expandafter\ekv at expB@unbraceA@\expandafter{#2}{#1}%
+  }
+\long\def\ekv at expB@unbraceA@#1#2{#2{#1}}%
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}{\ekv at name,\ekv at name@set,\ekv at name@key}
 % The keys will all follow the same naming scheme, so we define it here.
 %    \begin{macrocode}
-\def\ekv at name#1#2{\ekv at name@set{#1}\ekv at name@key{\detokenize{#2}}}
 \def\ekv at name@set#1{ekv#1(}
 \def\ekv at name@key#1{#1)}
+\edef\ekv at name
+  {%
+    \unexpanded\expandafter{\ekv at name@set{#1}}%
+    \unexpanded\expandafter{\ekv at name@key{\detokenize{#2}}}%
+  }
+\ekv at expB@unbraceA{\def\ekv at name#1#2}{\ekv at name}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1158,23 +1319,28 @@
 % 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 at checkvalid#1#2%
+\edef\ekv at checkvalid
   {%
-    \ekv at ifempty{#1}%
-      {%
+    \unexpanded\expandafter{\ekv at ifempty{#1}}%
+    \unexpanded
+      {{%
         \def\ekv at tmp{}%
         \errmessage{expkv Error: empty set name not allowed}%
-      }%
+      }}%
       {%
-        \ekv at ifempty{#2}%
+        \unexpanded\expandafter{\ekv at ifempty{#2}}%
+        \unexpanded
           {%
-            \def\ekv at tmp{}%
-            \errmessage{expkv Error: empty key name not allowed}%
+            {%
+              \def\ekv at tmp{}%
+              \errmessage{expkv Error: empty key name not allowed}%
+            }%
+            \@secondoftwo
           }%
-          \@secondoftwo
       }%
-    \@gobble
+    \unexpanded{\@gobble}%
   }
+\ekv at expB@unbraceA{\protected\def\ekv at checkvalid#1#2}{\ekv at checkvalid}%
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1181,8 +1347,10 @@
 % \begin{macro}{\ekvifdefined,\ekvifdefinedNoVal}
 % And provide user-level macros to test whether a key is defined.
 %    \begin{macrocode}
-\def\ekvifdefined#1#2{\ekv at ifdefined{\ekv at name{#1}{#2}}}
-\def\ekvifdefinedNoVal#1#2{\ekv at ifdefined{\ekv at name{#1}{#2}N}}
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\def\ekvifdefined#1#2}}%
+  {\expandafter\ekv at ifdefined\expandafter{\ekv at name{#1}{#2}}}
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\def\ekvifdefinedNoVal#1#2}}%
+  {\expandafter\ekv at ifdefined\expandafter{\ekv at name{#1}{#2}N}}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1191,74 +1359,71 @@
 %     \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 at 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 at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+        \protected\long\def\ekvdefunknown##1##2}}}%
       {%
-        \expandafter\def\csname\ekv at name{#1}{#2}\endcsname##1{#3}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at expB@unbraceA@\expandafter
+          {%
+            \expandafter\expandafter\expandafter
+            \def\expandafter\csname\ekv at name{##1}{}u\endcsname####1####2{##2}%
+            #3%
+          }%
+          {\ekv at checkvalid{##1}.}%
       }%
-  }
-\protected\long\def\ekvdefNoVal#1#2#3%
-  {%
-    \ekv at checkvalid{#1}{#2}%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+        \protected\long\def\ekvdefunknownNoVal##1##2}}}%
       {%
-        \expandafter\def\csname\ekv at name{#1}{#2}N\endcsname{#3}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at expB@unbraceA@\expandafter
+          {%
+            \expandafter\expandafter\expandafter
+            \def\expandafter\csname\ekv at name{##1}{}uN\endcsname####1{##2}%
+            #3%
+          }%
+          {\ekv at checkvalid{##1}.}%
       }%
-  }
-\protected\def\ekvlet#1#2#3%
-  {%
-    \ekv at checkvalid{#1}{#2}%
+    \protected\def\ekvletkv##1##2##3##4%
       {%
-        \expandafter\let\csname\ekv at name{#1}{#2}\endcsname#3%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        #1%
+          {%
+            \expandafter\let\csname#2\expandafter\endcsname
+            \csname#4\endcsname
+            #3%
+          }%
       }%
-  }
-\protected\def\ekvletNoVal#1#2#3%
-  {%
-    \ekv at checkvalid{#1}{#2}%
+    \protected\def\ekvletkvNoVal##1##2##3##4%
       {%
-        \expandafter\let\csname\ekv at name{#1}{#2}N\endcsname#3%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        #1%
+          {%
+            \expandafter\let\csname#2N\expandafter\endcsname
+            \csname#4N\endcsname
+            #3%
+          }%
       }%
   }
-\protected\def\ekvletkv#1#2#3#4%
+\edef\ekvdefNoVal
   {%
-    \ekv at checkvalid{#1}{#2}%
-      {%
-        \expandafter\let\csname\ekv at name{#1}{#2}\expandafter\endcsname
-        \csname\ekv at name{#3}{#4}\endcsname
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
-      }%
-  }
-\protected\def\ekvletkvNoVal#1#2#3#4%
-  {%
-    \ekv at checkvalid{#1}{#2}%
-      {%
-        \expandafter\let\csname\ekv at name{#1}{#2}N\expandafter\endcsname
-        \csname\ekv at name{#3}{#4}N\endcsname
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
-      }%
-  }
-\protected\def\ekvdefunknown#1#2%
-  {%
-    \ekv at checkvalid{#1}{.}%
-      {%
-        \expandafter\def\csname\ekv at name{#1}{}u\endcsname##1##2{#2}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
-      }%
-  }
-\protected\def\ekvdefunknownNoVal#1#2%
-  {%
-    \ekv at checkvalid{#1}{.}%
-      {%
-        \expandafter\def\csname\ekv at name{#1}{}uN\endcsname##1{#2}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
-      }%
-  }
+    {\unexpanded\expandafter{\ekv at checkvalid{#1}{#2}}}%
+    {\unexpanded\expandafter{\ekv at name{#1}{#2}}}%
+    {%
+      \unexpanded{\expandafter\ekv at defsetmacro\csname}%
+      \unexpanded\expandafter{\ekv at undefined@set{#1}\endcsname{#1}}%
+    }%
+    {\unexpanded\expandafter{\ekv at name{#3}{#4}}}%
+  }%
+\expandafter\ekvdef\ekvdefNoVal
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1267,20 +1432,24 @@
 %   into a control sequence pretty early, so we have to define that control
 %   sequence.
 %    \begin{macrocode}
-\protected\def\ekv at defsetmacro#1#2%
+\edef\ekv at defsetmacro
   {%
-    \ifx#1\relax
-      \edef#1##1{\ekv at name@set{#2}\ekv at name@key{\noexpand\detokenize{##1}}}%
-    \fi
+    \unexpanded{\ifx#1\relax\edef#1##1}%
+      {%
+        \unexpanded\expandafter{\ekv at name@set{#2}}%
+        \unexpanded\expandafter{\ekv at name@key{##1}}%
+      }%
+    \unexpanded{\fi}%
   }
+\ekv at expB@unbraceA{\protected\def\ekv at defsetmacro#1#2}{\ekv at defsetmacro}
 %    \end{macrocode}
 % \end{macro}
 %
 % \begin{macro}{\ekvifdefinedset}
 %    \begin{macrocode}
-\def\ekvifdefinedset#1%
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\def\ekvifdefinedset#1}}%
   {%
-    \ekv at ifdefined{\ekv at undefined@set{#1}}%
+    \expandafter\ekv at ifdefined\expandafter{\ekv at undefined@set{#1}}%
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1294,11 +1463,13 @@
 % |#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 at expB@unbraceA{\long\def\ekvset##1##2}%
   {%
-    \expandafter\ekv at set\csname\ekv at undefined@set{##1}\endcsname
+    \expandafter\expandafter\expandafter
+    \ekv at set\expandafter\csname\ekv at undefined@set{##1}\endcsname
       \ekv at mark##2#1\ekv at stop#1{}%
   }
 %    \end{macrocode}
@@ -1315,13 +1486,9 @@
 %    \begin{macrocode}
     \ekv at gobble@from at mark@to at stop##2\ekv at endset\ekv at stop
 %    \end{macrocode}
-% else go on with other commas,
+% else go on with other commas.
 %    \begin{macrocode}
     \ekv at set@other##1##2,\ekv at stop,%
-%    \end{macrocode}
-% and get the next active comma delimited \kv\ pair.
-%    \begin{macrocode}
-    \ekv at set##1\ekv at mark
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1331,9 +1498,8 @@
 % of |\ekv at set| and unbrace the sneaked stuff.
 %    \begin{macrocode}
 \long\def\ekv at endset
-    \ekv at stop\ekv at set@other##1,\ekv at stop,\ekv at set##2\ekv at mark
-    ##3%
-  {##3}
+    \ekv at stop\ekv at set@other##1\ekv at mark\ekv at stop,\ekv at stop,##2%
+  {##2}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1349,11 +1515,11 @@
 %   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 at eq@other##1=##2\ekv at mark##3##4\ekv at stop
+\long\def\ekv at eq@other##1=##2\ekv at mark##3%
   {%
     ##3##1\ekv at stop\ekv at mark##2%
   }
-\long\def\ekv at eq@active##1#2##2\ekv at mark##3##4\ekv at stop
+\long\def\ekv at eq@active##1#2##2\ekv at mark##3%
   {%
     ##3##1\ekv at stop\ekv at mark##2%
   }
@@ -1373,12 +1539,12 @@
 %   If not we split at the equal sign of category other.
 %    \begin{macrocode}
     \ekv at eq@other##2\ekv at nil\ekv at mark\ekv at set@eq at other@a
-      =\ekv at mark\ekv at set@eq at active\ekv at stop
+      =\ekv at mark\ekv at set@eq at active
 %    \end{macrocode}
-%   And insert the set name and the next recursion step of |\ekv at set@other|.
+%   And insert the set name for the next recursion step of |\ekv at set@other|.
 %    \begin{macrocode}
     ##1%
-    \ekv at set@other##1\ekv at mark
+    \ekv at mark
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1391,39 +1557,41 @@
 %    \begin{macrocode}
 \long\def\ekv at set@eq at other@a##1\ekv at stop
   {%
-    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at set@eq at other@active at a
-      #2\ekv at mark\ekv at set@eq at other@b\ekv at stop
+    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at set@eq at other@active
+      #2\ekv at mark\ekv at set@eq at other@b
   }
 %    \end{macrocode}
 %   The second macro will have been called by |\ekv at 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 at set@pair|.
+%   test and forward the \kv\ pair to |\ekv at set@pair|. Normally we would have to
+%   also gobble an additional |\ekv at mark| after |\ekv at stop|, but this mark is
+%   needed to delimit |\ekv at set@pair|'s argument anyway, so we just leave it
+%   there.
 %    \begin{macrocode}
-\long\def\ekv at set@eq at other@b
-    ##1\ekv at nil\ekv at mark\ekv at set@eq at other@active at a\ekv at stop\ekv at mark
+\ekv at expB@unbraceA
   {%
-    \ekv at strip{##1}\ekv at set@pair
-  }
+    \long\def\ekv at set@eq at other@b
+        ##1\ekv at nil\ekv at mark\ekv at set@eq at other@active\ekv at stop\ekv at mark
+        ##2\ekv at nil=\ekv at mark\ekv at set@eq at active
+  }%
+  {\ekv at strip{##1}{\expandafter\ekv at set@pair\detokenize}\ekv at mark##2\ekv at nil}
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[internal]{\ekv at set@eq at other@active at a,\ekv at set@eq at other@active at b}
-%   |\ekv at set@eq at other@active at a| will be called if the \kv\ pair was wrongly
+% \begin{macro}[internal]{\ekv at set@eq at other@active}
+%   |\ekv at set@eq at 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 at set@eq at other@active at b| which calls |\ekv at set@pair| on the then
-%   correctly split \kv\ pair.
+%   to reinsert the equal sign and forward things to |\ekv at set@pair|.
 %    \begin{macrocode}
-\long\def\ekv at set@eq at other@active at a##1\ekv at stop##2\ekv at nil\ekv at mark
+\ekv at expB@unbraceA
   {%
-    \ekv at set@eq at other@active at b{##1}##2=%
-  }
-\long\def\ekv at set@eq at other@active at b##1%
-  {%
-    \ekv at strip{##1}\ekv at set@pair
-  }
+    \long\def\ekv at set@eq at other@active
+        ##1\ekv at stop##2\ekv at nil#2\ekv at mark
+        \ekv at set@eq at other@b\ekv at mark##3=\ekv at mark\ekv at set@eq at active
+  }%
+  {\ekv at strip{##1}{\expandafter\ekv at set@pair\detokenize}\ekv at mark##2=##3}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1436,15 +1604,16 @@
     ##1\ekv at nil\ekv at mark\ekv at set@eq at other@a\ekv at stop\ekv at mark
   {%
     \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at set@eq at active@
-      #2\ekv at mark\ekv at set@noeq\ekv at stop
+      #2\ekv at mark\ekv at set@noeq
   }
 %    \end{macrocode}
 %   If an active equal sign was found in |\ekv at set@eq at active| we'll have to pass
 %   the now split \kv\ pair on to |\ekv at set@pair|.
 %    \begin{macrocode}
-\long\def\ekv at set@eq at active@##1\ekv at stop
+\ekv at expB@unbraceA
+  {\long\def\ekv at set@eq at active@##1\ekv at stop##2\ekv at nil#2\ekv at mark\ekv at set@noeq}%
   {%
-    \ekv at strip{##1}\ekv at set@pair
+    \ekv at strip{##1}{\expandafter\ekv at set@pair\detokenize}\ekv at mark##2\ekv at nil
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1456,12 +1625,31 @@
 %   to gobble the set-name which was put after these tests by |\ekv at set@other|).
 %   Else this is a |NoVal| key and the entry is passed on to |\ekv at set@key|.
 %    \begin{macrocode}
-\long\def\ekv at set@noeq##1\ekv at nil\ekv at mark\ekv at set@eq at active@\ekv at stop\ekv at mark
+\edef\ekv at set@noeq
   {%
-    \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at ifempty@true at F@gobble
-      \ekv at ifempty@A\ekv at ifempty@B\@firstofone
-      {\ekv at strip{##1}\ekv at set@key}%
+    \unexpanded
+      {%
+        \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at set@was at blank
+          \ekv at ifempty@A\ekv at ifempty@B
+      }%
+    \unexpanded\expandafter
+      {\ekv at strip{##1}{\expandafter\ekv at set@key\detokenize}\ekv at mark}%
   }
+\ekv at expB@unbraceA
+  {%
+    \long\def\ekv at set@noeq
+        ##1\ekv at nil\ekv at mark\ekv at set@eq at active@\ekv at stop\ekv at mark
+  }%
+  {\ekv at set@noeq}
+\def\ekv at set@was at blank##1%
+  {%
+    \def\ekv at set@was at blank
+        \ekv at ifempty@A\ekv at ifempty@B
+        \ekv at strip@a\ekv at mark####1\ekv at nil\ekv at mark##1##1\ekv at nil\ekv at stop
+        ####2\ekv at mark
+      {\ekv at set@other}%
+  }
+\ekv at set@was at blank{ }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1471,11 +1659,9 @@
 %    \begin{macrocode}
 \long\def\ekv at endset@other
     \ekv at stop
-    \ekv at eq@other##1\ekv at nil\ekv at mark\ekv at set@eq at other@a
-    =\ekv at mark\ekv at set@eq at active\ekv at stop
-    ##2%
-    \ekv at set@other##3\ekv at mark
-  {}
+    \ekv at eq@other\ekv at mark\ekv at stop\ekv at nil\ekv at mark\ekv at set@eq at other@a
+    =\ekv at mark\ekv at set@eq at active
+  {\ekv at set}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1524,7 +1710,6 @@
   {%
     \ekv at gobble@from at mark@to at stop##3\ekv at endparse\ekv at stop
     \ekv at parse@other##1##2##3,\ekv at stop,%
-    \ekv at parse##1##2\ekv at mark
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1532,7 +1717,7 @@
 % \begin{macro}[internal]{\ekv at endparse}
 %    \begin{macrocode}
 \long\def\ekv at endparse
-    \ekv at stop\ekv at parse@other##1,\ekv at stop,\ekv at parse##2\ekv at mark
+    \ekv at stop\ekv at parse@other##1\ekv at mark\ekv at stop,\ekv at stop,%
   {}
 %    \end{macrocode}
 % \end{macro}
@@ -1543,9 +1728,9 @@
   {%
     \ekv at gobble@from at mark@to at stop##3\ekv at endparse@other\ekv at stop
     \ekv at eq@other##3\ekv at nil\ekv at mark\ekv at parse@eq at other@a
-      =\ekv at mark\ekv at parse@eq at active\ekv at stop
+      =\ekv at mark\ekv at parse@eq at active
     ##1##2%
-    \ekv at parse@other##1##2\ekv at mark
+    \ekv at mark
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1554,28 +1739,28 @@
 %    \begin{macrocode}
 \long\def\ekv at parse@eq at other@a##1\ekv at stop
   {%
-    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active at a
-      #2\ekv at mark\ekv at parse@eq at other@b\ekv at stop
+    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active
+      #2\ekv at mark\ekv at parse@eq at other@b
   }
-\long\def\ekv at parse@eq at other@b
-    ##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active at a\ekv at stop\ekv at mark
+\ekv at expB@unbraceA
   {%
-    \ekv at strip{##1}\ekv at parse@pair
-  }
+    \long\def\ekv at parse@eq at other@b
+        ##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active\ekv at stop\ekv at mark
+        ##2\ekv at nil=\ekv at mark\ekv at parse@eq at active
+  }%
+  {\ekv at strip{##1}\ekv at parse@pair##2\ekv at nil}
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[internal]
-%   {\ekv at parse@eq at other@active at a,\ekv at parse@eq at other@active at b}
+% \begin{macro}[internal]{\ekv at parse@eq at other@active}
 %    \begin{macrocode}
-\long\def\ekv at parse@eq at other@active at a##1\ekv at stop##2\ekv at nil\ekv at mark
+\ekv at expB@unbraceA
   {%
-    \ekv at parse@eq at other@active at b{##1}##2=%
-  }
-\long\def\ekv at parse@eq at other@active at b##1%
-  {%
-    \ekv at strip{##1}\ekv at parse@pair
-  }
+    \long\def\ekv at parse@eq at other@active
+        ##1\ekv at stop##2\ekv at nil#2\ekv at mark
+        \ekv at parse@eq at other@b\ekv at mark##3=\ekv at mark\ekv at parse@eq at active
+  }%
+  {\ekv at strip{##1}\ekv at parse@pair##2=##3}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1585,11 +1770,12 @@
     ##1\ekv at nil\ekv at mark\ekv at parse@eq at other@a\ekv at stop\ekv at mark
   {%
     \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at parse@eq at active@
-      #2\ekv at mark\ekv at parse@noeq\ekv at stop
+      #2\ekv at mark\ekv at parse@noeq
   }
-\long\def\ekv at parse@eq at active@##1\ekv at stop
+\ekv at expB@unbraceA
+  {\long\def\ekv at parse@eq at active@##1\ekv at stop##2#2\ekv at mark\ekv at parse@noeq}%
   {%
-    \ekv at strip{##1}\ekv at parse@pair
+    \ekv at strip{##1}\ekv at parse@pair##2%
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1596,13 +1782,30 @@
 %
 % \begin{macro}[internal]{\ekv at parse@noeq}
 %    \begin{macrocode}
-\long\def\ekv at parse@noeq
-    ##1\ekv at nil\ekv at mark\ekv at parse@eq at active@\ekv at stop\ekv at mark
+\edef\ekv at parse@noeq
   {%
-    \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at ifempty@true at F@gobbletwo
-      \ekv at ifempty@A\ekv at ifempty@B\@firstofone
-      {\ekv at strip{##1}\ekv at parse@key}%
+    \unexpanded
+      {%
+        \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at parse@was at blank
+          \ekv at ifempty@A\ekv at ifempty@B
+      }%
+      \unexpanded\expandafter{\ekv at strip{##1}\ekv at parse@key}%
   }
+\ekv at expB@unbraceA
+  {%
+    \long\def\ekv at parse@noeq
+        ##1\ekv at nil\ekv at mark\ekv at parse@eq at active@\ekv at stop\ekv at mark
+  }%
+  {\ekv at parse@noeq}
+\def\ekv at parse@was at blank##1%
+  {%
+    \def\ekv at parse@was at blank
+        \ekv at ifempty@A\ekv at ifempty@B
+        \ekv at strip@a\ekv at mark####1\ekv at nil\ekv at mark##1##1\ekv at nil\ekv at stop
+        \ekv at parse@key
+      {\ekv at parse@other}%
+  }
+\ekv at parse@was at blank{ }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1610,17 +1813,15 @@
 %    \begin{macrocode}
 \long\def\ekv at endparse@other
     \ekv at stop
-    \ekv at eq@other##1\ekv at nil\ekv at mark\ekv at parse@eq at other@a
-    =\ekv at mark\ekv at parse@eq at active\ekv at stop
-    ##2%
-    \ekv at parse@other##3\ekv at mark
-  {}
+    \ekv at eq@other\ekv at mark\ekv at stop\ekv at nil\ekv at mark\ekv at parse@eq at other@a
+    =\ekv at mark\ekv at parse@eq at active
+  {\ekv at parse}
 %    \end{macrocode}
 % \end{macro}
 %
 % \begin{macro}[internal]{\ekv at parse@pair,\ekv at parse@pair@}
 %    \begin{macrocode}
-\long\def\ekv at parse@pair##1##2\ekv at nil
+\ekv at expB@unbraceA{\long\def\ekv at parse@pair##1##2\ekv at nil}%
   {%
     \ekv at strip{##2}\ekv at parse@pair@{##1}%
   }
@@ -1627,6 +1828,7 @@
 \long\def\ekv at parse@pair@##1##2##3##4%
   {%
     \unexpanded{##4{##2}{##1}}%
+    \ekv at parse@other##3##4%
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1636,6 +1838,7 @@
 \long\def\ekv at parse@key##1##2##3%
   {%
     \unexpanded{##2{##1}}%
+    \ekv at parse@other##2##3%
   }
 %    \end{macrocode}
 % \end{macro}
@@ -1643,12 +1846,26 @@
 % 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 at expB@unbraceA{\ekv at 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,112 +1875,148 @@
 % 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 at expB@unbraceA{\def\ekvchangeset#1}%
   {%
-    \expandafter\ekv at changeset\csname\ekv at undefined@set{#1}\endcsname\ekv at mark
+    \expandafter\expandafter\expandafter
+    \ekv at changeset\expandafter\csname\ekv at undefined@set{#1}\endcsname\ekv at empty
   }
 %    \end{macrocode}
 % \end{macro}
 %
 % \begin{macro}[internal]{\ekv at changeset}
-% This macro does the real change-out of |\ekvchangeset|. We introduced an
-% |\ekv at 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 at 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 at changeset#1#2\ekv at set@other#3#4\ekv at set#5%
+\long\def\ekv at changeset#1#2\ekv at set@other#3%
   {%
-    \ekv at gobble@mark#2\ekv at set@other#1#4\ekv at set#1%
+    #2\ekv at set@other#1%
   }
 %    \end{macrocode}
 % \end{macro}
 %
 %
-% \begin{macro}[internal]{\ekv at set@pair}
-%   |\ekv at 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 at 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 at set@pair| if it isn't.
+% \begin{macro}[internal]
+%   {
+%     \ekv at set@pair,\ekv at set@pair at a,\ekv at set@pair at b,\ekv at set@pair at c,
+%     \ekv at set@pair at d,\ekv at set@pair at e
+%   }
+%   |\ekv at 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 at set@pair|.
 %    \begin{macrocode}
-\long\def\ekv at set@pair#1#2\ekv at nil#3%
+\ekv at if@lastnamedcs
   {%
-    \expandafter\ekv at set@pair@
-      \csname
-        \ifcsname #3{#1}\endcsname
-          #3{#1}%
-        \else
-          relax%
-        \fi
-      \endcsname
-      {#2}%
+    \long\def\ekv at set@pair#1\ekv at mark#2\ekv at nil#3%
       {%
-        \expandafter\ekv at set@pair@
-          \csname
-            \ifcsname #3{}u\endcsname
-              #3{}u%
-            \else
-              relax%
-            \fi
-          \endcsname
+        \ifcsname #3{#1}\endcsname\ekv at set@pair at a\fi\@secondoftwo
           {#2}%
           {%
-            \ekv at ifdefined{#3{#1}N}%
-              \ekv at err@noarg
-              \ekv at err@unknown
-              #3%
+            \ifcsname #3{}u\endcsname\ekv at set@pair at a\fi\@secondoftwo
+              {#2}%
+              {%
+                \ekv at ifdefined{#3{#1}N}%
+                  \ekv at err@noarg
+                  \ekv at err@unknown
+                  #3%
+              }%
+              {#1}%
           }%
-          {#1}%
-      }%
+        \ekv at set@other#3%
+      }
+    \def\ekv at set@pair at a\fi\@secondoftwo
+      {\fi\expandafter\ekv at set@pair at b\lastnamedcs}
   }
-\long\def\ekv at set@pair@#1#2%
   {%
+    \long\def\ekv at set@pair#1\ekv at mark#2\ekv at nil#3%
+      {%
+        \ifcsname #3{#1}\endcsname
+            \ekv at set@pair at a\fi\ekv at set@pair at c#3{#1}\endcsname
+          {#2}%
+          {%
+            \ifcsname #3{}u\endcsname
+                \ekv at set@pair at a\fi\ekv at set@pair at c#3{}u\endcsname
+              {#2}%
+              {%
+                \ekv at ifdefined{#3{#1}N}%
+                  \ekv at err@noarg
+                  \ekv at err@unknown
+                  #3%
+              }%
+              {#1}%
+          }%
+        \ekv at set@other#3%
+      }
+    \def\ekv at set@pair at a\fi\ekv at set@pair at c{\fi\expandafter\ekv at set@pair at b\csname}
+    \long\def\ekv at set@pair at c#1\endcsname#2#3{#3}
+  }
+\long\def\ekv at set@pair at b#1%
+  {%
     \ifx#1\relax
-      \ekv at fi@secondoftwo
+      \ekv at set@pair at e
     \fi
-    \@firstoftwo
-    {\ekv at strip{#2}#1}%
+    \ekv at set@pair at d#1%
   }
+\ekv at expB@unbraceA{\long\def\ekv at set@pair at d#1#2#3}{\ekv at strip{#2}#1}
+\long\def\ekv at set@pair at e\fi\ekv at set@pair at d#1#2#3{\fi#3}
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[internal]{\ekv at set@key}
+% \begin{macro}[internal]
+%   {\ekv at set@key,\ekv at set@key at a,\ekv at set@key at b,\ekv at set@key at c}
 % Analogous to |\ekv at set@pair|, |\ekv at set@key| builds the |NoVal| key-macro and
 % provides an error-branch. |\ekv at 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 at set@key#1#2%
+\ekv at if@lastnamedcs
   {%
-    \expandafter\ekv at set@key@
-      \csname
-        \ifcsname #2{#1}N\endcsname
-          #2{#1}N%
-        \else
-          relax%
-        \fi
-      \endcsname
+    \long\def\ekv at set@key#1\ekv at mark#2%
       {%
-        \expandafter\ekv at set@key@
-          \csname
-            \ifcsname #2{}uN\endcsname
-              #2{}uN%
-            \else
-              relax%
-            \fi
-          \endcsname
+        \ifcsname #2{#1}N\endcsname\ekv at set@key at a\fi\@firstofone
           {%
-            \ekv at ifdefined{#2{#1}}%
-              \ekv at err@reqval
-              \ekv at err@unknown
-              #2%
+            \ifcsname #2{}uN\endcsname\ekv at set@key at a\fi\@firstofone
+              {%
+                \ekv at ifdefined{#2{#1}}%
+                  \ekv at err@reqval
+                  \ekv at err@unknown
+                  #2%
+              }%
+              {#1}%
           }%
-          {#1}%
-      }%
+        \ekv at set@other#2%
+      }
+    \def\ekv at set@key at a\fi\@firstofone{\fi\expandafter\ekv at set@key at b\lastnamedcs}
   }
-\def\ekv at set@key@#1%
   {%
+    \long\def\ekv at set@key#1\ekv at mark#2%
+      {%
+        \ifcsname #2{#1}N\endcsname
+            \ekv at set@key at a\fi\ekv at set@key at c#2{#1}N\endcsname
+          {%
+            \ifcsname #2{}uN\endcsname
+                \ekv at set@key at a\fi\ekv at set@key at c#2{}uN\endcsname
+              {%
+                \ekv at ifdefined{#2{#1}}%
+                  \ekv at err@reqval
+                  \ekv at err@unknown
+                  #2%
+              }%
+              {#1}%
+          }%
+        \ekv at set@other#2%
+      }
+    \def\ekv at set@key at a\fi\ekv at set@key at c{\fi\expandafter\ekv at set@key at b\csname}
+    \long\def\ekv at set@key at c#1N\endcsname#2{#2}
+  }
+\long\def\ekv at set@key at b#1%
+  {%
     \ifx#1\relax
       \ekv at fi@secondoftwo
     \fi
@@ -1774,25 +2027,35 @@
 %
 % \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 at 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 at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+\protected\def\ekvsetdef#1#2}}}}%
   {%
-    \expandafter\expandafter\expandafter
-    \ekv at setdef\expandafter\expandafter\expandafter{\ekvset{#2}{##1}}#1%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\long\def#1##1}}%
+      {\ekvset{#2}{##1}}%
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[internal]{\ekv at 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 at setdef#1#2%
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+\protected\def\ekvsetSneakeddef#1#2}}}}%
   {%
-    \long\def#2##1{#1}%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\long\def#1##1##2}}%
+      {\ekvsetSneaked{#2}{##1}{##2}}%
   }
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+\protected\def\ekvsetdefSneaked#1#2#3}}}}%
+  {%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\long\def#1##1}}%
+      {\ekvsetSneaked{#2}{#3}{##1}}%
+  }
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1827,47 +2090,15 @@
 %    \begin{macrocode}
 \long\def\ekv at err@common #1#2{\expandafter\ekv at err@common@\string#2{#1}}
 \long\def\ekv at err@common@#1`#2' #3.#4#5{\ekv at err{#4 (`#5', set `#2')}}
-\long\def\ekv at err@unknown#1#2{\ekv at err@common{unknown key}#1{#2}}
-\long\def\ekv at err@noarg  #1#2{\ekv at err@common{value forbidden}#1{#2}}
-\long\def\ekv at err@reqval #1#2{\ekv at err@common{value required}#1{#2}}
+\ekv at expB@unbraceA{\long\def\ekv at err@unknown#1}%
+  {\ekv at err@common{unknown key}{#1}}
+\ekv at expB@unbraceA{\long\def\ekv at err@noarg  #1}%
+  {\ekv at err@common{value forbidden}{#1}}
+\ekv at expB@unbraceA{\long\def\ekv at err@reqval #1}%
+  {\ekv at err@common{value required}{#1}}
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[internal]{\ekv at strip,\ekv at strip@a,\ekv at strip@b,\ekv at strip@c}
-% Finally we borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
-% from keys and values. This |\ekv at 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 at mark|. Also this
-% implementation at most strips \emph{one} space from both sides.
-%    \begin{macrocode}
-\def\ekv at strip#1%
-  {%
-    \long\def\ekv at strip##1%
-      {%
-        \ekv at strip@a
-          ##1%
-          \ekv at nil
-          \ekv at mark#1%
-          #1\ekv at nil{}%
-        \ekv at stop
-      }%
-    \long\def\ekv at strip@a##1\ekv at mark#1##2\ekv at nil##3%
-      {%
-        \ekv at strip@b##3##1##2\ekv at nil
-      }%
-    \long\def\ekv at strip@b##1#1\ekv at nil
-      {%
-        \ekv at strip@c##1\ekv at nil
-      }%
-    \long\def\ekv at strip@c\ekv at mark##1\ekv at nil##2\ekv at stop##3%
-      {%
-        ##3{##1}%
-      }%
-  }
-\ekv at strip{ }
-%    \end{macrocode}
-% \end{macro}
-%
 % Now everything that's left is to reset the category code of |@|.
 %    \begin{macrocode}
 \catcode`\@=\ekv at tmp

Modified: trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex	2020-10-11 20:49:19 UTC (rev 56633)
+++ trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex	2020-10-11 20:49:36 UTC (rev 56634)
@@ -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 at tmp\endcsname
 \expandafter\chardef\csname ekv at tmp\endcsname=\catcode`\@
 \catcode`\@=11
+\begingroup
+  \edef\ekv at tmpa{\string \lastnamedcs}
+  \edef\ekv at tmpb{\meaning\lastnamedcs}
+  \ifx\ekv at tmpa\ekv at tmpb
+    \def\ekv at if@lastnamedcs{\long\def\ekv at if@lastnamedcs##1##2{##1}}
+  \else
+    \def\ekv at if@lastnamedcs{\long\def\ekv at if@lastnamedcs##1##2{##2}}
+  \fi
+  \expandafter
+\endgroup
+\ekv at if@lastnamedcs
+\def\ekv at empty{}
 \long\def\@gobble#1{}
 \long\def\@firstofone#1{#1}
 \long\def\@firstoftwo#1#2{#1}
@@ -74,118 +86,169 @@
       \ekv at ifempty@A\ekv at ifempty@B\@secondoftwo
   }
 \long\def\ekv at ifblank@\ekv at mark#1{\ekv at ifempty@\ekv at ifempty@A}
-\def\ekv at ifdefined#1%
+\ekv at if@lastnamedcs
   {%
-    \expandafter
-    \ifx\csname\ifcsname #1\endcsname #1\else relax\fi\endcsname\relax
-      \ekv at fi@secondoftwo
-    \fi
-    \@firstoftwo
+    \def\ekv at ifdefined#1{\ifcsname#1\endcsname\ekv at ifdef@\fi\@secondoftwo}
+    \def\ekv at ifdef@\fi\@secondoftwo
+      {%
+        \fi
+        \expandafter\ifx\lastnamedcs\relax
+          \ekv at fi@secondoftwo
+        \fi
+        \@firstoftwo
+      }
   }
-\def\ekv at name#1#2{\ekv at name@set{#1}\ekv at name@key{\detokenize{#2}}}
-\def\ekv at name@set#1{ekv#1(}
-\def\ekv at name@key#1{#1)}
-\def\ekv at undefined@set#1{! expkv Error: Set `#1' undefined.}
-\protected\def\ekv at checkvalid#1#2%
   {%
-    \ekv at ifempty{#1}%
+    \def\ekv at ifdefined#1%
       {%
-        \def\ekv at tmp{}%
-        \errmessage{expkv Error: empty set name not allowed}%
-      }%
-      {%
-        \ekv at ifempty{#2}%
-          {%
-            \def\ekv at tmp{}%
-            \errmessage{expkv Error: empty key name not allowed}%
-          }%
-          \@secondoftwo
-      }%
-    \@gobble
+        \ifcsname#1\endcsname\ekv at ifdef@\fi\ekv at ifdef@false#1\endcsname\relax
+          \ekv at fi@secondoftwo
+        \fi
+        \@firstoftwo
+      }
+    \def\ekv at ifdef@\fi\ekv at ifdef@false{\fi\expandafter\ifx\csname}
+    \long\def\ekv at ifdef@false
+        #1\endcsname\relax\ekv at fi@secondoftwo\fi\@firstoftwo#2#3%
+      {#3}
   }
-\def\ekvifdefined#1#2{\ekv at ifdefined{\ekv at name{#1}{#2}}}
-\def\ekvifdefinedNoVal#1#2{\ekv at ifdefined{\ekv at name{#1}{#2}N}}
-\protected\long\def\ekvdef#1#2#3%
+\def\ekv at strip#1%
   {%
-    \ekv at checkvalid{#1}{#2}%
+    \long\def\ekv at strip##1%
       {%
-        \expandafter\def\csname\ekv at name{#1}{#2}\endcsname##1{#3}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \ekv at strip@a
+          ##1\ekv at nil
+          \ekv at mark#1%
+          #1\ekv at nil
+        \ekv at stop
       }%
+    \long\def\ekv at strip@a##1\ekv at mark#1{\ekv at strip@b##1\ekv at mark}%
+    \long\def\ekv at strip@b##1#1\ekv at nil {\ekv at strip@c##1\ekv at nil}%
   }
-\protected\long\def\ekvdefNoVal#1#2#3%
+\ekv at strip{ }
+\long\def\ekv at strip@c\ekv at mark#1\ekv at nil\ekv at mark#2\ekv at nil\ekv at stop#3{#3{#1}}
+\long\def\ekv at expB@unbraceA#1#2%
   {%
-    \ekv at checkvalid{#1}{#2}%
-      {%
-        \expandafter\def\csname\ekv at name{#1}{#2}N\endcsname{#3}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
-      }%
+    \expandafter\ekv at expB@unbraceA@\expandafter{#2}{#1}%
   }
-\protected\def\ekvlet#1#2#3%
+\long\def\ekv at expB@unbraceA@#1#2{#2{#1}}%
+\def\ekv at name@set#1{ekv#1(}
+\def\ekv at name@key#1{#1)}
+\edef\ekv at name
   {%
-    \ekv at checkvalid{#1}{#2}%
-      {%
-        \expandafter\let\csname\ekv at name{#1}{#2}\endcsname#3%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
-      }%
+    \unexpanded\expandafter{\ekv at name@set{#1}}%
+    \unexpanded\expandafter{\ekv at name@key{\detokenize{#2}}}%
   }
-\protected\def\ekvletNoVal#1#2#3%
+\ekv at expB@unbraceA{\def\ekv at name#1#2}{\ekv at name}
+\def\ekv at undefined@set#1{! expkv Error: Set `#1' undefined.}
+\edef\ekv at checkvalid
   {%
-    \ekv at checkvalid{#1}{#2}%
+    \unexpanded\expandafter{\ekv at ifempty{#1}}%
+    \unexpanded
+      {{%
+        \def\ekv at tmp{}%
+        \errmessage{expkv Error: empty set name not allowed}%
+      }}%
       {%
-        \expandafter\let\csname\ekv at name{#1}{#2}N\endcsname#3%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \unexpanded\expandafter{\ekv at ifempty{#2}}%
+        \unexpanded
+          {%
+            {%
+              \def\ekv at tmp{}%
+              \errmessage{expkv Error: empty key name not allowed}%
+            }%
+            \@secondoftwo
+          }%
       }%
+    \unexpanded{\@gobble}%
   }
-\protected\def\ekvletkv#1#2#3#4%
+\ekv at expB@unbraceA{\protected\def\ekv at checkvalid#1#2}{\ekv at checkvalid}%
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\def\ekvifdefined#1#2}}%
+  {\expandafter\ekv at ifdefined\expandafter{\ekv at name{#1}{#2}}}
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\def\ekvifdefinedNoVal#1#2}}%
+  {\expandafter\ekv at ifdefined\expandafter{\ekv at name{#1}{#2}N}}
+\def\ekvdef#1#2#3#4%
   {%
-    \ekv at 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 at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+        \protected\long\def\ekvdefunknown##1##2}}}%
       {%
-        \expandafter\let\csname\ekv at name{#1}{#2}\expandafter\endcsname
-        \csname\ekv at name{#3}{#4}\endcsname
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at expB@unbraceA@\expandafter
+          {%
+            \expandafter\expandafter\expandafter
+            \def\expandafter\csname\ekv at name{##1}{}u\endcsname####1####2{##2}%
+            #3%
+          }%
+          {\ekv at checkvalid{##1}.}%
       }%
-  }
-\protected\def\ekvletkvNoVal#1#2#3#4%
-  {%
-    \ekv at checkvalid{#1}{#2}%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+        \protected\long\def\ekvdefunknownNoVal##1##2}}}%
       {%
-        \expandafter\let\csname\ekv at name{#1}{#2}N\expandafter\endcsname
-        \csname\ekv at name{#3}{#4}N\endcsname
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at expB@unbraceA@\expandafter
+          {%
+            \expandafter\expandafter\expandafter
+            \def\expandafter\csname\ekv at name{##1}{}uN\endcsname####1{##2}%
+            #3%
+          }%
+          {\ekv at checkvalid{##1}.}%
       }%
-  }
-\protected\def\ekvdefunknown#1#2%
-  {%
-    \ekv at checkvalid{#1}{.}%
+    \protected\def\ekvletkv##1##2##3##4%
       {%
-        \expandafter\def\csname\ekv at name{#1}{}u\endcsname##1##2{#2}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        #1%
+          {%
+            \expandafter\let\csname#2\expandafter\endcsname
+            \csname#4\endcsname
+            #3%
+          }%
       }%
+    \protected\def\ekvletkvNoVal##1##2##3##4%
+      {%
+        #1%
+          {%
+            \expandafter\let\csname#2N\expandafter\endcsname
+            \csname#4N\endcsname
+            #3%
+          }%
+      }%
   }
-\protected\def\ekvdefunknownNoVal#1#2%
+\edef\ekvdefNoVal
   {%
-    \ekv at checkvalid{#1}{.}%
+    {\unexpanded\expandafter{\ekv at checkvalid{#1}{#2}}}%
+    {\unexpanded\expandafter{\ekv at name{#1}{#2}}}%
+    {%
+      \unexpanded{\expandafter\ekv at defsetmacro\csname}%
+      \unexpanded\expandafter{\ekv at undefined@set{#1}\endcsname{#1}}%
+    }%
+    {\unexpanded\expandafter{\ekv at name{#3}{#4}}}%
+  }%
+\expandafter\ekvdef\ekvdefNoVal
+\edef\ekv at defsetmacro
+  {%
+    \unexpanded{\ifx#1\relax\edef#1##1}%
       {%
-        \expandafter\def\csname\ekv at name{#1}{}uN\endcsname##1{#2}%
-        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \unexpanded\expandafter{\ekv at name@set{#2}}%
+        \unexpanded\expandafter{\ekv at name@key{##1}}%
       }%
+    \unexpanded{\fi}%
   }
-\protected\def\ekv at defsetmacro#1#2%
+\ekv at expB@unbraceA{\protected\def\ekv at defsetmacro#1#2}{\ekv at defsetmacro}
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\def\ekvifdefinedset#1}}%
   {%
-    \ifx#1\relax
-      \edef#1##1{\ekv at name@set{#2}\ekv at name@key{\noexpand\detokenize{##1}}}%
-    \fi
+    \expandafter\ekv at ifdefined\expandafter{\ekv at undefined@set{#1}}%
   }
-\def\ekvifdefinedset#1%
-  {%
-    \ekv at ifdefined{\ekv at undefined@set{#1}}%
-  }
+\begingroup
 \def\ekvset#1#2{%
 \endgroup
-\long\def\ekvset##1##2%
+\ekv at expB@unbraceA{\long\def\ekvset##1##2}%
   {%
-    \expandafter\ekv at set\csname\ekv at undefined@set{##1}\endcsname
+    \expandafter\expandafter\expandafter
+    \ekv at set\expandafter\csname\ekv at undefined@set{##1}\endcsname
       \ekv at mark##2#1\ekv at stop#1{}%
   }
 \long\def\ekv at set##1##2#1%
@@ -192,17 +255,15 @@
   {%
     \ekv at gobble@from at mark@to at stop##2\ekv at endset\ekv at stop
     \ekv at set@other##1##2,\ekv at stop,%
-    \ekv at set##1\ekv at mark
   }
 \long\def\ekv at endset
-    \ekv at stop\ekv at set@other##1,\ekv at stop,\ekv at set##2\ekv at mark
-    ##3%
-  {##3}
-\long\def\ekv at eq@other##1=##2\ekv at mark##3##4\ekv at stop
+    \ekv at stop\ekv at set@other##1\ekv at mark\ekv at stop,\ekv at stop,##2%
+  {##2}
+\long\def\ekv at eq@other##1=##2\ekv at mark##3%
   {%
     ##3##1\ekv at stop\ekv at mark##2%
   }
-\long\def\ekv at eq@active##1#2##2\ekv at mark##3##4\ekv at stop
+\long\def\ekv at eq@active##1#2##2\ekv at mark##3%
   {%
     ##3##1\ekv at stop\ekv at mark##2%
   }
@@ -210,51 +271,70 @@
   {%
     \ekv at gobble@from at mark@to at stop##2\ekv at endset@other\ekv at stop
     \ekv at eq@other##2\ekv at nil\ekv at mark\ekv at set@eq at other@a
-      =\ekv at mark\ekv at set@eq at active\ekv at stop
+      =\ekv at mark\ekv at set@eq at active
     ##1%
-    \ekv at set@other##1\ekv at mark
+    \ekv at mark
   }
 \long\def\ekv at set@eq at other@a##1\ekv at stop
   {%
-    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at set@eq at other@active at a
-      #2\ekv at mark\ekv at set@eq at other@b\ekv at stop
+    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at set@eq at other@active
+      #2\ekv at mark\ekv at set@eq at other@b
   }
-\long\def\ekv at set@eq at other@b
-    ##1\ekv at nil\ekv at mark\ekv at set@eq at other@active at a\ekv at stop\ekv at mark
+\ekv at expB@unbraceA
   {%
-    \ekv at strip{##1}\ekv at set@pair
-  }
-\long\def\ekv at set@eq at other@active at a##1\ekv at stop##2\ekv at nil\ekv at mark
+    \long\def\ekv at set@eq at other@b
+        ##1\ekv at nil\ekv at mark\ekv at set@eq at other@active\ekv at stop\ekv at mark
+        ##2\ekv at nil=\ekv at mark\ekv at set@eq at active
+  }%
+  {\ekv at strip{##1}{\expandafter\ekv at set@pair\detokenize}\ekv at mark##2\ekv at nil}
+\ekv at expB@unbraceA
   {%
-    \ekv at set@eq at other@active at b{##1}##2=%
-  }
-\long\def\ekv at set@eq at other@active at b##1%
-  {%
-    \ekv at strip{##1}\ekv at set@pair
-  }
+    \long\def\ekv at set@eq at other@active
+        ##1\ekv at stop##2\ekv at nil#2\ekv at mark
+        \ekv at set@eq at other@b\ekv at mark##3=\ekv at mark\ekv at set@eq at active
+  }%
+  {\ekv at strip{##1}{\expandafter\ekv at set@pair\detokenize}\ekv at mark##2=##3}
 \long\def\ekv at set@eq at active
     ##1\ekv at nil\ekv at mark\ekv at set@eq at other@a\ekv at stop\ekv at mark
   {%
     \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at set@eq at active@
-      #2\ekv at mark\ekv at set@noeq\ekv at stop
+      #2\ekv at mark\ekv at set@noeq
   }
-\long\def\ekv at set@eq at active@##1\ekv at stop
+\ekv at expB@unbraceA
+  {\long\def\ekv at set@eq at active@##1\ekv at stop##2\ekv at nil#2\ekv at mark\ekv at set@noeq}%
   {%
-    \ekv at strip{##1}\ekv at set@pair
+    \ekv at strip{##1}{\expandafter\ekv at set@pair\detokenize}\ekv at mark##2\ekv at nil
   }
-\long\def\ekv at set@noeq##1\ekv at nil\ekv at mark\ekv at set@eq at active@\ekv at stop\ekv at mark
+\edef\ekv at set@noeq
   {%
-    \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at ifempty@true at F@gobble
-      \ekv at ifempty@A\ekv at ifempty@B\@firstofone
-      {\ekv at strip{##1}\ekv at set@key}%
+    \unexpanded
+      {%
+        \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at set@was at blank
+          \ekv at ifempty@A\ekv at ifempty@B
+      }%
+    \unexpanded\expandafter
+      {\ekv at strip{##1}{\expandafter\ekv at set@key\detokenize}\ekv at mark}%
   }
+\ekv at expB@unbraceA
+  {%
+    \long\def\ekv at set@noeq
+        ##1\ekv at nil\ekv at mark\ekv at set@eq at active@\ekv at stop\ekv at mark
+  }%
+  {\ekv at set@noeq}
+\def\ekv at set@was at blank##1%
+  {%
+    \def\ekv at set@was at blank
+        \ekv at ifempty@A\ekv at ifempty@B
+        \ekv at strip@a\ekv at mark####1\ekv at nil\ekv at mark##1##1\ekv at nil\ekv at stop
+        ####2\ekv at mark
+      {\ekv at set@other}%
+  }
+\ekv at set@was at blank{ }
 \long\def\ekv at endset@other
     \ekv at stop
-    \ekv at eq@other##1\ekv at nil\ekv at mark\ekv at set@eq at other@a
-    =\ekv at mark\ekv at set@eq at active\ekv at stop
-    ##2%
-    \ekv at set@other##3\ekv at mark
-  {}
+    \ekv at eq@other\ekv at mark\ekv at stop\ekv at nil\ekv at mark\ekv at set@eq at other@a
+    =\ekv at mark\ekv at set@eq at active
+  {\ekv at set}
 \long\def\ekvbreak##1##2\ekv at stop#1##3{##1}
 \long\def\ekvbreakPreSneak ##1##2\ekv at stop#1##3{##1##3}
 \long\def\ekvbreakPostSneak##1##2\ekv at stop#1##3{##3##1}
@@ -274,62 +354,78 @@
   {%
     \ekv at gobble@from at mark@to at stop##3\ekv at endparse\ekv at stop
     \ekv at parse@other##1##2##3,\ekv at stop,%
-    \ekv at parse##1##2\ekv at mark
   }
 \long\def\ekv at endparse
-    \ekv at stop\ekv at parse@other##1,\ekv at stop,\ekv at parse##2\ekv at mark
+    \ekv at stop\ekv at parse@other##1\ekv at mark\ekv at stop,\ekv at stop,%
   {}
 \long\def\ekv at parse@other##1##2##3,%
   {%
     \ekv at gobble@from at mark@to at stop##3\ekv at endparse@other\ekv at stop
     \ekv at eq@other##3\ekv at nil\ekv at mark\ekv at parse@eq at other@a
-      =\ekv at mark\ekv at parse@eq at active\ekv at stop
+      =\ekv at mark\ekv at parse@eq at active
     ##1##2%
-    \ekv at parse@other##1##2\ekv at mark
+    \ekv at mark
   }
 \long\def\ekv at parse@eq at other@a##1\ekv at stop
   {%
-    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active at a
-      #2\ekv at mark\ekv at parse@eq at other@b\ekv at stop
+    \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active
+      #2\ekv at mark\ekv at parse@eq at other@b
   }
-\long\def\ekv at parse@eq at other@b
-    ##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active at a\ekv at stop\ekv at mark
+\ekv at expB@unbraceA
   {%
-    \ekv at strip{##1}\ekv at parse@pair
-  }
-\long\def\ekv at parse@eq at other@active at a##1\ekv at stop##2\ekv at nil\ekv at mark
+    \long\def\ekv at parse@eq at other@b
+        ##1\ekv at nil\ekv at mark\ekv at parse@eq at other@active\ekv at stop\ekv at mark
+        ##2\ekv at nil=\ekv at mark\ekv at parse@eq at active
+  }%
+  {\ekv at strip{##1}\ekv at parse@pair##2\ekv at nil}
+\ekv at expB@unbraceA
   {%
-    \ekv at parse@eq at other@active at b{##1}##2=%
-  }
-\long\def\ekv at parse@eq at other@active at b##1%
-  {%
-    \ekv at strip{##1}\ekv at parse@pair
-  }
+    \long\def\ekv at parse@eq at other@active
+        ##1\ekv at stop##2\ekv at nil#2\ekv at mark
+        \ekv at parse@eq at other@b\ekv at mark##3=\ekv at mark\ekv at parse@eq at active
+  }%
+  {\ekv at strip{##1}\ekv at parse@pair##2=##3}
 \long\def\ekv at parse@eq at active
     ##1\ekv at nil\ekv at mark\ekv at parse@eq at other@a\ekv at stop\ekv at mark
   {%
     \ekv at eq@active##1\ekv at nil\ekv at mark\ekv at parse@eq at active@
-      #2\ekv at mark\ekv at parse@noeq\ekv at stop
+      #2\ekv at mark\ekv at parse@noeq
   }
-\long\def\ekv at parse@eq at active@##1\ekv at stop
+\ekv at expB@unbraceA
+  {\long\def\ekv at parse@eq at active@##1\ekv at stop##2#2\ekv at mark\ekv at parse@noeq}%
   {%
-    \ekv at strip{##1}\ekv at parse@pair
+    \ekv at strip{##1}\ekv at parse@pair##2%
   }
-\long\def\ekv at parse@noeq
-    ##1\ekv at nil\ekv at mark\ekv at parse@eq at active@\ekv at stop\ekv at mark
+\edef\ekv at parse@noeq
   {%
-    \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at ifempty@true at F@gobbletwo
-      \ekv at ifempty@A\ekv at ifempty@B\@firstofone
-      {\ekv at strip{##1}\ekv at parse@key}%
+    \unexpanded
+      {%
+        \ekv at ifblank@##1\ekv at nil\ekv at ifempty@B\ekv at parse@was at blank
+          \ekv at ifempty@A\ekv at ifempty@B
+      }%
+      \unexpanded\expandafter{\ekv at strip{##1}\ekv at parse@key}%
   }
+\ekv at expB@unbraceA
+  {%
+    \long\def\ekv at parse@noeq
+        ##1\ekv at nil\ekv at mark\ekv at parse@eq at active@\ekv at stop\ekv at mark
+  }%
+  {\ekv at parse@noeq}
+\def\ekv at parse@was at blank##1%
+  {%
+    \def\ekv at parse@was at blank
+        \ekv at ifempty@A\ekv at ifempty@B
+        \ekv at strip@a\ekv at mark####1\ekv at nil\ekv at mark##1##1\ekv at nil\ekv at stop
+        \ekv at parse@key
+      {\ekv at parse@other}%
+  }
+\ekv at parse@was at blank{ }
 \long\def\ekv at endparse@other
     \ekv at stop
-    \ekv at eq@other##1\ekv at nil\ekv at mark\ekv at parse@eq at other@a
-    =\ekv at mark\ekv at parse@eq at active\ekv at stop
-    ##2%
-    \ekv at parse@other##3\ekv at mark
-  {}
-\long\def\ekv at parse@pair##1##2\ekv at nil
+    \ekv at eq@other\ekv at mark\ekv at stop\ekv at nil\ekv at mark\ekv at parse@eq at other@a
+    =\ekv at mark\ekv at parse@eq at active
+  {\ekv at parse}
+\ekv at expB@unbraceA{\long\def\ekv at parse@pair##1##2\ekv at nil}%
   {%
     \ekv at strip{##2}\ekv at parse@pair@{##1}%
   }
@@ -336,106 +432,152 @@
 \long\def\ekv at parse@pair@##1##2##3##4%
   {%
     \unexpanded{##4{##2}{##1}}%
+    \ekv at parse@other##3##4%
   }
 \long\def\ekv at parse@key##1##2##3%
   {%
     \unexpanded{##2{##1}}%
+    \ekv at parse@other##2##3%
   }
 }
-\begingroup
 \catcode`\,=13
 \catcode`\==13
 \ekvset,=
-\def\ekvchangeset#1%
+\edef\ekvsetSneaked
   {%
-    \expandafter\ekv at changeset\csname\ekv at undefined@set{#1}\endcsname\ekv at mark
+    \unexpanded{\ekvsneak{#2}}%
+    \unexpanded\expandafter{\ekvset{#1}{#3}}%
   }
-\long\def\ekv at changeset#1#2\ekv at set@other#3#4\ekv at set#5%
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\long\def\ekvsetSneaked#1#2#3}}%
+  {\ekvsetSneaked}
+\ekv at expB@unbraceA{\def\ekvchangeset#1}%
   {%
-    \ekv at gobble@mark#2\ekv at set@other#1#4\ekv at set#1%
+    \expandafter\expandafter\expandafter
+    \ekv at changeset\expandafter\csname\ekv at undefined@set{#1}\endcsname\ekv at empty
   }
-\long\def\ekv at set@pair#1#2\ekv at nil#3%
+\long\def\ekv at changeset#1#2\ekv at set@other#3%
   {%
-    \expandafter\ekv at set@pair@
-      \csname
-        \ifcsname #3{#1}\endcsname
-          #3{#1}%
-        \else
-          relax%
-        \fi
-      \endcsname
-      {#2}%
+    #2\ekv at set@other#1%
+  }
+\ekv at if@lastnamedcs
+  {%
+    \long\def\ekv at set@pair#1\ekv at mark#2\ekv at nil#3%
       {%
-        \expandafter\ekv at set@pair@
-          \csname
-            \ifcsname #3{}u\endcsname
-              #3{}u%
-            \else
-              relax%
-            \fi
-          \endcsname
+        \ifcsname #3{#1}\endcsname\ekv at set@pair at a\fi\@secondoftwo
           {#2}%
           {%
-            \ekv at ifdefined{#3{#1}N}%
-              \ekv at err@noarg
-              \ekv at err@unknown
-              #3%
+            \ifcsname #3{}u\endcsname\ekv at set@pair at a\fi\@secondoftwo
+              {#2}%
+              {%
+                \ekv at ifdefined{#3{#1}N}%
+                  \ekv at err@noarg
+                  \ekv at err@unknown
+                  #3%
+              }%
+              {#1}%
           }%
-          {#1}%
-      }%
+        \ekv at set@other#3%
+      }
+    \def\ekv at set@pair at a\fi\@secondoftwo
+      {\fi\expandafter\ekv at set@pair at b\lastnamedcs}
   }
-\long\def\ekv at set@pair@#1#2%
   {%
+    \long\def\ekv at set@pair#1\ekv at mark#2\ekv at nil#3%
+      {%
+        \ifcsname #3{#1}\endcsname
+            \ekv at set@pair at a\fi\ekv at set@pair at c#3{#1}\endcsname
+          {#2}%
+          {%
+            \ifcsname #3{}u\endcsname
+                \ekv at set@pair at a\fi\ekv at set@pair at c#3{}u\endcsname
+              {#2}%
+              {%
+                \ekv at ifdefined{#3{#1}N}%
+                  \ekv at err@noarg
+                  \ekv at err@unknown
+                  #3%
+              }%
+              {#1}%
+          }%
+        \ekv at set@other#3%
+      }
+    \def\ekv at set@pair at a\fi\ekv at set@pair at c{\fi\expandafter\ekv at set@pair at b\csname}
+    \long\def\ekv at set@pair at c#1\endcsname#2#3{#3}
+  }
+\long\def\ekv at set@pair at b#1%
+  {%
     \ifx#1\relax
-      \ekv at fi@secondoftwo
+      \ekv at set@pair at e
     \fi
-    \@firstoftwo
-    {\ekv at strip{#2}#1}%
+    \ekv at set@pair at d#1%
   }
-\long\def\ekv at set@key#1#2%
+\ekv at expB@unbraceA{\long\def\ekv at set@pair at d#1#2#3}{\ekv at strip{#2}#1}
+\long\def\ekv at set@pair at e\fi\ekv at set@pair at d#1#2#3{\fi#3}
+\ekv at if@lastnamedcs
   {%
-    \expandafter\ekv at set@key@
-      \csname
-        \ifcsname #2{#1}N\endcsname
-          #2{#1}N%
-        \else
-          relax%
-        \fi
-      \endcsname
+    \long\def\ekv at set@key#1\ekv at mark#2%
       {%
-        \expandafter\ekv at set@key@
-          \csname
-            \ifcsname #2{}uN\endcsname
-              #2{}uN%
-            \else
-              relax%
-            \fi
-          \endcsname
+        \ifcsname #2{#1}N\endcsname\ekv at set@key at a\fi\@firstofone
           {%
-            \ekv at ifdefined{#2{#1}}%
-              \ekv at err@reqval
-              \ekv at err@unknown
-              #2%
+            \ifcsname #2{}uN\endcsname\ekv at set@key at a\fi\@firstofone
+              {%
+                \ekv at ifdefined{#2{#1}}%
+                  \ekv at err@reqval
+                  \ekv at err@unknown
+                  #2%
+              }%
+              {#1}%
           }%
-          {#1}%
-      }%
+        \ekv at set@other#2%
+      }
+    \def\ekv at set@key at a\fi\@firstofone{\fi\expandafter\ekv at set@key at b\lastnamedcs}
   }
-\def\ekv at set@key@#1%
   {%
+    \long\def\ekv at set@key#1\ekv at mark#2%
+      {%
+        \ifcsname #2{#1}N\endcsname
+            \ekv at set@key at a\fi\ekv at set@key at c#2{#1}N\endcsname
+          {%
+            \ifcsname #2{}uN\endcsname
+                \ekv at set@key at a\fi\ekv at set@key at c#2{}uN\endcsname
+              {%
+                \ekv at ifdefined{#2{#1}}%
+                  \ekv at err@reqval
+                  \ekv at err@unknown
+                  #2%
+              }%
+              {#1}%
+          }%
+        \ekv at set@other#2%
+      }
+    \def\ekv at set@key at a\fi\ekv at set@key at c{\fi\expandafter\ekv at set@key at b\csname}
+    \long\def\ekv at set@key at c#1N\endcsname#2{#2}
+  }
+\long\def\ekv at set@key at b#1%
+  {%
     \ifx#1\relax
       \ekv at fi@secondoftwo
     \fi
     \@firstoftwo#1%
   }
-\protected\def\ekvsetdef#1#2%
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+\protected\def\ekvsetdef#1#2}}}}%
   {%
-    \expandafter\expandafter\expandafter
-    \ekv at setdef\expandafter\expandafter\expandafter{\ekvset{#2}{##1}}#1%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\long\def#1##1}}%
+      {\ekvset{#2}{##1}}%
   }
-\protected\def\ekv at setdef#1#2%
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+\protected\def\ekvsetSneakeddef#1#2}}}}%
   {%
-    \long\def#2##1{#1}%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\long\def#1##1##2}}%
+      {\ekvsetSneaked{#2}{##1}{##2}}%
   }
+\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{\ekv at expB@unbraceA{%
+\protected\def\ekvsetdefSneaked#1#2#3}}}}%
+  {%
+    \ekv at expB@unbraceA{\ekv at expB@unbraceA{\long\def#1##1}}%
+      {\ekvsetSneaked{#2}{#3}{##1}}%
+  }
 \begingroup
 \edef\ekv at err
   {%
@@ -451,34 +593,12 @@
 \def\ekv at err@{\expandafter\ekv at gobbleto@stop}
 \long\def\ekv at err@common #1#2{\expandafter\ekv at err@common@\string#2{#1}}
 \long\def\ekv at err@common@#1`#2' #3.#4#5{\ekv at err{#4 (`#5', set `#2')}}
-\long\def\ekv at err@unknown#1#2{\ekv at err@common{unknown key}#1{#2}}
-\long\def\ekv at err@noarg  #1#2{\ekv at err@common{value forbidden}#1{#2}}
-\long\def\ekv at err@reqval #1#2{\ekv at err@common{value required}#1{#2}}
-\def\ekv at strip#1%
-  {%
-    \long\def\ekv at strip##1%
-      {%
-        \ekv at strip@a
-          ##1%
-          \ekv at nil
-          \ekv at mark#1%
-          #1\ekv at nil{}%
-        \ekv at stop
-      }%
-    \long\def\ekv at strip@a##1\ekv at mark#1##2\ekv at nil##3%
-      {%
-        \ekv at strip@b##3##1##2\ekv at nil
-      }%
-    \long\def\ekv at strip@b##1#1\ekv at nil
-      {%
-        \ekv at strip@c##1\ekv at nil
-      }%
-    \long\def\ekv at strip@c\ekv at mark##1\ekv at nil##2\ekv at stop##3%
-      {%
-        ##3{##1}%
-      }%
-  }
-\ekv at strip{ }
+\ekv at expB@unbraceA{\long\def\ekv at err@unknown#1}%
+  {\ekv at err@common{unknown key}{#1}}
+\ekv at expB@unbraceA{\long\def\ekv at err@noarg  #1}%
+  {\ekv at err@common{value forbidden}{#1}}
+\ekv at expB@unbraceA{\long\def\ekv at err@reqval #1}%
+  {\ekv at err@common{value required}{#1}}
 \catcode`\@=\ekv at tmp
 %% 
 %%



More information about the tex-live-commits mailing list.