texlive[59864] Master/texmf-dist: expkv-cs (7jul21)

commits+karl at tug.org commits+karl at tug.org
Wed Jul 7 22:54:42 CEST 2021


Revision: 59864
          http://tug.org/svn/texlive?view=revision&revision=59864
Author:   karl
Date:     2021-07-07 22:54:41 +0200 (Wed, 07 Jul 2021)
Log Message:
-----------
expkv-cs (7jul21)

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

Modified: trunk/Master/texmf-dist/doc/latex/expkv-cs/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/expkv-cs/README.md	2021-07-07 20:54:00 UTC (rev 59863)
+++ trunk/Master/texmf-dist/doc/latex/expkv-cs/README.md	2021-07-07 20:54:41 UTC (rev 59864)
@@ -1,7 +1,7 @@
 -------------------------------------------------------------------------------
 # expkv-cs -- define expandable key=val macros using expkv
 
-Version 2021-06-20 v1.0
+Version 2021-07-07 v1.1
 
 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-cs/expkv-cs.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/expkv-cs/expkv-cs.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/expkv-cs/expkv-cs.dtx	2021-07-07 20:54:00 UTC (rev 59863)
+++ trunk/Master/texmf-dist/source/latex/expkv-cs/expkv-cs.dtx	2021-07-07 20:54:41 UTC (rev 59864)
@@ -658,9 +658,10 @@
 %
 % To remove some of the limitations with the approach that each primary key
 % matches an argument or hash entry, you can define secondary keys. Those have
-% to be defined for each macro but it doesn't matter whether that macro was a
-% split or a hash variant. If a secondary key references another key it doesn't
-% matter whether that other key is primary or secondary.
+% to be defined for each macro individually but it doesn't matter whether that
+% macro was a split or a hash variant. If a secondary key references another key
+% it doesn't matter whether that other key is primary or secondary unless
+% otherwise specified.
 %
 % Secondary keys can have a prefix (like |long|) which are called |p|-type
 % prefix and must have a type (like |meta|) which are called |t|-type prefix.
@@ -744,6 +745,53 @@
 %   \autoref{sec:change} for this). \key\ can be a primary or secondary key.
 % \end{function}
 %
