texlive[54654] Master/texmf-dist: expkv (10apr20)

commits+karl at tug.org commits+karl at tug.org
Sun Apr 12 00:21:50 CEST 2020


Revision: 54654
          http://tug.org/svn/texlive?view=revision&revision=54654
Author:   karl
Date:     2020-04-12 00:21:50 +0200 (Sun, 12 Apr 2020)
Log Message:
-----------
expkv (10apr20)

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

Modified: trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex	2020-04-11 22:21:31 UTC (rev 54653)
+++ trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex	2020-04-11 22:21:50 UTC (rev 54654)
@@ -30,17 +30,17 @@
 %%                                 expkv.sty
 %%                                 expkv.tex
 %% 
+\expandafter\ifx\csname ekvVersion\endcsname\relax
+\else
+  \expandafter\endinput
+\fi
 \begingroup\expandafter\expandafter\expandafter\endgroup
 \expandafter\ifx\csname numexpr\endcsname\relax
   \errmessage{expkv requires e-TeX}
   \expandafter\endinput
 \fi
-\expandafter\ifx\csname ekvVersion\endcsname\relax
-\else
-  \expandafter\endinput
-\fi
-\def\ekvVersion{0.5a}
-\def\ekvDate{2020-02-27}
+\def\ekvVersion{1.2}
+\def\ekvDate{2020-04-10}
 \csname ekv at tmp\endcsname
 \expandafter\chardef\csname ekv at tmp\endcsname=\catcode`\@
 \catcode`\@=11
@@ -51,6 +51,7 @@
 \long\def\ekv at fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2}
 \long\def\ekv at gobbleto@stop#1\ekv at stop{}
 \def\ekv at gobble@mark\ekv at mark{}
