texlive[55731] Master/texmf-dist: expkv (2jul20)

commits+karl at tug.org commits+karl at tug.org
Thu Jul 2 23:46:44 CEST 2020


Revision: 55731
          http://tug.org/svn/texlive?view=revision&revision=55731
Author:   karl
Date:     2020-07-02 23:46:44 +0200 (Thu, 02 Jul 2020)
Log Message:
-----------
expkv (2jul20)

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-07-02 21:46:28 UTC (rev 55730)
+++ trunk/Master/texmf-dist/doc/latex/expkv/README.md	2020-07-02 21:46:44 UTC (rev 55731)
@@ -1,7 +1,7 @@
 -------------------------------------------------------------------------------
 # expkv -- an expandable key=val implementation
 
-Version 2020-04-10 v1.2
+Version 2020-07-02 v1.3
 
 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-07-02 21:46:28 UTC (rev 55730)
+++ trunk/Master/texmf-dist/source/latex/expkv/expkv.dtx	2020-07-02 21:46:44 UTC (rev 55731)
@@ -149,6 +149,7 @@
   }
 \newcommand*\expkvd{\expkvpkg{def}}
 \newcommand*\expkvc{\expkvpkg{cs}}
+\newcommand*\expkvo{\expkvpkg{opt}}
 \newcommand\kv{\meta{key}=\meta{value}}
 \newcommand\key{\meta{key}}
 \newcommand\val{\meta{value}}
@@ -157,7 +158,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}
+\DoNotIndex{\@,\unexpanded,\string,\expanded,\detokenize}
 \DoNotIndex{\ifcsname}
 \DoNotIndex{\ifx}
 \DoNotIndex{\else}
@@ -233,6 +234,8 @@
 %     a key-defining frontend for \expkv\ using a \kv\ syntax
 %   \item[cs]
 %     define expandable \kv\ macros using \expkv
+%   \item[opt]
+%     parse package and class options with \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}).
@@ -254,9 +257,9 @@
 % ``|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
-% inside of |\csname ...\endcsname|.
+% 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.
 %
 % \begin{function}{\ekvdef}
 %   \begin{syntax}
@@ -305,6 +308,28 @@
 %   whether that second key exists.
 % \end{function}
 %
+% \begin{function}{\ekvdefunknown}
+%   \begin{syntax}
+%     \cs{ekvdefunknown}\marg{set}\marg{code}
+%   \end{syntax}
+%   By default an error will be thrown if an unknown \key\ is encountered. With
+%   this macro you can define \meta{code} that will be executed for a given
+%   \set\ when an unknown \key\ with a \val\ was encountered instead of throwing
+%   an error. You can refer to the given \val\ with |#1| and to the unknown
+%   \key's name with |#2| in \meta{code}.\footnotemark
+% \end{function}
+% \footnotetext{That order is correct, this way the code is faster.}
+%
+% \begin{function}{\ekvdefunknownNoVal}
+%   \begin{syntax}
+%     \cs{ekvdefunknownNoVal}\marg{set}\marg{code}
+%   \end{syntax}
+%   As already explained for \cs[no-index]{ekvdefunknown}, \expkv\ would throw
+%   an error when encountering an unknown \key. With this you can instead let it
+%   execute \meta{code} if an unknown |NoVal| \key\ was encountered. You can
+%   refer to the given \key\ with |#1| in \meta{code}.
+% \end{function}
+%
 % \subsection{Parsing Keys}
 %
 % \begin{function}{\ekvset}
@@ -324,6 +349,18 @@
 %   |\ekvset| should be nestable.
 % \end{function}
 %