+% \begin{function}{aggregate}
+%   \begin{syntax}
+%     aggregate \key\ = \marg{primary}\marg{definition} \prefixes3
+%   \end{syntax}
+%   While all other key types replace the current value of the associated
+%   \meta{primary} key, with |aggregate| you can create keys that append or
+%   prepend (or whatever you like) the new value to the current one. The
+%   value must be exactly two \TeX\ arguments, where \meta{primary} should
+%   be the name of a \meta{primary} key, and \meta{definition} the way you want
+%   to store the current and the new value. Inside \meta{definition} you
+%   can use |#1| for the current, and |#2| for the new value. The
+%   \meta{definition} will not expand any further during the entire parsing (so
+%   this doesn't allow general processing of current and new values). The
+%   resulting \key\ will inherit being either |short| or |long| from the
+%   \meta{primary} key.
+% \end{function}
+% \example The following defines an internal key (|k-internal|), which is used
+% to build a comma separated list from each call of the user facing key (|k|):\\
+% \begin{minipage}[c]{.75\linewidth}
+% \begin{lstlisting}
+% \ekvcSplit\foo
+%   {k-internal=0,color=red}
+%   {\textcolor{#2}{#1}}
+% \ekvcSecondaryKeys\foo
+%   {aggregate k = {k-internal}{#1,#2}}
+% \foo{}\par
+% \foo{k=1,k=2,k=3,k=4}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+%   \ekvcSplit\foo
+%     {k-internal=0,color=red}
+%     {\textcolor{#2}{#1}}
+%   \ekvcSecondaryKeys\foo
+%     {aggregate k = {k-internal}{#1,#2}}
+%   \foo{}\par
+%   \foo{k=1,k=2,k=3,k=4}
+% \end{exresult}
+%
+% But also more strange stuff could end there, like macros or using the same
+% value multiple times:
+% \begin{lstlisting}
+% \ekvcSecondaryKeys\foo
+%   {aggregate k = {k-internal}{\old{#1}\new{#2\old{#1}}}}
+% \end{lstlisting}
+%
+%
 % \begin{function}{flag-bool}
 %   \begin{syntax}
 %     flag-bool \key\ = \meta{cs} \prefixes3
@@ -1283,7 +1331,50 @@
 %   \foo{c=1-2}
 % \end{exresult}
 %
+% Additionally, there is a more general version of the |aggregate| secondary key
+% type (described in \autoref{sec:secondaries}), namely the |process| key type:
 %
+% \begin{function}{process}
+%   \begin{syntax}
+%     process \key\ = \marg{primary}\marg{definition} \prefixes2
+%   \end{syntax}
+%   This will grab the current value of a \meta{primary} key as |#1| (without
+%   changing the current value) and the new value as |#2| and leave all the
+%   processing to \meta{definition}. You should use |\ekvcPass| to forward the
+%   values afterwards. Unlike |aggregate| you can specify whether the \key\
+%   should be long or not, this isn't inherited from the \meta{primary} key.
+%   Keep in mind that you could easily break things here if your code does not
+%   work by expansion.
+% \end{function}
+% \example We could define a key that only accepts values greater than the
+% current value with this:\\
+% \begin{minipage}[c]{.75\linewidth}
+% \begin{lstlisting}
+% \ekvcSplit\foo{internal=5}{a is #1.\par}
+% \ekvcSecondaryKeys\foo
+%   {
+%     process a={internal}
+%       {%
+%         \ifnum#1<#2
+%           \ekvcPass\foo{internal}{#2}%
+%         \fi
+%       }
+%   }
+% \foo{a=1}
+% \foo{a=5}
+% \foo{a=9}
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+%   \ekvcSplit\foo{internal=5}{a is #1.\par}
+%   \ekvcSecondaryKeys\foo
+%     {process a={internal}{\ifnum#1<#2 \ekvcPass\foo{internal}{#2}\fi}}
+%   \foo{a=1}
+%   \foo{a=5}
+%   \foo{a=9}
+% \end{exresult}
+%
+%
 % \subsection{Speed Considerations}\label{sec:speed}
 %
 % As already mentioned in the introduction there are some speed considerations
@@ -1457,8 +1548,8 @@
 % \begin{macro}{\ekvcVersion,\ekvcDate}
 % We're on our first input, so lets store the version and date in a macro.
 %    \begin{macrocode}
-\def\ekvcVersion{1.0}
-\def\ekvcDate{2021-06-20}
+\def\ekvcVersion{1.1}
+\def\ekvcDate{2021-07-07}
 %    \end{macrocode}
 % \end{macro}
 %
@@ -2535,6 +2626,190 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{\ekvc at t@aggregate}
+%   Aggregating isn't easy to define. We'll have to extract the correct mark for
+%   the specified key, branch correctly for short and long keys, and use a small
+%   hack to have the correct arguments on the user interface (|#1| as the
+%   current contents, |#2| as the new value). This is split into a few steps
+%   here.
+%
+%   First, assert that the user input is well-behaved.
+%    \begin{macrocode}
+\protected\def\ekvc at t@aggregate#1%
+  {%
+    \ekvc at assert@not at long{aggregate #1}%
+    \ekvc at type@aggregate
+      \ekvc at type@aggregate at long\ekvc at type@aggregate at short
+      {process}%
+      {#1}%
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+%   {\ekvc at type@aggregate,\ekvc at type@aggregate at a,\ekvc at type@aggregate at b}
+%   The next step stores the user defined processing in a temporary macro that's
+%   used to do the parameter number swapping later. It also builds the names of
+%   the key macro and the helper which would be used for processing a short key.
+%    \begin{macrocode}
+\protected\long\def\ekvc at type@aggregate#1#2#3#4#5%
+  {%
+    \ekvc at assert@twoargs{#5}{#3 #4}{\ekvc at type@aggregate at a#1#2{#4}#5}%
+  }
+\protected\long\def\ekvc at type@aggregate at a#1#2#3#4#5%
+  {%
+    \ekvifdefined\ekvc at set{#4}%
+      {%
+        \def\ekvc at type@aggregate at tmp##1##2{#5}%
+        \begingroup\expandafter\endgroup
+        \expandafter\ekvc at type@aggregate at b
+          \csname\ekv at name\ekvc at set{#4}\expandafter\endcsname
+          \csname ekvc@\ekvc at set(#4)\endcsname
+          #1#2%
+          {#3}%
+      }%
+      {\ekvc at err@unknown at key{#4}}%
+  }
+\protected\long\def\ekvc at type@aggregate at b#1#2#3#4%
+  {%
+    \ekvc at type@aggregate at check@long#1#2%
+      {#3#1}%
+      {#4#2}%
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+%   {
+%     \ekvc at type@aggregate at check@long,
+%     \ekvc at type@aggregate at check@long at a,\ekvc at type@aggregate at check@long at b
+%   }
+%   To check whether the primary key is long we see whether its |\meaning|
+%   contains the helper which would only be there for short keys. For this we
+%   have to get the stringified name of the internal (using |\detokenize|),
+%   and afterwards get the |\meaning| of the macro. A temporary helper does the
+%   real test by gobbling and forwarding the result to |\ekv at ifempty|.
+%    \begin{macrocode}
+\protected\long\def\ekvc at type@aggregate at check@long#1#2%
+  {\expandafter\ekvc at type@aggregate at check@long at a\detokenize{#2}\ekv at stop#1}
+\protected\long\def\ekvc at type@aggregate at check@long at a#1\ekv at stop#2%
+  {%
+    \def\ekvc at type@aggregate at check@long@@##1#1{}%
+    \expandafter\ekvc at type@aggregate at check@long at b\meaning#2\ekv at stop{#1}%
+  }
+\protected\def\ekvc at type@aggregate at check@long at b#1\ekv at stop#2%
+  {\expandafter\ekv at ifempty\expandafter{\ekvc at type@aggregate at check@long@@#1#2}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc at type@aggregate at long,\ekvc at type@aggregate at long@}
+%   The long variant just builds the split mark we extract, uses the hack to
+%   swap argument order, and then does the definition via |\ekvlet| and a
+%   temporary macro.
+%    \begin{macrocode}
+\protected\long\def\ekvc at type@aggregate at long#1%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@aggregate at long@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+  }
+\protected\long\def\ekvc at type@aggregate at long@#1#2#3%
+  {%
+    \long\def\ekvc at type@aggregate at tmp##1##2#1##3{##2#1{#2}}
+    \ekvlet\ekvc at set{#3}\ekvc at type@aggregate at tmp
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+%   {\ekvc at type@aggregate at short,\ekvc at type@aggregate at short@}
+%   The short variant will have to build the marker and the name of the helper
+%   function, and swap the user argument order. Hence here are a few more
+%   |\expandafter|s involved. But afterwards we can do the definition of the key
+%   and the helper macro directly.
+%    \begin{macrocode}
+\protected\long\def\ekvc at type@aggregate at short#1#2%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@aggregate at short@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \csname ekvc@\ekvc at set(#2)\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+      {#2}%
+  }
+\protected\long\def\ekvc at type@aggregate at short@#1#2#3#4%
+  {%
+    \ekvdef\ekvc at set{#4}{#2{##1}}%
+    \long\def#2##1##2#1##3{##2#1{#3}}%
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc at t@process}
+%   The |process| type can reuse much of |aggregate|, just the last step of
+%   definition differ.
+%    \begin{macrocode}
+\protected\def\ekvc at t@process
+  {%
+    \ifx\ekvc at long\long
+      \ekv at fi@firstoftwo
+    \fi
+    \@secondoftwo
+      {%
+        \ekvc at type@aggregate
+          \ekvc at type@process at long\ekvc at type@process at long
+      }%
+      {%
+        \ekvc at type@aggregate
+          \ekvc at type@process at short\ekvc at type@process at short
+      }%
+      {process}%
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc at type@process at long,\ekvc at type@process at long@}
+%   This defines a temporary macro to grab the current value (found after the
+%   marker |#1|), executes the user code and puts everything back to where it
+%   belongs. Then |\ekvlet| is used to assign that meaning to the key macro.
+%    \begin{macrocode}
+\protected\long\def\ekvc at type@process at long#1%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@process at long@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+  }
+\protected\long\def\ekvc at type@process at long@#1#2#3%
+  {%
+    \long\def\ekvc at type@aggregate at tmp##1##2#1##3{#2##2#1{##3}}%
+    \ekvlet\ekvc at set{#3}\ekvc at type@aggregate at tmp
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc at type@process at short,\ekvc at type@process at short@}
+%   We define the key macro directly to just grab the argument once and forward
+%   it to the auxiliary. That one does essentially the same as the long variant.
+%    \begin{macrocode}
+\protected\long\def\ekvc at type@process at short#1#2%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@process at short@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \csname ekvc@\ekvc at set(#2)\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+      {#2}%
+  }
+\protected\long\def\ekvc at type@process at short@#1#2#3#4%
+  {%
+    \ekvdef\ekvc at set{#4}{#2{##1}}%
+    \long\def#2##1##2#1##3{#3##2#1{##3}}%
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[internal]{\ekvc at t@flag-bool}
 %    \begin{macrocode}
 \protected\expandafter\def\csname ekvc at t@flag-bool\endcsname#1#2%
@@ -2806,7 +3081,34 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{\ekvc at ifnottwoargs,\ekvc at ifempty@gtwo}
+%   Used to test whether a token list contains exactly two \TeX\ arguments.
+%    \begin{macrocode}
+\long\def\ekvc at ifnottwoargs#1%
+  {%
+    \ekvc at ifempty@gtwo#1\ekv at ifempty@B
+      \ekv at ifempty@false\ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
+  }
+\long\def\ekvc at ifempty@gtwo#1#2{\ekv at ifempty@\ekv at ifempty@A}
+%    \end{macrocode}
+% \end{macro}
 %
+% \begin{macro}[internal]{\ekvc at extract@mark,\ekvc at extract@mark@}
+%   This is used to extract the mark of a split or hash key from its definition.
+%   This is kind of fragile, it assumes |#1| is always a macro used for hashing
+%   or splitting. Also it assumes that the escape character is a backslash.
+%    \begin{macrocode}
+\def\ekvc at extract@mark#1{\expandafter\ekvc at extract@mark@\meaning#1\ekv at stop}
+\begingroup
+\lccode`;=`\#
+\lccode`/=`\\
+\lowercase{\endgroup
+\def\ekvc at extract@mark@#1:#2/#3 ;#4\ekv at stop{#3}%
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%
 % \subsubsection{Assertions}
 % \begin{macro}[internal]{\ekvc at assert@not at long}
 %   Some keys don't want to be |long| and we have to educate the user, so let's
@@ -2816,13 +3118,23 @@
 %    \end{macrocode}
 % \end{macro}
 %
+% \begin{macro}[internal]{\ekvc at assert@twoargs}
+%   Some keys need exactly two arguments as their definition, so we have to
+%   somehow assert this.
+%    \begin{macrocode}
+\protected\long\def\ekvc at assert@twoargs#1#2%
+  {\ekvc at ifnottwoargs{#1}{\ekvc at err@not at two{#2}}}
+%    \end{macrocode}
+% \end{macro}
 %
+%
 % \subsubsection{Messages}
 %
 % \begin{macro}[internal]
 %   {
 %     \ekvc at err@toomany,\ekvc at err@value at required,\ekvc at err@missing at type,
-%     \ekvc at err@already at defined,\ekvc at err@no at key@macro
+%     \ekvc at err@already at defined,\ekvc at err@no at key@macro,
+%     \ekvc at err@not at two
 %   }
 %   Boring unexpandable error messages.
 %    \begin{macrocode}
@@ -2859,6 +3171,14 @@
   }
 \long\def\ekvc at err@no at key@macro#1%
   {\errmessage{expkv-cs Error: \string#1 is no key=val macro}}
+\protected\long\def\ekvc at err@not at two#1%
+  {%
+    \errmessage
+      {%
+        expkv-cs Error: Definition of `\unexpanded{#1}' doesn't contain exactly
+        two arguments%
+      }%
+  }
 %    \end{macrocode}
 % \end{macro}
 %

Modified: trunk/Master/texmf-dist/tex/generic/expkv-cs/expkv-cs.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/expkv-cs/expkv-cs.tex	2021-07-07 20:54:00 UTC (rev 59863)
+++ trunk/Master/texmf-dist/tex/generic/expkv-cs/expkv-cs.tex	2021-07-07 20:54:41 UTC (rev 59864)
@@ -35,8 +35,8 @@
 \else
   \expandafter\endinput
 \fi
-\def\ekvcVersion{1.0}
-\def\ekvcDate{2021-06-20}
+\def\ekvcVersion{1.1}
+\def\ekvcDate{2021-07-07}
 \csname ekvc at tmp\endcsname
 \expandafter\chardef\csname ekvc at tmp\endcsname=\catcode`\@
 \catcode`\@=11
@@ -690,6 +690,115 @@
       }%
       {\ekvc at err@unknown at key{#1}}%
   }
+\protected\def\ekvc at t@aggregate#1%
+  {%
+    \ekvc at assert@not at long{aggregate #1}%
+    \ekvc at type@aggregate
+      \ekvc at type@aggregate at long\ekvc at type@aggregate at short
+      {process}%
+      {#1}%
+  }
+\protected\long\def\ekvc at type@aggregate#1#2#3#4#5%
+  {%
+    \ekvc at assert@twoargs{#5}{#3 #4}{\ekvc at type@aggregate at a#1#2{#4}#5}%
+  }
+\protected\long\def\ekvc at type@aggregate at a#1#2#3#4#5%
+  {%
+    \ekvifdefined\ekvc at set{#4}%
+      {%
+        \def\ekvc at type@aggregate at tmp##1##2{#5}%
+        \begingroup\expandafter\endgroup
+        \expandafter\ekvc at type@aggregate at b
+          \csname\ekv at name\ekvc at set{#4}\expandafter\endcsname
+          \csname ekvc@\ekvc at set(#4)\endcsname
+          #1#2%
+          {#3}%
+      }%
+      {\ekvc at err@unknown at key{#4}}%
+  }
+\protected\long\def\ekvc at type@aggregate at b#1#2#3#4%
+  {%
+    \ekvc at type@aggregate at check@long#1#2%
+      {#3#1}%
+      {#4#2}%
+  }
+\protected\long\def\ekvc at type@aggregate at check@long#1#2%
+  {\expandafter\ekvc at type@aggregate at check@long at a\detokenize{#2}\ekv at stop#1}
+\protected\long\def\ekvc at type@aggregate at check@long at a#1\ekv at stop#2%
+  {%
+    \def\ekvc at type@aggregate at check@long@@##1#1{}%
+    \expandafter\ekvc at type@aggregate at check@long at b\meaning#2\ekv at stop{#1}%
+  }
+\protected\def\ekvc at type@aggregate at check@long at b#1\ekv at stop#2%
+  {\expandafter\ekv at ifempty\expandafter{\ekvc at type@aggregate at check@long@@#1#2}}
+\protected\long\def\ekvc at type@aggregate at long#1%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@aggregate at long@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+  }
+\protected\long\def\ekvc at type@aggregate at long@#1#2#3%
+  {%
+    \long\def\ekvc at type@aggregate at tmp##1##2#1##3{##2#1{#2}}
+    \ekvlet\ekvc at set{#3}\ekvc at type@aggregate at tmp
+  }
+\protected\long\def\ekvc at type@aggregate at short#1#2%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@aggregate at short@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \csname ekvc@\ekvc at set(#2)\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+      {#2}%
+  }
+\protected\long\def\ekvc at type@aggregate at short@#1#2#3#4%
+  {%
+    \ekvdef\ekvc at set{#4}{#2{##1}}%
+    \long\def#2##1##2#1##3{##2#1{#3}}%
+  }
+\protected\def\ekvc at t@process
+  {%
+    \ifx\ekvc at long\long
+      \ekv at fi@firstoftwo
+    \fi
+    \@secondoftwo
+      {%
+        \ekvc at type@aggregate
+          \ekvc at type@process at long\ekvc at type@process at long
+      }%
+      {%
+        \ekvc at type@aggregate
+          \ekvc at type@process at short\ekvc at type@process at short
+      }%
+      {process}%
+  }
+\protected\long\def\ekvc at type@process at long#1%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@process at long@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+  }
+\protected\long\def\ekvc at type@process at long@#1#2#3%
+  {%
+    \long\def\ekvc at type@aggregate at tmp##1##2#1##3{#2##2#1{##3}}%
+    \ekvlet\ekvc at set{#3}\ekvc at type@aggregate at tmp
+  }
+\protected\long\def\ekvc at type@process at short#1#2%
+  {%
+    \begingroup\expandafter\endgroup\expandafter
+    \ekvc at type@process at short@
+      \csname\ekvc at extract@mark#1\expandafter\endcsname
+      \csname ekvc@\ekvc at set(#2)\expandafter\endcsname
+      \expandafter{\ekvc at type@aggregate at tmp{##3}{##1}}%
+      {#2}%
+  }
+\protected\long\def\ekvc at type@process at short@#1#2#3#4%
+  {%
+    \ekvdef\ekvc at set{#4}{#2{##1}}%
+    \long\def#2##1##2#1##3{#3##2#1{##3}}%
+  }
 \protected\expandafter\def\csname ekvc at t@flag-bool\endcsname#1#2%
   {%
     \ekvc at assert@not at long{flag-bool #1}%
@@ -831,7 +940,22 @@
   {%
     \ekv at ifempty@\ekv at ifempty@A
   }
+\long\def\ekvc at ifnottwoargs#1%
+  {%
+    \ekvc at ifempty@gtwo#1\ekv at ifempty@B
+      \ekv at ifempty@false\ekv at ifempty@A\ekv at ifempty@B\@firstoftwo
+  }
+\long\def\ekvc at ifempty@gtwo#1#2{\ekv at ifempty@\ekv at ifempty@A}
+\def\ekvc at extract@mark#1{\expandafter\ekvc at extract@mark@\meaning#1\ekv at stop}
+\begingroup
+\lccode`;=`\#
+\lccode`/=`\\
+\lowercase{\endgroup
+\def\ekvc at extract@mark@#1:#2/#3 ;#4\ekv at stop{#3}%
+}
 \long\def\ekvc at assert@not at long#1{\ifx\ekvc at long\long\ekvc at err@no at long{#1}\fi}
+\protected\long\def\ekvc at assert@twoargs#1#2%
+  {\ekvc at ifnottwoargs{#1}{\ekvc at err@not at two{#2}}}
 \protected\def\ekvc at err@toomany#1%
   {%
     \errmessage{expkv-cs Error: Too many keys for macro `\string#1'}%
@@ -865,6 +989,14 @@
   }
 \long\def\ekvc at err@no at key@macro#1%
   {\errmessage{expkv-cs Error: \string#1 is no key=val macro}}
+\protected\long\def\ekvc at err@not at two#1%
+  {%
+    \errmessage
+      {%
+        expkv-cs Error: Definition of `\unexpanded{#1}' doesn't contain exactly
+        two arguments%
+      }%
+  }
 \ekv at exparg{\long\def\ekvc at err#1}{\ekverr{expkv-cs}{#1}}
 \long\def\ekvc at err@unknown at hash#1{\ekvc at err{unknown hash `#1'}}
 \long\def\ekvc at err@missing at hash#1{\ekvc at err{hash `#1' not found}}



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