+\long\def\ekv at gobble@from at mark@to at stop\ekv at mark#1\ekv at stop{}
 \long\def\ekv at ifempty#1%
   {%
     \ekv at ifempty@\ekv at ifempty@A#1\ekv at ifempty@B\ekv at ifempty@true
@@ -60,6 +61,11 @@
 \long\def\ekv at ifempty@true\ekv at ifempty@A\ekv at ifempty@B\@secondoftwo#1#2{#1}
 \long\def\ekv at ifempty@false\ekv at ifempty@A\ekv at ifempty@B\@firstoftwo#1#2{#2}
 \long\def\ekv at ifempty@true at F\ekv at ifempty@A\ekv at ifempty@B\@firstofone#1{}
+\long\def\ekv at ifempty@true at F@gobble\ekv at ifempty@A\ekv at ifempty@B\@firstofone#1#2%
+  {}
+\long\def\ekv at ifempty@true at F@gobbletwo
+    \ekv at ifempty@A\ekv at ifempty@B\@firstofone#1#2#3%
+  {}
 \long\def\ekv at ifblank@\ekv at mark#1{\ekv at ifempty@\ekv at ifempty@A}
 \def\ekv at ifdefined#1%
   {%
@@ -69,44 +75,6 @@
     \fi
     \@firstoftwo
   }
-  % \begin{macro}[internal]
-\def\ekv at ifdefined@pair#1#2%
-  {%
-    \expandafter\ekv at ifdefined@pair@
-      \csname
-        \ifcsname #1{#2}\endcsname
-          #1{#2}%
-        \else
-          relax%
-        \fi
-      \endcsname
-  }
-\def\ekv at ifdefined@pair@#1%
-  {%
-    \ifx#1\relax
-      \ekv at fi@secondoftwo
-    \fi
-    \@firstoftwo
-    {\ekv at set@pair@#1\ekv at mark}%
-  }
-\def\ekv at ifdefined@key#1#2%
-  {%
-    \expandafter\ekv at ifdefined@key@
-      \csname
-        \ifcsname #1{#2}N\endcsname
-          #1{#2}N%
-        \else
-          relax%
-        \fi
-      \endcsname
-  }
-\def\ekv at ifdefined@key@#1%
-  {%
-    \ifx#1\relax
-      \ekv at fi@secondoftwo
-    \fi
-    \@firstoftwo#1%
-  }
 \def\ekv at name#1#2{\ekv at name@set{#1}\ekv at name@key{#2}}
 \def\ekv at name@set#1{ekv#1(}
 \def\ekv at name@key#1{#1)}
@@ -135,7 +103,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\def\csname\ekv at name{#1}{#2}\endcsname##1{#3}%
-        \ekv at defset{#1}%
+        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\long\def\ekvdefNoVal#1#2#3%
@@ -143,7 +111,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\def\csname\ekv at name{#1}{#2}N\endcsname{#3}%
-        \ekv at defset{#1}%
+        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvlet#1#2#3%
@@ -151,7 +119,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}\endcsname#3%
-        \ekv at defset{#1}%
+        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletNoVal#1#2#3%
@@ -159,7 +127,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}N\endcsname#3%
-        \ekv at defset{#1}%
+        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletkv#1#2#3#4%
@@ -168,7 +136,7 @@
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}\expandafter\endcsname
         \csname\ekv at name{#3}{#4}\endcsname
-        \ekv at defset{#1}%
+        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletkvNoVal#1#2#3#4%
@@ -177,13 +145,14 @@
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}N\expandafter\endcsname
         \csname\ekv at name{#3}{#4}N\endcsname
-        \ekv at defset{#1}%
+        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
-\protected\def\ekv at defset#1%
+\protected\def\ekv at defset#1#2%
   {%
-    \expandafter\edef\csname\ekv at undefined@set{#1}\endcsname##1%
-      {\ekv at name@set{#1}\ekv at name@key{##1}}%
+    \ifx#1\relax
+      \edef#1##1{\ekv at name@set{#2}\ekv at name@key{##1}}%
+    \fi
   }
 \def\ekvset#1#2{%
 \endgroup
@@ -194,49 +163,68 @@
   }
 \long\def\ekv at set##1##2#1%
   {%
-    \ekv at gobbleto@markstop##2\ekv at endset\ekv at mark\ekv at stop
+    \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 mark\ekv at stop\ekv at set@other##1,\ekv at stop,\ekv at set##2\ekv at mark
+    \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
+  {%
+    ##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
+  {%
+    ##3##1\ekv at stop\ekv at mark##2%
+  }
 \long\def\ekv at set@other##1##2,%
   {%
-    \ekv at gobbleto@markstop##2\ekv at endset@other\ekv at mark\ekv at stop
-    \ekv at ifhas@eq at other##2=\ekv at ifempty@B\ekv at ifempty@false
-      \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
-      {\ekv at set@eq at other##1##2\ekv at stop}%
-      {%
-        \ekv at ifhas@eq at active##2#2\ekv at ifempty@B\ekv at ifempty@false
-          \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
-          {\ekv at set@eq at active##1##2\ekv at stop}%
-          {%
-            \ekv at ifblank@##2\ekv at nil\ekv at ifempty@B\ekv at ifempty@true at F
-              \ekv at ifempty@A\ekv at ifempty@B\@firstofone
-              {\ekv at strip{##2}\ekv at set@key##1}%
-          }%
-      }%
-    \ekv at set@other##1\ekv at mark%
+    \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
+    ##1%
+    \ekv at set@other##1\ekv at mark
   }
-\long\def\ekv at set@eq at other##1##2=%
+\long\def\ekv at set@eq at other@a##1\ekv at stop
   {%
-    \ekv at ifhas@eq at active##2#2\ekv at ifempty@B\ekv at ifempty@false
-      \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
-      {\ekv at set@eq at active##1##2=}%
-      {\ekv at strip{##2}\ekv at set@pair##1}%
+    \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
   }
-\long\def\ekv at set@eq at active##1##2#2%
+\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 strip{##2}\ekv at set@pair##1%
+    \ekv at strip{##1}\ekv at set@pair
   }
-\long\def\ekv at ifhas@eq at other\ekv at mark##1={\ekv at ifempty@\ekv at ifempty@A}
-\long\def\ekv at ifhas@eq at active\ekv at mark##1#2{\ekv at ifempty@\ekv at ifempty@A}
+\long\def\ekv at set@eq at other@active at a##1\ekv at stop##2\ekv at nil\ekv at mark
+  {%
+    \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 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
+  }
+\long\def\ekv at set@eq at active@##1\ekv at stop
+  {%
+    \ekv at strip{##1}\ekv at set@pair
+  }
+\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 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}%
+  }
 \long\def\ekv at endset@other
-    \ekv at mark\ekv at stop
-    \ekv at ifhas@eq at other##1=\ekv at ifempty@B\ekv at ifempty@false
-    \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
+    \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
   {}
@@ -257,58 +245,72 @@
   }
 \long\def\ekv at parse##1##2##3#1%
   {%
-    \ekv at gobbleto@markstop##3\ekv at endparse\ekv at mark\ekv at stop
+    \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 mark\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 stop,\ekv at parse##2\ekv at mark
   {}
 \long\def\ekv at parse@other##1##2##3,%
   {%
-    \ekv at gobbleto@markstop##3\ekv at endparse@other\ekv at mark\ekv at stop
-    \ekv at ifhas@eq at other##3=\ekv at ifempty@B\ekv at ifempty@false
-      \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
-      {\ekv at parse@eq at other##3\ekv at stop##2}%
-      {%
-        \ekv at ifhas@eq at active##3#2\ekv at ifempty@B\ekv at ifempty@false
-          \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
-          {\ekv at parse@eq at active##3\ekv at stop##2}%
-          {%
-            \ekv at ifblank@##3\ekv at nil\ekv at ifempty@B\ekv at ifempty@true at F
-              \ekv at ifempty@A\ekv at ifempty@B\@firstofone
-              {\ekv at strip{##3}\ekv at parse@key##1}%
-          }%
-      }%
+    \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
+    ##1##2%
     \ekv at parse@other##1##2\ekv at mark
   }
-\long\def\ekv at parse@eq at other##1=%
+\long\def\ekv at parse@eq at other@a##1\ekv at stop
   {%
-    \ekv at ifhas@eq at active##1#2\ekv at ifempty@B\ekv at ifempty@false
-      \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
-      {\ekv at parse@eq at active##1=}%
-      {\ekv at strip{##1}\ekv at parse@pair\ekv at mark}%
+    \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
   }
-\long\def\ekv at parse@eq at active##1#2%
+\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 strip{##1}\ekv at parse@pair\ekv at mark
+    \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
+  {%
+    \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 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
+  }
+\long\def\ekv at parse@eq at active@##1\ekv at stop
+  {%
+    \ekv at strip{##1}\ekv at parse@pair
+  }
+\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 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}%
+  }
 \long\def\ekv at endparse@other
-    \ekv at mark\ekv at stop
-    \ekv at ifhas@eq at other##1=\ekv at ifempty@B\ekv at ifempty@false
-    \ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
+    \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 stop
+\long\def\ekv at parse@pair##1##2\ekv at nil
   {%
     \ekv at strip{##2}\ekv at parse@pair@{##1}%
   }
-\long\def\ekv at parse@pair@##1##2##3%
+\long\def\ekv at parse@pair@##1##2##3##4%
   {%
-    \unexpanded{##3{##2}{##1}}%
+    \unexpanded{##4{##2}{##1}}%
   }
-\long\def\ekv at parse@key##1##2%
+\long\def\ekv at parse@key##1##2##3%
   {%
     \unexpanded{##2{##1}}%
   }
@@ -325,25 +327,42 @@
   {%
     \ekv at gobble@mark#2\ekv at set@other#1#4\ekv at set#1%
   }
-\long\def\ekv at gobbleto@markstop#1\ekv at mark\ekv at stop{}
-\long\def\ekv at set@pair#1#2%
+\long\def\ekv at set@pair#1#2\ekv at nil#3%
   {%
-    \ekv at ifdefined@pair#2{#1}%
+    \expandafter\ekv at set@pair@
+      \csname
+        \ifcsname #3{#1}\endcsname
+          #3{#1}%
+        \else
+          relax%
+        \fi
+      \endcsname
+      {#2}%
       {%
-        \ekv at ifdefined{#2{#1}N}%
+        \ekv at ifdefined{#3{#1}N}%
           \ekv at err@noarg
           \ekv at err@unknown
-          #2{#1}%
-        \ekv at gobbleto@stop
+          #3{#1}%
       }%
   }
-\long\def\ekv at set@pair@#1#2\ekv at stop
+\long\def\ekv at set@pair@#1#2%
   {%
-    \ekv at strip{#2}#1%
+    \ifx#1\relax
+      \ekv at fi@secondoftwo
+    \fi
+    \@firstoftwo
+    {\ekv at strip{#2}#1}%
   }
 \long\def\ekv at set@key#1#2%
   {%
-    \ekv at ifdefined@key#2{#1}%
+    \expandafter\ekv at set@key@
+      \csname
+        \ifcsname #2{#1}N\endcsname
+          #2{#1}N%
+        \else
+          relax%
+        \fi
+      \endcsname
       {%
         \ekv at ifdefined{#2{#1}}%
           \ekv at err@reqval
@@ -351,6 +370,13 @@
           #2{#1}%
       }%
   }
+\def\ekv at set@key@#1%
+  {%
+    \ifx#1\relax
+      \ekv at fi@secondoftwo
+    \fi
+    \@firstoftwo#1%
+  }
 \begingroup
 \edef\ekv at err
   {%
@@ -358,7 +384,7 @@
     \unexpanded{\long\def\ekv at err}##1%
       {%
         \unexpanded{\expandafter\ekv at err@\@firstofone}%
-        {\expandafter\noexpand\csname ! expkv Error:\endcsname ##1.}%
+        {\unexpanded\expandafter{\csname ! expkv Error:\endcsname}##1.}%
         \unexpanded{\ekv at stop}%
       }%
   }



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