+% \begin{function}{\ekvsetdef}
+%   \begin{syntax}
+%     \cs{ekvsetdef}\meta{cs}\marg{set}
+%   \end{syntax}
+%   With this function you can define a shorthand macro \meta{cs} to parse keys
+%   of a specified \set. It is always defined |\long|, but if you need to you
+%   can also prefix it with |\global|. The resulting macro is a bit faster than
+%   the idiomatic definition:\par
+%   \texttt
+%     {\string\long\string\def\meta{cs}\#1\{\string\ekvset\marg{set}\{\#1\}\}}
+% \end{function}
+%
 % \begin{function}{\ekvparse}
 %   \begin{syntax}
 %     \cs{ekvparse}\meta{cs1}\meta{cs2}\{\kv,\ldots\}
@@ -440,7 +477,11 @@
 %   ``\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{\cs[no-index]{ekv at name@set}\marg{set}\cs{ekv at name@key}\marg{key}}.
+%   \texttt
+%     {^^A
+%       \cs[no-index]{ekv at name@set}\marg{set}\cs{ekv at name@key}^^A
+%       \{\cs[no-index]{detokenize}\marg{key}\}^^A
+%     }.
 %   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
@@ -542,17 +583,16 @@
 % premature unbracing bug \pkg{keyval} has.
 %
 % \paragraph{\pkg{simplekv}} is hard to compare because I don't speak French (so
-% I don't understand the documentation) and from what I can see, there is no
-% direct way to define the equivalent test key. Nevertheless, I tested the
-% closest possible equivalent of my test key while siding for \pkg{simplekv}'s
-% design not forcing something into it it doesn't seem to be designed for. It is
-% 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}
-% \setKVdefault[simplekv]{height={ abc}}                     % key setup
-% \setKV[simplekv]{ height = 6 }                             % benchmarked
-% \end{lstlisting}
+% I don't understand the documentation). There was an update released on
+% 2020-04-27 which greatly improved the package's performance and adds
+% functionality so that it can be used more like most of the other \kv\
+% 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
+% 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.
 %
 % \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
@@ -592,16 +632,16 @@
 %     \toprule
 %     \rmfamily Package & {$p_1$} & {$p_0$} & {$T_0$}& BB & CF & Date \\
 %     \midrule
-%     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 \\
+%     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 \\
 %     \bottomrule
 %   \end{tabular}
 %   \par
@@ -610,13 +650,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{7.473}$, $p_1=\num{51.276}$, and $p_0=\num{49.568}$. Of course the
+%   $p_2=\num{8.811}$, $p_1=\num{36.015}$, and $p_0=\num{81.792}$. 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{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{11.396}$, $p_1=\num{3276.713}$, and $p_0=\num{6132.315}$.
+%   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}$.
 % \end{table}
 %
 % \subsection{Examples}
@@ -797,7 +836,7 @@
 % \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.
+% way easier to code for the user.
 % \begin{lstlisting}
 % \makeatletter
 % \ekvcSplitAndForward\sine\sine@
@@ -963,8 +1002,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.2}
-\def\ekvDate{2020-04-10}
+\def\ekvVersion{1.3}
+\def\ekvDate{2020-07-02}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -1042,12 +1081,18 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[internal]{\ekv at ifblank@}
+% \begin{macro}[internal]{\ekv at ifblank,\ekv at ifblank@}
 % The obvious test that can be based on an if-empty is if-blank, meaning a test
 % checking whether the argument is empty or consists only of spaces. Our version
 % here will be tweaked a bit, as we want to check this, but with one leading
-% |\ekv at mark| token that is to be ignored.
+% |\ekv at mark| token that is to be ignored. The wrapper |\ekv at ifblank| will not
+% be used by \expkv\ for speed reasons but \expkvo\ uses it.
 %    \begin{macrocode}
+\long\def\ekv at ifblank#1%
+  {%
+    \ekv at ifblank@#1\ekv at nil\ekv at ifempty@B\ekv at ifempty@true
+      \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}
 %    \end{macrocode}
 % \end{macro}
@@ -1073,7 +1118,7 @@
 % \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{#2}}
+\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)}
 %    \end{macrocode}
@@ -1129,7 +1174,10 @@
 % \end{macro}
 %
 % \begin{macro}
-%   {\ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal}
+%   {
+%     \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,
+%     \ekvdefunknown,\ekvdefunknownNoVal
+%   }
 % Set up the key defining macros |\ekvdef| etc.
 %    \begin{macrocode}
 \protected\long\def\ekvdef#1#2#3%
