texlive[59949] Master/texmf-dist: expkv (16jul21)
commits+karl at tug.org
commits+karl at tug.org
Fri Jul 16 21:56:18 CEST 2021
Revision: 59949
http://tug.org/svn/texlive?view=revision&revision=59949
Author: karl
Date: 2021-07-16 21:56:17 +0200 (Fri, 16 Jul 2021)
Log Message:
-----------
expkv (16jul21)
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 2021-07-15 23:48:36 UTC (rev 59948)
+++ trunk/Master/texmf-dist/doc/latex/expkv/README.md 2021-07-16 19:56:17 UTC (rev 59949)
@@ -1,7 +1,7 @@
-------------------------------------------------------------------------------
# expkv -- an expandable key=val implementation
-Version 2021-06-03 v1.8a
+Version 2021-07-15 v1.9
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 2021-07-15 23:48:36 UTC (rev 59948)
+++ trunk/Master/texmf-dist/source/latex/expkv/expkv.dtx 2021-07-16 19:56:17 UTC (rev 59949)
@@ -421,7 +421,7 @@
% \end{function}
% \example Define |text| in |foo| to store the value inside |\foo at text|:
% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \protected\long\ekvdef{foo}{text}{\def\foo at width{#1}}
+% \protected\long\ekvdef{foo}{text}{\def\foo at text{#1}}
% \end{lstlisting}
%
% \begin{function}{\ekvdefNoVal}
@@ -440,7 +440,8 @@
% \cs{ekvlet}\marg{set}\marg{key}\meta{cs}
% \end{syntax}
% Let the value taking \key\ in \set\ to \meta{cs}, there are no checks on
-% \meta{cs} enforced.
+% \meta{cs} enforced, but the code should expect the value as a single braced
+% argument directly following it.
% \end{function}
% \example Let |cmd| in |foo| do the same as |\foo at cmd|:
% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
@@ -811,7 +812,8 @@
% argument will be wrapped in braces, the mandatory argument will be
% untouched). If there was no optional argument the result will be
% \meta{next}\marg{default}\marg{mandatory} (so the default will be used and
-% the mandatory argument will be wrapped in braces).
+% the mandatory argument will be wrapped in braces after being read once -- if
+% it was already wrapped it is effectively unchanged).
% \end{function}
% |\ekvoptarg| expands in exactly two steps, grabs all the arguments only at the
% second expansion step, and is alignment safe. It has its limitations however.
@@ -845,6 +847,43 @@
% \newcommand\foo at b[1]{Mandatory: #1\par No optional.}
% \end{lstlisting}
%
+% \begin{function}{\ekvcsvloop}
+% \begin{syntax}
+% \cs{ekvcsvloop}\marg{code}\marg{csv-list}
+% \end{syntax}
+% This loops over the comma separated items in \meta{csv-list} and, after
+% stripping spaces from either end of \meta{item} and removing at most one set
+% of outer braces, leaves
+% \texttt
+% {^^A
+% \cs[no-index]{unexpanded}\hskip0pt
+% \{\hskip0pt
+% \meta{code}\hskip0pt
+% \marg{item}\hskip0pt
+% \}^^A
+% }
+% for each list item in the input stream. Blank elements are ignored (if you
+% need a blank element it should be given as |{}|). It supports both active
+% commas and commas of category other. You could consider it as a watered down
+% version of |\ekvparse|. However it is not alignment safe, which you could
+% achieve by nesting it in |\expanded| (since the braces around the argument
+% of |\expanded| will hide |&|s from \TeX's alignment parsing).
+% \end{function}
+% \example The following splits a comma separated list and prints it in a
+% typewriter font with parentheses around each element.\\
+% \begin{minipage}{.75\linewidth}
+% \begin{lstlisting}
+% \newcommand*\myprocessor[1]{\texttt{(#1)}}
+% \ekvcsvloop\myprocessor{abc,def,ghi}\par
+% \ekvcsvloop\myprocessor{1,,2,,3,,4}\par
+% \end{lstlisting}
+% \end{minipage}^^A
+% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
+% \newcommand*\myprocessor[1]{\texttt{(#1)}}
+% \ekvcsvloop\myprocessor{abc,def,ghi}\par
+% \ekvcsvloop\myprocessor{1,,2,,3,,4}\par
+% \end{exresult}
+%
% \begin{function}{\ekverr}
% \begin{syntax}
% \cs{ekverr}\marg{package}\marg{message}
@@ -1554,8 +1593,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.8a}
-\def\ekvDate{2021-06-03}
+\def\ekvVersion{1.9}
+\def\ekvDate{2021-07-15}
% \end{macrocode}
% \end{macro}
%
@@ -1762,35 +1801,73 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\ekvcsvloop}
+% \begin{macro}[internal]{\ekv at csv@loop at active,\ekv at csv@loop at active@end}
+% An |\ekvcsvloop| will just loop over a csv list in a simple manner. First we
+% split at active commas (gives better performance this way), next we have to
+% check whether we're at the end of the list (checking for |\ekv at stop|). If
+% not we go on splitting at commas of category other.
+% \begin{macrocode}
+\begingroup
+\def\ekvcsvloop#1{%
+\endgroup
+\long\def\ekvcsvloop##1##2%
+ {\ekv at csv@loop at active{##1}\ekv at mark##2#1\ekv at stop#1}
+% \end{macrocode}
+% This does the same as |\ekv at csv@loop| but for active commas.
+% \begin{macrocode}
+\long\def\ekv at csv@loop at active##1##2#1%
+ {%
+ \ekv at gobble@from at mark@to at stop##2\ekv at csv@loop at active@end\ekv at stop
+ \ekv at csv@loop{##1}##2,\ekv at stop,%
+ }%
+\long\def\ekv at csv@loop at active@end
+ \ekv at stop
+ \ekv at csv@loop##1\ekv at mark\ekv at stop,\ekv at stop,%
+ {}%
+}
+% \end{macrocode}
+% Do the definitions with the weird catcode.
+% \begin{macrocode}
+\catcode`\,=13
+\ekvcsvloop,
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}[internal]{\ekv at csv@loop,\ekv at csv@loop at do,\ekv at csv@loop at end}
-% This is just a very simple loop over a list of comma separated values,
-% leaving each element as the argument to a specified function inside of
-% |\unravel|. It should be used as
-% \texttt
-% {^^A
-% \cs[no-index]{ekv at csv@loop}\hskip0pt^^A
-% \marg{function}\hskip0pt^^A
-% \cs[no-index]{ekv at mark}\hskip0pt^^A
-% \meta{csv-list}\hskip0pt^^A
-% ,\cs[no-index]{ekv at stop},^^A
-% }.
-% We use some |\expandafter| chain to preexpand |\ekv at strip| here.
+% We use temporary macros and an |\expandafter| chain to preexpand
+% |\ekv at strip| here. After splitting at other commas we check again for end
+% the end of the sublist, check for blank elements which should be ignored,
+% and else strip spaces and execute the user code (protecting it from further
+% expanding with |\unexpanded|).
% \begin{macrocode}
-\ekv at exparg{\long\def\ekv at csv@loop#1#2,}%
+\def\ekv at csv@loop#1%
{%
- \expandafter
- \ekv at gobble@from at mark@to at stop
- \expandafter#\expandafter2\expandafter\ekv at csv@loop at end\expandafter
- \ekv at stop
- \ekv at strip{#2}{\ekv at csv@loop at do{#1}}%
- \ekv at csv@loop{#1}\ekv at mark
+ \long\def\ekv at csv@loop##1##2,%
+ {%
+ \ekv at gobble@from at mark@to at stop##2\ekv at csv@loop at end\ekv at stop
+ \ekv at ifblank@##2\ekv at nil\ekv at ifempty@B\ekv at csv@loop at blank
+ \ekv at ifempty@A\ekv at ifempty@B
+ #1\ekv at csv@loop at do{##1}%
+ }%
}
-\long\def\ekv at csv@loop at do#1#2{\unexpanded{#1{#2}}}
-\long\expandafter\def\expandafter\ekv at csv@loop at end
- \expandafter\ekv at stop
- \ekv at strip{#1}#2%
- \ekv at csv@loop#3\ekv at mark
- {}
+\expandafter\ekv at csv@loop\expandafter{\ekv at strip{#2}}
+\long\def\ekv at csv@loop at do#1#2{\unexpanded{#2{#1}}\ekv at csv@loop{#2}\ekv at mark}
+\def\ekv at csv@loop at end#1%
+ {%
+ \long\def\ekv at csv@loop at end
+ \ekv at stop
+ \ekv at ifblank@\ekv at mark\ekv at stop\ekv at nil\ekv at ifempty@B\ekv at csv@loop at blank
+ \ekv at ifempty@A\ekv at ifempty@B
+ #1\ekv at csv@loop at do##1%
+ {\ekv at csv@loop at active{##1}\ekv at mark}%
+ }
+\expandafter\ekv at csv@loop at end\expandafter{\ekv at strip{\ekv at mark\ekv at stop}}
+\long\expandafter\def\expandafter\ekv at csv@loop at blank
+ \expandafter\ekv at ifempty@A\expandafter\ekv at ifempty@B
+ \ekv at strip{\ekv at mark#1}\ekv at csv@loop at do#2%
+ {\ekv at csv@loop{#2}\ekv at mark}
% \end{macrocode}
% \end{macro}
%
@@ -1969,9 +2046,9 @@
\begingroup
\edef\ekv at tmp
{%
- \ekv at csv@loop#1\ekv at mark#6,\ekv at stop,%
+ \ekvcsvloop#1{#6}%
\unexpanded{#2}%
- {\ekv at csv@loop{}\ekv at mark#5,#6,\ekv at stop,}%
+ {\ekvcsvloop{}{#5,#6}}%
}%
\ekv at expargtwice
{\endgroup#3{#5}}%
@@ -2690,7 +2767,10 @@
% possibilities (they don't care for nested bracket levels).
%
% We start with a temporary definition to pre-expand |\ekv at alignsafe| (will be
-% |#1|) and |\ekv at endalignsafe| (will be |#2|).
+% |#1|) and |\ekv at endalignsafe| (will be |#2|). As |\ekv at alignsafe| starts with
+% a |\romannumeral| we use that to also control the number of steps needed
+% instead of adding another |\romannumeral|. For this we have to remove the
+% space token from the end of |\ekv at alignsafe|'s definition.
% \begin{macrocode}
\begingroup
\def\ekvoptarg#1#2{%
@@ -2702,12 +2782,12 @@
% bracket, if it is found grab the optional argument, else leave |#1{#2}| in the
% input stream after ending the expansion context.
% \begin{macrocode}
-\def\ekvoptarg{\romannumeral#1\ekv at optarg@a}
+\def\ekvoptarg{#1\ekv at optarg@a}
\long\def\ekv at optarg@a##1##2##3%
{%
\ekv at optarg@if\ekv at mark##3\ekv at mark\ekv at optarg@b\ekv at mark[\ekv at mark
#2%
- \@firstofone{\ekv at zero##1}{##2}{##3}%
+ \@firstofone{ ##1}{##2}{##3}%
}%
% \end{macrocode}
% The other variant of this will do roughly the same. Here, |#1| will be the
@@ -2714,12 +2794,12 @@
% next step if an optional argument is found, |#2| the next step else, and |#3|
% might be the opening bracket or mandatory argument.
% \begin{macrocode}
-\def\ekvoptargTF{\romannumeral#1\ekv at optargTF@a}
+\def\ekvoptargTF{#1\ekv at optargTF@a}
\long\def\ekv at optargTF@a##1##2##3%
{%
\ekv at optarg@if\ekv at mark##3\ekv at mark\ekv at optargTF@b{##1}\ekv at mark[\ekv at mark
#2%
- \@firstofone{\ekv at zero##2}{##3}%
+ \@firstofone{ ##2}{##3}%
}
% \end{macrocode}
% The two macros to grab the optional argument have to remove the remainder of
@@ -2729,12 +2809,19 @@
{#2##2{##5}}
\long\def\ekv at optargTF@b
##1\ekv at mark[\ekv at mark\ifnum`##2\fi\@firstofone##3##4##5]%
- {#2\ekv at zero##1{##5}}
+ {#2 ##1{##5}}
}
% \end{macrocode}
-% Do the definitions and add the test macro.
+% Do the definitions and add the test macro. We use |\ekv at strip| to remove the
+% trailing space from the definition of |\ekv at alignsafe|.
% \begin{macrocode}
-\ekv at exparg{\expandafter\ekvoptarg\expandafter{\ekv at alignsafe}}\ekv at endalignsafe
+\ekv at exparg
+ {%
+ \expandafter\ekv at strip\expandafter
+ {\expandafter\ekv at mark\ekv at alignsafe}%
+ \ekvoptarg
+ }%
+ \ekv at endalignsafe
\long\def\ekv at optarg@if#1\ekv at mark[\ekv at mark{}
% \end{macrocode}
% \end{macro}
Modified: trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex
===================================================================
--- trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex 2021-07-15 23:48:36 UTC (rev 59948)
+++ trunk/Master/texmf-dist/tex/generic/expkv/expkv.tex 2021-07-16 19:56:17 UTC (rev 59949)
@@ -44,8 +44,8 @@
\errmessage{expkv Error: e-TeX and \noexpand\expanded required}
\expandafter\endinput
\fi
-\def\ekvVersion{1.8a}
-\def\ekvDate{2021-06-03}
+\def\ekvVersion{1.9}
+\def\ekvDate{2021-07-15}
\csname ekv at tmp\endcsname
\expandafter\chardef\csname ekv at tmp\endcsname=\catcode`\@
\catcode`\@=11
@@ -136,21 +136,49 @@
\long\def\ekv at exparg@#1#2{#2{#1}}%
\long\def\ekv at expargtwice#1#2{\expandafter\ekv at expargtwice@\expandafter{#2}{#1}}
\def\ekv at expargtwice@{\expandafter\ekv at exparg@\expandafter}
-\ekv at exparg{\long\def\ekv at csv@loop#1#2,}%
+\begingroup
+\def\ekvcsvloop#1{%
+\endgroup
+\long\def\ekvcsvloop##1##2%
+ {\ekv at csv@loop at active{##1}\ekv at mark##2#1\ekv at stop#1}
+\long\def\ekv at csv@loop at active##1##2#1%
{%
- \expandafter
- \ekv at gobble@from at mark@to at stop
- \expandafter#\expandafter2\expandafter\ekv at csv@loop at end\expandafter
+ \ekv at gobble@from at mark@to at stop##2\ekv at csv@loop at active@end\ekv at stop
+ \ekv at csv@loop{##1}##2,\ekv at stop,%
+ }%
+\long\def\ekv at csv@loop at active@end
\ekv at stop
- \ekv at strip{#2}{\ekv at csv@loop at do{#1}}%
- \ekv at csv@loop{#1}\ekv at mark
+ \ekv at csv@loop##1\ekv at mark\ekv at stop,\ekv at stop,%
+ {}%
+}
+\catcode`\,=13
+\ekvcsvloop,
+\def\ekv at csv@loop#1%
+ {%
+ \long\def\ekv at csv@loop##1##2,%
+ {%
+ \ekv at gobble@from at mark@to at stop##2\ekv at csv@loop at end\ekv at stop
+ \ekv at ifblank@##2\ekv at nil\ekv at ifempty@B\ekv at csv@loop at blank
+ \ekv at ifempty@A\ekv at ifempty@B
+ #1\ekv at csv@loop at do{##1}%
+ }%
}
-\long\def\ekv at csv@loop at do#1#2{\unexpanded{#1{#2}}}
-\long\expandafter\def\expandafter\ekv at csv@loop at end
- \expandafter\ekv at stop
- \ekv at strip{#1}#2%
- \ekv at csv@loop#3\ekv at mark
- {}
+\expandafter\ekv at csv@loop\expandafter{\ekv at strip{#2}}
+\long\def\ekv at csv@loop at do#1#2{\unexpanded{#2{#1}}\ekv at csv@loop{#2}\ekv at mark}
+\def\ekv at csv@loop at end#1%
+ {%
+ \long\def\ekv at csv@loop at end
+ \ekv at stop
+ \ekv at ifblank@\ekv at mark\ekv at stop\ekv at nil\ekv at ifempty@B\ekv at csv@loop at blank
+ \ekv at ifempty@A\ekv at ifempty@B
+ #1\ekv at csv@loop at do##1%
+ {\ekv at csv@loop at active{##1}\ekv at mark}%
+ }
+\expandafter\ekv at csv@loop at end\expandafter{\ekv at strip{\ekv at mark\ekv at stop}}
+\long\expandafter\def\expandafter\ekv at csv@loop at blank
+ \expandafter\ekv at ifempty@A\expandafter\ekv at ifempty@B
+ \ekv at strip{\ekv at mark#1}\ekv at csv@loop at do#2%
+ {\ekv at csv@loop{#2}\ekv at mark}
\def\ekv at name@set#1{ekv#1(}
\def\ekv at name@key#1{#1)}
\edef\ekv at name
@@ -269,9 +297,9 @@
\begingroup
\edef\ekv at tmp
{%
- \ekv at csv@loop#1\ekv at mark#6,\ekv at stop,%
+ \ekvcsvloop#1{#6}%
\unexpanded{#2}%
- {\ekv at csv@loop{}\ekv at mark#5,#6,\ekv at stop,}%
+ {\ekvcsvloop{}{#5,#6}}%
}%
\ekv at expargtwice
{\endgroup#3{#5}}%
@@ -658,27 +686,33 @@
\begingroup
\def\ekvoptarg#1#2{%
\endgroup
-\def\ekvoptarg{\romannumeral#1\ekv at optarg@a}
+\def\ekvoptarg{#1\ekv at optarg@a}
\long\def\ekv at optarg@a##1##2##3%
{%
\ekv at optarg@if\ekv at mark##3\ekv at mark\ekv at optarg@b\ekv at mark[\ekv at mark
#2%
- \@firstofone{\ekv at zero##1}{##2}{##3}%
+ \@firstofone{ ##1}{##2}{##3}%
}%
-\def\ekvoptargTF{\romannumeral#1\ekv at optargTF@a}
+\def\ekvoptargTF{#1\ekv at optargTF@a}
\long\def\ekv at optargTF@a##1##2##3%
{%
\ekv at optarg@if\ekv at mark##3\ekv at mark\ekv at optargTF@b{##1}\ekv at mark[\ekv at mark
#2%
- \@firstofone{\ekv at zero##2}{##3}%
+ \@firstofone{ ##2}{##3}%
}
\long\def\ekv at optarg@b\ekv at mark[\ekv at mark\ifnum`##1\fi\@firstofone##2##3##4##5]%
{#2##2{##5}}
\long\def\ekv at optargTF@b
##1\ekv at mark[\ekv at mark\ifnum`##2\fi\@firstofone##3##4##5]%
- {#2\ekv at zero##1{##5}}
+ {#2 ##1{##5}}
}
-\ekv at exparg{\expandafter\ekvoptarg\expandafter{\ekv at alignsafe}}\ekv at endalignsafe
+\ekv at exparg
+ {%
+ \expandafter\ekv at strip\expandafter
+ {\expandafter\ekv at mark\ekv at alignsafe}%
+ \ekvoptarg
+ }%
+ \ekv at endalignsafe
\long\def\ekv at optarg@if#1\ekv at mark[\ekv at mark{}
\def\ekv at err@cleanup\par{}
\def\ekv at err@collect#1%
More information about the tex-live-commits
mailing list.