texlive[60364] Master/texmf-dist: etl (29aug21)

commits+karl at tug.org commits+karl at tug.org
Sun Aug 29 22:25:20 CEST 2021


Revision: 60364
          http://tug.org/svn/texlive?view=revision&revision=60364
Author:   karl
Date:     2021-08-29 22:25:20 +0200 (Sun, 29 Aug 2021)
Log Message:
-----------
etl (29aug21)

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

Modified: trunk/Master/texmf-dist/doc/latex/etl/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/etl/README.md	2021-08-29 20:24:58 UTC (rev 60363)
+++ trunk/Master/texmf-dist/doc/latex/etl/README.md	2021-08-29 20:25:20 UTC (rev 60364)
@@ -1,7 +1,7 @@
 -------------------------------------------------------------------------------
 # etl -- expandable token list operations
 
-Version 2021-08-20 v0.1
+Version 2021-08-28 v0.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/etl/etl.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/source/latex/etl/etl.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/etl/etl.dtx	2021-08-29 20:24:58 UTC (rev 60363)
+++ trunk/Master/texmf-dist/source/latex/etl/etl.dtx	2021-08-29 20:25:20 UTC (rev 60364)
@@ -110,9 +110,9 @@
 % to unexpandable functions found inside the \pkg{l3tl} module of \pkg{expl3}.
 % All user functions must not contain the tokens \cs{s__etl_stop}\footnote{At
 % any nesting level of groups} or \cs{__etl_act_result:n}\footnote{Outside of
-% some local brace groups} in any argument (but there might be other forbidden
-% tokens, all of which are internals to this package, and usually shouldn't
-% somehow end up inside the input stream by accident).
+% some local brace groups} in any argument unless specified otherwise (there
+% might be other forbidden tokens, all of which are internals to this package,
+% and usually shouldn't somehow end up inside the input stream by accident).
 %
 % There is another limitation of this package: There are tokens which cannot
 % expandably be differentiated from each other, those are active characters let
@@ -406,7 +406,7 @@
 %
 % \begin{function}[EXP]{\etl_replace_once:nnn}
 %   \begin{syntax}
-%     \cs{etl_replace_once:nnn} \meta{token list} \meta{search text} \meta{replacement}
+%     \cs{etl_replace_once:nnn} \Arg{token list} \Arg{search text} \Arg{replacement}
 %   \end{syntax}
 %   This function will replace the first occurrence of \meta{search text}
 %   inside of \meta{token list} that is not hidden inside a group with
@@ -422,7 +422,7 @@
 %
 % \begin{function}[EXP]{\etl_replace_all:nnn}
 %   \begin{syntax}
-%     \cs{etl_replace_all:nnn} \meta{token list} \meta{search text} \meta{replacement}
+%     \cs{etl_replace_all:nnn} \Arg{token list} \Arg{search text} \Arg{replacement}
 %   \end{syntax}
 %   This function will replace all occurrences of \meta{search text}
 %   inside of \meta{token list} that are not hidden inside a group with
@@ -438,7 +438,7 @@
 %
 % \begin{function}[EXP]{\etl_replace_all_deep:nnn}
 %   \begin{syntax}
-%     \cs{etl_replace_all_deep:nnn} \meta{token list} \meta{search text} \meta{replacement}
+%     \cs{etl_replace_all_deep:nnn} \Arg{token list} \Arg{search text} \Arg{replacement}
 %   \end{syntax}
 %   This function will replace all occurrences of \meta{search text}
 %   inside of \meta{token list} with \meta{replacement}.
@@ -452,14 +452,21 @@
 % \end{function}
 %
 %
-% \subsection{New expandable fast tests}
+% \subsection{New expandable functions}
 %
-% Functions generated with the means in this section are as fast as the
-% \pkg{l3tl} variants of them, but have at least one fixed argument.
+% Functions generated with the means in this section are roughly as fast as the
+% \pkg{l3tl} variants of them (there might be performance differences; in any
+% case they are faster than the generic functions above), but have at least one
+% fixed argument. They don't have the drawback of not being able to tell apart
+% an active character from a token with the same character code and different
+% category code if the active character was let to it and they don't normalise
+% braces to \texttt{\{\textsubscript{1}} and \texttt{\}\textsubscript{2}}.
 %
+% \subsubsection{Conditionals}
+%
 % \begin{function}{\etl_new_if_in:Nnn}
 %   \begin{syntax}
-%     \cs{etl_new_if_in:Nnn} \meta{function} \meta{search text} \meta{conditions}
+%     \cs{etl_new_if_in:Nnn} \meta{function} \Arg{search text} \Arg{conditions}
 %   \end{syntax}
 %   This will define a new \meta{function} which will act as a conditional and
 %   search for \meta{search text} inside of an |n|-type argument completely
@@ -479,6 +486,57 @@
 % \my_if_a_in:nTF { a text } { true } { false }
 % \my_if_a_in:nTF {   text } { true } { false }
 % \end{verbatim}
+%
+%
+% \subsubsection{Modifiers}
+%
+% \begin{function}{\etl_new_replace_once:Nn}
+%   \begin{syntax}
+%     \cs{etl_new_replace_once:Nn} \meta{function} \Arg{search text}
+%   \end{syntax}
+%   This defines a new \meta{function} that'll accept two arguments (the first
+%   being a token list, the second a replacement). The generated \meta{function}
+%   will replace the first occurrence of \meta{search text} inside the token
+%   list with replacement. It'll ignore things hidden inside a group in the
+%   token list.  Neither the \meta{search text} nor the token list given to the
+%   generated \meta{function} can contain \cs{s__etl_stop} (this would result in
+%   undefined behaviour), the given replacement on the other hand might contain
+%   that token. Additionally \meta{search text} can't contain tokens of category
+%   group begin or group end (usually |{| and |}|) or macro parameters (usually
+%   |#|).
+%
+%   \begin{texnote}
+%     The result of \meta{function} is returned within \cs{exp_not:n}, which
+%     means that the token list does not expand further when appearing in an
+%     \hbox{|x|- or} |e|-type argument expansion. The result will be returned
+%     after exactly two steps of expansion.
+%   \end{texnote}
+% \end{function}
+% So the following would yield |AcDC|:
+% \begin{verbatim}
+% \etl_new_replace_once:Nn \my_replace_C_once:nn { C }
+% \my_replace_C_once:nn { ACDC } { c }
+% \end{verbatim}
+%
+% \begin{function}{\etl_new_replace_all:Nn}
+%   \begin{syntax}
+%     \cs{etl_new_replace_all:Nn} \meta{function} \Arg{search text}
+%   \end{syntax}
+%   This behaves like \cs{etl_new_replace_once:Nn}, but the \meta{function} will
+%   replace all occurrences of \meta{search text} instead of just the first.
+%
+%   \begin{texnote}
+%     The result of \meta{function} is returned within \cs{exp_not:n}, which
+%     means that the token list does not expand further when appearing in an
+%     \hbox{|x|- or} |e|-type argument expansion. The result will be returned
+%     after exactly two steps of expansion.
+%   \end{texnote}
+% \end{function}
+% So the following would yield |AcDc|:
+% \begin{verbatim}
+% \etl_new_replace_all:Nn \my_replace_C_all:nn { C }
+% \my_replace_C_all:nn { ACDC } { c }
+% \end{verbatim}
 % 
 %
 % \subsection{Bugs and Feature Requests}
@@ -506,7 +564,7 @@
 % Tell who we are:
 %    \begin{macrocode}
 \ProvidesExplPackage{etl}
-  {2021-08-20} {0.1}
+  {2021-08-28} {0.2}
   {expandable token list manipulation}
 %    \end{macrocode}
 %
@@ -515,7 +573,7 @@
 \cs_if_exist:NF \tex_expanded:D
   {
     \msg_new:nnn { etl } { expanded-missing }
-      { The expanded primitive is required. }
+      { The~ expanded~ primitive~ is~ required. }
     \msg_fatal:nn { etl } { expanded-missing }
   }
 %    \end{macrocode}
@@ -666,12 +724,10 @@
 \cs_new:Npn \etl_act:nnnnnnn #1#2#3#4#5#6#7
   {
     \@@_unexpanded:w \@@_expanded:w
-      {
-        {
-          \@@_act:w #7 {\s_@@_stop} . \s_@@_stop {#5} {#1} {#2} {#3}
-          \@@_act_result:n {#6} {#4}
-        }
-      }
+      {{
+        \@@_act:w #7 {\s_@@_stop} . \s_@@_stop {#5} {#1} {#2} {#3}
+        \@@_act_result:n {#6} {#4}
+      }}
   }
 %    \end{macrocode}
 %   We also provide a version without the \cs{@@_unexpanded:w} around it for
@@ -1298,6 +1354,9 @@
 % \end{macro}
 % \end{macro}
 %
+%
+% \subsection{Expandably modify token lists}
+%
 % \begin{macro}[EXP]{\etl_token_replace_all:nNn}
 % \begin{macro}[EXP]{\@@_token_replace:NnnN}
 %   Replaceing a single token (and in fact the same is true for all the
@@ -1647,23 +1706,46 @@
 %    \end{macrocode}
 % \end{macro}
 %
+%
+% \subsection{Defining new tests}
+%
 % \begin{macro}{\etl_new_if_in:Nnn}
-% \begin{macro}{\@@_new_if_in:NNnn}
+% \begin{macro}{\@@_new_if_in:NnNnn, \@@_new_if_in:NNnn}
 %   These tests work essentially in the same way as \cs{tl_if_in:nnTF}, but
 %   instead they use a predefined internal macro so that no definition at use
-%   time is necessary.
+%   time is necessary. We use a small loop to get a unique auxiliary macro name
+%   for the search text.
 %    \begin{macrocode}
-\exp_args:Nno \use:n { \cs_new_protected:Npn \etl_new_if_in:Nnn #1#2 }
+\exp_args:Nno \use:n { \cs_new_protected:Npn \etl_new_if_in:Nnn #1#2#3 }
   {
-    \exp_args:Nc \@@_new_if_in:NNnn
-      { @@_user_function ~ \cs_to_str:N #1 ~ \tl_to_str:n {#2} :w }
+    \scan_stop:
+    \if_false: { \fi:
+    \exp_args:Nc \@@_new_if_in:NnNnn
+      { @@_user_function ~ if_in ~ \tl_to_str:n {#2} :w }
+      ?
       #1 {#2}
+      {#3}
+    \if_false: } \fi:
   }
+\cs_new_protected:Npn \@@_new_if_in:NnNnn #1#2#3#4
+  {
+    \cs_if_exist:NTF #1
+      {
+        \cs_set:Npn \@@_tmp:w ##1 #4 {}
+        \cs_if_eq:NNTF #1 \@@_tmp:w
+          { \@@_new_if_in:NNnn #1 #3 {#4} }
+          {
+            \exp_args:Nc \@@_new_if_in:NnNnn
+              { @@_user_function ~ if_in #2 ~ \tl_to_str:n {#4} :w }
+              { #2? }
+              #3 {#4}
+          }
+      }
+      { \@@_new_if_in:NNnn #1 #3 {#4} }
+  }
 \cs_new_protected:Npn \@@_new_if_in:NNnn #1#2#3#4
   {
-    \scan_stop:
-    \if_false: { \fi:
-    \cs_new:Npn #1 ##1 #3 {}
+    \cs_gset:Npn #1 ##1 #3 {}
     \prg_new_conditional:Npnn #2 ##1 {#4}
       {
         \if:w
@@ -1678,13 +1760,156 @@
           \prg_return_false:
         \fi:
       }
-    \if_false: } \fi:
   }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 %
+%
+% \subsection{Defining new modifiers}
+%
+% The implementation of |replace_once| and |replace_all| is modelled closely on
+% the implementation used in \pkg{l3tl}. The difference is that we use a hard
+% coded delimiter (\cs{s_@@_stop}) instead of searching for one that is always
+% legal (we can't do redefinitions, so can't change the delimiter later based on
+% the token list input).
+%
+%
+% \begin{macro}
+%   {
+%     \@@_new_replace_def:NNn,
+%     \@@_new_replace_def_aux:NnNnN, \@@_new_replace_def_aux:Nn
+%   }
+%   We need another loop to guarantee unique names, if everything's alright we
+%   go on and define the user function using |#1| of
+%   \cs{@@_new_replace_def:NNn}. An empty search pattern is forbidden and should
+%   throw an error.
 %    \begin{macrocode}
+\msg_new:nnn { etl } { empty-search-text }
+  { The~ search~ text~ of~ #1 must~ not~ be~ empty. }
+\cs_new_protected:Npn \@@_new_replace_def:NNn #1#2#3
+  {
+    \tl_if_empty:nTF {#3}
+      { \msg_error:nnn { etl } { empty-search-text } { #2 } }
+      {
+        \scan_stop:
+        \if_false: { \fi:
+        \exp_args:Nc \@@_new_replace_def_aux:NnNnN
+          { @@_user_function ~ replace ~ \tl_to_str:n {#3} ~ :Nnw }
+          ?
+          #2 {#3}
+          #1
+        \if_false: } \fi:
+      }
+  }
+\cs_new_protected:Npn \@@_new_replace_def_aux:NnNnN #1#2#3#4#5
+  {
+    \cs_if_exist:NTF #1
+      {
+        \@@_new_replace_def_aux:Nn \@@_tmp:w {#4}
+        \cs_if_eq:NNTF #1 \@@_tmp:w
+          { #5 #1#3 {#4} }
+          {
+            \exp_args:Nc \@@_new_replace_def_aux:NnNnN
+              { @@_user_function ~ replace #2 ~ \tl_to_str:n {#4} ~ :Nnw }
+              { #2? } #3 {#4} #5
+          }
+      }
+      {
+        \@@_new_replace_def_aux:Nn #1 {#4}
+        #5 #1#3 {#4}
+      }
+  }
+%    \end{macrocode}
+%   The auxiliary macro uses a loop for the replacement. This is also used for
+%   the |once| variant. This saves internal functions if both an |all| and a
+%   |once| function are generated for the same search text (though the |once|
+%   variant could be coded easier and faster otherwise, but the performance hit
+%   should be small).
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_new_replace_def_aux:Nn #1#2
+  {
+    \cs_gset:Npn #1 ##1##2 ##3#2
+      {
+        \@@_new_replace_wrap:w ##3 \s_@@_stop \@@_unexpanded:w {##2}
+        ##1 #1 {##2} {}{}
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_new_replace_wrap:w}
+% \begin{macro}{\@@_new_replace_once:w}
+% \begin{macro}{\@@_new_replace_done:w}
+%   We need a few auxiliaries for the two replacement variants here. The first
+%   just grabs the already processed part of the token list and protects it from
+%   further expanding. The second breaks the loop for the |once| variant by
+%   protecting the remainder of the token list from further expanding. The last
+%   just gobbles the remainder of the loop by using an unbalanced brace trick.
+%    \begin{macrocode}
+\cs_new:Npn \@@_new_replace_wrap:w #1\s_@@_stop
+  { \@@_unexpanded:w \exp_after:wN { \use_none:nn #1 } }
+\cs_new:Npn \@@_new_replace_once:w #1#2 #3\s_@@_stop
+  { \@@_unexpanded:w \exp_after:wN { \use_none:nn #3 } }
+\cs_new:Npn \@@_new_replace_done:w
+  { \exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\etl_new_replace_once:Nn}
+% \begin{macro}{\@@_new_replace_once:NNn}
+%   The |once| variant will use \cs{@@_new_replace_done_once:w} if the
+%   replacement is successful (that will remove the remainder of the loop, and
+%   protect both the replacement and the rest of the token list on which we work
+%   from further expanding).
+%    \begin{macrocode}
+\cs_new_protected:Npn \etl_new_replace_once:Nn
+  { \@@_new_replace_def:NNn \@@_new_replace_once:NNn }
+\cs_new_protected:Npn \@@_new_replace_once:NNn #1#2#3
+  {
+    \cs_new:Npn #2 ##1##2
+      {
+        \@@_unexpanded:w \@@_expanded:w
+          {{
+            \if_false: { \fi:
+              #1 \@@_new_replace_once:w {##2} {}{} ##1 \s_@@_stop
+              \@@_new_replace_done:w #3
+            }
+          }}
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\etl_new_replace_all:Nn}
+% \begin{macro}{\@@_new_replace_all:NNn}
+%   The |all| variant will directly protect the replacement from further
+%   expanding and reiterate (due to the way the auxiliary is defined) until the
+%   replacement isn't found anymore.
+%    \begin{macrocode}
+\cs_new_protected:Npn \etl_new_replace_all:Nn
+  { \@@_new_replace_def:NNn \@@_new_replace_all:NNn }
+\cs_new_protected:Npn \@@_new_replace_all:NNn #1#2#3
+  {
+    \cs_new:Npn #2 ##1##2
+      {
+        \@@_unexpanded:w \@@_expanded:w
+          {{
+            \if_false: { \fi:
+              #1 #1 {##2} {}{} ##1 \s_@@_stop
+              \@@_new_replace_done:w #3
+            }
+          }}
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%    \begin{macrocode}
 %</pkg>
 %    \end{macrocode}
 %

Modified: trunk/Master/texmf-dist/tex/latex/etl/etl.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/etl/etl.sty	2021-08-29 20:24:58 UTC (rev 60363)
+++ trunk/Master/texmf-dist/tex/latex/etl/etl.sty	2021-08-29 20:25:20 UTC (rev 60364)
@@ -30,12 +30,12 @@
 %%                                 etl.sty
 %% 
 \ProvidesExplPackage{etl}
-  {2021-08-20} {0.1}
+  {2021-08-28} {0.2}
   {expandable token list manipulation}
 \cs_if_exist:NF \tex_expanded:D
   {
     \msg_new:nnn { etl } { expanded-missing }
-      { The expanded primitive is required. }
+      { The~ expanded~ primitive~ is~ required. }
     \msg_fatal:nn { etl } { expanded-missing }
   }
 \cs_new_eq:NN \__etl_expanded:w \tex_expanded:D
@@ -93,12 +93,10 @@
 \cs_new:Npn \etl_act:nnnnnnn #1#2#3#4#5#6#7
   {
     \__etl_unexpanded:w \__etl_expanded:w
-      {
-        {
-          \__etl_act:w #7 {\s__etl_stop} . \s__etl_stop {#5} {#1} {#2} {#3}
-          \__etl_act_result:n {#6} {#4}
-        }
-      }
+      {{
+        \__etl_act:w #7 {\s__etl_stop} . \s__etl_stop {#5} {#1} {#2} {#3}
+        \__etl_act_result:n {#6} {#4}
+      }}
   }
 \cs_new:Npn \__etl_act:nnnnnnn #1#2#3#4#5#6#7
   {
@@ -684,17 +682,36 @@
       { {#2} {#2} {} {#3} \s__etl_mark }
       {#1}
   }
-\exp_args:Nno \use:n { \cs_new_protected:Npn \etl_new_if_in:Nnn #1#2 }
+\exp_args:Nno \use:n { \cs_new_protected:Npn \etl_new_if_in:Nnn #1#2#3 }
   {
-    \exp_args:Nc \__etl_new_if_in:NNnn
-      { __etl_user_function ~ \cs_to_str:N #1 ~ \tl_to_str:n {#2} :w }
+    \scan_stop:
+    \if_false: { \fi:
+    \exp_args:Nc \__etl_new_if_in:NnNnn
+      { __etl_user_function ~ if_in ~ \tl_to_str:n {#2} :w }
+      ?
       #1 {#2}
+      {#3}
+    \if_false: } \fi:
   }
+\cs_new_protected:Npn \__etl_new_if_in:NnNnn #1#2#3#4
+  {
+    \cs_if_exist:NTF #1
+      {
+        \cs_set:Npn \__etl_tmp:w ##1 #4 {}
+        \cs_if_eq:NNTF #1 \__etl_tmp:w
+          { \__etl_new_if_in:NNnn #1 #3 {#4} }
+          {
+            \exp_args:Nc \__etl_new_if_in:NnNnn
+              { __etl_user_function ~ if_in #2 ~ \tl_to_str:n {#4} :w }
+              { #2? }
+              #3 {#4}
+          }
+      }
+      { \__etl_new_if_in:NNnn #1 #3 {#4} }
+  }
 \cs_new_protected:Npn \__etl_new_if_in:NNnn #1#2#3#4
   {
-    \scan_stop:
-    \if_false: { \fi:
-    \cs_new:Npn #1 ##1 #3 {}
+    \cs_gset:Npn #1 ##1 #3 {}
     \prg_new_conditional:Npnn #2 ##1 {#4}
       {
         \if:w
@@ -709,8 +726,86 @@
           \prg_return_false:
         \fi:
       }
-    \if_false: } \fi:
   }
+\msg_new:nnn { etl } { empty-search-text }
+  { The~ search~ text~ of~ #1 must~ not~ be~ empty. }
+\cs_new_protected:Npn \__etl_new_replace_def:NNn #1#2#3
+  {
+    \tl_if_empty:nTF {#3}
+      { \msg_error:nnn { etl } { empty-search-text } { #2 } }
+      {
+        \scan_stop:
+        \if_false: { \fi:
+        \exp_args:Nc \__etl_new_replace_def_aux:NnNnN
+          { __etl_user_function ~ replace ~ \tl_to_str:n {#3} ~ :Nnw }
+          ?
+          #2 {#3}
+          #1
+        \if_false: } \fi:
+      }
+  }
+\cs_new_protected:Npn \__etl_new_replace_def_aux:NnNnN #1#2#3#4#5
+  {
+    \cs_if_exist:NTF #1
+      {
+        \__etl_new_replace_def_aux:Nn \__etl_tmp:w {#4}
+        \cs_if_eq:NNTF #1 \__etl_tmp:w
+          { #5 #1#3 {#4} }
+          {
+            \exp_args:Nc \__etl_new_replace_def_aux:NnNnN
+              { __etl_user_function ~ replace #2 ~ \tl_to_str:n {#4} ~ :Nnw }
+              { #2? } #3 {#4} #5
+          }
+      }
+      {
+        \__etl_new_replace_def_aux:Nn #1 {#4}
+        #5 #1#3 {#4}
+      }
+  }
+\cs_new_protected:Npn \__etl_new_replace_def_aux:Nn #1#2
+  {
+    \cs_gset:Npn #1 ##1##2 ##3#2
+      {
+        \__etl_new_replace_wrap:w ##3 \s__etl_stop \__etl_unexpanded:w {##2}
+        ##1 #1 {##2} {}{}
+      }
+  }
+\cs_new:Npn \__etl_new_replace_wrap:w #1\s__etl_stop
+  { \__etl_unexpanded:w \exp_after:wN { \use_none:nn #1 } }
+\cs_new:Npn \__etl_new_replace_once:w #1#2 #3\s__etl_stop
+  { \__etl_unexpanded:w \exp_after:wN { \use_none:nn #3 } }
+\cs_new:Npn \__etl_new_replace_done:w
+  { \exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: }
+\cs_new_protected:Npn \etl_new_replace_once:Nn
+  { \__etl_new_replace_def:NNn \__etl_new_replace_once:NNn }
+\cs_new_protected:Npn \__etl_new_replace_once:NNn #1#2#3
+  {
+    \cs_new:Npn #2 ##1##2
+      {
+        \__etl_unexpanded:w \__etl_expanded:w
+          {{
+            \if_false: { \fi:
+              #1 \__etl_new_replace_once:w {##2} {}{} ##1 \s__etl_stop
+              \__etl_new_replace_done:w #3
+            }
+          }}
+      }
+  }
+\cs_new_protected:Npn \etl_new_replace_all:Nn
+  { \__etl_new_replace_def:NNn \__etl_new_replace_all:NNn }
+\cs_new_protected:Npn \__etl_new_replace_all:NNn #1#2#3
+  {
+    \cs_new:Npn #2 ##1##2
+      {
+        \__etl_unexpanded:w \__etl_expanded:w
+          {{
+            \if_false: { \fi:
+              #1 #1 {##2} {}{} ##1 \s__etl_stop
+              \__etl_new_replace_done:w #3
+            }
+          }}
+      }
+  }
 %% 
 %%
 %% End of file `etl.sty'.



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