@@ -1137,7 +1185,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\def\csname\ekv at name{#1}{#2}\endcsname##1{#3}%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\long\def\ekvdefNoVal#1#2#3%
@@ -1145,7 +1193,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\def\csname\ekv at name{#1}{#2}N\endcsname{#3}%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvlet#1#2#3%
@@ -1153,7 +1201,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}\endcsname#3%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletNoVal#1#2#3%
@@ -1161,7 +1209,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}N\endcsname#3%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletkv#1#2#3#4%
@@ -1170,7 +1218,7 @@
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}\expandafter\endcsname
         \csname\ekv at name{#3}{#4}\endcsname
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletkvNoVal#1#2#3#4%
@@ -1179,21 +1227,37 @@
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}N\expandafter\endcsname
         \csname\ekv at name{#3}{#4}N\endcsname
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \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}%
+      }%
+  }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[internal]{\ekv at defset}
+% \begin{macro}[internal]{\ekv at defsetmacro}
 %   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#2%
+\protected\def\ekv at defsetmacro#1#2%
   {%
     \ifx#1\relax
-      \edef#1##1{\ekv at name@set{#2}\ekv at name@key{##1}}%
+      \edef#1##1{\ekv at name@set{#2}\ekv at name@key{\noexpand\detokenize{##1}}}%
     \fi
   }
 %    \end{macrocode}
@@ -1202,10 +1266,11 @@
 % \begin{macro}{\ekvset}
 % Set up |\ekvset|, which should not be affected by active commas and equal
 % signs. The equal signs are a bit harder to cope with and we'll do that later,
-% but replacing the active commas with commas of category other can be done
-% beforehand. That's why we define |\ekvset| here with a temporary meaning just
-% to set up the things with two different category codes. |#1| will be a
-% \texttt{,\textsubscript{13}} and |#2| will be a \texttt{=\textsubscript{13}}.
+% but the active commas can be handled by just doing two comma-splitting loops
+% one at actives one at others. That's why we define |\ekvset| here with a
+% temporary meaning just to set up the things with two different category codes.
+% |#1| will be a \texttt{,\textsubscript{13}} and |#2| will be a
+% \texttt{=\textsubscript{13}}.
 %    \begin{macrocode}
 \def\ekvset#1#2{%
 \endgroup
@@ -1597,8 +1662,9 @@
 %   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|.
+%   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{macrocode}
 \long\def\ekv at set@pair#1#2\ekv at nil#3%
   {%
@@ -1612,10 +1678,22 @@
       \endcsname
       {#2}%
       {%
-        \ekv at ifdefined{#3{#1}N}%
-          \ekv at err@noarg
-          \ekv at err@unknown
-          #3{#1}%
+        \expandafter\ekv at set@pair@
+          \csname
+            \ifcsname #3{}u\endcsname
+              #3{}u%
+            \else
+              relax%
+            \fi
+          \endcsname
+          {#2}%
+          {%
+            \ekv at ifdefined{#3{#1}N}%
+              \ekv at err@noarg
+              \ekv at err@unknown
+              #3%
+          }%
+          {#1}%
       }%
   }
 \long\def\ekv at set@pair@#1#2%
@@ -1645,10 +1723,21 @@
         \fi
       \endcsname
       {%
-        \ekv at ifdefined{#2{#1}}%
-          \ekv at err@reqval
-          \ekv at err@unknown
-          #2{#1}%
+        \expandafter\ekv at set@key@
+          \csname
+            \ifcsname #2{}uN\endcsname
+              #2{}uN%
+            \else
+              relax%
+            \fi
+          \endcsname
+          {%
+            \ekv at ifdefined{#2{#1}}%
+              \ekv at err@reqval
+              \ekv at err@unknown
+              #2%
+          }%
+          {#1}%
       }%
   }
 \def\ekv at set@key@#1%
@@ -1661,6 +1750,30 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \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.
+%    \begin{macrocode}
+\protected\def\ekvsetdef#1#2%
+  {%
+    \expandafter\expandafter\expandafter
+    \ekv at setdef\expandafter\expandafter\expandafter{\ekvset{#2}{##1}}#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{macrocode}
+\protected\def\ekv at setdef#1#2%
+  {%
+    \long\def#2##1{#1}%
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[internal]{\ekv at err,\ekv at err@}
 % Since |\ekvset| is fully expandable as long as the code of the keys is (which
 % is unlikely) we want to somehow throw expandable errors, in our case via

Modified: trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex	2020-07-02 21:46:28 UTC (rev 55730)
+++ trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex	2020-07-02 21:46:44 UTC (rev 55731)
@@ -39,8 +39,8 @@
   \errmessage{expkv requires e-TeX}
   \expandafter\endinput
 \fi
-\def\ekvVersion{1.2}
-\def\ekvDate{2020-04-10}
+\def\ekvVersion{1.3}
+\def\ekvDate{2020-07-02}
 \csname ekv at tmp\endcsname
 \expandafter\chardef\csname ekv at tmp\endcsname=\catcode`\@
 \catcode`\@=11
@@ -66,6 +66,11 @@
 \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#1%
+  {%
+    \ekv at ifblank@#1\ekv at nil\ekv at ifempty@B\ekv at ifempty@true
+      \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%
   {%
@@ -75,7 +80,7 @@
     \fi
     \@firstoftwo
   }
-\def\ekv at name#1#2{\ekv at name@set{#1}\ekv at name@key{#2}}
+\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.}
@@ -103,7 +108,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\def\csname\ekv at name{#1}{#2}\endcsname##1{#3}%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\long\def\ekvdefNoVal#1#2#3%
@@ -111,7 +116,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\def\csname\ekv at name{#1}{#2}N\endcsname{#3}%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvlet#1#2#3%
@@ -119,7 +124,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}\endcsname#3%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletNoVal#1#2#3%
@@ -127,7 +132,7 @@
     \ekv at checkvalid{#1}{#2}%
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}N\endcsname#3%
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletkv#1#2#3#4%
@@ -136,7 +141,7 @@
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}\expandafter\endcsname
         \csname\ekv at name{#3}{#4}\endcsname
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
 \protected\def\ekvletkvNoVal#1#2#3#4%
@@ -145,13 +150,29 @@
       {%
         \expandafter\let\csname\ekv at name{#1}{#2}N\expandafter\endcsname
         \csname\ekv at name{#3}{#4}N\endcsname
-        \expandafter\ekv at defset\csname\ekv at undefined@set{#1}\endcsname{#1}%
+        \expandafter\ekv at defsetmacro\csname\ekv at undefined@set{#1}\endcsname{#1}%
       }%
   }
-\protected\def\ekv at defset#1#2%
+\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}%
+      }%
+  }
+\protected\def\ekv at defsetmacro#1#2%
+  {%
     \ifx#1\relax
-      \edef#1##1{\ekv at name@set{#2}\ekv at name@key{##1}}%
+      \edef#1##1{\ekv at name@set{#2}\ekv at name@key{\noexpand\detokenize{##1}}}%
     \fi
   }
 \def\ekvset#1#2{%
@@ -339,10 +360,22 @@
       \endcsname
       {#2}%
       {%
-        \ekv at ifdefined{#3{#1}N}%
-          \ekv at err@noarg
-          \ekv at err@unknown
-          #3{#1}%
+        \expandafter\ekv at set@pair@
+          \csname
+            \ifcsname #3{}u\endcsname
+              #3{}u%
+            \else
+              relax%
+            \fi
+          \endcsname
+          {#2}%
+          {%
+            \ekv at ifdefined{#3{#1}N}%
+              \ekv at err@noarg
+              \ekv at err@unknown
+              #3%
+          }%
+          {#1}%
       }%
   }
 \long\def\ekv at set@pair@#1#2%
@@ -364,10 +397,21 @@
         \fi
       \endcsname
       {%
-        \ekv at ifdefined{#2{#1}}%
-          \ekv at err@reqval
-          \ekv at err@unknown
-          #2{#1}%
+        \expandafter\ekv at set@key@
+          \csname
+            \ifcsname #2{}uN\endcsname
+              #2{}uN%
+            \else
+              relax%
+            \fi
+          \endcsname
+          {%
+            \ekv at ifdefined{#2{#1}}%
+              \ekv at err@reqval
+              \ekv at err@unknown
+              #2%
+          }%
+          {#1}%
       }%
   }
 \def\ekv at set@key@#1%
@@ -377,6 +421,15 @@
     \fi
     \@firstoftwo#1%
   }
+\protected\def\ekvsetdef#1#2%
+  {%
+    \expandafter\expandafter\expandafter
+    \ekv at setdef\expandafter\expandafter\expandafter{\ekvset{#2}{##1}}#1%
+  }
+\protected\def\ekv at setdef#1#2%
+  {%
+    \long\def#2##1{#1}%
+  }
 \begingroup
 \edef\ekv at err
   {%



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