summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2009-09-24 00:09:27 +0000
committerKarl Berry <karl@freefriends.org>2009-09-24 00:09:27 +0000
commit3f39a4fbdf08fa724e5047b82e3437ddf9b83bf4 (patch)
treeee6cb8c37626cf0b68201a5cb9da34a62fa2b326
parentaf45cd2890473eac240e9e1aa27996cdbcf16192 (diff)
etextools update (23sep09)
git-svn-id: svn://tug.org/texlive/trunk@15437 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/latex/etextools/README26
-rw-r--r--Master/texmf-dist/doc/latex/etextools/etextools-examples.pdfbin80209 -> 0 bytes
-rw-r--r--Master/texmf-dist/doc/latex/etextools/etextools-examples.tex131
-rw-r--r--Master/texmf-dist/doc/latex/etextools/etextools.pdfbin635108 -> 1041283 bytes
-rw-r--r--Master/texmf-dist/source/latex/etextools/etextools.drv62
-rw-r--r--Master/texmf-dist/source/latex/etextools/etextools.dtx4956
-rw-r--r--Master/texmf-dist/source/latex/etextools/etextools.ins9
-rw-r--r--Master/texmf-dist/tex/latex/etextools/etextools.sty1260
8 files changed, 5067 insertions, 1377 deletions
diff --git a/Master/texmf-dist/doc/latex/etextools/README b/Master/texmf-dist/doc/latex/etextools/README
index e8d69bc75ea..4e4ce44b417 100644
--- a/Master/texmf-dist/doc/latex/etextools/README
+++ b/Master/texmf-dist/doc/latex/etextools/README
@@ -1,8 +1,7 @@
% This work consists of the main source file etextools.dtx
% and the derived files
% etextools.sty, etextools.pdf, etextools.ins,
-% etextools-examples.tex and etextools-examples.pdf
-%
+% examples will be uploaded later...
% Unpacking:
% (a) If etextools.ins is present:
% etex etextools.ins
@@ -11,7 +10,24 @@
% (c) If you insist on using LaTeX
% latex \let\install=y\input{etextools.dtx}
% (quote the arguments according to the demands of your shell)
+% Documentation: (pdf)latex etextools.dtx; ...
+% ---------------------------------------------------------------------
+% Nota Bene: I worked hard to produce a linked and colored pdf documentation.
+% ---------------------------------------------------------------------
+% etextools focuses on purely expandability. The main contributions are :
+%
+% \expandaftercmds, \expandnext, \ExpandNext: vectorized form of \expandafter
+%
+% \FE@testopt,\FE@ifstar,\FE@ifchar,\FE@modifiers: define purely expandable
+% macros with option and/or star version or other modifiers.
+%
+% \DeclareStringFilter to compare strings in a purely expandable way.
+% count characters, replace in string, take care of blank spaces or not...
+%
+% \ifstrnum: to test if \number (or \romannumeral) will fail or not
+%
+% \futuredef: a macro (and vectorized) version of \futurelet.
%
-% Documentation:
-% (pdf)latex etextools.dtx; ...
-
+% \DeclareCmdListParser: purely expandable loops into lists (csvloop, toksloop
+% etc.) with a general constructor (count elements, get their index etc.)
+% ---------------------------------------------------------------------
diff --git a/Master/texmf-dist/doc/latex/etextools/etextools-examples.pdf b/Master/texmf-dist/doc/latex/etextools/etextools-examples.pdf
deleted file mode 100644
index 3906cf7c21e..00000000000
--- a/Master/texmf-dist/doc/latex/etextools/etextools-examples.pdf
+++ /dev/null
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/etextools/etextools-examples.tex b/Master/texmf-dist/doc/latex/etextools/etextools-examples.tex
index 572e76e479d..6d86965ec67 100644
--- a/Master/texmf-dist/doc/latex/etextools/etextools-examples.tex
+++ b/Master/texmf-dist/doc/latex/etextools/etextools-examples.tex
@@ -21,44 +21,51 @@
%% etextools.sty, etextools.pdf, etextools.ins,
%% and etextools-examples.tex
%%
-%%% etextools : more e-TeX useful tools for LaTeX package writers (v.
-
+%%% etextools : e-TeX tools for LaTeX Users and package Writers (v.3.0)
\documentclass[11pt,french,a4paper,oneside]{scrartcl}
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[american]{babel}
-\usepackage{geometry,doc,ltxdockit,txfonts,fancyhdr,stmaryrd,graphicx,fancyvrb}
+\usepackage{geometry,doc,ltxdockit,txfonts,fancyhdr,stmaryrd,graphicx,enumitem}
\usepackage{etextools}
+
+\usepackage{fancyvrb}
+
+\def\textvb#1{{\usefont{T1}{txtt}{m}{n}#1}}
+\def\thispackage{\textsf{etextools}}
\hypersetup{colorlinks,pdfstartview={FitH}}
\geometry{top=1.5cm,bottom=1.2cm,left=2.5cm,right=1cm}
\fancyhf{}
-\fancyhead[L]{Examples for the \sty{etextools} package}
+\fancyhead[L]{Examples for the \thispackage package}
\pagestyle{fancy}
-\MakeShortVerb{\|}
-
+\DefineShortVerb{\|}
+\catcode`\§ \active\def§{\par\nobreak\vskip-\parskip}
\makeatletter
+\DefineVerbatimEnvironment{VerbLines}{Verbatim}
+ {gobble=1,commandchars=!(),frame=lines,framesep=6pt,fontfamily=txtt,fontseries=m}
+\apptocmd\@list@extra{\parsep\parskip\topsep\z@\itemsep\z@}{}{}
+
\def\smex{\leavevmode\hb@xt@2em{\hfil$\longrightarrow$\hfil}}
\def\FE{\setbox8\hbox{$\m@th\bindnasrepma$}%
\textcolor{fecc}{\scalebox{2}{$\copy8\mkern-13.5mu\copy8\mkern-13.5mu\copy8$}}}
+\def\pdfFE{\setbox8\hbox{$\m@th\bindnasrepma$}%
+ \textcolor{fecc}{\llap{\textsf{pdf}\TeX{}\,}\scalebox{2}{$\copy8\mkern-13.5mu\copy8\mkern-13.5mu\copy8$}}}
\definecolor{fecc}{rgb}{.2,.6,.2}
-\def\strip@meaning{\expandafter\strip@prefix\meaning}
-\def\strip@macro{\expandafter\strip@macroprefix\meaning}
-\def\get@params#1{\expandafter\@get@params\meaning#1\@nil}
-\edef\@get@params{%
- \def\noexpand\@get@params\detokenize{macro:}##1\detokenize{->}##2\noexpand\@nil{##1}%
-}\@get@params
-\def\make@macro#1{\string\def\string#1\get@params#1\string{\strip@meaning#1\string}}
+\definecolor{dg}{rgb}{0.00,0.37,0.00} \newrobustcmd\dg{\color{dg}} \newrobustcmd\dgbf{\dg\bfseries}
+
+\newrobustcmd\blue{\color{blue}
+\newrobustcmd\nnn{\normalfont\mdseries\upshape}
+
+\def\make@macro#1{\string\def\string#1\parameters@meaning#1\string{\strip@meaning#1\string}}
\newcommand\preline{\@ifstar{\@preline}{\hrulefill\par\@preline}}
-\def\@preline#1{\noindent\hskip6pt\texttt{\make@macro#1}\par\vskip1.5ex}
+\newcommand\@preline[2][1.5ex]{\noindent\hskip6pt\textvb{\make@macro#2}\par\ifblank{#1}{}{\vskip#1}}
-\def\meaningcs#1{\expandafter\meaning\csname#1\endcsname}
-\def\Meaningcs#1{\expandafter\strip@meaning\csname #1\endcsname}
-\@ifundefined{pdfstrcmp}{\let\ifpdfTeX\iffalse}{\let\ifpdfTeX\iftrue}
+\ifdef\pdfstrcmp{\let\ifpdfTeX\iffalse}{\let\ifpdfTeX\iftrue}
-\newcommand*\test{\@ifstar{\let\fe\relax\testi}{\let\fe\FE\testi}}
+\newcommand*\test{\@ifstar{\let\fe\pdfFE\testi}{\let\fe\FE\testi}}
\newcommand\testi[1]{%
\csname test#1\endcsname
- \edef\usercmd{\Meaningcs{test#1}}\edef\result{\meaningcs{#1Test}}\noindent
+ \edef\usercmd{\strip@meaningcs{test#1}}\edef\result{\meaningcs{#1Test}}\noindent
\begin{tabular}{lp{15cm}}
\multicolumn{2}{l}{\textcolor{blue}{\llap{\fe\,\smex}\tt \usercmd}} \\[1.5ex]
\cmd{#1Test}= & \tt\bfseries\result
@@ -66,12 +73,12 @@
\begin{document}
\title{etextools examples}
-\subtitle{Examples for some macros provided by the \sty{etextools} package}
+\subtitle{Examples for some macros provided by the \thispackage package}
\author{Florent Chervet}
\date{July 22, 2009}
\maketitle
-\tableofcontents
+\tableofcontents\hyperdef{ettlex}{toc}{}
\section{\cmd{expandnext} examples}
@@ -88,7 +95,7 @@
\preline\xx
\test{expandnext}
-\clearpage
+\ClearPage
\subsection{Test if the replacement text of a macro is blank (empty or spaces)}
\def\xx{something}
@@ -102,12 +109,74 @@
\preline\xx
\test{expandnext}
-\subsection{Detokenize the replacement text of a named-sequence}
-\def\detokenizecs#1{\expandnext\expandnext\detokenize{\csname #1\endcsname}}
-\def\testexpandnext{%
- \edef\expandnextTest{\detokenizecs{document}}}
-\preline\detokenizecs
-\test{expandnext}
+\section{\cmd{ExpandNext} examples}
+
+Example of the main documentation file to reverse the order of the characters in a string:
+
+\def\swap#1#2{{#2#1}} \def\do[#1]#2{\swap #2}% \do{abcdef} -> \swap ab + cdef -> {ba}cdef
+ % \do{{ba}cdef} -> \swap {ba}c + def -> {cba}def
+
+\edef\result{\naturalloop[\do]{4}{12345}}
+\ExpandNext{\def\RESULT}{\naturalloop[\do]{4}{12345}}
+
+\begin{VerbLines}
+\def\swap#1#2{{#2#1}} \def\do[#1]#2{\swap #2}
+\edef\result{\naturalloop[\do]{4}{12345}}
+\meaning\result = !bfseries!meaning!result
+\ExpandNext{\def\RESULT}{\naturalloop[\do]{4}{12345}}
+\meaning\RESULT = !bfseries!meaning!RESULT
+\end{VerbLines}
+
+\subsection{Test the parameter string of a macro}
+
+The following commands create the filter for the string: "\textvb{[\#1]\#2"}":§
+\begin{VerbLines}[commandchars=!()]
+\ExpandNext{(!blue\DeclareStringFilter\ParaFilt)}
+ {\ExpandAftercmds\@gobblescape{\expandafter\string\csname(!blue[#1]#2)\endcsname}}
+\end{VerbLines}
+
+\ExpandNext{\DeclareStringFilter\ParaFilt}
+ {\ExpandAftercmds\@gobblescape{\expandafter\string\csname[#1]#2\endcsname}}
+
+\begin{enumerate}[label=\arabic*)~,noitemsep,nolistsep]
+\item |\csname[#1]#2\endcsname| is expanded first
+\item Immediately after: |\string|
+\item At this stage: |\[#1]#2| (everything in category code other) is no more expandable
+\item Then |\ExpandAftercmds| expands |\@gobblescape|
+\item |[#1]#2| is no more expandable
+\item Then |\ExpandNext| expands its first argument: |\DeclareStringFilter\ParaFilt{[#1]#2}|
+\end{enumerate}
+
+Remark: |\detokenize| would have doubled the \# characters. Another possibility is to temporarily change the
+category code of \# to 12 (other):
+\begin{VerbLines}[commandchars=!()]
+\begingroup\catcode`\#=12
+ (!blue\DeclareStringFilter\ParaFilt{[#1]#2}) !nnn global declaration
+\endgroup
+\end{VerbLines}
+
+\def\macroA#1#2{Something to do with #1 and #2}
+\def\macroB[#1]#2{Something to do with #1 and #2}
+
+\makeatother
+
+\preline[]\macroA
+\preline*[]\macroB
+\begin{Verbatim}[commandchars=!()]
+ !blue\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroA}{macro complies with [\#1]\#2}
+ !blue{macro does not comply }
+\end{Verbatim}
+\makeatletter
+\hfill\textvb{\dgbf\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroA}{macro complies with [\#1]\#2}
+ {macro does not comply }}
+\begin{Verbatim}[commandchars=!()]
+ !blue\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroB}{macro complies with [\#1]\#2}
+ !blue{macro does not comply }
+\end{Verbatim}
+\hfill\textvb{\dgbf\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroB}{macro complies with [\#1]\#2}
+ {macro does not comply }}
+\par\hrulefill\par
+\makeatother
\section{Testing characters}
\subsection{\cmd{ifsinglechar} versus \cmd{iffirstchar}}
@@ -211,13 +280,13 @@
\edef\getlistindexTest{\getlistindex{alpha}\mylist}
}\hrulefill\par
\noindent\hskip6pt|\csvtolist*\mylist{one,two,three,four,five,alpha,beta,gamma}|\par\vskip1.5ex
-\test{getlistindex}
+\test*{getlistindex}
\leavevmode\vadjust{\textsl{Require the }\string\pdfstrcmp\ \textsl{primitive (pdf\TeX{}) :}}
\def\testgetlistindex{%
\edef\getlistindexTest{\getcsvlistindex*{alpha}{one,two,three,four,five,alpha,beta}}
}\hrulefill\par
-\test{getlistindex}
+\test*{getlistindex}
\fi
\hrulefill\par
@@ -243,7 +312,7 @@
}\hrulefill\par
\noindent\hskip6pt|\csvtolist*\mylist{one,two,three,four,five,alpha,beta,gamma}|\par\vskip1.5ex
\preline*\x
-\test{xgetlistindex}
+\test*{xgetlistindex}
\fi
\subsubsection{\cmd{getlistindex} with \cmd{ifcase}}
diff --git a/Master/texmf-dist/doc/latex/etextools/etextools.pdf b/Master/texmf-dist/doc/latex/etextools/etextools.pdf
index 5e82e254a98..407f03693cd 100644
--- a/Master/texmf-dist/doc/latex/etextools/etextools.pdf
+++ b/Master/texmf-dist/doc/latex/etextools/etextools.pdf
Binary files differ
diff --git a/Master/texmf-dist/source/latex/etextools/etextools.drv b/Master/texmf-dist/source/latex/etextools/etextools.drv
new file mode 100644
index 00000000000..96465ed4e6c
--- /dev/null
+++ b/Master/texmf-dist/source/latex/etextools/etextools.drv
@@ -0,0 +1,62 @@
+%%
+%% This is file `etextools.drv',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% etextools.dtx (with options: `driver')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2009 by Florent Chervet <florent.chervet@free.fr>
+%%
+%% This work may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3 of this license or (at your option) any later
+%% version. The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%%
+%% This work consists of the main source file etextools.dtx
+%% and the derived files
+%% etextools.sty, etextools.pdf, etextools.ins,
+%% and etextools-examples.tex
+%%
+%%% etextools : e-TeX tools for LaTeX Users and package Writers (v.3.0)
+\edef\thisfile{\jobname}
+\def\thisinfo{The \thispackage\ package -- an \eTeX{} package for \LaTeX{}}
+\def\thisrevision{3.0}
+\def\thisdate{27 August 2009}
+\newcommand\makebookmark[1]{}
+\documentclass[a4paper,oneside]{ltxdockit}
+\usepackage[latin1]{inputenc}
+\usepackage[american]{babel}
+\usepackage{doc,tocloft,stmaryrd,amsmath,amssymb,xspace,graphics,geometry,fancyhdr,titlesec,framed,bbding,ltxnew,enumitem,embedfile,etoolbox,marvosym,wasysym,soul,makecell,arydshln,numprint}
+\CodelineNumbered\CodelineIndex
+\usepackage{fancyvrb}
+\newrobustcmd*\cmdLabel[1]{\csgdef{cmdlabel->#1}{}}
+\embedfile{\thisfile.dtx}
+\geometry{left=4.5cm,marginparwidth=14pt,right=1.5cm,top=3mm,headsep=3mm,bottom=3mm,footskip=8mm,includeheadfoot}
+\titlepage{%
+ title={The \Thispackage macros},
+ subtitle={An \etex package providing useful (purely expandable) tools \\ for LaTeX Users and package Writers},
+ url={http://www.ctan.org/tex-archive/macros/latex/contrib/etextools/},
+ author={Florent CHERVET},
+ email={\footnotesize\mdseries florent.chervet@free.fr},
+ revision={\thisrevision},
+ date={\thisdate}}
+\hypersetup{%
+ hyperindex=true,
+ pdftitle={The etextools package},
+ pdfsubject={An e-TeX package providing useful tools for LaTeX package writers -- essay on purely expandability},
+ pdfauthor={Florent CHERVET},
+ colorlinks,linkcolor=reflink,urlcolor=spot,
+ pdfkeywords={tex, e-tex, latex, package, programming},
+ bookmarksopen=true,bookmarksopenlevel=2}
+\begin{document}
+ \DocInput{\thisfile.dtx}
+\end{document}
+
+
+\endinput
+%%
+%% End of file `etextools.drv'.
diff --git a/Master/texmf-dist/source/latex/etextools/etextools.dtx b/Master/texmf-dist/source/latex/etextools/etextools.dtx
index 6dded5c5e0a..cf15fe5d34d 100644
--- a/Master/texmf-dist/source/latex/etextools/etextools.dtx
+++ b/Master/texmf-dist/source/latex/etextools/etextools.dtx
@@ -1,5 +1,5 @@
% \iffalse meta-comment
-%%% etextools : more e-TeX useful tools for LaTeX package writers (v.
+%%% etextools : e-TeX tools for LaTeX Users and package Writers (v.3.0)
%
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either
@@ -9,8 +9,9 @@
%
% This work consists of the main source file etextools.dtx
% and the derived files
-% etextools.sty, etextools.pdf, etextools.ins,
-% and etextools-examples.tex
+% etextools.sty, etextools.ins, etextools.drv
+% etextools-examples.tex
+% etextools.pdf and etextools-examples.pdf
%
% Unpacking:
% (a) If etextools.ins is present:
@@ -37,7 +38,7 @@
\input docstrip.tex
\Msg{************************************************************************}
\Msg{* Installation}
-\Msg{* Package: etextools 2009/07/14 v2h e-TeX more useful tools for LaTeX package writers}
+\Msg{* Package: etextools 2009/07/14 v.3.0 e-TeX tools for LaTeX Users and package Writers}
\Msg{************************************************************************}
\keepsilent
@@ -69,6 +70,10 @@ and etextools-examples.tex
\file{etextools.sty}{\from{etextools.dtx}{package}}%
\file{etextools-examples.tex}{\from{etextools.dtx}{example}}%
}
+\askforoverwritetrue
+\generate{%
+ \file{etextools.drv}{\from{etextools.dtx}{driver}}%
+}
\obeyspaces
\Msg{************************************************************************}
@@ -93,27 +98,33 @@ and etextools-examples.tex
%<*driver>
\edef\thisfile{\jobname}
\def\thisinfo{The \thispackage\ package -- an \eTeX{} package for \LaTeX{}}
+\def\thisrevision{3.0}
+\def\thisdate{27 August 2009}
+\newcommand\makebookmark[1]{}
+%-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\documentclass[a4paper,oneside]{ltxdockit}
-\usepackage[latin9]{inputenc}
+\usepackage[latin1]{inputenc}
\usepackage[american]{babel}
-\usepackage{doc,tocloft,stmaryrd,amsmath,graphics,geometry,fancyhdr,framed,bbding,trace,embedfile,etoolbox,marvosym,fancyvrb}
+\usepackage{doc,tocloft,stmaryrd,amsmath,amssymb,xspace,graphics,geometry,fancyhdr,titlesec,framed,bbding,ltxnew,enumitem,embedfile,etoolbox,marvosym,wasysym,soul,makecell,arydshln,numprint}
\CodelineNumbered\CodelineIndex
+\usepackage{fancyvrb}
+\newrobustcmd*\cmdLabel[1]{\csgdef{cmdlabel->#1}{}}
\embedfile{\thisfile.dtx}
-\geometry{left=4.5cm,marginparwidth=14pt,right=2cm,totalheight=26.5cm}
+\geometry{left=4.5cm,marginparwidth=14pt,right=1.5cm,top=3mm,headsep=3mm,bottom=3mm,footskip=8mm,includeheadfoot}
\titlepage{%
- title={The \sty{etextools} package},
- subtitle={An \etex package providing useful tools for LaTeX Users \\ and package Writers},
+ title={The \Thispackage macros},
+ subtitle={An \etex package providing useful (purely expandable) tools \\ for LaTeX Users and package Writers},
url={http://www.ctan.org/tex-archive/macros/latex/contrib/etextools/},
author={Florent CHERVET},
- email={florent.chervet@free.fr},
- revision={2\:$\boldsymbol{\eta}$},
- date={12 août 2009}}
+ email={\footnotesize\mdseries florent.chervet@free.fr},
+ revision={\thisrevision},
+ date={\thisdate}}
\hypersetup{%
hyperindex=true,
pdftitle={The etextools package},
- pdfsubject={An e-TeX package for more useful tools for LaTeX package writers},
+ pdfsubject={An e-TeX package providing useful tools for LaTeX package writers -- essay on purely expandability},
pdfauthor={Florent CHERVET},
- colorlinks,linkcolor=reflink,
+ colorlinks,linkcolor=reflink,urlcolor=spot,
pdfkeywords={tex, e-tex, latex, package, programming},
bookmarksopen=true,bookmarksopenlevel=2}
\begin{document}
@@ -140,10 +151,10 @@ and etextools-examples.tex
% Grave accent \` Left brace \{ Vertical bar \|
% Right brace \} Tilde \~}
%
-% \DoNotIndex{\begin,\CodelineIndex,\CodelineNumbered,\def,\DisableCrossrefs,\if}
-% \DoNotIndex{\DocInput,\documentclass,\EnableCrossrefs,\end,\GetFileInfo}
-% \DoNotIndex{\NeedsTeXFormat,\OnlyDescription,\RecordChanges,\usepackage}
-% \DoNotIndex{\ProvidesClass,\ProvidesPackage,\ProvidesFile,\RequirePackage}
+% \DoNotIndex{\begin,\CodelineIndex,\CodelineNumbered,\def,\DisableCrossrefs,\if,\scalebox,\TeX,\strut,\q,\quad\,\qquad,\Next}
+% \DoNotIndex{\DocInput,\EnableCrossrefs,\end,\GetFileInfo,\PackageWarning,\PackageError\ParaFilt,\parskip,\parsep,\ProcessOptions,\documentclass}
+% \DoNotIndex{\NeedsTeXFormat,\OnlyDescription,\RecordChanges,\usepackage,\protected,\reserved@a,\reserved@b,\reserved@c,\reserved@d}
+% \DoNotIndex{\ProvidesClass,\ProvidesPackage,\ProvidesFile,\RequirePackage,\RESULT}
% \DoNotIndex{\filename,\fileversion,\filedate,\let}
% \DoNotIndex{\@listctr,\@nameuse,\csname,\else,\endcsname,\expandafter}
% \DoNotIndex{\gdef,\global,\if,\item,\newcommand,\nobibliography}
@@ -163,173 +174,600 @@ and etextools-examples.tex
% \DoNotIndex{\un,\deux,\xx,\tt,\title,\times,\texttt,\tableofcontents,\&,\@preline,\@redef,\\,\`,\|,\ ,\author}
% \DoNotIndex{\bfseries,\clearpage,\cmd,\csvloopTest,\defineparser,\endinput,\expandnextTest}
% \DoNotIndex{\fancyhf,\fancyhead,\FE@testoptTest,\FE@ifstarTest,\get@params,\goodbreak,\hypersetup,\iffirstcharTest,\ifsinglecharTest}
-% \DoNotIndex{\llap,\rlap,\longrightarrow,\make@macro,\makequotes,\MakeShortVerb,\mdseries,\multicolumn,\mylist}
-% \DoNotIndex{\nobreak,\noindent,\null,\OPTmacro,\notstarred,\pagestyle,\preline,\quad,\result,\smex,\starmacro,\starred,\strip@macro}
-% \DoNotIndex{\strip@macroprefix,\strip@meaning,\strip@prefix,\sty,\subsubsection,\subtitle,\test}
+% \DoNotIndex{\llap,\rlap,\longrightarrow,\make@macro,\makequotes,\MakeShortVerb,\mdseries,\multicolumn,\mylist,\textsl,\textsc,\uparrow,\myindex,\mkern}
+% \DoNotIndex{\nobreak,\noindent,\null,\OPTmacro,\notstarred,\pagestyle,\preline,\quad,\result,\smex,\starmacro,\starred,\strip@macro,\@nil,\@ne}
+% \DoNotIndex{\strip@macroprefix,\strip@prefix,\sty,\subsubsection,\subtitle,\test}
% \DoNotIndex{\testcsvloop,\testexpandnext,\testFE@testopt,\testFE@ifstar,\testgetlistitem,\testiffirstchar,\testifsinglechar,\getlistitemTest}
+% \DoNotIndex{\testgetlistindex,\testxgetlistindex}
% \DoNotIndex{\textbf,\textcolor,\vskip,\long,\hrulefill,\&,\@get@params,\geometry,\edef,\BySeven,\optmacro,\@xifblank,\ettl@onlyonce,\ettl@undefined,\usercmd,\noexpand}
-% \DoNotIndex{\@listedel,\@listgdel,\@listxdel}
+% \DoNotIndex{\@listedel,\@listgdel,\@listxdel,\bindnasrepma,\color,\copy,\count,\definecolor,\finale,\testi,\small,\newcount}
+% \DoNotIndex{\lastcmditem,\laststarredcmditem,\textsf,\textvb,\textvbbf,\or,\thispackage,\TMP@EnsureCode,\topsep,\usefont,\upshape}
+% \DoNotIndex{\vadjust,\nnn,\newrobustcmd,\macroA,\macroB,\m@th,\itemsep,\ifpdfTeX,\iftrue,\FE,\fe,\FE@ifcharequal,\hyperdef,\iffalse}
+% \DoNotIndex{\cslet,\csedef,\csgdef,\blue,\baselineskip,\active,\afterassignment,\apptocmd,\dg,\dgbf,\DefineShortVerb,\DefineVerbatimEnvironment}
+% \DoNotIndex{\#,\&,\,\@list@extra,\[,\],\ ,\AtEndOfPackage,\arabic,\ClearPage,\csdef,\csundef,\ifnumcomp,\ifundef,\ifcsdef,\ifcsmacro}
+% \DoNotIndex{\ifcsundef,\ifdef,\ifcsparam,\pdfFE,\textvb,\unless,\unexpanded,\undef,\letcs}
+% \hypersetup{hyperindex=true}
%
% \makeatletter
-% \def\thispackage{\sty{\thisfile}}
+% \AtEndDocument{\immediate\write\@outlinefile{\let\noexpand\makebookmark\noexpand\@firstofone}}^^A \immediate because there is no more \shipout...
+% \immediate\write\@outlinefile{\noexpand\makeatletter}
+% \newrobustcmd\AddBookMark[1]{\write\@outlinefile{\noexpand\makebookmark{\noexpand\pdfoutline#1}}}
+% ^^A\let\ClearPage\clearpage^^A problem with Verbatim and page break-to be fixed for final print
+% \newrobustcmd\ClearPage{\@ifstar{\clearpage}{}}
+% \newrobustcmd\thispackage{\xpackage{\spot\thisfile}\xspace}
+% \newrobustcmd\Thispackage{\Xpackage[\thisfile]{\spot\thisfile}\xspace}
+% \newrobustcmd\xpackage[1]{{\usefont{T1}{lmss}{bx}{n}\db\mbox{#1}}}
+% \newcommand\Xpackage{\@dblarg\X@package}
+% \protected\def\X@package[#1]#2{\xpackage {#2\footnotemark}\footnotetext {\noindent \xpackage{#2}: \CTAN{macros/latex/contrib/#1}}}
+% \newrobustcmd*\CTAN[1]{\href{http://www.ctan.org/tex-archive/#1}{\nolinkurl{CTAN:#1}}}
% \font\ding=dingbat scaled 800
-% \hypersetup{hyperindex=true}
-% \fancyhf{}\fancyhead[L]{The \sty{etextools} package -- an \eTeX\, package for \LaTeX}
-% \fancyfoot[L]{\color[gray]{.35}\scriptsize\thispackage\quad\copyright\,\lower.3ex\hbox{\NibRight}\,Florent Chervet}
-% \fancyfoot[R]{\oldstylenums{\thepage} / \oldstylenums{\pageref{LastPage}}}
-% \pagestyle{fancy}
-% \fancypagestyle{plain}{%
-% \fancyhf{}\let\headrulewidth\z@
-% \fancyfoot[R]{\oldstylenums{\thepage} / \oldstylenums{\pageref{LastPage}}}}
-% \def\CTAN#1{\href{http://www.ctan.org/tex-archive/#1}{\nolinkurl{CTAN:#1}}}
-% \definecolor{spot}{rgb}{.7,0.1,0.2}
-% \newcommand\fecccolor{\color{fecc}}\definecolor{fecc}{rgb}{.2,.6,.2}
-% \newcommand\macrocodecolor{\color{macrocode}}\definecolor{macrocode}{rgb}{0.18,0.00,0.45}
-% \newcommand\reflinkcolor{\color{reflink}}\definecolor{reflink}{rgb}{.3,0,0}
-% \newcommand\rmklinkcolor{\color{rmklink}}\definecolor{rmklink}{rgb}{.2,.2,.2}
-% \newcommand\rmkcolor{\color{rmk}\let\reflinkcolor\rmklinkcolor}\definecolor{rmk}{gray}{.35}
-% \newcommand\rmk{\par\nobreak\footnotesize\rmkcolor}
-% \definecolor{shadecolor}{rgb}{0.93,0.94,0.81}
-% \renewcommand\ltxsyntaxlabelfont{\spotcolor \displayverbfont\bfseries}
-% \newcommand\eol{\textcolor[gray]{.5}{$\hookleftarrow$}}
+% \new\font\manual=manfnt
+% \robustify\footnotesize \robustify\mdseries
+% \catcode`\§\active\def§{\par\nobreak\vspace*{-\parskip}\nobreak}
+% \catcode`\¤\active\let¤\quad
+% \newcommand\smex{\leavevmode\hb@xt@2em{\hfil\spot$\longrightarrow$\hfil}}
+% \newcommand*\manfntsymb[1]{\manual\symbol{#1}}
+% \newcommand\dbend{\marginpar{\rmkcolor\manfntsymb{127}}\xspace} \newcommand\manerrarrow{\manfntsymb{121}}
+% \newcommand*\tinybullet[1][3pt]{\kern.4em\raise2pt\hbox{\fontsize{#1}\z@\selectfont\textbullet}\kern.4em}
+% \renewcommand\#[1]{{\usefont{T1}{pcr}{bx}{n}\char`\##1}}
+% \renewcommand\%{{\vb\char`\%}}
+% \DeclareInputText{128}{\texteuro}
+% \let\eTeX@mathsubscript=_
+% \catcode`\_ 13 \def _{\@ifnextchar _\DoubleSubScript\eTeX@mathsubscript}
+% \long\def\DoubleSubScript_#1{\eTeX@mathsubscript{\eTeX@mathsubscript{#1}}}
+% \newcommand\negquad{\hskip-1em\relax} \newcommand\negqquad{\hskip-2em\relax}
+% \renewcommand\ttdefault{txtt}
+% \renewcommand\rmdefault{ua1}
+% \renewcommand\sfdefault{txss}
+% \newrobustcmd\verbfont{\usefont{T1}{\ttdefault}{\f@series}{n}} \let\vb\verbfont
+% \newrobustcmd\verbfontbf{\usefont{T1}{\ttdefault}{b}{n}} \let\vbbf\verbfontbf
+% \newrobustcmd\verbfontmd{\usefont{T1}{\ttdefault}{m}{n}} \let\vbmd\verbfontmd
+% \newrobustcmd\textvb[2][]{\mbox{\vb#1#2}} \newrobustcmd\textvbbf[2][]{\mbox{\vbbf#1#2}} \let\textbfvb\textvbbf
+% \renewcommand\tt{\usefont{T1}{pcr}{\f@series}{n}\upshape} \newcommand\ttbf{\usefont{T1}{pcr}{b}{n}}
+% \newrobustcmd\CS[2][]{\mbox{\tt#1\expandafter\@gobble\string\\#2}}
+% \newrobustcmd\CSbf[2][]{\mbox{\ttbf#1\expandafter\@gobble\string\\#2}}
+% \renewrobustcmd\cs[2][]{\mbox{\vb#1\expandafter\@gobble\string\\#2}}
+% \newrobustcmd\csbf[2][]{\mbox{\vbbf#1\expandafter\@gobble\string\\#2}}
+% \renewrobustcmd\itshape{\not@math@alphabet\itshape\mathit\normalfont\fontshape\itdefault\selectfont}
+% \newrobustcmd\nnn{\normalfont\upshape\mdseries}
+% \newrobustcmd\nitbf{\normalfont\itshape\bfseries}
+% \newrobustcmd\nslbf{\normalfont\slshape\bfseries}
+% \newrobustcmd\nit{\normalfont\itshape}\newrobustcmd\nsl{\normalfont\slshape}
+% \newrobustcmd\nbf{\normalfont\bfseries}\newrobustcmd\nup{\normalfont\upshape}
+% \newrobustcmd\itbf{\itshape\bfseries}
+% \newrobustcmd\sfbf{\sffamily\bfseries}
+% \newrobustcmd\textsfbf[1]{{\sffamily\bfseries #1}} \let\textbfsf\textsfbf \let\textbf\textsfbf
+% \newrobustcmd\textttbf[1]{{\ttfamily\bfseries #1}} \let\textbftt\textttbf
+% \newrobustcmd\textitbf[1]{{\itshape\bfseries #1}} \let\textbfit\textitbf
+% \newrobustcmd\textslbf[1]{{\slshape\bfseries #1}} \let\textbfsl\textslbf
+% \newrobustcmd\textsfsl[1]{{\slshape\sffamily #1}} \let\textslsf\textsfsl \let\emph\textsfsl
+% \newrobustcmd\textbfbf[1]{{\rmfamily\bfseries #1}}
+% \newrobustcmd\txtbf[2][]{\textbf{#1#2}}
+% \newrobustcmd\hlbf[1]{\bfseries\hl{#1}}
+% \newrobustcmd\scs[1]{\expandafter\@gobble\string\\#1}
+% \newrobustcmd\md{\mdseries}\newrobustcmd*\mdsm{\mdseries\small}\newrobustcmd*\mdfs{\mdseries\footnotesize}
+% \newrobustcmd\prmb[1]{\prm{\bfseries #1}} \newrobustcmd\PRM[2][]{\prm{#1#2}}
+% \newrobustcmd\CH[2][]{`\,\textvb[#1]{#2}\,`\xspace}
+% \newrobustcmd\chcat[3][\blue]{\textvb[#1]{#2}$__{\mathbf{#3}}$}
+% \newrobustcmd\stform[2][\red]{{\ttbf#1\if*#2\textasteriskcentered\else#2\fi}}%
+% \newrobustcmd\spview[1][\blue]{{\ttbf#1\textvisiblespace}}
+% \newrobustcmd\tsptb{\medspace\textbackslash}
+% \renewrobustcmd\{{\ifmmode\lbrace\else{\usefont{T1}{cmr}{\f@series}{n}\textbraceleft}\fi}
+% \renewrobustcmd\}{\ifmmode\rbrace\else{\usefont{T1}{cmr}{\f@series}{n}\textbraceright}\fi}
+% ^^A\newrobustcmd\mymprm[1]{\mbox{\{\prm{ \ignorespaces#1\ignorespaces\ }\}}}
+% \renewrobustcmd\ltxsyntaxlabelfont{\spot\usefont{T1}{pcr}{b}{n}}
+% \newrobustcmd\mycolorbox[1][{[rgb]{1.00,1.00,0.79}}]{\@testopt{\my@colorbox[{#1}]}{\red}}
+% \protected\long\def\my@colorbox[#1][#2]#3{\colorbox#1{#2#3}}
+% ^^A\newrobustcmd\mycolorbox[1]{\colorbox[rgb]{1.00,1.00,0.79}{\red #1}}
+% \def\Underbrace#1_#2{$\underbrace{\vtop to2ex{}\hbox{#1}}_{\footnotesize\hbox{#2}}$}
+% \newrobustcmd*\mydotleader[2][\z@]{\leavevmode\xleaders\hbox to\dimexpr1.7pt+#1{\hss\raise#2\hbox{$\scriptscriptstyle\cdotp$}\hss}}
+% \globcount\ettl@AfterGroup
+% \newrobustcmd\AfterGroup[1]{\global\advance\ettl@AfterGroup1\relax
+% \csxdef{ettl@aftergroup@hook\the\ettl@AfterGroup}{\expandonce{#1}}%
+% \expandafter\aftergroup\csname ettl@aftergroup@hook\the\ettl@AfterGroup\endcsname}
+% \long\def\avoidcsvoid[#1]#2{\expandafter\ifcsvoid\expandafter{\romannumeral-`\q#2}{#1}{#2}} \let\avoidvoidcs\avoidcsvoid
+% \long\def\avoidvoid[#1]#2{\ifdefvoid{#2}{#1}{#2}}
+% \newrobustcmd*\movepage[2][]{\advance\hsize by#2\hoffset\ifblank{#1}{-#2}{#1}\linewidth\the\hsize\textwidth\the\hsize}
+% \newrobustcmd\pagenumberdisplay{\leavevmode\lower5pt\hbox{\ttfamily\oldstylenums{\thepage} / \oldstylenums{\pageref{LastPage}}}}
+% \fancypagestyle{corpus}{\fancyhf{}\let\headrulewidth\z@ \footskip=\z@
+% \fancyhead[L]{\deflength\@tempdima{\the\hsize+\the\thesecwidth}\rmkcolor
+% \hskip-\thesecwidth\rlap{\lower6pt\hbox to\@tempdima{\mydotleader\z@\hfill}}\hfill
+% \small The \textcolor{black}{\thispackage}\ macros -- an \eTeX{} package for \LaTeX\hfill}
+% \fancyfoot[L]{\color[gray]{.35}\footnotesize\textcolor{black}{\thispackage\unskip\enspace\copyright}\enspace\scriptsize\lower.3ex\hbox{\NibRight}\enspace Florent Chervet}
+% \fancyfoot[R]{\pagenumberdisplay}}
+% \fancypagestyle{toc}{\fancyhf{}\let\headrulewidth\z@ \fancyfoot[R]{\pagenumberdisplay}}
+% \fancypagestyle{empty}{\fancyhf{}\let\headrulewidth\z@}
+% ^^A COLORS :
+% \let\Org@definecolor\definecolor
+% \renewrobustcmd\definecolor[1][]{\ettl@definecolor{#1}}
+% \newrobustcmd\ettl@definecolor[4]{\Org@definecolor{#2}{#3}{#4}%
+% \ifblank{#1}{\ifcsname#2\endcsname\expandafter\expandafter\expandafter\renewrobustcmd
+% \else\expandafter\expandafter\expandafter\newrobustcmd
+% \fi\csname#2\endcsname{\color{#2}}}
+% {\newrobustcmd#1{\color{#2}}}}
+% \definecolor{spot}{rgb}{1.00,0.33,0.00} \definecolor{fecc}{rgb}{.2,.6,.2}
+% \definecolor[\macrocodecolor]{macrocode}{rgb}{0.18,0.00,0.45}
+% \definecolor{ly}{rgb}{0.81,1.00,0.42}
+% \definecolor{dc}{rgb}{0,0.6,0.6}
+% \definecolor{cream}{rgb}{1.00,1.00,0.77} \definecolor{db}{rgb}{0.00,0.00,0.25}
+% \newrobustcmd\black{\color{black}} \newrobustcmd\blue{\color{blue}}
+% \renewcommand*\MacroFont{\usefont{T1}{lmtt}{m}{n}\macrocodecolor}
+% \pretocmd\macrocode{\def§{\IeC{\S}}}{}{} \apptocmd\macro@font{\macrocodecolor\let\AltMacroFont\macro@font}{}{}
+% \definecolor{reflink}{rgb}{1.00,0.00,0.00} \definecolor{reflinkabstract}{rgb}{0.79,0.00,0.00}
+% \definecolor{rmklink}{rgb}{.2,.2,.2} \let\reflink\rmklink
+% \definecolor[\rmkcolor]{rmk}{gray}{.35} \definecolor{copper}{rgb}{0.71,0.45,0.02}
+% \definecolor{dg}{rgb}{0.16,0.33,0.00} \definecolor{ddg}{rgb}{0.11,0.21,0.00}
+% \definecolor{shadecolor}{rgb}{0.93,0.94,0.81}^^A for framed
+% \definecolor{dgray}{gray}{.3} \definecolor[\rred]{r}{rgb}{1,0,0}
+% \definecolor{dr}{rgb}{0.49,0.00,0.00} \let\red\dr
+% \newrobustcmd\rmk{\footnotesize\rmkcolor\@ifstar{}{\endgraf\nobreak}}
+% \newrobustcmd\hint{\rmk\everypar{\marginpar{\footnotesize\textcolor{rmk}{hint}$\bigstar$}\everypar{}}}
+% ^^A\setul{2pt}{1pt}
+% \newrobustcmd\eol{\textcolor[gray]{.5}{$\hookleftarrow$}}
+% \newrobustcmd\mysep[1][\blue]{\PRM[#1]{sep}}
+% \newrobustcmd\itemitemitem{\@ifstar\itemitemitem@star\itemitemitem@nost}
+% \newrobustcmd\itemitemitem@star[1][\mysep]{\textvb{item}#1\textvb{item}#1\textvb{item}}
+% \newrobustcmd\itemitemitem@nost[1][\mysep]{\{\textvb{item}#1\textvb{item}#1\textvb{item}\}}
% \newenvironment{codecomment}{\par\vskip\parskip\begin{small}\color[gray]{.2}\parskip=0pt}{\end{small}}
-% \g@addto@macro\macro@font{\macrocodecolor\let\AltMacroFont\macro@font}
+% \renewcommand\partformat{}\let\thepart\partformat\renewcommand\raggedpart{\hskip-\thesecwidth\centering}%
+% ^^A Labels:
+% \newrobustcmd*\cmdlabel[1]{\begingroup\let\stform\@empty
+% \protected@edef\cmdlabel@name{#1}\@onelevel@sanitize\cmdlabel@name
+% \xdef\cmdlabel@name{\cmdlabel@name}\endgroup
+% \cslet{\detokenize{cmdlabel->}\cmdlabel@name}\@empty
+% \immediate\write\@mainaux{\cmdLabel{\cmdlabel@name}} \hyperdef{cmdlabel}{\cmdlabel@name}{}}
+% \newrobustcmd*\cmdref{\@ifstar{\@dblarg\cmdrefst}{\@ifchar={\@dblarg\cmdrefeq}{\@dblarg\@cmdref}}}
+% \def\cmdrefst[#1]#2{\@cmdref[impl:#1]{#2}}
+% \def\cmdrefeq[#1]#2{\def\cmdref@display##1{\underline{\mbox{\reflink\vb ##1}}}\cmd@hyper[#1]{#2}}
+% \newcommand\cmdrefdisplay[1]{\underline{\mbox{\reflink\vb\textbackslash #1}}}
+% \def\@cmdref[#1]#2{\let\cmdref@display\cmdrefdisplay \cmd@hyper[#1]{#2}}
+% \protected\def\cmd@hyper[#1]{\@testopt{\cmd@@hyper[{#1}]}{}}
+% \def\cmd@@hyper[#1][#2]#3{\@testopt{\cmd@@@hyper[{#1}][{#2}]{#3}}{\xspace}}
+% \def\cmd@@@hyper[#1][#2]#3[#4]{\ifcsdef{\detokenize{cmdlabel->#1}}%
+% {#2\hyperref{}{cmdlabel}{\detokenize{#1}}{\cmdref@display{#3}}#4}%
+% {#2\cmdref@display{\colorbox{black}{\color{white}#3}}#4}}%
+% \newrobustcmd*\seeimpl[2][]{\expandafter\@seeimpl\expandafter{\romannumeral-`\q#2}[{#1}]}
+% \long\def\@seeimpl#1[#2]{\ifblank{#1}{}
+% ^^A{\vadjust\bgroup\vtop to-3pt\bgroup\vss\hbox to\z@\bgroup\hss
+% ^^A \colorbox{yellow}{\textcolor{red}{\large\Laserbeam}}\kern\dimexpr5.3em#2\egroup\egroup\egroup\unskip\ignorespaces}
+% {\def\cmdref@display##1{\colorbox{yellow}{\textcolor{red}{\large##1}}}%
+% \cmd@@@hyper[impl:#1][\vadjust\bgroup\vtop to-3pt\bgroup\vss\hbox to\z@\bgroup\hss]{\Laserbeam}[\kern\dimexpr5.3em#2\egroup\egroup\egroup\unskip\ignorespaces]}}
+% \newsavebox\seedescbox\setbox\seedescbox\hbox to\z@{\kern.4em\colorbox{green}{\textcolor{red}{\SunshineOpenCircled}}\hss}
+% \newrobustcmd*\seedesc[1]{\ifblank{#1}{\copy\seedescbox}
+% \ifcsdef{cmdlabel->#1}{%
+% \vadjust{\vskip-1.5\ht\seedescbox\hfill
+% \hbox to\z@{\kern.4em\hyperref{}{cmdlabel}{\detokenize{#1}}{\colorbox{green}{\textcolor{red}{\SunshineOpenCircled}}}\hss}}}
+% {\vadjust{\vskip-1.5\ht\seedescbox\hfill
+% \hbox to\z@{\kern.4em\colorbox{black}{\textcolor{white}{\SunshineOpenCircled}}\hss}}}}
+% \newsavebox\FE@box \setbox\FE@box\hbox{$\m@th\bindnasrepma$}
+% \setbox\FE@box\hbox{\scalebox{2}{$\copy\FE@box\mkern-13.5mu\copy\FE@box\mkern-13.5mu\copy\FE@box$}}
+% \newsavebox\FEI@box \setbox \FEI@box\hbox{\rlap{\bfseries\color{red}\raisebox{-3pt}{\LARGE\bfseries\oldstylenums{1}}}\kern1pt{\fecc\unhcopy\FE@box}}
+% \newsavebox\FEII@box \setbox\FEII@box\hbox{\rlap{\bfseries\color{red}\raisebox{-3pt}{\LARGE\bfseries\oldstylenums{2}}}\kern1pt{\fecc\unhcopy\FE@box}}
+% \newsavebox\pdfFE@box \setbox\pdfFE@box\hbox{\llap{\hbox to3.3em{\dg\bfseries\textsf{pdf}\TeX{}}}\copy\FE@box}
+% \newsavebox\FEtiny@box\setbox\FEtiny@box\hbox{\scalebox{.6}{$\copy\FE@box\mkern-33mu\copy\FE@box$}}
+% \newcommand*\FEbox[1]{\raisebox{\glueexpr#1}{\fecc\copy\FE@box}}
+% \newrobustcmd\FEtiny[1][.2ex]{\raise\glueexpr#1\hbox to\z@{\hss\fecc\copy\FEtiny@box\kern.35em}}
+% \newcommand*\pdfFEbox[1]{\raisebox{\glueexpr#1}{\fecc\copy\pdfFE@box}}
+% \newcommand*\FEIbox[1]{\raisebox{\glueexpr#1}{\copy\FEI@box}}
+% \newcommand*\FEIIbox[1]{\raisebox{\glueexpr#1}{\copy\FEII@box}}
+% \newcommand\AddtoFE[1]{\listxadd#1\lastcmditem\listxadd#1\laststarredcmditem}
+% \newcommand\FE{\@ifstar{\AddtoFE\FEcmdlist}
+% {\ifx\@currenvir\macroenvirname \marginpar{\FEbox{-\the\baselineskip*2-4pt}}
+% \else \marginpar{\FEbox{-2pt}} \AddtoFE\FEcmdlist\seeimpl@display
+% \fi}}
+% \newcommand\pdfFE{\@ifstar{\AddtoFE\pdfFEcmdlist}
+% {\ifx\macroenvirname\@currenvir \marginpar{\pdfFEbox{-\the\baselineskip*2-4pt}}
+% \else \marginpar{\pdfFEbox{-2pt}} \AddtoFE\pdfFEcmdlist\seeimpl@display[+1.5em]
+% \fi}}
+% \newcommand\FEI{\@ifstar{\AddtoFE\FEIcmdlist\AddtoFE\FEcmdlist}
+% {\ifx\macroenvirname\@currenvir \marginpar{\FEIbox{-\the\baselineskip*2-4pt}}
+% \else \marginpar{\FEIbox{-2pt}} \AddtoFE\FEIcmdlist\AddtoFE\FEcmdlist\seeimpl@display
+% \fi}}
+% \newcommand\FEII{\@ifstar{\AddtoFE\FEIIcmdlist\AddtoFE\FEcmdlist}
+% {\ifx\macroenvirname\@currenvir \marginpar{\FEIIbox{-\the\baselineskip*2-4pt}}
+% \else \marginpar{\FEIIbox{-2pt}} \AddtoFE\FEIIcmdlist\AddtoFE\FEcmdlist\seeimpl@display
+% \fi}}
+% \newcommand\notFE{\@ifstar\relax\seeimpl@display}
+% \def\macroenvirname{macro}\let\lastcmditem\@empty \let\laststarredcmditem\@empty
+% ^^A Patching of \cmditem to make automatic cross reference with \FE symbol:
+% \let\Org@ltd@cmditem\ltd@cmditem
+% \let\Org@ltd@pdfbookmark\ltd@pdfbookmark
+% \renewcommand\ltd@pdfbookmark[2]{\begingroup\let\stform\@empty
+% \protected@edef\ltd@pdfbookmark{\endgroup\noexpand\Org@ltd@pdfbookmark{#1}{#2}}\ltd@pdfbookmark}
+% \def\@ifchar#1#2{\expandafter\@ifnextchar\string#1{\@firstoftwo{#2}}}
+% ^^A\let\cmditem\relax
+% \renewrobustcmd\ltd@cmditem[1][]{\goodbreak
+% \@ifchar-{\my@cmditem@starred[{#1}]\@gobble}
+% {\@ifstar{\my@cmditem@starred[{#1}]\@firstofone}{\my@cmditem[{#1}]}}}
+% \newcommand\my@cmditem@starred[3][]{%
+% \edef\laststarredcmditem{\ifblank{#1}{#3}{#1}}%
+% \edef\cmditem@end@hook{\cmditem@labelize{\ifblank{#1}{#3}{#1}}}%
+% #2{\refstepcounter{command}
+% \expandafter\addcommand\expandafter{\laststarredcmditem}{}{#3}}%
+% \Org@ltd@cmditem{#3}}^^A Make bookmark anyway (no star form)
+% \newrobustcmd\my@cmditem[1][]{\@ifchar+%
+% {\@ifchar @{\my@cmd@item[{#1}]{\spot}\@gobble}{\my@cmd@item[{#1}]{\spot}\@firstofone}}
+% {\@ifchar @{\my@cmd@item[{#1}]\@firstofone\@gobble}{\my@cmd@item[{#1}]\@firstofone\@firstofone}}}
+% \newrobustcmd\my@cmd@item[4][]{%
+% \let\lastcmditem\@empty\let\laststarredcmditem\@empty
+% \edef\lastcmditem{\ifblank{#1}{#4}{#1}}%
+% \def\cmditem@end@hook{\cmditem@labelize@display{\avoidvoid[\laststarredcmditem]\lastcmditem}}
+% \refstepcounter{command}
+% \expandafter\addcommand\expandafter{\lastcmditem}{#2}{#4}%
+% #3{\Org@ltd@cmditem{#4}}}
+% \newrobustcmd\addcommand[3]{%
+% \addcontentsline{cmd}{command}{\protect\numberline{\cftcommandnum{#1}{#2\arabic{command}}}\cftcommandfont#2{\protect\textbackslash#3}}}
+% \newrobustcmd\cftcommandnum[2]{\ifinlist{#1}\listofFEcommands \FEtiny{}\cftcommandfont \mdseries\sffamily\scriptsize\hfill #2\kern.4em}
+% \AtEndDocument{\immediate\write\@mainaux{%
+% \begingroup\catcode124 3\relax\gdef\noexpand\listofFEcommands{\detokenize\expandafter{\FEcmdlist}}\endgroup}}
+% \unless\ifdefined\listofFEcommands\let\listofFEcommands\@empty\fi
+% \newrobustcmd\seeimpl@display[1][]{\seeimpl[{#1}]{\avoidvoid[\laststarredcmditem]\lastcmditem}}%
+% \newrobustcmd\cmditem@labelize@display[1]{\cmdlabel{#1}\hfill\par}
+% \newrobustcmd\cmditem@labelize[1]{\cmdlabel{#1}\hfill\par}
+% ^^A At the end of the ltxdockit scanner for \cmditem, the labelize-macro must be expanded:
+% \apptocmd\ltd@parseargs@end{\cmditem@end@hook}{}{}
+% ^^A Now Macro envir may use the labels:
+% \def\@Macro#1{\begin{macro}{#1}}
+% \newenvironment{Macro}[2][]{%
+% \expandafter\@Macro\expandafter{\@backslashchar#2} \cmdlabel{impl:#2}%
+% \ifblank{#1}{\Check@FEList{#2}}{\Check@FEList{#1}}}
+% {\end{macro}}
+% \def\Check@FEList#1{%
+% \ifinlist{#1}\FEIcmdlist \FEI
+% {\ifinlist{#1}\FEIIcmdlist \FEII
+% {\ifinlist{#1}\FEcmdlist \FE
+% {\ifinlist{#1}\pdfFEcmdlist \pdfFE{}}}}
+% \everypar\expandafter{\the\everypar\seedesc{#1}\everypar{}}}
+%
+% \newenvironment{Macro*}[1]{%
+% \expandafter\@Macro\expandafter{\@backslashchar#1} \cmdlabel{impl:#1}}
+% {\end{macro}}
+% \newlistof{command}{cmd}{\listcommandname}\let\listcommandname\@empty
+% \DefineVerbatimEnvironment{VerbLines}{Verbatim}{gobble=1,frame=lines,framesep=6pt,fontfamily=txtt,fontseries=b}
+% \DefineVerbatimEnvironment{Verb}{Verbatim}{gobble=1}
+% \DefineVerbatimEnvironment{VerbZ}{Verbatim}{gobble=1}
+% \cftbeforepartskip=6pt
+% \cftsubsecnumwidth=1.5em
+% \renewcommand\cftsubsecpresnum{\hbox to.5em\bgroup\hss}
+% \renewcommand\cftsubsecaftersnum{\egroup\hbox to1em{\hss\tinybullet\hss}}
+% \renewcommand\cftsubsecpagefont{\scriptsize}
+% \renewrobustcmd\cftsubsecleader{\kern.4em\mydotleader[1pt]\z@\hfill}
+% \cftbeforesubsecskip=-.7pt^^Aplus.01fil
+% \cftbeforesecskip=3pt^^Aplus.01fil
+% \cftsecnumwidth=1.5em
+% \renewrobustcmd\cftsecfont{\usekomafont{section}\large\bfseries\red}
+% \renewcommand\cftpartfont{\usekomafont{section}\large\bfseries}
+% \renewcommand\cftsecpresnum{\cftsecfont\hbox to.5em\bgroup\hss}
+% \renewcommand\cftsecaftersnum{\egroup\raise.2ex\hbox to1em{\hss\scriptsize\Forward\hss}}
+% \cftcommandnumwidth=1.5em
+% \let\cftcommandleader\cftsubsecleader
+% \renewcommand\thecommand{\arabic{command}}
+% \renewrobustcmd\cftcommandfont{\large\sfbf\db}
+% \newlength\thesecwidth\thesecwidth=2.2cm
+% \titleformat\section[hang]{\LARGE\bfseries}
+% {\llap{\hbox to\thesecwidth{\hfil\arabic{section}\hfil\kern.4em{\spot\Forward}\kern.4em\hfil}}}\z@{}
+% \titlespacing\section\z@{6pt plus4pt minus2pt}{3pt plus2pt minus1pt}
+% \newcommand\sectionbreak{\penalty-3000}
+% \newrobustcmd\normalsubsecformat{%
+% \titleformat\subsection[hang]{\Large\bfseries}
+% {\llap{\hbox to\thesecwidth{\arabic{section}\textbullet\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}}\z@{}%
+% \titlespacing\subsection\z@{6pt plus4pt minus2pt}{3pt plus2pt minus1pt}%
+% \renewcommand\sectionmark[1]{\addcontentsline{cmd}{section}{\protect\numberline{\arabic{section}}##1}}}%
+% \newrobustcmd\implementationsubsecformat{%
+% \titleformat\subsection[hang]{\Large\bfseries}
+% {\llap{\hbox to\thesecwidth{I\textbullet\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}}\z@{}%
+% \titlespacing\subsection\z@{6pt plus4pt minus2pt}{3pt plus2pt minus1pt}%
+% \titleformat\subsubsection[hang]{\large\bfseries}
+% {\llap{\hbox to\thesecwidth{I\textbullet\arabic{subsection}\textbullet\arabic{subsubsection}\hfil{\fecc--}\hfil}}}\z@{}%
+% }%
+% ^^A\renewcommand\sectionmark[1]{\addcontentsline{cmd}{section}{\protect\numberline{I.\arabic{subsection}}##1}}}
+% \newrobustcmd\firstsubsecformat{%
+% \titleformat\subsection[hang]{\large\bfseries}
+% {\llap{\hbox to\thesecwidth{\hss\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}}\z@{}
+% \titlespacing\subsection\z@{5pt plus2pt minus2pt}{3pt plus2pt minus1pt}%
+% \let\sectionmark\@gobble
+% }\firstsubsecformat
+% \newcommand\subsectionbreak{\penalty-500}
+% \newcommand\Section{\@ifstar{\section*}{\@ifchar.{\@dblarg{\@Section.}}{\@dblarg{\@Section{}}}}}
+% \long\def\@Section#1[#2]#3{%
+% \ifblank{#1}{}{\let\WriteBookmarks\relax}%
+% \section[{\texorpdfstring{\protect\cftsecfont}{}#2}]{#3}%
+% \ifblank{#1}{}{\let\WriteBookmarks\@empty\numdef\Hy@currentbookmarklevel{\Hy@currentbookmarklevel-1}}}
+% \newcommand\Subsection{\@ifstar{\subsection*}{\@ifchar.{\@dblarg{\@Subsection.}}{\@dblarg{\@Subsection{}}}}}
+% \long\def\@Subsection#1[#2]#3{%
+% \ifblank{#1}{}{\let\WriteBookmarks\relax}%
+% \subsection[{#2}]{#3}%
+% \ifblank{#1}{}{\let\WriteBookmarks\@empty\numdef\Hy@currentbookmarklevel{\Hy@currentbookmarklevel-1}}}
+% \newsavebox\helpbox \newsavebox\helpboxx
+% \newcommand\hpbox{\copy\helpbox} \newcommand\hpboxx{\copy\helpboxx}
+% \lastlinefit999 \parindent\z@ \topsep\z@ \partopsep\z@ \parskip.3\baselineskip
+% \fontfamily{ua1}\selectfont \pagestyle{corpus}
% \MakeShortVerb{\|}
-% \catcode`\§\active\def§{\par\nobreak\vskip-\parskip}
-% \renewcommand\partformat{}\let\thepart\partformat\renewcommand\raggedpart{\centering}
-% \newcommand\cmdref[1]{\hyperref[#1]{\underline{\sty{\reflinkcolor\textbackslash #1}}}}
-% \newcommand\cmdlabel[1]{\label{#1}\hyperdef{cmdlabel}{#1}{}}
-% \newcommand\seeimpl[1]{%
-% \ifblank{#1}{\colorbox{yellow}{\textcolor{red}{\LARGE\Laserbeam}}}
-% {\hfill \hyperref{}{cmdlabel}{impl:#1}{\colorbox{yellow}{\textcolor{red}{\LARGE\Laserbeam}}}}}
-% \newsavebox\seedescbox
-% \setbox\seedescbox\hbox{\rlap{\kern.4em\colorbox{green}{\textcolor{red}{\SunshineOpenCircled}}}}
-% \newcommand\seedesc[1]{%
-% \ifblank{#1}{\copy\seedescbox}
-% {\vadjust{\vskip-1.5\ht\seedescbox\hfill
-% \hbox{\rlap{\kern.4em\hyperref{}{cmdlabel}{#1}{\colorbox{green}{\textcolor{red}{\SunshineOpenCircled}}}}}}}}
-% \def\FE{\setbox8\hbox{$\m@th\bindnasrepma$}%
-% \marginpar{\raisebox{-2pt}{{\fecccolor\scalebox{2}{$\copy8\mkern-13.5mu\copy8\mkern-13.5mu\copy8$}}}}\space}
-% \def\pdfFE{\setbox8\hbox{$\m@th\bindnasrepma$}%
-% \marginpar{\raisebox{-2pt}{{\fecccolor\llap{\textsf{pdf}\TeX{}\,}\scalebox{2}{$\copy8\mkern-13.5mu\copy8\mkern-13.5mu\copy8$}}}}}
-% \def\clap#1{\hb@xt@\z@{\hss#1\hss}}
-% \def\smex{\leavevmode\hb@xt@2em{\hfil\spotcolor$\longrightarrow$\hfil}}
-% \font\manual=manfnt\def\dbend{\marginpar{\manual\char127}\space}
-% \def\CS#1{\texttt{\expandafter\@gobble\string\\#1}}
-% \def\CSbf#1{\textbf{\CS{#1}}}
-% \def\Xpackage{\@dblarg\X@package}
-% \def\X@package[#1]#2{%
-% \sty{#2\footnote{\noindent\sty{#2}: \href{http://www.ctan.org/tex-archive/macros/latex/contrib/#1}{\nolinkurl{CTAN:macros/latex/contrib/#1}}}}}
-% \parindent\z@\topsep\z@\partopsep\z@\parskip.3\baselineskip
-% \cftbeforesecskip=4pt
-% \cftbeforepartskip=11pt
-% \let\footnoterule\relax
-% \footskip=0pt
-% \lastlinefit999
% \makeatother
%
-% \thispagestyle{plain}\printtitlepage\medskip
-% \fontfamily{ua1}\selectfont
-% \tableofcontents\medskip\thispagestyle{plain}\enlargethispage{2.5\baselineskip}
-%
-% \begin{shaded}\parindent0pt\noindent\normalsize\topsep=-\parskip\itemsep=-\parskip
-%
-% {\bfseries\catcode`\ \active\let =\,\hfil\NibSolidRight A b s t r a c t \NibSolidLeft\hfil}\par
-%
-% The \sty{etextools} package is based on the \sty{etex} and \sty{etoolbox}
-% packages and defines more tools for \LaTeX\ Users or package Writers.
+% ^^A TITLE PAGE + TABLE OF CONTENTS
+% \begingroup \movepage{2cm}\voffset-1.5\baselineskip \skip\footins=-1.5cm
+% \tocloftpagestyle{toc}
+% \pretocmd\pagenumberdisplay{\vspace*{1cm}}{}{} \enlargethispage{1.5cm}
+%
+% \definecolor{reflink}{gray}{0}
+% \printtitlepage
+% \AddBookMark{attr{/F 2}goto page 1{/FitH}{etextools}}
+%
+% \begingroup\makeatletter\parfillskip\z@
+% ^^A\cftsetpnumwidth{0pt}
+% \renewcommand\cfttoctitlefont{\mydotleader{.5ex}\hfill\kern.5em\Large\bfseries}
+% \renewcommand\cftaftertoctitle{\kern.5em\mydotleader{.5ex}\hfill\kern\z@\par\vskip-8pt}
+% \renewcommand\cftpartleader{\kern.4em\mydotleader{.4ex}\hfill\hbox to\z@{\mydotleader{.4ex}\hskip\@pnumwidth\kern\z@\hss}}
+% \cftbeforesubsecskip=-.7ptplus.01fil
+% \cftbeforesecskip=3ptplus.01fil
+% \definecolor{reflink}{rgb}{0.37,0.00,0.37}
+% ^^A\immediate\write18{copy \jobname.tocc \jobname.toc}
+% \vskip-6pt\tableofcontents
+% \vskip-2\parskip\leavevmode\mydotleader{0pt}\hfill\kern0pt\par\vskip-\parskip
+% \endgroup ^^A\the\pagetotal
+%
+% \vskip-6pt\begin{shaded}\parindent0pt\noindent\normalsize\topsep=-\parskip\itemsep=-\parskip
+% \let\reflink\reflinkabstract
+%
+% {\bfseries\catcode`\ \active\let =\,\hfil\NibSolidRight¤¤\raise3pt\hbox{ A b s t r a c t }¤¤\NibSolidLeft\hfil}\par
+%
+% The \thispackage package is based on the \xpackage{etex} and \xpackage{etoolbox}
+% packages and defines a lot of macros for \LaTeX\ Users or package Writers.
% Before using this package, it is highly recommended to read the
-% documentation (of this package and...) of the \sty{etoolbox} package.
+% documentation (of this package and...) of the \xpackage{etoolbox} package.
%
-% This package requires the \sty{etex} package from David Carlisle
-% and the \sty{etoolbox} package from Philipp Lehman. Both of them
-% are available on CTAN under the \sty{/latex/contrib/} directory \footnotemark.
+% This package requires the \xpackage{etex} package from David Carlisle
+% and the \xpackage{etoolbox} package from Philipp Lehman.
+% They are available on CTAN under the \sty{/latex/contrib/} directory \footnotemark.
%
-% \underline{The main contributions of this package are :}
+% \underline{\bfseries The main contributions of \thispackage are :}\hfill\smex\hyperref{}{Part}{ListOfCommands}{\blue see the complete list}
% \begin{itemize}
-% \item the \cmdref{expandnext} macro and the \cmdref{ifempty} and \cmdref{xifempty} macros
-% \item the ability to define fully expandable macros with parameter and/or star version (with a small restriction)
-% -- see \cmdref{FE@testopt}, \cmdref{FE@ifstar}
-% \item a Command-List Parser constructor that uses this new feature : command-list parsers are fully expandable:
-% \cmdref{csvloop}, \cmdref{listloop}, \cmdref{toksloop} and more...
-% \item four macros that are lacking from the \sty{etoolbox} package for removing elements from lists :
-% \cmdref{listdel} and \cmdref{listgdel}, \cmdref{listedel}, \cmdref{listxdel}
-% \item get the index of an item in a list: \cmdref{getlistindex} and \cmdref{xgetlistindex} and conversely
-% the item at a given position in a list: \cmdref{getlistitem}
-% \item a vectorized form of \cmd{futurelet}: \cmdref{collecttoks} is a standard token scanner.
+% \item \cmdref{expandnext}: a vectorized form of \csbf{expandafter} and \cmdref{ExpandNext} that works like
+% \cs{expandnext} but expands infinitely (with \cmdref{expandaftercmds} and \cmdref{ExpandAftercmds})
+% \item a \hyperref{}{cmdlabel}{DeclareStringFilter}{\underline{\vb\reflink String-Filter constructor}}
+% to compare strings in a purely expandable way and many other macros on strings among them \cmdref{ifstrnum}
+% \item \cmdref{futuredef}: a macro (and vectorized) version of \CSbf{futurelet}.
+% \item the ability to define fully expandable macros with optional parameters or star form (with a small restriction)
+% -- \cmdref{FE@testopt}, \cmdref{FE@ifstar}, \cmdref{FE@ifchar} and \cmdref{FE@modifiers}
+% \item a Command-List Parser constructor that uses those new features: command-list parsers are fully expandable:
+% \cmdref{csvloop}, \cmdref{listloop}, \cmdref{toksloop}, \cmdref{naturalloop} and more...
% \end{itemize}
-%
% \end{shaded}
-%
-% \footnotetext{This documentation is produced with the \sty{ltxdockit}
+% \footnotetext{This documentation is produced with the \xpackage{ltxdockit}
% classe and package by Philipp Lehman using the |DocStrip| utility.
% \begin{tabbing}
% \qquad\=\smex\=To get the documentation, \= run (twice):\quad\= \sty{pdflatex etextools.dtx} \\
% \>\smex\>To get the package, \> run:\> \sty{etex etextools.dtx}
% \end{tabbing}
-% The .dtx file is embeded in this pdf thank to \sty{embedfile} by H. Oberdiek.}
+% The .dtx file is embeded in this pdf thank to \xpackage{embedfile} by H. Oberdiek.\vskip0ptplus1filll}
%
-% \vfil\eject
+% ^^A END OF FIRST PAGE ----------------------------------------------------------------------------------------------
+% \clearpage
+% \endgroup
%
-% \section{Introduction}
+% \begingroup \movepage{1cm}
+% \Section*{Introduction}
+% \addcontentsline{toc}{section}{\hskip\cftsecnumwidth\texorpdfstring\dr{} Introduction}
+% \renewcommand\thesubsection{\arabic{subsection}}^^A for toc
%
-% \subsection{Motivation}
+% \Subsection{Motivation}
%
-% The first motivation for this package was to define a list-parser macro:
-% \begin{itemize}
-% \item just like the \cs{docsvlist} and \cs{dolistloop} macros from \sty{etoolbox}
-% \item fully expandable (\ie in an |\edef|)
-% \item that take the auxiliary command(s) (\cs{do} in \sty{etextools}) as an optional argument.
-% \end{itemize}
+% The first motivation for this package was to define a powerful list-parser macro that enhance the one
+% provided by \xpackage{etoolbox}. Loops are a basic in programming, and the need for them comes sooner or
+% later when using \LaTeX.
+%
+% As a result, a lot of ``derived'' macro have been build, their definition and name carefully chosen...
+% For exemple, removing an element in a list is the same as removing a substring in a string, and then
+% quite the same as testing if two strings are equal...
%
-% As a result, a method for defining fully expandable macros with optional parameter is built here.
+% Finally, \thispackage provides a lot a tools to make definitions of new commands more flexible (modifiers...)
+% maintain list for special purpose (like the lists of purely expandable macros in this very pdf document),
+% to get rid of catcode considerations when dealing with characters (the \emph{character-test}): the list of (nearly all)
+% commands defined by \thispackage lies on next page...
%
-% \subsection{Purely Expandable macros}
+% \Subsection{Purely Expandable macros}
%
-% The \FE fully expandable (or purely expandable) commands defined in this package
+% A \textbf{purely expandable command} is a command whose expected result can be obtained in an |\edef|.
+% They can also be placed inside |\csname|...|\endcsname|, and are totally expanded after
+% |\if|, |\ifnum|, |\ifcase|, |\ifcat|, |\number|, |\romannumeral|.
+%
+% The\FE fully expandable (or purely expandable) commands defined in \thispackage
% can be easily spotted with the special marker displayed here in the margin for information.
-% \medskip
%
-% Go directly to the implementation of a\marginpar{\llap{\seeimpl{}\hskip-1.5em}} command by clicking
-% on the symbol displayed here in the margin for information.
-% \medskip
+% A purely expandable macro may require one, two or many more \textbf{levels of expansion} in order
+% to reach its goal. Such macros that expands to the expected result at once\FEI are marked with the
+% special sign displayed here in the \textsf{marginpar}. And such macros that requires only two levels
+% of expansions are marked with the special sign displayed here\FEII in the \textsf{marginpar}.
%
-% Now from the implementation, \marginpar{\llap{\seedesc{}\kern4pt}} you can return to the description
-% section just by clicking on the symbol displayed here in the margin for information.
+% \hfil\begin{tabular}{|>{\rred}c|l|}\hline
+% \thead{levels} & \thead{sequence to get the result} \\ \hline
+% $\mathbf1$ & \cs[\red]{expandnext}|{\def\result}{|\cs[\copper]{FEmacro}\mprm{arguments}|}| \\ \hdashline[1pt/1pt]
+% $\mathbf2$ & \cs[\red]{expandnext}\cs[\red]{expandnext}|{\def\result}{|\cs[\copper]{FEmacro}\mprm{arguments}|}| \\ \hdashline[1pt/1pt]
+% more & \cs[\red]{ExpandNext}|{\def\result}{|\cs[\copper]{FEmacro}\mprm{arguments}|}| \footnotemark \\ \hline
+% \end{tabular}\hfil
+% \footnotetext{\cs{ExpandNext} is not alway enough: \cs{csvloop} for exemple requires \cs{edef} (or \cs{csname}...) to be completely expanded.}.
%
-% \subsection{The example file}
+% A few\pdfFE macros are only expandable if the |\pdfstrcmp| (or |\strcmp|) primitives are available
+% ^^A(this is notably the case of \cmdref{getlistindex}).
+% Those macros are marked with the special marker displayed here in the margin for information.
%
-% The example file provided with \thispackage\ illustrates the macros defined here.
+% \Subsection{The example file}
%
-% \subsection{Requirements}
+% The \hyperref{file:etextools-examples}{ettlex}{toc}{example file} provided with \thispackage\ illustrates the macros defined here.
%
-% This package requires the packages \sty{etex} package by David Carlisle and
-% \sty{etoolbox} by Philipp Lehman.
+% \Subsection{Requirements}
%
-% \subsection{Acknowledgements -- Thank You !}
+% This package requires the packages \Xpackage[etex-pkg]{etex} by David Carlisle and
+% \Xpackage{etoolbox} by Philipp Lehman. The \cmdref{aftergroup@def} macro uses the feature provided
+% by \Xpackage[oberdiek/letltxmacro]{letltxmacro} by Heiko Oberdiek.
%
-% Thanks to Philipp Lehman for the \sty{etoolbox} package (and also for this nice class of documentation).
+% \Subsection{Acknowledgements -- Thank You !}
+%
+% Thanks to Philipp Lehman for the \xpackage{etoolbox} package (and also for this nice class of documentation).
% Much of my work on lists are based on his work and package.
%
+% \Subsection{A note for package writers}
+%
+% If you are interested in writing your own purely expandable macros (using the features of \thispackage...)
+% it's important to know well the basics: you must understand the job of \cmdref[impl:ettl@nbk]{ettl@nbk} and \cs{romannumeral},
+% and take a lot of care of malicious spaces.
+% \vfill
+% {\hfill\spot\usefont{T1}{txss}{b}{n}\LARGE\raise1.5ex\hbox{\scalebox{1}[-1]\Lightning}\kern14pt Happy \eTeX ing\kern12pt\raise1.5ex\hbox{\scalebox{-1}[-1]\Lightning}\hfill}
+% \vfill\clearpage
+% \endgroup \normalsubsecformat
+%
+% \begingroup\makeatletter \movepage[-2cm]{2.5cm}%
+% ^^A\immediate\write18{copy \jobname.ccmd \jobname.cmd}
+% \def\@begincmdhook{\multicolsep\z@\let\normalcolor\spot\columnseprule.4pt\columnsep=1.5cm\begin{multicols}{2}}
+% \def\@endcmdhook{\AfterGroup{\enlargethispage{2\baselineskip}\mydotleader{-1ex}\hfill\kern\z@}\end{multicols}}
+% \cftsecindent=\glueexpr-\wd\FEtiny@box-.35em
+% \renewrobustcmd\cftsecfont{\sfbf\large\black}
+% \renewcommand\cftcmdtitlefont{\leavevmode\mydotleader{.4ex}\hfill\kern.5em\LARGE\bfseries}
+% \renewcommand\cftaftercmdtitle{\kern.5em\mydotleader{.4ex}\hfill}
+% \renewcommand\listcommandname{\makecellbox[bc]{\thispackage\\[-1ex]List of Commands Provided}}
+% \cftaftercmdtitleskip=6pt
+% \cftbeforesecskip=2pt plus.1fil
+% \cftbeforecommandskip=2.2pt plus.1fil
+% \tocloftpagestyle{empty}\catcode`\+ 12 \catcode`\! 12
+% \pdfdest name{ListOfCommands} xyz\hyperdef{Part}{ListOfCommands}{}
+% \addtocontents{toc}{\protect\contentsline{part}{\protect\colorbox[rgb]{1.00,1.00,0.79}{\protect\hyperref{}{Part}{ListOfCommands}{\blue List of commands}}}{}{}}
+% \vspace*{-18mm}\listofcommand
+% \AddBookMark{attr{/F 2/C[0 0 1]}goto name{ListOfCommands}{List of commands}}
% \clearpage
-% \part*{All User Commands}
-% \addtocontents{toc}{\protect\contentsline{part}{All User Commands}{}{}}
+% \endgroup
+% ^^A\stop
+%
+% \part*{{\spot\blacksmiley}\hfill All User Commands\hfill{\spot\blacksmiley}}
%
-% \section{Expansion control}
+% \hypersetup{bookmarksopenlevel=1}
+% \Section{General Helper Macros}
%
% \begin{ltxsyntax}
%
-% \cmditem{expandnext}{cstoken}{first parameter of cstoken} \cmdlabel{expandnext} \seeimpl{expandnext}
+% \cmditem{@gobblespace}{ code }
+%
+% This macro\FEI first gobbles the next space token and then expands the \prm{code}.
+% Truly, a ``space token'' means any character of category $10$.
+%
+% \cmditem{@gobblescape}
+%
+% Just gobble\FEI the first character on the result of \cmd{string} (escape character).
+%
+% {\rmk \cs{@gobblescape} is used in the definition of \cmdref{DeclareStringFilter}, \cmdref{DeclareCmdListParser} and
+% for the general constructor to remove elements from lists (\cs{listdel} etc.): \cmdref*{ettl@RemoveInList}.}
+%
+% \cmditem[@swap]+@{@swap\tsptb @swaparg\tsptb @swaplast}
+% \cmditem-{@swap}{ token1 }{ token2 }
+%
+% Just\FEI reverse the order of the two tokens:\hfill \cs[\red]{@swap}\#1\#2| |\smex\#2\#1.
+%
+% \CSbf{@swap} does not add any curly braces (be aware that it does not remove them, however).
%
-% We\FE often want a control sequence to be expanded after its first argument. For example, if you
-% want to test if a command |\foo| has a blank replacement text you will say:
+% \csbf{@swap} is so simple that it requires a special attention: \cs{@swap} is powerful...§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\@swap){ }\meaning !smex blank space
+% \expandafter(!red\@swap)\expandafter{!PRM[!copper](codeA)}{!PRM[!copper](codeB)}
+% !nnn will expand !PRM[!copper](codeA) once and the put !PRM[!copper](codeB) just before
+% \end{VerbLines}
%
-% \qquad |\expandafter\ifblank\expandafter{\foo}{|\prm{true part}|}{|\prm{false part}|}|
+% {\rmk \cs{@swap} is used in the definitions of \cmdref{expandaftercmds} and \cmdref{protectspace}.}
%
-% With |\expandnext| you'll just have to say:
+% \cmditem-{@swaparg}{ code }{ command }
%
-% \qquad |\expandnext\ifblank{\foo}{|\prm{true part}|}{|\prm{false part}|}|
+% Just\FEI make \prm{code} the first argument of \prm{command}:\hfill \cs[\red]{@swaparg}\#1\#2| |\smex\#2|{|\#1|}|.
%
+% {\rmk \cmd{@swaparg} is used in the definition of \cmdref{expandnext}}.
+%
+% \cmditem-{@swaplast}{ token1 }{ token2 }{ token3 }
+%
+% \CSbf{@swaplast}\FEI swaps \prm{token2} and \prm{token3} but \prm{token1} remains in first position:§
+% \hfill \cs[\red]{@swaplast}\#1\#2\#3| |\smex| |\#1\#3\#2
+%
+% {\rmk \cs{@swaplast} is used in the definition of the command-list-parser defined with \cmdref{DeclareCmdListParser}.}
+%
+% \cmditem{@swaptwo}{ token1 }{ token2 }
+%
+% Just\FEI reverse the order of the \textbfsf{arguments:}\hfill \cs[\red]{@swaptwo}\#1\#2| |\smex|{|\#2|}{|\#1|}|.
+%
+% \CSbf{@swaptwo} keeps the curly braces around its arguments (be aware that it does not add them, however).
+%
+% {\rmk \cmd{@swaptwo} is used in the definition of \cmdref{gettokslistindex} and \cmdref{getcharlistindex}.}
+%
+% \end{ltxsyntax}
+%
+% \Section{Expansion control}
+%
+% We often want a control sequence to be expanded after its first argument. It is normally the job
+% of \cs{expandafter}. With many \cs{expandafter}s it is always possible to expand once, twice, thrice
+% or more, the \textbfsf{very first token that occurs after the begin-group character} delimiting the argument.
+%
+% \cmdref{expandnext} simplifies the syntax (without making the execution process too heavy).
+%
+% Now it is also possible to expand the \textsfsl{very first} token \textsfbf{infinitely}:
+% this is the aim of \cmdref{ExpandNext}.
+%
+% \begin{ltxsyntax}
+% \ClearPage*
+% \cmditem+{expandaftercmds}{ code }{ control sequences }
+%
+% \csbf{expandafter}\FE is sometimes limited because it affects only the very next token.
+% \csbf{expandaftercmds} works just like the \csbf{expandafter} primitive but may be followed by
+% arbitrary \prm{code}, not only a single token.
+%
+% A typical example is the following code, which detokenizes the character \CH{\#{}}:§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\expandaftercmds{)\expandafter\@gobble\string(!red}){\csname !#\endcsname}
+% \end{VerbLines}
+% without duplication (|\detokenize{|\#{}|}| leads to \CH{\#{}\#{}} if catcode of \#{} is $6$)
+%
+% {\rmk \cs{expandaftercmds} is used in the definition of \cs{ettl@Remove} and then in
+% \cmdref{listdel}, and the string-comparators declared with \cmdref{DeclareStringFilter}}.
+%
+% \cmditem+{expandnext}{ code }{ control sequences }
+%
+% \CSbf{expandnext}\FE is quite the same as \CSbf{expandaftercmds} except that the \prm{control sequences}
+% are the \textbfsf{argument of} \prmb{code}, \ie they are enclosed with curly braces after expansion.
+%
+% Suppose you want to test if the replacement text of a macro is blank (only spaces). You will say:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!blue\expandafter)(!copper\ifblank)(!blue\expandafter) {\foo}{!prm(true part)}{!prm(false part)}
+% !normalfont(With !cs(expandnext) you'll just have to say:)
+% (!red\expandnext)(!copper\ifblank){\foo}{!prm(true part)}{!prm(false part)}
+% \end{VerbLines}
+%
+%
+% \textbfsf{\prmb{code} may be arbitrarily \TeX{} code, unlike \CSbf{expandafter},} you may say:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\expandnext{)(!copper\def\test)(!red}){\csname name\endcsname} !hfil!nsl and it is exactly:
+% !mdseries\edef\test{\expandafter\noexpand\csname name\endcsname}
+% !nsl and also exactly:
+% !mdseries!small \expandafter\def\expandafter\test\expandafter{\csname name\endcsname}
+% (!mdseries!normalfont!itshape Genauer gesagt:) \meaning\test = macro:->\name
+% \end{VerbLines}
+%
+% \csbf{expandnext} can be used for macros with optional arguments:§§
+% \begin{VerbLines}[commandchars=$()]
+% ($red expandnext{)($copper\Macro[option])($red}){$prm(argument)}
+%\end{VerbLines}
+%
+% \csbf{expandnext} can be used to test if a purely expandable macro is expandable at once.
+% (If it is not, the \cmdref{ExpandNext} macro can be used intead.)
+%
+% Now \csbf{expandnext} behaves like \cs{expandafter} and is cumulative: if you need two levels
+% of expansions you may say:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\expandnext\expandnext)(!copper{\def\test}){\csname name\endcsname}
+% !normalfont and it is exactly:
+% !mdseries!small\edef\test{\expandafter\expandafter\expandafter\noexpand\csname name\endcsname}
+% !normalfont and also exactly:
+% !mdfs\expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\test
+% !mdfs \expandafter\expandafter\expandafter{\csname name\endcsname}
+% (!mdseries!normalfont!emph(Genauer gesagt:)) \meaning\test = macro:-> !prmb(the meaning of !csbf(name))
+% \end{VerbLines}
+% \cs{expandnext} is an \cs{expandafter} saver !
+%
+% {\rmk
% Now observe the following game :
% \begin{tabbing}
% \qquad\= |\def\foo{foo}| \qquad \= \smex \qquad \= |\def\Foo{\foo}| \quad \= \eol \\
@@ -339,22 +777,66 @@ and etextools-examples.tex
% Guess how many \cmd{expandafter} are needed to test ``|\ifblank{foo}|'' directly from |\fool| ???
%
% |\expandnext| solves this problem : |\fool| has 5 degrees of expansion until it expands to ``foo'', therefore exactly 5
-% |\expandnext| are required. The solution is:
+% |\expandnext| are required. The solution is:§
+% \qquad |\expandnext\expandnext\expandnext\expandnext\expandnext\ifblank{\fool}|}
%
-% \qquad |\expandnext\expandnext\expandnext\expandnext\expandnext\ifblank{\fool}|
+% \cmditem{expandnexttwo}{ code }{ control sequences }{ control sequences }
%
-% Other example: suppose you want to define a macro |\detokenizecs{|\prm{csname}|}| that expands to the detokenized content
-% of |\csname |\prm{csname}|\endcsname|. Without |\expandnext| you will have to say:
-% \begin{tabbing}
-% \qquad\= |\expandafter\expandafter\expandafter\detokenize| \\
-% \> |\expandafter\expandafter\expandafter{\csname |\prm{csname}|\endcsname}|
-% \end{tabbing}
-% \textbf{six} \cmd{expandafter}(s). With |\expandnext| you just have to say:§
-% \qquad|\expandnext\expandnext\detokenize{\csname #1\endcsname}|
+% \csbf{expandnexttwo}\FE will act as \cs{expandnext} on two arguments:
+%
+% \qquad\cs{expandnexttwo}:\enspace\#1\#2\#3$\longrightarrow$
+% \cs{expandnext} {\textbf\{}\cs{expandnext}\{\#1\}\Underbrace{\{\#2\}}_{\scriptsize\makecellbox[c]{expanded\\\bfseries once after}}\textbf\}\Underbrace{\{\#3\}}_{\scriptsize\makecellbox[c]{expanded\\\bfseries once first}}
+%
+% You may easily define \cs{expandnextthree} the same way, if you need it...
+%
+% {\rmk \cs{expandnexttwo} is used in \cmdref{iffirstchar}.}
+%
+% \cmditem{ExpandAftercmds}{ code }{ control sequences }
+%
+% \csbf{ExpandAftercmds}\FE acts like the primitive \cs{expandafter} but:\enlargethispage{\baselineskip}
+% \begin{enumerate}[label=--~]
+% \item the \textslsf{very first} token in \prmb{control sequences} is \textbfsf{totally expanded}
+% \item \prmb{code} may be arbitrarily code (not necessarily a single token)
+% \end{enumerate}
+%
+% \ClearPage
+% \cmditem+{ExpandNext}{ code }{ control sequences }
+%
+% More\FE on expansion! Suppose you have a string say "12345"\ and you wish to reverse the order of
+% the letters (here, the \textit{figures}). To do that we need a macro that swaps two elements, and then
+% group them in order to swap with the next in a loop: the idea is to do:
+% \quad |12345|\smex swap |{21}345| \smex swap |{321}45| \smex swap |{4321}5|.
+%
+% \thispackage provides a tool to loop against natural integers from $1$ to $n$. \cmdref{naturalloop}
+% is purely expandable and we get the result with:§
+% \begin{VerbLines}[commandchars=!(),fontseries=m]
+% \def\swap!#1!#2{{!#2!#1}}
+% \def\do[!#1]!#2!#3{\swap !#3}
+% (!bfseries\edef\result{\naturalloop[\do]{4}{12345}} !smex macro:->54321)
+% (!bfseries(!red\ExpandNext{)(!copper\def\RESULT)(!red }){\naturalloop{4}{12345}}!smex:->54321)
+% \end{VerbLines}
+%
+% \textbfsf{\CSbf{ExpandNext} has expanded the second argument totally without the use of \CSbf{edef}!}
%
-% \cmditem{noexpandcs}{csname} \cmdlabel{noexpandcs}\seeimpl{noexpandcs}
+% In fact, it is possible because \CSbf{naturalloop} is defined in terms of \CSbf{ExpandNext}.
%
-% In an \FE expansion context (|\edef|) we often want a control sequence whose name results
+% {\rmk \cs{ExpandNext} is used in the definition of \cmdref{naturalloop} and \cmdref{DeclareStringFilter}.}
+%
+% \cmditem+{ExpandNextTwo}{ code }{ arg1 }{ arg2 }
+%
+% \cs{ExpandNextTwo}\FE will act like \cs{ExpandNext} on two arguments:
+%
+% \qquad\cs{ExpandNextTwo}:\enspace\#1\#2\#3$\longrightarrow$
+% \cs{ExpandNext} {\textbf\{}\cs{ExpandNext}\{\#1\}\Underbrace{\{\#2\}}_{\scriptsize\makecellbox[c]{totally\\expanded\\\bfseries after}}\textbf\}\Underbrace{\{\#3\}}_{\scriptsize\makecellbox[c]{totally\\expanded\\\bfseries first}}
+%
+% You may easily define \cs{ExpandNextThree} the same way, if you need it...
+%
+% {\rmk \cs{ExpandNextTwo} is used in the final step of \cmdref{gettokslistindex} and \cmdref{getcharlistindex}.}
+%
+%
+% \cmditem{noexpandcs}{ csname }
+%
+% In an \FEI expansion context (|\edef|) we often want a control sequence whose name results
% from the expansion of some macros and/or other tokens to be created, but not expanded at that point.
% Roughly:§
% \qquad |\edef{\noexpandcs{<balanced text to be expanded as a cs-name>}}|§
@@ -363,505 +845,1550 @@ and etextools-examples.tex
% \smex |\edef\abc{\noexpandcs{abc@\@gobblescape\controlword}}|§
% \smex if equivalent to:\quad|\def\abc{\abc@controlword}|.
%
-% {\rmk|\noexpandcs| may be abbreviated f.ex. in |\`#1`| in |\edef| that take place in a group. }
+% {\hint|\noexpandcs| may be abbreviated f.ex. in |\"#1"| in |\edef| that take place in a group. }
%
-% \cmditem{noexpandafter}\cmdlabel{noexpandafter}\seeimpl{noexpandafter}
+% \cmditem{noexpandafter}
%
-% |\noexpandafter|\FE only means |\noexpand\expandafter| and is shorter to type.
+% |\noexpandafter|\FEI only means |\noexpand\expandafter| and is shorter to type.
%
% {\rmk This command is used in the definition of \cmdref{DeclareCmdListParser}.}
%
% \end{ltxsyntax}
%
-% \clearpage
-% \section{Characters and Strings}
+% \ClearPage*
+% \Section[Meaning of control sequences]{Meaning of control sequences -- determining their type.}
+%
+% \begin{ltxsyntax}
+%
+% \cmditem{showcs}{ csname }
+%
+% \cs{showcs}\FE does \cs{show} on the named control sequence.
+%
+% \cmditem{meaningcs}{ csname }
+%
+% \cs{meaningcs}\FEII gives the \cs{meaning} of the named control sequence. However, if the control sequence is
+% not defined, \cs{meaningcs} expands to |\meaning\@undefined| (\ie the word \CH{undefined}) rather than the expected |\relax|.
+%
+% \cmditem{strip@meaning}{ cs-token }
+% \cmditem*{strip@meaningcs}{ csname } \FEII*
+%
+% \csbf{strip@meaning}\FEII gives the \cs{meaning} of the \prm{cs-token}:
+% \begin{enumerate}[label=\roman*)~]
+% \item without the prefix `\,|macro:|\#1\#2...|->|)\,` ¤ if \prm{cs-token} is a macro
+% \item integrally if \prm{cs-token} is defined and is not a macro
+% \item expands to an empty string if \prm{cs-token} is undefined.
+% \end{enumerate}
+%
+% \cs{strip@meaningcs} does the same for named control sequences.
+%
+% \cmditem{parameters@meaning}{ cs-token }
+% \cmditem*{parameters@meaningcs}{ csname } \FEII*
+%
+% \csbf{parameters@meaning}\FEII expands to the part of the \cs{meaning} which corresponds
+% to the \textitbf{parameter string}. If a macro has no parameter, then it expands to an empty string.
+% If the \prm{cs-token} or the \prm{csname} given is not a macro, it also expands to an empty string.
+%
+% \newcommand*\mycell{\small\makecell[c]} \newcommand*\macpf{\vb macro:} \let\theadfont=\nbf
+% \hskip-1.5em\begin{tabular}{|>{\vb\cs{}}l|c|c|c|}\hline
+% \multicolumn{4}{c}{\textbfbf{to summarize}} \\ \hline
+% \omit&\omit&\omit&\omit \\[.3ex] \cline{2-4}
+% \multicolumn{1}{l|}{} & \thead{macro} & \thead{not macro} & \thead{undefined} \\ \hline
+% meaning & \mycell{the meaning \\ \eg \macpf[\#1]\#2->\#1\#2} & \mycell{the meaning \\ \eg \cs{count21}} & \vb undefined \\
+% meaningcs & \mycell{the meaning \\ \eg \macpf[\#1]\#2->\#1\#2} & \mycell{the meaning \\ \eg \cs{count21}} & \vb undefined \\\hdashline[1pt/1pt]
+% strip@meaning & \mycell{the replacement text \\ \eg \#1\#2} & \mycell{the meaning \\ \eg\cs{count21}} & an empty string \\
+% strip@meaningcs & \mycell{the replacement text \\ \eg \#1\#2} & \mycell{the meaning \\ \eg\cs{count21}} & an empty string \\\hdashline[1pt/1pt]
+% parameters@meaning & \mycell{the parameter string \\ \eg[\#1]\#2} & an empty string & an empty string \\
+% parameters@meaningcs & \mycell{the parameter string \\ \eg[\#1]\#2} & an empty string & an empty string \\ \hline
+% \end{tabular}
+% \medbreak
+%
+% \cmditem{ifdefcount}{ single token }{ true }{ false }
+% \cmditem*{ifdeftoks}{ single token }{ true }{ false } \FEII*
+% \cmditem[ifdefskip]@{ifdefdimen\tsptb ifdefskip\tsptb ifdefmuskip}
+% \cmditem-{ifdefdimen} {cs-token }{ true }{ false } \FEII*
+% \cmditem-{ifdefskip}{ single token }{ true }{ false } \FEII*
+% \cmditem-{ifdefmuskip}{ single token }{ true }{ false } \FEII*
+% \cmditem[ifdefchar]@{ifdefchar\tsptb ifdefmathchar}
+% \cmditem-{ifdefchar}{ single token }{ true }{ false } \FEII*
+% \cmditem-{ifdefmathchar}{ single token }{ true }{ false } \FEII*
+%
+% \xpackage{etoolbox}\FEII provides \cs{ifdefmaco} to test if a given control sequence is defined as a macro.
+% \thispackage provides tests for other types of tokens.
+%
+% Test is made by a filter on the meaning of the \prm{single token} given as argument. The test is always false
+% if this \prm{single token} is an undefined control sequence.
+% \iffalse
+% \cs{ifdefblankspace} will expand \prm{true} if the \prm{single token} is a blank space.§
+% \cs{ifdefthechar} will expand \prm{true} is the \prm{single token} has a meaning of the form: |the character|\stform[\blue]\textellipsis§
+% \cs{ifdeftheletter} will expand \prm{true} is the \prm{single token} has a meaning of the form: |the letter|\stform[\blue]\textellipsis§
+%
+% {\rmk \cs{ifdefcount} is used -- indirectly -- in the definition of \cmdref{getlistindex} and the other macros
+% for getting indexes: \cmdref{getcsvlistindex} etc.}
+% \fi
+% \ClearPage*
+%
+% \cmditem[avoidvoid]+@{avoidvoid \tsptb avoidvoidcs}
+% \cmditem-{avoidvoid} [ replacement code ]{ cs-token / string } \FEII*
+% \cmditem-{avoidvoid\stform*}[ replacement code ]{ cs-token / string } \FEII*
+%
+% \csbf{avoidvoid}\FEII will test the \prm{cs-token} with \cs{ifdefvoid} (from \xpackage{etoolbox}). In case
+% \prm{cs-token} is void (that means: it is either undefined or has been |\let| to |\relax| or it is a parameterless macro
+% with blank -- \ie empty or space -- replacement string), then \cs{avoidvoid} expands \prm{replacement code}
+% (optional parameter whose default is an empty string).
+%
+% Otherwise, \prm{cs-token} is not void (that means: it is defined, its meaning is not |\relax| AND it is either
+% a macro with parameters or a parameterless macro with a replacement string which is NOT blank)
+% then \cs{avoidvoid} expands \prm{cs-token}:§§
+% \begin{VerbLines}[commandchars=$()]
+% ($red\avoidvoid) {\@undefined} ($nnn will expand to an empty string)
+% ($red\avoidvoid) [($copper\macro)]\relax ($nnn will expand) ($md$copper\macro)
+% ($red\avoidvoid) [($copper$!$!$! string is blank)]{$spview} ($nnn will expand$vb$copper string is blank)
+% ($red\avoidvoid$stform*)[($copper$!$!$! string is empty)]{$spview} ($nnn will expand $spview)
+% ($red\avoidvoid) [($copper\errmessage{string must not be empty})]{some text}
+% ($nnn will expand$vb some text)
+% ($red\avoidvoid) [($copper\errmessage{macro is void$})]\macro
+% ($nnn will expand ($vb$copper\errmessage{...}) if ($vb\macro) is void)
+% \protected\def($dg\test){$spview}
+% \edef($copper\result){($red\avoidvoid$stform*)($dg\test)}
+% \meaning($copper\result) macro:->($dg\test) ($nnn1-expansion of ($dg\test) not empty)
+% \edef($copper\result){($red\avoidvoid)[other]($dg\test)}
+% \meaning($copper\result) macro:->other ($nnn1-expansion of ($dg\test) is blank)
+% \end{VerbLines}
+%
+% \cs{avoidvoid} is based on \cs{ifblank} test, either onto \prm{string} or, if \prm{string} is in fact a
+% control word (tested with \cmdref{ifiscs}) on the replacement text of this control word\footnote{if it is defined
+% as a macro. Well: the test occurs on the result of \cmdref{strip@meaning} onto the control-sequence!}. If for your
+% special purpose, you prefer to test if the \prm{string} (or the replacement text of \prm{cs-token}) is \textbfsf{really empty
+% and not only blank}, the \stform* star-form of \cs{avoidvoid} is made for you!
+%
+% \cs{avoidvoid} is purely expandable and uses \cmdref{FE@ifstar} and \cmdref{FE@testopt}:
+% if the mandatory argument is a \prm{string} equal to \CH{\stform[\blue]*$__{12}$} or \CH{\stform[\blue][$__{12}$}^^A]
+% there will be a problem (and most probably an error). Therefore, \textbfsf{when using \csbf{avoidvoid} you are encourage to
+% specify always an option, even if it is empty.}
+%
+% \cmditem-{avoidvoidcs} [ replacement code ]{ csname } \FEII*
+% \cmditem-{avoidvoidcs\stform*}[ replacement code ]{ csname } \FEII*
+%
+% \csbf{avoidvoidcs}\FEII will do the same as the former (\cs{avoidvoid}) but the mandatory argument \prm{csname}
+% is interpreted as a control sequence name.
+% Therefore, \textbfsf{you cannot test a \textvbbf{string} with \csbf{avoidvoidcs}!}§§
+% \begin{VerbLines}[commandchars=$()]
+% ($red\avoidvoidcs){@undefined} ($nnn will expand to an empty string)
+% ($red\avoidvoidcs)[\deblank]{zap@space} ($nnn will expand to $cs(zap@space))
+% \def($dg\test){This is a test}
+% ($red\avoidvoidcs)[($copper\errmessage{void macro})]{test}
+% ($nnn will expand) $dg\test
+% ($red\avoidvoidcs)[($copper\errmessage{void macro})]{($dg\test)}
+% ($nnn will expand) ($md$copper\errmessage{void macro})
+% ($nnn this is because) \csname This is a test\endcsname($nnn is not defined !)
+% ($nbf Finally, clever !)
+% \protected\def($dg\test){$spview}
+% ($red\avoidvoidcs) [other]{test} ($nnn will expand) other ($nnn: $cs(test) is void)
+% ($red\avoidvoidcs*)[other]{test} ($nnn will expand) ($dg\test) ($nnn: $cs(test) is not $cs(@empty))
+% ($red\avoidvoidcs) [other]($dg\test) ($nnn will expand) \ ($nnn: control space, which is not void)
+% ($red\avoidvoidcs*)[other]($dg\test) ($nnn will expand) \ ($nnn: control space, which is not void)
+%\end{VerbLines}
+%
+% \end{ltxsyntax}
+% \ClearPage*
+%
+% \Section{Single tokens/single characters}
+%
+% A single token is either a control word (that means a caracter of category $0$ followed by caracters of category $11$)
+% or a single character with a valid category code (\ie $\ne 15$ and $\ne 9$).
+%
+%
+% \Subsection{The \cs{ifx} test and the character test}
+% \cmdlabel{character-test}
+%
+% When dealing with single tokens, we need an \emph{equality-test} macro that expands to |\@firstoftwo| in case of
+% equality and |\@secondoftwo| in case of inequality.
+%
+% \thispackage implements two such \textbfsf{\slshape equality-test macros}:
+%
+% \begin{enumerate}[label={\blue\arabic*)~}]
+% \item The \csbf[\blue]{ifx} test: is the standard test for tokens:\\
+% \null¤¤\prm{tokenA} is equal to \prm{tokenB} if:¤¤ {\rred\cs{ifx}\PRM[\black]{tokenA}\PRM[\black]{tokenB}}¤ returns \textbf{true}\\
+% {\rmk* The \csbf{ifx} test is implemented in \cmdref*{ettl@ifx}.}
+% \item The \textbfsf{\blue character test} is a bit more sophisticated and works as follow:§
+% \begin{enumerate}[label=\roman*)~,labelwidth=1em]
+% \item if \prm{tokenA} and \prm{tokenB} have the same category code (tested with an unexpandable |\ifcat|):\\
+% \prm{tokenA} is equal to \prm{tokenB} if:¤¤ {\rred\cs{ifx}\PRM[\black]{tokenA}\PRM[\black]{tokenB}}¤ returns \textbf{true}
+% \item otherwise:\\
+% \prm{tokenA} is equal to \prm{tokenB} if:¤{\rred\cs{if}\cs{noexpand}\PRM[\black]{tokenB}\cs{string}\PRM[\black]{tokenA}}\\
+% \null\hphantom{\prm{tokenA} is equal to \prm{tokenB} if:¤¤ {\rred\cs{ifx}\PRM[\black]{tokenA}\PRM[\black]{tokenB}}¤} returns \textbf{true}
+% \end{enumerate}\vskip-\parskip
+% {\rmk* The \textbfsf{character test} is implemented in \cmdref*{ettl@ifchar} and its behaviour may be tested with \cmdref{ifsinglechar}.}
+% \end{enumerate}
+%
+% \Subsection.{Basic test macros}
+%
+% \begin{ltxsyntax}
+%
+% \cmditem[ifsingletoken]+@{ifsingletoken\db~\tsptb ifOneToken}
+% \cmditem-{ifsingletoken}{ single token }{ code }{ true }{ false }
+%
+% \csbf{ifsingletoken}\FE expands to \prm{true} only if \textsfbf{\prmb{code} is a single token and is equal
+% to \prmb{single token} in the sense of \cs{ifx}.}
+%
+% \cs{ifsingletoken} is a \textbfsf{safe \cs{ifx} test}: \prm{code} may be anything (including |\if| conditionals,
+% even not properly closed):§§
+% \begin{VerbLines}[commandchars=$()]
+% ($red\ifsingletoken){A}{A} $nnn will expand $prmb(true)
+% ($red\ifsingletoken){\else}{($blue$textvisiblespace)\else}$nnn will expand $prmb(false)
+% ($red\ifsingletoken){($blue$textvisiblespace)}{($blue$textvisiblespace)} $nnn will expand $prmb(true)
+% ($red\ifsingletoken){\ifx}{\else D\fi} $nnn will expand $prmb(false)
+% ($red\ifsingletoken){}$mprm( whatever ) $nnn will expand $prmb(true) only if $prmb(whatever) is empty !!
+% $md$dg \begingroup\catcode`\: 13\global\def($copper\test){:}\endgroup \catcode`\: 12
+% \expandnext($red\ifsingletoken){($copper\test)}{:} $nnn will expand $prmb(false)
+%$nnn$!$!$!now clever !
+% $md$dg\begingroup\catcode`\: 13 \global\let$stform[$blue]:=\fi \gdef($copper\test){($red\ifsingletoken) $stform[$blue]:}
+% $md$dg\endgroup
+% ($copper\test)\fi$mprm(true)$mprm(false) $nnn will expand $prmb(true)
+% \end{VerbLines}
+%
+% Be aware that \prm{single token} (the first parameter) must be a single token (or empty, but then the test is always false unless \prm{code} is empty).
+%
+% \ClearPage
+% \cmditem-{ifOneToken}{ code }{ true }{ false }
+%
+% \csbf{ifOneToken}\FEII expands to \prm{true} if \textbfsf{\prmb{code} is a single token}. \prm{code} may be
+% anything (including |\if| conditionals, even not properly closed):§§
+% \begin{VerbLines}[commandchars=$()]
+% ($red\ifOneToken){\relax}{($blue$textvisiblespace)\relax} $nnn will expand $prmb(false)
+% ($red\ifOneToken){\relax}{\relax($blue$textvisiblespace)} $nnn will expand $prmb(true)
+% ($red\ifOneToken){A}{A($blue$textvisiblespace)} $nnn will expand $prmb(false)
+% ($red\ifOneToken){\ifx AB C\else D\fi} $nnn will expand $prmb(false)
+% ($red\ifOneToken){C\else D\fi} $nnn will expand $prmb(false)
+% \end{VerbLines}
+%
+% {\rmk \cs{ifOneToken} is used in the definition of \cmdref{FE@modifiers}.}
+%
+% \ClearPage*
+% \cmditem[ifsinglechar]+@{ifsinglechar~\db\tsptb ifOneChar}
+% \cmditem-{ifsinglechar}{ single token }{ string }{ true }{ false }
+%
+% \csbf{ifsinglechar}\FEII expands to \prm{true} only if \textbfsf{\prmb{string} is a single token and is equal
+% to \prmb{single token} in the sense of the \cmdref={character-test}.}
+%
+% \cs{ifsinglechar} is a \textbfsf{safe \slshape character-test}: \prm{string} may be anything (including |\if| conditionals,
+% even not properly closed):§§
+% \begin{VerbLines}[commandchars=$()]
+% ($red\ifsinglechar){A}{A} $nnn will expand $prmb(true)
+% ($red\ifsinglechar){A}{($blue$textvisiblespace)A} $nnn will expand $prmb(false)
+% ($red\ifsinglechar){($blue$textvisiblespace)}{($blue$textvisiblespace)} $nnn will expand $prmb(true) (no matter the number of spaces)
+% ($red\ifsinglechar){\ifx}{\ifx\test\relax YES\else NO\fi} $nnn will expand $prmb(false)
+% ($red\ifsinglechar){}$mprm( whatever )$nnn will expand $prmb(true) only if $prmb(whatever) is empty
+% ($red\ifsinglechar){\scantokens}{\scantokens} $nnn will expand $prmb(true)
+% $vbmd$dg\begingroup\catcode`\: 13\global\def($copper\test){:}\endgroup \catcode`\: 12
+% \expandnext($red\ifsinglechar){($copper\test)}{:} $nnn will expand $prmb(true)
+%$nnn$!$!$!now clever!
+% \catcode`\$stform[$blue]: \active \let$stform[$blue]:=\fi
+% \def($copper\test){($red\ifsinglechar)$stform[$blue]:}
+% \let:=\else
+% ($copper\test):$mprm(true)$mprm(false) $nnn will expand $prmb(true)
+% ($copper\test)\fi$mprm(true)$mprm(false) $nnn will expand $prmb(false)
+% ($copper\test)\else$mprm(true)$mprm(false) $nnn will expand $prmb(false)
+% \end{VerbLines}
+%
+% {\rmk \cs{ifsinglechar} is used in the definition of \cmdref{FE@ifchar}.}
+%
+% \cmditem-{ifOneChar}{ string }{ true }{ false }
+%
+% \csbf{ifOneChar} \FEII expands to \prm{true} if \textbfsf{\prmb{string} is a single character}.
+%
+% \textbfsf{\prmb{string} is detokenized} before the test (therefore, |\relax| for example does not contain a single \textsfsl{character}):§§
+% \begin{VerbLines}[commandchars=$\[\]]
+% [$red\ifOneChar]{A} $nnn will expand $prmb[true]
+% [$red\ifOneChar]{[$blue$textvisiblespace]A} $nnn will expand $prmb[false]
+% [$red\ifOneChar]{A[$blue$textvisiblespace]} $nnn will expand $prmb[false]
+% [$red\ifOneChar]{[$blue$textvisiblespace]} $nnn will expand $prmb[true] (even if there are many spaces !)
+% [$red\ifOneChar]{} $nnn will expand $prmb[false]
+% [$red\ifOneChar]{\relax} $nnn will expand $prmb[false] ($cs[relax] is detokenized)
+% [$vbmd$dg\let\ZERO=0]
+% [$red\ifOneChar]{\ZERO} $nnn will expand $prmb[false] ($cs[ZERO] is detokenized)
+% \end{VerbLines}
+%
+% {\rmk \cs{ifOneChar} is used in \cmdref{detokenizeChars} }
+%
+% \cmditem-{ifOneCharWithBlanks}{ string }{ true }{ false }
+%
+% \csbf{ifOneCharWithBlanks}\FEII switches to \prm{true} if and only if \prm{string} contains a single \textsfbf{character}
+% possibly with blank spaces before and/or after. It's an optimisation of:§
+% \qquad|\ExpandNext\ifOneChar{\expandnext\deblank{\detokenize{|\prm{string}|}}}|
+%
+% If \prm{string} contains \textbfsf{only spaces}, \cs{ifOneCharWithBlanks} expands \prmb{false}.
+%
+% \cmditem{iffirstchar}{ string1 }{ string2 }{ true }{ false }
+%
+% \csbf{iffirstchar}\FEII compares the character codes of the \textbf{first} characters of each \prm{string}. The
+% comparison is \emph{catcode agnostic} and the macro is fully expandable. Neither \prm{string1} nor \prm{string2}
+% is expanded before comparison. Example:§
+% \qquad|\iffirstchar *{*hello*}{begins with a star}{begins with something else}|
+%
+% Alternatively, you may use the \cmdref{ifstrmatch} test.
+%
+% \qquad|\iffirstchar|\mprm{}\mprm{whatever}¤expands\prmb{true} only if \prmb{whatever} is empty.
+%
+% \ClearPage*
+% \cmditem+{ifiscs}{ string }{ true }{ false }
+%
+% \csbf{ifiscs}\FEII will expand \prmb{true} only \textbfsf{if \prmb{string} is a single control word.} \prm{string}
+% may be anything, including \cs{if}-conditional, even not properly closed:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\ifiscs){\MyMacro} !nnn will expand !prmb(true)
+% (!red\ifiscs){x} !nnn will expand !prmb(false) !textemdash even if x is active
+% (!red\ifiscs){\ifx AB C\else D\fi} !nnn will expand !prmb(false)
+% (!red\ifiscs){(!blue!textvisiblespace)\else} !nnn will expand !prmb(false)
+% (!red\ifiscs){\else(!blue!textvisiblespace)} !nnn will expand !prmb(true)
+% (!red\ifiscs){(!blue!textvisiblespace)} !nnn will expand !prmb(false)
+% (!red\ifiscs){\@sptoken} !nnn will expand !prmb(true)
+% (!red\ifiscs){} !nnn will expand !prmb(false)
+% (!dg!md\let\ALPHA=A)
+% (!red\ifiscs){\ALPHA} !nnn will expand !prmb(true)
+% \end{VerbLines}
+%
+% \cs{ifiscs} is an optimized form of: ``\cs{ifOneToken} AND NOT \cs{ifOneChar}''.
+%
+% {\rmk \cs{ifiscs} is used in the definition of the \cmdref=[DeclareCmdListParser]{command-list parsers}.}
+%
+% \cmditem{detokenizeChars}{ list of single tokens }
+%
+% \csbf{detokenizeChars}\FE will selectively detokenize the tokens in \prm{list of single tokens}. That means: single
+% characters (tested with \cmdref{ifOneChar}) are detokenized while control sequences are not detokenized:§§
+% \begin{VerbLines}[commandchars=!()]
+% \edef(!copper\result){(!red\detokenizeChars){!blue*+=!spview[!black]$@(!dg\relax\else);}}
+% (!copper\result): !chcat*(12)!chcat+(12)!chcat=(12)!chcat(!spview)(10)!chcat$(12)!chcat@(12)(!dg\relax\else)!chcat;(12)
+% \end{VerbLines}
+%
+% {\rmk \cs{detokenizeChars} is used in the normal form of \cmdref{futuredef}.}
+%
+% \cmditem{protectspace}{ code }
+%
+% \csbf{protectspace}\FEII will protect the spaces in \prm{code}, replacing spaces by a space surrounded by braces:§§
+% \setbox\helpbox\hbox{\texthl{\spview[\red]}} \setbox\helpboxx\hbox{\hl{\hbox{\{\spview[\red]\}}}}
+% \begin{VerbLines}[commandchars=$()]
+% \def($copper\test){abc$hpbox$hpbox$!$!$! def\else\relax\fi ghi$hpbox$hpbox$!$!$! j$hpbox}
+% \edef($dg\result){\unexpanded\expandafter\expandafter\expandafter{%
+% ($red\protectspace){($copper\test)}}}
+% \meaning($dg\result): macro:->abc$hpboxx$!$!$! def\else \relax \fi ghi$hpboxx$!$!$! j$hpboxx
+% \end{VerbLines}
+%
+% N.B.: there is no space after |\fi| in the definition of \cs[\copper]{test}...
+%
+% {\rmk \cs{protectspace} is used in \cmdref{detokenizeChars}.§
+% \cs{protectspace} is an example of a \textbf{recursive macro which is 2-purely expandable. }}
+%
+% \end{ltxsyntax}
+%
+% \Section{Characters and Strings}
%
% \begin{ltxsyntax}
%
-% \cmditem{ifempty}{string}{true}{false} \cmdlabel{ifempty} \seeimpl{ifempty}
+% \cmditem+{ifempty}{ string }{ true }{ false }
%
-% |\ifempty|\FE is similar to |\ifblank| but it test if a string is really empty
+% \csbf{ifempty}\FEII is similar to |\ifblank| but it test if a string is really empty
% (it shall not contain any character nor spaces). To test if the replacement
% text of a macro is empty, one may use |\ifempty| in conjunction with \cmdref{expandnext}:
+%
% \begin{tabbing}
% \quad\=|\expandnext\ifempty{\macro}| \prm{true}\prm{false}
% \end{tabbing}
%
% |\ifempty| is based on |\detokenize| and accept anything in its argument.
%
+% {\rmk This is NOT: |\expandafter\ifx\expandafter\relax\detokenize{\#1}\relax| !}
%
-% \cmditem{xifempty}{string or cs-token}{true}{false} \cmdlabel{xifempty} \seeimpl{xifempty}
+% \cmditem{xifempty}{ string or cs-token }{ true }{ false }
%
% |\xifempty|\pdfFE is similar to |\ifempty| but the argument is expanded during comparison.
%
% \begin{tabbing}
% \quad\=|\def\x{\@empty}\def\y{}| \\
-% \>|\xifempty{\x\y}| \prm{true}\prm{false}
+% \>|\xifempty{\x\y}| \prm{true}\prm{false}¤¤ will expand \prm{true}
% \end{tabbing}
%
-% {\rmk The macro is based on the \cs{pdfstrcmp} primitive.}
+% {\rmk If pdf\TeX{} is in use, the macro is based on the \cs{pdfstrcmp} primitive.}
%
-% \cmditem{ifnotempty}{string}{true}{false} \cmdlabel{ifnotempty}\seeimpl{ifnotempty}
+% \cmditem{ifnotempty}{ string }{ true }{ false }
%
-% |\ifnotempty|\FE reverses the test of |\ifempty|
+% \csbf{ifnotempty}\FEII reverses the test of |\ifempty|.
%
%
-% \cmditem{xifblank}{string}{true}{false} \seeimpl{xifblank}
+% \cmditem{xifblank}{ string }{ true }{ false }
%
-% |\xifblank| is similar to |\ifblank| except that the \prm{string} is first expanded
-% with |\protected@edef|.
-% \medbreak
+% |\xifblank|\notFE\\ is similar to |\ifblank| except that the \prm{string} is first expanded
+% with \cs{protected@edef}.
%
-% \cmditem{iffirstchar}{string1}{string2}{true}{false} \cmdlabel{iffirstchar}\seeimpl{iffirstchar}
-% \cmditem*{iffirstchar}{}{string}{true}{false}
+% \cmditem{ifnotblank}{ string }{ true }{ false }
%
-% |\iffirstchar| \FE compares the character codes of the \textbf{first} characters of each \prm{string}. The
-% comparison is \emph{catcode agnostic} and the macro is fully expandable. Neither \prm{string1} nor \prm{string2}
-% is expanded before comparison. Example:§
-% \qquad|\iffirstchar *{*hello*}{begins with a star}{begins with something else}|
+% \csbf{ifnotblank} \FEII reverses the test of |\ifblank|.
%
-% Alternatively, you may use the \cmdref{ifstrmatch} test.
+% {\rmk |\ifnotblank| is a foundamental of purely expandability. It is extensively used in \thispackage
+% but in an optimized form: \cmdref[impl:ettl@nbk]{ettl@nbk}.}
%
-% There is a ``special'' use of this command when one want to test if a \prm{string} begins
-% with an \emph{escape} character (\,\textbackslash\,) one may say:
-% \begin{tabbing}
-%\qquad\= |\iffirstchar \@backslashchar{|\prm{string}|}|\qquad\= or even easier:\\
-% \>|\iffirstchar {}{|\prm{string}|}|
-% \end{tabbing}
%
-% Please note that the tests:
-% \begin{tabbing}
-% \qquad\qquad\=|\iffirstchar |\=|{|\prm{whatever string1 is}|}{}|\\
-% and:\>|\iffirstchar |\>|{}{}|
-% \end{tabbing}
-% are \textbf{always expanded into \underline{\prm{false}}}
-% (for consistency with the shortcut-test for |\@backslashchar|).\medbreak
+% \cmditem+{deblank}{ string }
%
-% \cmditem{ifsinglechar}{string1}{string2}{true}{false} \cmdlabel{ifsinglechar}\seeimpl{ifsinglechar}
+% |\deblank|\FEII removes all leading and trailing blank spaces from its argument.\medbreak
%
-% |\ifsinglechar|\FE performs the test |\iffirstchar| but only if \prm{string2} has one single character.
+% An application is for the normalisation of comma separated lists:§§
+% \begin{VerbLines}[commandchars=!()]
+% \csvloop!stform*[(!red\deblank)]{ item1 , item2 , item3
+% , item4 , item5 ,item6 ,
+% item7 , item8}%
+% !nnn will normalize the list:§
+% {item1,item2,item3,item4,item5,item6,item7,item8}
+% \end{VerbLines}
%
-% Note that there is a small difference if you run on pdf\TeX{} or on another system:§
-% \DeleteShortVerb{\|}
-% \hfil
-% \begin{tabular}{|c|c|}\hline
-% pdf\TeX{} (use \cs{pdfstrcmp}) & Other \\ \hline
-% \cs{ifsinglechar} *\{\textvisiblespace*\} is \textbf{false} & \cs{ifsinglechar} *\{\textvisiblespace*\} is \textbf{true} \\ \hline
-% \end{tabular}\hfil
+% This construction is purely expandable:§
+% \qquad |\edef\result{|\cmdref{csvloop}|[|\cs[\red]{deblank}|]{|...|}}|§
+% will normalize the list and assign the result to the replacement text of \cs{result}.
%
-% \MakeShortVerb{\|}
-% But: \cs{ifsinglechar} *\{*\textvisiblespace\}\quad is \textbf{always false}.
+% For more on normalisation, refer to the \Xpackage{kvsetkeys}\footnote{\xpackage{kvsetkeys}-normalisation also
+% include a replacement of \CH{,} and \CH{=} to ensure that their category code are 12.} package.
+%
+%
+% \cmditem{ifstrcmp}{ string1 }{ string2 }{ true }{ false }
+%
+% \csbf{ifstrcmp}\pdfFE is based on the |\pdfstrcmp| primitive (or the XeTeX-|\strcmp|) if available. Otherwise,
+% |\ifstrcmp| is |\let| to \xpackage{etoolbox}-\cs{ifstrequal}.
+%
+% Neither \prm{string1} nor \prm{string2} is expanded during comparison. The comparison is
+% \emph{catcode agnostic} (use of |\detokenize |).
+%
+% \cmditem{xifstrequal}{ string1 }{ string2 }{ true }{ false }
+%
+% |\xifstrequal|\notFE\ is the same as \xpackage{etoolbox}-|\ifstrequal| apart that each parameter string is expanded
+% (with |\protected@edef|) before comparison.
+%
+% \cmditem{xifstrcmp}{ string1 }{ string2 }{ true }{ false }
+%
+% |\xifstrcmp|\pdfFE is the \LaTeX{} form of |\pdfstrcmp| primitive. If this primitive is not available,
+% |\xifstrcmp| is |\let| to |\xifstrequal|.
%
+% \prm{string1} and \prm{string2} are expanded during comparison.
%
-% \cmditem{iflastchar}{string1}{string2}{true}{false} \cmdlabel{iflastchar}\seeimpl{impl:iflastchar}
+% \cmditem[ifcharupper]@{ifcharupper\tsptb ifcharlower}
+% \cmditem-{ifcharupper}{ single char }{ true }{ false }
+% \cmditem-{ifcharlower}{ single char }{ true }{ false } \FEII*
%
-% |\iflastchar| compares the end of \prm{string2} with the totality of \prm{string1} (\prm{string1} is not
-% necessarily a single character but the macro has been designed for this purpose first, hence the name).
+% \csbf{ifcharupper}\FEII compares with |\ifnum| the character code of \prm{single char} with its |\uccode|.
%
-% |\iflastchar| is NOT purely expandable (use \cmdref{ifstrmatch} for purely expandable test).
+% \csbf{ifcharlower} compares with |\ifnum| the character code of \prm{single char} with its |\lccode|.
%
+% \cmditem{ifuppercase}{ string }{ true }{ false }
+% \cmditem-{iflowercase} {string }{ true }{ false }
%
-% \cmditem{ifstrcmp}{string1}{string2}{true}{false} \cmdlabel{ifstrcmp}\seeimpl{ifstrcmp}
+% \csbf{ifuppercase}\notFE\ compares the \prm{string} with |\uppercase{|\prm{string}|}|.
%
-% |\ifstrcmp|\pdfFE is the \LaTeX{} form of |\pdfstrcmp| primitive.
+% \csbf{iflowercase} compares the \prm{string} with |\lowercase{|\prm{string}|}|.
%
-% Neither \prm{string1} not \prm{string2} is expanded during comparison. The comparison is
-% \textit{catcode agnostic} (use of |\detokenize |).
+% The commands are robust.
%
-% \cmditem{ifstrmatch}{pattern}{string}{true}{false} \cmdlabel{ifstrmatch}\seeimpl{ifstrmatch}
+% \cmditem{ifstrmatch}{ pattern }{ string }{ true }{ false }
%
-% |\ifstrmatch|\pdfFE is based on the |\pdfmatch| primitive that implements POSIX-regex.
+% \csbf{ifstrmatch}\pdfFE is based on the |\pdfmatch| primitive that implements POSIX-regex.
%
% You can test the last character of a string in a purely expandable way by:
% \begin{tabbing}
% \quad\=\cs{ifstrmatch}\{[\textasteriskcentered]\$\}\{\prm{string}\}
% \end{tabbing}
-% for example to test \raise2pt\hbox{\textasteriskcentered}.
+% for example to test \CH{\textasteriskcentered} at the end of a string.
+%
+% \ClearPage
+% \cmditem{ifstrdigit}{ string }{ true }{ false }
+%
+% \csbf{ifstrdigit}\FEII expands to \prm{true} if \prm{string} is a single digit.
+%
+% A \emph{single digit} is $0,1,2,3,4,5,6,7,8$ or $9$ without spaces around, no matter of the category code.
+%
+% \ClearPage
+% \cmditem+{ifstrnum}{ string }{ true }{ false }
+%
+% \csbf{ifstrnum}\FEII expands to \prm{true} if \prm{string} is a \textbfsf{number in the sense of \eTeX}, that means:
+%
+% \qquad|\number|\prm{string}\qquad will be the same as:\qquad|\deblank|\mprm{string}
+%
+% under the standard catcode regime, if \prm{string} is a positive integer.
+%
+% in other words:§§
+% \begin{VerbLines}[commandchars=!()]
+% \edef(!copper\resultA){(!red\number)(!nnn!prm(string))}
+% \edef(!dg\resultB){(!red\deblank)(!nnn!mprm(string))}
+% \ifx(!copper\resultA)(!dg\resultB) !nnn will be !nbf true
+% \end{VerbLines}
+%
+% \prm{string} must be of the form:¤{\Large{\blue\textvisiblespace--\textvisiblespace--\textvisiblespace}{\red$\mathbf{\star\star\star}$}{\blue\textvisiblespace}}\par
+% \hfil where {\blue blue} is optional (one ore more spaces and/or minus signs)\hfil§
+% \hfil {\red$\mathbf{\star\star\star}$} denotes 1 or more digit(s) without spaces around\hfil§
+% for \cs{ifstrnum} to expand to \prm{true}.
+%
+% To tell all the truth, \cs{ifstrnum} expands \prm{true} even if digits have a category code$\neq 12$ whereas
+% |\number| throws an error or stops.
+% But if numbers and minus signs are of category 12 (more than recommended after all...) \cs{ifstrnum} may be
+% a test to check if it is possible to expand |\number| (or |\romannumeral|) onto \prm{string}.
+% \bigbreak
+%
+% \ClearPage
+% \cmditem+{DeclareStringFilter}[\cs{global}]{ command-name }{ stringA }
+% \newcommand\myitem[1]{\item[\hss{\stform[\rred\large]{#1}}\hss]} \newcommand*\interitem{\item[]\hskip-\leftmargin}
+%
+% With \csbf{DeclareStringFilter}\notFE, you will define \textbf{a purely expandable command} designed to test
+% if a string:
+% \begin{itemize}[labelsep=2em,leftmargin=5em]
+% \myitem= is is \textbfsf{equal} to a \textsl{given} string \prm{stringA} (with possibly spaces before and after)
+% \myitem{==} is \textbfsf{strictly equal} to a \textsl{given} string \prm{stringA} (no spaces allowed)
+% \myitem< \textbfsf{begins with} \prm{stringA} (possibly with leading spaces)
+% \myitem{<=} \textbfsf{strictly begins with} \prm{stringA} (no leading spaces allowed)
+% \myitem> \textbfsf{ends with} \prm{stringA} (possibly with trailing spaces)
+% \myitem{>=} \textbfsf{strictly ends with} \prm{stringA} (no trailing spaces allowed)
+% \myitem? \textbfsf{contains} \prm{stringA}, and optionally how many times
+% \interitem and also your \textitbf{\sffamily string-filter} will be able to
+% \myitem\textendash \textbfsf{remove} \prm{stringA} from any string $0$, $1$ or more times\\
+% ¤¤(maximum = |\ettl@intmax|$ = 2^{13}-1 = $\numprint{2147483647})
+% \myitem+ \textbfsf{replace} \prm{stringA} by any other string $0$, $1$ or more times
+% \myitem! \textbfsf{count} the number of occurences of \prm{stringA} in any string
+% \end{itemize}
+%
+% {\hfill\mycolorbox{\bf Equality is \CSbf{catcode} dependent.}\hfill}
+%
+% You may also check that \prm{stringA} may be a blank space (but as for now, you cannot
+% replace blank spaces at the end of the string...).
+% \ClearPage*\newcommand\¤[1][]{\textcolor{blue}{\bfseries{\vbbf\textvisiblespace}#1}}
+%
+% Let's see how this works (\¤\ is zero or more spaces):§§\enlargethispage{5\baselineskip}
+% \def\YES{\textcolor{blue}{\bfseries YES}} \newcommand\bigskipneg{\vskip-8pt}
+% \def\YYESS{\¤[YES]\¤}
+% \def\YYES{\¤[YES]}
+% \def\YESS{\textcolor{blue}{\bfseries YES}\¤}
+% \let\verbatimfont\tt
+% \begin{VerbLines}[commandchars=$(),fontseries=b]
+% ($red\DeclareStringFilter)($copper\CompareYES){$YES} ($nnn defines $CSbf(CompareYES))
+% ($nnn$csbf(CompareYES) is the ($itbf$sffamily string-filter) for the string "$YES" $quad$smex $prm(stringA))
+%
+% ($copper\CompareYES) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string) $nbf is "$YYESS")
+% ($copper\CompareYES)($rred$large=) $mprm(string)$mprm(true)$mprm(false)($nnn is the same)
+% ($copper\CompareYES)($rred$large=.)$mprm(string)$mprm(true)$mprm(false)($nnn is also the same)
+% ($copper\CompareYES)($rred$large==)$mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf is "$YES")
+%
+% ($copper\CompareYES)($rred$large<) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf begins with "$YYES")
+% ($copper\CompareYES)($rred$large<=)$mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf begins with "$YES")
+%
+% ($copper\CompareYES)($rred$large>) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf ends with "$YESS")
+% ($copper\CompareYES)($rred$large>=)$mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf ends with "$YES")
+%
+% ($copper\CompareYES)($rred$large?) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf contains "$YES")
+% ($copper\CompareYES)($rred$large?[($itbf$!$!$! n)])$mprm(string)$mprm(true)$mprm(false)$nnn expands $prm(true) if $prm(string)
+% $hfill$nbf contains "$YES" more than($itbf n) times
+%
+% ($copper\CompareYES)($rred$large-) $mprm(string) $nbf removes all occurences $nnn of "$YES" in $prm(string)
+% ($copper\CompareYES)($rred$large-[($itbf$!$!$! n)])$mprm(string) $nbf removes at most($itbf n) occurences $nnn of "$YES"
+%
+% ($copper\CompareYES)($rred$large+) $mprm(string)$mprm(stringB) $nbf replaces all occurences
+% $hfill$nbf of "$YES" by $prm(stringB) in $prm(string)
+% ($copper\CompareYES)($rred$large+[($itbf$!$!$! n)])$mprm(string)$mprm(stringB) $nbf replaces at most($it n) occurences
+% $hfill$nbf of "$YES" by $prm(stringB) in $prm(string)
+% ($nnn And finally:)
+% ($copper\CompareYES)($rred$large!){$prm(string)} $nnn expands to($nbf the number of times "$YES") can be found in $prm(string)
+% $negqquad$negqquad$negqquad($red\edef)\result{($copper\CompareYES)($red+[2]){($mdseries$!She never says YES but he says YES to everything. YES...}{NO})}
+% $negqquad$negqquad$negqquad($red\meaning)\result: macro:->She never says NO but he says NO to everything. YES...
+% \end{VerbLines}
+%
+% \let\verbatimfont\verbfont
+% A problem may arise if the \prm{string} to compare is the string \CH{\vbbf\blue=}, because purely expandable
+% tests for modifiers don't make difference between \CH{=} and \CH{\{=\}}. To avoid this problem,
+% you may say {\vbbf\red=.} or {\vbbf\red>.} or {\vbbf\red>.} instead of {\vbbf\red=}, {\vbbf\red>} and {\vbbf\red<}.
+%
+% All the same, you may say {\vbbf\red?.}, {\vbbf\red+.} and {\vbbf\red-.} to avoid problems if the \prm{string} is \CH{\stform[\blue][}.^^A]
+%
+% {\rmk \cs{CompareYES} and each of its form are purely expandable thank to \cmdref{FE@modifiers}.}
+%
+% You should not test a \prm{string} which contains the following sequence:§
+% \hfill\colorbox{ly}{$/__3$E$__{11}$n$__{11}$d$__{11}\S__8$S$__{11}$t$__{11}$r$__{11}$i$__{11}$n$__{11}$g$__{11}/__3$}\hfill\kern0pt\par
+%
% \end{ltxsyntax}
%
-% \section{Fully expandable macros with options}
-% \vskip-\baselineskip
-% Now with the macro |\ifsinglechar| it becomes possible to write fully expandable macros with an option, \textbf{provided
-% that this macro has at least one non-optional argument}, as far as we don't use |\futurelet| nor any assignation.
-% The ``trick'' is the following:
-% \begin{tabbing}
-% \qquad\= |\def\MacroWithOption#1{\ifsing|\=|lechar|\=|[{#1}| \\
-% \>\>|{\MacroHasOption[}| \\
-% \>\>|{\MacroNoOption{#1}}}}|\\
-% \> |\def\MacroHasOption[#1]#2|... \>\textit{definition} \\
-% \> |\def\MacroNoOption#1|...\>\textit{definition}
-% \end{tabbing}
+% \ClearPage*
%
-% Moreover (in the style of |\@testopt|):
-% \begin{tabbing}
-% \qquad\= |\def\MacroWithOption#1{\ifsing|\=|lechar|\=|[{#1}|\\
-% \>\>|{\MacroHasOption#1}|\\
-% \>\>|{\MacroHasOption[default]{#1}}}|
-% \end{tabbing}
+% \Section{Fully expandable macros with options and modifiers}
+%
+% With \cs{ifblank} and \cs{ifempty} which are purely expandable macros, it becomes possible to write fully expandable
+% macros with an option, \textbf{provided that this macro has at least one non-optional argument},
+% as far as we don't use |\futurelet| nor any assignment.
%
% \begin{ltxsyntax}
%
-% \cmditem{FE@testopt}{argument to be tested}{commands}{default option} \cmdlabel{FE@testopt}\seeimpl{FE@testopt}
+% \cmditem{FE@testopt}{\#1}{ commands }{ default option }
%
-% |\FE@testopt|\FE mimics the behaviour of |\@testopt| but is Fully Expandable (\sty{FE}) and can be used as follow:§
-% \qquad |\def\MacroWithOption#1{\FE@testopt{#1}\MacroHasOption{default}}|\par
+% \csbf{FE@testopt}\FE mimics the behaviour of |\@testopt| but is Fully Expandable (\sty{FE}) and can be used as follow:§§
+% \begin{VerbLines}[commandchars=!()]
+% \def(!copper\MacroWithOption)!#1{(!red\FE@testopt){!#1}\MacroHasOption{default}}
+% \end{VerbLines}
%
-% Note that |\MacroWithOption| \textbf{must have at least one mandatory argument.}\medbreak
+% \textbfsf{Limitation:} \cs{FE@testopt} will look for an option if \#1 is \CH{\chcat{[}{12}} (without spaces around). Therefore:§
+% \qquad|\MacroWithOption{|{\stform[\blue][}|}{|...|}|¤ will most probably lead to an error... because \cs{FE@testopt} is looking
+% for an option. This is the price, for purely expandability (all the same for \cmdref{FE@ifstar}, \cmdref{FE@ifchar}
+% and \cmdref{FE@modifiers}).
%
-% {\rmk |\FE@testopt| is used in the definition of \cmdref{DeclareCmdListParser}.}
+% Just like \cs{@testopt}, \cs{FE@testopt} is sensitive to the category code of \CH{\chcat\textasteriskcentered{12}} which must be \textvb{other}.
%
-% \cmditem{FE@ifstar}{argument to be tested}{star-commands}{non-star commands} \cmdlabel{FE@ifstar}\seeimpl{FE@ifstar}
+% {\rmk |\FE@testopt| is used in the definition of \cmdref{DeclareStringFilter}, \cmdref{avoidvoid}, \cmdref{ettl@supergobble}
+% and \cmdref{csvtolist}.}
%
-% Similarly,\FE it becomes possible to mimic the behaviour of |\@ifstar| but in a fully expandable(\sty{FE}) way.
-% |\FE@ifstar| can be used as follow :§
-% \begin{tabbing}
-% \qquad\= |\def\StarOrNotCommand#1{\FE@|\=|ifstar|\=|{#1}|\\
-% \>\>|{\StarredCommand}|\\
-% \>\>|{\NotStarredCommand}}|
-% \end{tabbing}
+% \cmditem{FE@ifstar}{\#1}{ star-commands }{ non-star commands }
%
-% Remember that |\StarredCommand| and |\NotStarredCommand| \textbf{must have at least one mandatory argument.}
+% Similarly, it\FE becomes possible to mimic the behaviour of |\@ifstar| but in a fully expandable(\sty{FE}) way.
+% \csbf{FE@ifstar} can be used as follow:§§
+% \begin{VerbLines}[commandchars=!()]
+% \def(!copper\StarOrNotCommand)!#1{(!red\FE@ifstar){!#1}
+% {\StarredCommand}
+% {\NotStarredCommand}}
+% \end{VerbLines}
%
-% {\rmk |\FE@ifstar| is used in the definitions of \cmdref{DeclareCmdListParser}, \cmdref{csvloop}, \cmdref{listloop}
-% and \cmdref{toksloop}.}
+% Just like \cs{@ifstar}, \cs{FE@ifstar} is sensitive to the category code of \stform* which must be \textvb{other}.
%
-% \cmditem{FE@ifchar}{Variant Mark Character}{argument to be tested}{special-commands}{normal-commands}\cmdlabel{FE@ifchar}\seeimpl{FE@ifchar}
+% {\rmk |\FE@ifstar| is used in the definitions of \cmdref{csvtolist}, \cmdref{listtocsv} and \cmdref{tokstolist}.}
%
-% As a\FE generalisation of \cs{FE@ifstar} \sty{etextools} provides \cmd{FE@ifchar} for use with other variants than the star-form.
+% \cmditem{FE@ifchar}{ Variant Character }{\#1}{ special-commands }{ normal-commands }
%
-% For example, to define a `\,$\boldsymbol{+}$\,` variant:
-% \begin{tabbing}
-% \qquad\=|\def\SpecialMacro#1{\FE@|\=|ifchar|{+}\=|{#1}|\\
-% \>\>|{\SpecialFormMacro}|\\
-% \>\>|{\NormalFormMacro}}|
-% \end{tabbing}
+% As a\FE generalisation of \cs{FE@ifstar} \thispackage provides \csbf{FE@ifchar} for use with other variants than the \stform*-form.
%
-% |\SpecialMacro| must have at least one mandatory argument.
+% For example, to define a \CH{\stform+} variant:§§
+% \begin{VerbLines}[commandchars=!()]
+% \def(!copper\SpecialFormMacro)!#1{(!red\FE@ifchar)(!blue!ttbf+){!#1}
+% {\SpecialFormMacro}
+% {\NormalFormMacro}
+% \end{VerbLines}
%
-% \end{ltxsyntax}
+% Like \cmdref{@ifchar} but \textsfsl{\bfseries unlike} \cs{@ifstar} and \cs{FE@ifstar}, \cs{@testopt} and \cs{FE@testopt}
+% \csbf{FE@ifchar} is NOT sensitive to the category code of the \prm{Variant Character} (the \cmdref={character-test} is used).
%
-% \section{Lists management}
+% \textsfsl{Really, \csbf{FE@ifchar} is based on \cmdref{ifsinglechar} therefore the ``caracter'' to test may be any token,
+% and you may define a purely expandable macro with a \CH{\cs{relax}} form, a \CH{\cs{ignorespaces}} form and a
+% \CH{\cs{afterassignment}} form.} But may be this is useless...
%
-% \subsection{The Command-List Parser}
%
-% The \sty{etoolbox} package provides a way to define list parsers a fully expandable macros:
-% the list parser is able to expand the auxiliary command |\do| on each item of a list.
+% \ClearPage*
+% \cmditem+{FE@modifiers}{ Allowed Modifiers }{\#1}{ 1st case }{ 2nd case }{...}{ Normal case }
+%
+% \csbf{FE@modifiers}\FE is a generalization of \cmdref{FE@ifchar} to allow different modifiers for a single macro.
+% The first argument is the \prm{Allowed Modifiers} for this macro.
+%
+% For example, if you want to define a \textbf{purely expandable} macro with a \stform[\blue]* \textbfsf{star} form, a
+% \stform[\blue]+ \textbfsf{plus} form and a \stform[\blue]{--} \textbfsf{minus} form you may say:§§
+% \begin{VerbLines}[commandchars=&()]
+% \def(&copper\MySuperMacro) &#1{(&red\FE@modifiers{(&blue * + - )}){&#1}
+% {(&mdseries\MySuper(&blue&!Starred)Macro)} (&nnn&% first position)
+% {(&mdseries\MySuper(&blue&!Plus)Macro)} (&nnn&% second position)
+% {(&mdseries\MySuper(&blue&!Minus)Macro)} (&nnn&% third position)
+% {(&mdseries\MySuperMacro(&blue&!Without)Modifier)}} (&nnn&% next to last position)
+% \end{VerbLines}
+% Then when called by the user, {\copper|\MySuperMacro|} will switch to the sub-macro corresponding
+% to the modifier specified (purely expandable macro with different modalities).
% \iffalse
-% Declaration of a list parser is done via the |\DeclareListParser| macro\footnotemark.
-% \footnotetext{besides, \sty{etoolbox} defines the \sty{\textbackslash docsvlist} and the
-% \sty{\textbackslash dolistloop} macros: the choice of this name is not very friendly
-% and we expected to have a \sty{\textbackslash docsvloop} macro instead...}.
+% If you don't care on pure-expandability, you may define macros with modifiers yet more easily with
+% the \cmdref={macromodifiers} environment.
% \fi
+%
+% \cs{FE@modifiers} works as follow:\par\nobreak
+% \begin{enumerate}[label=\arabic*)~,beginpenalty=10000]
+% \item it checks if \#1 is a single character (\cmdref{ifOneToken} does the job)
+% \item then it tries to find it in the list of \prm{Allowed Modifiers} (this is a \cmdref={list of single tokens})
+% \item if found, the index of the modifier in the list is known, as well as the length of the list. Then,
+% \cmdref{ettl@supergobble} expands the chosen one.
+% \end{enumerate}
%
-% Here we provide a |\DeclareCmdListParser| macro that is compatible and slightly different, because the auxiliary
-% command is not necessarily |\do|. Such a command-list-parser is fully expandable.
+% \cs{FE@modifiers} uses the \cmdref={character-test}. Therefore, single \textbfsf{\slshape character tokens} are found
+% in the list of \prm{Allowed Modifiers} even if their category code don't match.
%
-% The idea is that if |\csvloop| has been defined as a command-parser then, thank to the fully expandable macro |\FE@testopt|
-% we can call for expansion:
-% \begin{tabbing}
-% \qquad\= |\csvloop*{item,item,...}|\,\= as a shortcut for\,\= |\csvloop*[\do]{item,...}|\\
-% or:\> |\csvloop*[\listadd\mylist]{item,item,...}|\quad
-% \end{tabbing}
-% for example to convert the csv-list into internal \sty{etoolbox} list.
+% {\rmk \cs{FE@modifiers} is used in the definition of the string-filters defined with \cmdref{DeclareStringFilter}.§
+% An intesting example of use of \cs{FE@modifiers} is given in the implementation of \cmdref*{ettl@lst@modif}.}
%
-% {\rmk The star-form of \cmdref{csvloop} will be explained below.}
+% \cmditem{ettl@supergobble}[code]{\blue$\mathbf n$}{\blue $\mathbf N$}{tok$_1$}|...|{tok$_n$}{\blue\bfseries TOK$_{\mathbf{n+1}}$}{tok$_{n+2}$}|...|{tok$_{\blue\mathbf N}$}
%
-% \begin{ltxsyntax}
+% \csbf{ettl@supergobble}\{\PRM[\blue]{$\mathbf n$}\}\{\PRM[\blue]{$\mathbf N$}\}\FE will:
+% \begin{enumerate}[label=\roman*)~]
+% \item gobble the first \PRM[\blue]{$\mathbf n$} tokens (or groups of tokens) it founds just after
+% \item keep the \PRM[\blue]{$\mathbf{n+1}$} token
+% \item gobble the last tokens \PRM[\blue]{$\mathbf{n+2}$} to \PRM[\blue]{$\mathbf{N}$}
+% \item then and after all, expand to \PRM[\blue\bfseries]{TOK$_{\mathbf{n+1}}$}
+% \end{enumerate}
%
-% \cmditem{DeclareCmdListParser}{command}{separator}\cmdlabel{DeclareCmdListParser}\seeimpl{DeclareCmdListParser}
+% In other words, the list contains \PRM[\blue]{$\mathbf{N}$} tokens, \csbf{ettl@supergobble} expands the \PRM[\blue]{$\mathbf{n+1}$}
+% and discards the rest.
%
-% |\DeclareCmdListParser| acts in the same way as \sty{etoolbox}-|\DeclareListParser| and the command-list-parser
-% are sensitive to the category code of the \prm{separator}
-% {\catcode`\ =13\let =-\it(which is not necessarily a single character and shall not be a {\tt\string&} with a catcode of 3)}.
+% Now if \PRM[\blue]{$\mathbf{n}$}$=$\PRM[\blue]{$\mathbf{N}$}, \csbf{ettl@supergobble}
+% gobbles the \PRM[\blue]{$\mathbf{N}$} tokens (including the last).
%
-% A Command-List-Parser is then defined as a purely expandable macro. It has a \textit{star form} for the case
-% of the list given is already expanded, and a \textit{normal form} if the list is given as a macro name.
+% And if \PRM[\blue]{$\mathbf{n}$}$>$\PRM[\blue]{$\mathbf{N}$} or if \PRM[\blue]{$\mathbf{n}$}$<0$,
+% \csbf{ettl@supergobble} expands to \PRM[\blue]{\bfseries TOK$_\mathbf{N}$} (the last).
%
-% You may then use the following syntaxes:
-% \begin{tabbing}
-% \qquad\=|\CmdListParser\mylist| \\
-% \>|\CmdListParser*{item|\prm{sep}|item|\prm{sep}|item}| \\
-% \>|\CmdListParser[\Commands]\mylist| \\
-% or:\>|\CmdListParser*[\Commands]{item|\prm{sep}|item|\prm{sep}|item}|
-% \end{tabbing}
+% Finally, if the optional parameter \oprm{code} is specified, it will be appended to the list after \prm{tok$_{N}$} (but not in the
+% special case where $n$=$N$...).
%
-% \subsection{Loops into lists}
+% {\rmk \cs{ettl@supergobble} has been designed for and is used in \cmdref{FE@modifiers}.§
+% If you're interested in what \cs{ettl@supergobble} does when \PRM[\blue]{$\mathbf N$}$\leq 0$: it does nothing!}
%
-% Now we have to declare two command-list-parsers : |\listloop| for \sty{etoolbox} lists
-% and |\csvloop| for comma-separated lists.
+% \end{ltxsyntax}
%
-% \cmditem{csvloop}[auxiliary commands]{csvlistmacro} \cmdlabel{csvloop}\seeimpl{csvloop}
-% \cmditem*{csvloop*}[auxiliary commands]{item,item,item,...}
-% \cmditem*{listloop}[auxiliary commands]{listmacro} \cmdlabel{listloop}
-% \cmditem*{listloop*}[auxiliary commands]{expanded list}
-% \cmditem{toksloop}[auxiliary commands]{tokenslistmacro} \cmdlabel{toksloop}
-% \cmditem*{toksloop*}[auxiliary commands]{list of tokens}
+% \ClearPage*
+% \Section{Define control sequences through groups}
%
-% |\listloop|\FE acts exactly as \sty{etoolbox}-|\dolistloop| with an optional argument to change
-% the default auxiliary command |\do| to apply to each item of the list :
-% \begin{tabbing}
-% \qquad\=|\listloop\mylist|\;\=\textit{is}\;\= |\listloop[\do]\mylist|\;\=\textit{and is also}\;\= |\dolistloop\mylist|\\
-% \> |\csvloop\csvlist|\> \textit{is}\> |\csvloop[\do]\csvlist|\> \textit{and is also}: \eol \\
-% \>\>\> |\expandafter\docsvlist\expandafter{\csvlist}|
-% \end{tabbing}
+% \begin{ltxsyntax}
%
-% The token list is a list without delimiter.
+% \cmditem[AfterGroup]@{AfterGroup\tsptb AfterGroup\stform*}
+% \cmditem-{AfterGroup}{ code }
+% \cmditem-{AfterGroup\stform*}{ code }
%
+% The \cs[\red]{aftergroup}\notFE\ primitive does not allow arbitrary code: only a single token may be placed after \cs{aftergroup}.
+% \csbf{AfterGroup} allows arbitrary \prm{code} to be expanded after \cs{endgroup} or an end-group character.
%
+% The \stform* star form of \cs{AfterGroup} does the same, but expands its argument with |\edef|:§§
+% \begin{VerbLines}[commandchars=!()]
+%!md \newcommand(!copper\macro)[1]{\textbf{Just to see...!#1}}
+% (!dg\begingroup)
+%!md \newcommand(!copper\othermacro)[1]{\textbf{will we see...!#1}}
+% (!red\AfterGroup)!md{(!copper\macro){if it works}}
+% (!red\AfterGroup*)!md{\expandonce{(!copper\othermacro){if it works}}}
+% (!dg\endgroup)
+% (!nnn and here) (!md(!copper\macro){if it works}) (!nnn will be executed)
+% (!nnn and here) (!md\textbf{will we see...if it works}) (!nnn will be executed)
+% \end{VerbLines}
%
-% \subsection{Converting csv lists to \sty{etoolbox}-lists}
+% \cmditem{AfterAssignment}{ code }
%
-% \cmditem{csvtolist}{listmacro}{csvlistmacro} \cmdlabel{csvtolist}\seeimpl{csvtolist}
-% \cmditem*{csvtolist*}{listmacro}{item,item,item...}
+% In the same order of idea,\notFE\ \csbf{AfterAssignment} allows arbitrary \prm{code} to be expanded \cs{afterassignment}.
%
-% |\csvtolist| converts a comma separated list into an internal \sty{etoolbox} list. It is useful to insert more than one item
-% at a time in a list. Those macros are not fully expandable because of the redefinition of \prm{listmacro} done by |\listadd|...
+% \cmditem+{aftergroup@def}{ command }
%
-% It's also the first application of the \cmdref{csvloop} macro just defined.
+% When leaving\notFE\ a group with the end-group character \CH{\stform[\dg]\}} or the execution of \csbf[\dg]{endgroup}
+% the meaning of the control sequences that where locally defined inside the group are restored to
+% what they were before.
%
+% The idea of \cs{aftergroup@def} is to keep a control sequence though \csbf[\dg]{endgroup} or \CH{\stform[\dg]\}}.
+% This is done by redefining it after the group. \cs{aftergroup@def} is based on \Xpackage[oberdiek/letltxmacro]{letltxmacro} and
+% on \cmdref{AfterGroup} just defined. Therefore, \cs{aftergroup@def} works with commands with optional arguments declared
+% with \LaTeX's \cs{newcommand}, with robust commands from \xpackage{etoolbox}-\cs{newrobustcmd} and
+% with \LaTeX's robust commands (\cs{DeclareRobustCommand}).
%
-% \cmditem{csvtolistadd}{listmacro}{csvlistmacro} \cmdlabel{csvtolistadd}\seeimpl{csvtolistadd}
-% \cmditem*{csvtolistadd*}{listmacro}{item,item,item...}
+% \begin{VerbLines}[commandchars=!()]
+% { (!dg\newcommand)(!copper\test)[2][default]{ !#1 and !#2 }
+% (!red\aftergroup@def)(!copper\test)
+% }
+% (!copper\test)[option]{mandatory} (!nnn is defined outside the group - but NOT globally)
+% \end{VerbLines}
%
-% |\csvtolistadd| acts similarly but does not reset the \prm{listmacro} to |\@empty|.
%
+% \end{ltxsyntax}
%
-% \subsection{Converting lists of tokens to \sty{etoolbox}-lists}
+% \ClearPage*
%
-% \cmditem{tokstolist}{listmacro}{tokenslistmacro} \cmdlabel{tokstolist}\seeimpl{tokstolist}
-% \cmditem*{tokstolist*}{listmacro}{list of tokens}
+% \Section[{Vectorized \texorpdfstring{\cs[\sfbf]{futurelet}}{\cs{futurelet}}}]{Vectorized \csbf{future{\blue let}}: \csbf{future{\spot def}}}
%
-% |\tokstolist| converts a list of tokens (no separator) into an internal \sty{etoolbox} list.
+% \begin{ltxsyntax}
%
-% It's also the first application of the \cmdref{toksloop} macro just defined.
+% \cmditem+{@ifchar}{ single token }{ true }{ false }
%
-% \cmditem{tokstolistadd}{listmacro}{tokslistmacro} \cmdlabel{tokstolistadd}\seeimpl{tokstolistadd}
-% \cmditem*{tokstolistadd*}{listmacro}{list of tokens}
+% \csbf{@ifchar}\notFE\ does the same as \LaTeX'\cs{@ifstar} but for any character (or \textsfsl{modifier}). Whereas
+% \cs{@ifstar}-test is sensitive to the category code of the star (the \textsfsl{character
+% \CH{\chcat[\blue\vbbf]\textasteriskcentered{12}}} -- that means that the category code of \stform[\blue]* must be $12$
+% as defined in \LaTeX's kernel), \csbf{@ifchar} is based on the \cmdref={character-test}
+% and does not check the equality of category code for single \textbf{characters}.
%
-% |\tokstolistadd| acts similarly but does not reset the \prm{listmacro} to |\@empty|.
-
+% \cs{@ifchar} is NOT purely expandable. It relies on |\futurelet| and on the \cmdref={character-test}.
+% The syntax is the same as for \cs{@ifstar} with the specification of the (character) token to test:§§
+% \begin{VerbLines}[commandchars=!()]
+% \newcommand(!copper\SpecialMacro){(!red\@ifchar)(!blue+)%
+% {\let\modifier=+\GeneralMacro}
+% {\let\modifier=\relax\GeneralMacro}}
+% \end{VerbLines}
%
-% \subsection{Removing elements from \sty{etoolbox}-lists}
+% {\rmk Unless \cs{@ifstar}, \cs{@ifchar} is a |\long| macro...}
%
-% The \sty{etoolbox} package provides |\listadd|, |\listgadd| and |\listxadd| commands
-% to add items to a list. However, no command is designed to remove an element from a
-% list.
+% \cmditem{ettl@ifnextchar}{ single token }{ true }{ false }
%
+% \csbf{ettl@ifnextchar}\notFE\ is the engine for \csbf{@ifchar}. It is based on \cs{futurelet} and on the \cmdref={character-test}:§§
+% \begin{VerbLines}[commandchars=$()]
+% $dg\begingroup \catcode`\$stform[$blue]! \active \let$stform[$blue]!=\else
+% $dg\gdef ($copper\test) {($red\ettl@ifnextchar) $stform[$blue]!{true}{false\@gobble}}
+% $dg\endgroup
+% \catcode`\$stform[$dc]!\active \let$stform[$dc]!=\ifodd
+% ($copper\test)$stform[$dc]! $nnn will expand $prmb(true)
+% ($copper\test)\ifodd $nnn will expand $prmb(false)
+% ($copper\test)\else $nnn will expand $prmb(false)
+% \end{VerbLines}
+% \bigbreak
%
-% \cmditem{listdel}{listmacro}{item} \cmdlabel{listdel}\seeimpl{listdel}
-% \cmditem*{listgdel}{listmacro}{item} \cmdlabel{listgdel}
-% \cmditem*{listedel}{listmacro}{item} \cmdlabel{listedel}
-% \cmditem*{listxdel}{listmacro}{item} \cmdlabel{listxdel}
+% \thispackage defines a vectorized version of \cs{futurelet}. The idea is to say:
%
-% The |\listdel| command removes the element \prm{item} from the list \prm{listmacro}. Note that the
-% \prm{listmacro} is redefined after deletion:
+% \quad|\futuredef[|\prm{list of allowed tokens}|]\macro{|\prm{commands to execute next}|}|
+%
+% Then \cs{futuredef} is a kind of simple scanner for tokens. It can be used to define an \textbf{\textit{undelimited macro}}
+% \ie a macro that has no delimiter but whose content of arguments is restricted.
%
-% Commands |\listgdel| and |\listxdel| are similar, except that the assignment (\ie the redefinition
-% of the list) is global; for the latter, the \prm{item} is first expanded using |\protected@edef|:
%
+% \cmditem+{futuredef}[ list of allowed tokens ]{ \cs{macro} }{ commands to expand after }
+% \cmditem-{futuredef\stform*}[ list of allowed tokens ]{ \cs{macro} }{ commands to expand after }
% \end{ltxsyntax}
%
-% \subsection{Index of an element in a list}
+% \csbf{futuredef}\notFE\ will read the following token with \csbf{futurelet}. If that token is in the
+% \prm{list of allowed tokens}, then it will append it to \cs{macro} and continue, scanning the tokens one after another.
+%
+% Until it founds a token which is not in the \prm{list of allowed tokens}. Then it stops reading
+% and executes the \prm{commands to expand after}. Those commands may use the \cs{macro}
+% just defined for analyse or whatever the user want.
+%
+% The space token must be \textbfsf{explicitly specified} in the \prm{list of allowed tokens}:
+% otherwise \cs{futuredef} stops at a space (and execute the \prm{commands to expand after}).
+%
+% \textbfsf{A token is in the \prmb{list of allowed tokens} \textcolor{blue}{if it can be found in this list using
+% the \cmdref={character-test}}.} This means that if \cs[\blue]{relax} is in the \prmb{list of allowed tokens}, then it will
+% be appended to \cs{macro} (if encountered) and if \CH{\chcat\${3}} is in the \prmb{list of allowed tokens}, any
+% \CH{\stform[\blue]\$} character will be appended to \cs{macro} (if encountered) no matter of its category code. If you really
+% absolutely need the \cs{ifx}-test, you shall use \cmdref[futuredef=]{futuredef\stform=}\footnote{this may be the case if,
+% for some reason, you have detokenized the \prm{list of allowed tokens} before, and want to skip the expansion of \cs{detokenizeChars}
+% which occurs at the beginning of the normal form of \cs{futuredef}...}.
+%
+% \textbfsf{If the \prmb{list of allowed tokens} is not specified,} \cs{futuredef} will read all tokens until the next
+% \textsfsl{begin-group} or \textsfsl{end-group} token.
+%
+% \cs{futuredef} may be used instead of \cs{FE@modifiers} for (non purely expandable) macros with multiple modifiers.
+% (The modifiers of the \cs{newkeycommand} macro in the \Xpackage{keycommand} package are scanned with this feature.)
+% As far as it is based on \cs{futurelet}, the limitation of \cs{FE@modifiers} (\ie |{|\stform*|}| is the same as \stform*
+% without the braces) is not applicable to \cs{futuredef}.
+%
+% \textbf{Limitation: } as far as \cs{macro} has to be correctly defined (it's replacement text must be balanced
+% in begin-group\slash end-group delimiters) \textbfsf{it is not allowed to have a character of category code $\mathbf1$ or $\mathbf2$}
+% (or a token having been |\let| to such a character)\textbfsf{ in the } \prmb{list of allowed tokens}:
+% \cs{futuredef} will stop scanning the next tokens if it encounters a begin-group or an end-group character.
+%
+% The \textbfsf{star-form} of \cs{futuredef} is more dangerous: \csbf{futuredef\stform*} captures the tokens as \cs{futuredef} does,
+% storing them into \cs{macro} as long as they are in the \prm{list of allowed tokens}. But if the next token is not in the
+% list, \cs{futuredef\stform*} does not stop at first stage but expands this very token and starts again.
+% \ClearPage
+%
+% Example:§§
+% \begin{VerbLines}[commandchars=!()]
+% \def\test{TeX\relax{*}}
+% (!red\futuredef)(!blue[TeX\relax])(!copper\macro){"\meaning\macro"}eTeX\test.
+% !hfill "macro:->eTeX" (!nnn each token is allowed until !cs(test))
+% (!red\futuredef!stform*)(!blue[TeX\relax])(!copper\macro){"\meaning\macro"}eTeX\test.
+% !hfill "macro:->eTeXTeX\relax " (!nnn!cs(test) is expanded and)
+% !hfill(!nnn futuredef stops at begin-group character)
+%\end{VerbLines}
%
-% \subsubsection{\sty{etoolbox}-lists}
+% \medskip
+% As an application, it can be used to define an easy interface for |\hdashline| (the dashed lines in tabulars and arrays
+% provided by the \xpackage{arydshln} package): modifying \cmd{hline} in order to give sense to the following:
+% \begin{tabbing}
+% \qquad\=|\hline..|\qquad\=|\hline--|\qquad\=|\hline==|\qquad\= |\hline.-|\qquad\=|\hline.-.|\ \= etc.
+% \end{tabbing}
%
-% \begin{ltxsyntax}
+% After having collected the allowed tokens with:§
+% \csbf{futuredef}\textvbbf{[.-=]}\csbf{nexttokens}\{\prm{commands next}\} \quad it is possible to
+% test the pattern given using \cs{pdfstrcmp} or \cs{ifstrequal} (or even a \cmdref[DeclareStringFilter]{string-filter})
+% and, for example, the \CSbf{switch} construction of the \xpackage{boolexpr} package:
+% \begin{VerbLines}[fontseries=m]
+% \switch[\pdfstrcmp{\nexttokens}]%
+% \case{{..}}\hdashline[parameters]%
+% \case{{--}}\hdashline[parameters]%
+% \case{{==}}\hdashline[parameters]%
+% \case{{.-.}}\hdashline[parameters]%
+% \otherwise \original@hline%
+% \endswitch
+% \end{VerbLines}
%
-% \cmditem{getlistindex}[myindex]{item}{listmacro} \cmdlabel{getlistindex}\seeimpl{getlistindex}
-% \cmditem*{xgetlistindex}[myindex]{item}{listmacro} \cmdlabel{xgetlistindex}
-% \cmditem*{getlistindex*}[myindex]{item}{list}
-% \cmditem*{xgetlistindex*}[myindex]{item}{list}
+% \CSbf{switch} is purely expandable when used with \cs{pdfstrcmp} (pdf\TeX{}).
%
+% See \xpackage{boolexpr} (\CTAN{macros/latex/contrib/boolexpr/}) for more information on \cs{switch}.
+%
+% \begin{ltxsyntax}
+% \cmditem{futuredef\stform=}[ list of allowed tokens ]{ \cs{macro} }{ commands to expand after }
+% \cmditem-{futuredef\stform*\stform=}[ list of allowed tokens ]{ \cs{macro} }{ commands to expand after }
% \end{ltxsyntax}
%
-% Sometimes it is interesting to know at which offset in a list lies a given item. |\getlistindex| answers to this question.
-% |\xgetlistindex| does the same thing but expands the \prm{item} while looking for it in the list.
+% The \CH{\stform=} form\notFE\ of \cs{futuredef} is the same as \cs{futuredef} but the checking of single characters
+% is sensitive to their category code. If a control sequence is in the \prm{list of allowed tokens} it is appended to \cs{macro}
+% (if encountered) just like the normal \cs{futuredef} does. But if it is a single character token, then it is appended to \cs{macro}
+% only if the same character with the same ccategory code is found in the \prm{list of allowed tokens}: otherwise, \cs{futuredef}
+% stops reading and execute the \prm{commands to expand after}.
%
-% The comparison is \textit{catcode agnostic}.
+% In general, we are not willing this behaviour and the \stform= form of \cs{futuredef} would probably never be used, unless you know
+% that the \prm{list of allowed tokens} is already detokenized...
+% Anyway, it was not difficult at all to \cmdref=[impl:futuredef=]{implement}.
%
-% As for the command-list-parser, the star versions are designed in case the list (in the second argument) is already expanded.
+% {\rmk You may use indifferently \cs{futuredef\stform*\stform=} or \cs{futuredef\stform=\stform*}.}
%
-% When used\pdfFE on pdf\TeX{}, |\pdfstrcmp| does the comparison and the macros are purely expandable:
+% \ClearPage*
+% \Section{Lists management}
%
-% \begin{itemize}
-% \item \ If \prm{item} is not found in the list, \cs{getlistindex} expands to 0
-% \item \ If \prm{item} is found in first position then \cs{getlistindex} expands to 1 and so on.
-% \end{itemize}
+% \Subsection{The natural loop}
%
+% \begin{ltxsyntax}
+% \cmditem{naturalloop}[auxiliary commands]{ number of times }{ argument }
%
-% Those macros are purely expandable only if |\pdfstrcmp| exists.
-% Otherwise, the comparison is done with \sty{etoolbox}-|\ifstrequal| and you shall use the optional argument
-% to let the result in:
+% {\bfseries The \csbf{naturalloop}\FE macro applies the \prmb{auxiliary commands} exactly $n$ times onto the
+% \prmb{argument},} \ie:§
+% \begin{framed}
% \begin{tabbing}
-% \qquad\=|\getlistindex[\myindex]{|\prm{item}|}{|\prm{listmacro}|}| \\
+% ¤¤\hskip2em\=\CSbf[\red]{naturalloop} [\csbf[\copper]{MyCommand}]\textbf{\{3\}}\{\prmb{argument}\} \\
+% will expand to:\\
+% \> \Underbrace{\csbf[\copper]{MyCommand} \{\Underbrace{\csbf[\copper]{MyCommand} \{\Underbrace{\csbf[\copper]{MyCommand} \{\prmb{argument}\}}_{expanded first}\}}_{expanded second}\}}_{expanded last}
% \end{tabbing}
+% \end{framed}
+% \csbf{MyCommand} should be purely expandable.
+% \ClearPage
+% In fact, it's a bit more sophisticated: \csbf{MyCommand} should be defined as:
+% \begin{VerbLines}[commandchars=!()]
+% (!copper\MyCommand):macro [!#1]!#2!#3 -> (!normalfont!bfseries Something to do with !#1 !#2 and !#3)
+%!normalfont Where:
+% !#1: (!normalfont is the current index of the loop (1, 2, 3 until to n))
+% !#2: (!normalfont is the original !prm(argument))
+% !#3: (!normalfont is the result of the recursion :ie) \do{\do{\do{\do{!prm(argument)}}}}
+% (!normalfont f.ex. in loop of index 4.)
+%\end{VerbLines}
+%
+% If you want a list of integers from 17 to 24 separated by semi-colon:
+% \begin{VerbLines}[commandchars=!()]
+% \def\do[#1]#2#3{#3 ; \number\numexpr#2+#1}
+% \naturalloop{7}{17} (!nnn !smex 17 ; 18 ; 19 ; 20 ; 21 ; 22 ; 23 ; 24)
+%\end{VerbLines}
+%
+% Another example is given in the \cmdref{ExpandNext} section.
+%
+% \end{ltxsyntax}
%
-% \textbf{N.B. If \cs{myindex} is not a counter it is (possibly \textit{re-})defined as macro.}
%
-% \subsubsection{Comma-separated lists}
+% \Subsection{Lists of single tokens / characters} \cmdlabel{list of single tokens}
+%
+% Lists of single tokens are a special case of lists: they have no separator. The test for equalty of tokens
+% is made by \csbf[\red]{ifx} and therefore, finding a token in a list of single tokens is always a purely expandable operation.
+%
+% A \textsfbf{\slshape list of single tokens} is a list of \textitbf{single} tokens: that means you can't group them with braces
+% (the list may contain the |\bgroup| and |\egroup| tokens however).
+%
+% Lists of single tokens may also be tested with a special test which is |\ifx| in case of control sequences and
+% a detokenized-|\if| in case of single characters.
+%
+% Lists of single characters are used for testing \textsl{modifiers} in a purely expandable way. \textsfbf{\slshape modifiers} are
+% a vectorialisation of \cs{FE@ifstar} (and \cs{FE@ifchar}).
+%
+% \begin{ltxsyntax}
+%
+% \ClearPage
+% \cmditem[ifintokslist]+@{ifintokslist\tsptb ifincharlist}
+% \cmditem-{ifintokslist}{ single token }{ list of single tokens }{ true }{ false } \FEII*
+% \cmditem-{ifincharlist}{ single token }{ list of single tokens }{ true }{ false } \FEII*
+%
+% \csbf{ifintokslist} will switch\FEII to \prm{true} if the \prm{single token} is found
+% in the \prm{list of single tokens} while testing against each token of the list using \csbf{ifx}.
+%
+% {\rmk\cs{ifintokslist} could be tested with |\ifnum\getokslistindex{|\prm{token}|}{|\prm{list of tokens}|}|
+% but \cs{ifintokslist} optimises the loop in case the token is in the list.}
+%
+% \csbf{ifincharlist} will expands \prm{true} if the \prm{single token} is found in the \prm{list of single tokens}
+% but the test for equality of tokens is the \cmdref={character-test}.
+%
+% \end{ltxsyntax}
+% \ClearPage*
+%
+% Therefore, \cs{ifincharlist} behaves as follow:§§
+% \begin{VerbLines}[commandchars=$()]
+% \begingroup \catcode`\!=13 \catcode`\.=8 \catcode`\: 3
+% \global\def($copper\mylist){($blue:!\relax=.0)} ($nbf|) ($red\ifintokslist)
+% \endgroup $nbf|
+% $cs(expandnext){($red\ifincharlist)($blue!)}($copper\mylist){true}{false} $nbf true | false
+% \expandnext{($red\ifincharlist)($blue0)}($copper\mylist){true}{false} $nbf true | true
+% \expandnext{($red\ifincharlist)($blue:)}($copper\mylist){true}{false} $nbf true | false
+% \expandnext{($red\ifincharlist)($blue\relax)}($copper\mylist){true}{false} $nbf true | true
+% \end{VerbLines}
+%
+% {\rmk \cs{ifincharlist} is used in the definition of \cmdref{futuredef}.}
%
% \begin{ltxsyntax}
-% \cmditem{getcsvlistindex}[myindex]{item}{csvlistmacro} \cmdlabel{getcsvlistindex}\seeimpl{getcsvlistindex}
-% \cmditem*{xgetcsvlistindex}[myindex]{item}{csvlistmacro} \cmdlabel{xgetcsvlistindex}
-% \cmditem*{getcsvlistindex*}[myindex]{item}{item,item,item,...}
-% \cmditem*{xgetcsvlistindex*}[myindex]{item}{item,item,item,...}
+% \cmditem+{gettokslistindex}{item}{list of single tokens}
+%
+% \csbf{gettokslistindex}\FEII expands to the index of \prmb{item} in the list of single tokens given as a second argument.
+%
+%
+% \textbf{Note that the \opt{index} is $\mathbf0-$based} for consistency with |\ifcase| ({\mdfs and also with
+% \cmdref{ettl@supergobble}}).
+% \ClearPage
+%
+% It is possible to say:§§\makeatletter\setbox\helpbox\hbox{\colorbox{yellow}{\vbbf 3}}\setbox\helpboxx\hbox{\colorbox{yellow}{\vbbf -1}}
+% \begin{VerbLines}[commandchars=!\[\]]
+% \newcount[!copper\result]
+% [!copper\result] = [!red\gettokslistindex]{d}{abcdef} !smex \result=!box!helpbox
+% \ifcase [!red\gettokslistindex]{d}{abcef}
+% [!nnn what to do if ] a
+% \or [!nnn what to do if ] b
+% \or [!nnn what to do if ] c
+% \or [!nnn etc. etc. etc.]
+% \else [!nnn what to do if] d [!nnn is not in the list:] !smex result=!box!helpboxx
+% \fi
+% \end{VerbLines}
+% \makeatother
+%
+% Please, refer to the examples...
+%
+% This feature is extensively used in \cmdref{FE@modifiers}.
+%
+% {\rmk \cmdref*{gettokslistindex} is kind of masterpiece of purely expandable programming with \eTeX}
+%
+% \cmditem+{getcharlistindex}{item}{list of single tokens}
+%
+% \csbf{getcharlistindex}\FEII expands to the index of \prmb{item} in the list of single tokens
+% (the index is $\mathbf0$ for the first item, $\mathbf{-1}$ if \prm{item} is not in the list).
+% The character-test is used instead of |\ifx| (see \cmdref{ifincharlist}).
+%
+% {\rmk \cmdref{getcharlistindex} is used - indirectly - in the definition of \cmdref{FE@modifiers}.}
+%
+% \ClearPage
+% \cmditem[gettokslistcount] @{gettokslistcount/token}
+% \cmditem-{gettokslistcount}{list of single tokens} \FEII*
+% \cmditem-{gettokslisttoken}{item}{list of single tokens} \FEII*
+%
+% \csbf{gettokslistcount},\FEII \csbf{gettokslisttoken} and \csbf{gettokslistindex} work all three with
+% the same engine, and this is also the case for \cmdref{getcharlistcount}, \cmdref{getcharlisttoken} and \cmdref{getcharlistindex}.
+% All are fully expandable.
+% \ClearPage
+%
+% \cs{gettokslistcount} gives the number of tokens in the list, while \cs{gettokslisttoken} should be seldom used (but
+% it was natural to define it as well).§§
+% \begin{VerbLines}[commandchars=!(),fontseries=m]
+% (!nnn if you say:) \let(!dg\plus) = !stform[!blue]+
+% (!red\gettokslisttokens){(!dg\plus)}{ABCD!stform[!blue]+EFG} (!nnn will expand to: )!stform[!blue]+
+% (!nnn and:)
+% (!red\gettokslisttokens){!stform[!blue]+}{ABCD(!dg\plus) EFG} (!nnn will expand to: )!dg\plus
+% \end{VerbLines}
+%
+% The idea is to loop into the list, testing each token of the list against \prm{item} with |\ifx|.
+% The \textsl{test-macro} (together with its own parameters) is a parameter of the \textsl{loop-macro},
+% and therefore, it can be changed without redefining it. As a result, the loop is purely expandable.
+%
+% Finally, when the loop is finished, the test macro becomes the \textsl{give-result-macro} (without |\let|)
+% and its own parameters are \textsl{extracted using projections} (like |\@firstoftwo|).
+%
+% The parameters of the \textsl{test-macro} include:
+% \begin{enumerate}[label=--~]
+% \item the current index in the list
+% \item the index of the \prm{item} found if |\ifx| returned \textvb{true}
+% \item the name of the \textsl{test-macro} to use at the next iteration. Usually it is the \textsl{test-macro}
+% itself, but for the last token in the list, this parameter is the \textsl{give-result-macro}.
+% \end{enumerate}
+%
+% Definition of \cs{ettl@gettokslist} worth a close look!
+%
+% Back to the begining: lists of single tokens are also lists without separator. Therefore, the other standard
+% macros \cmdref{toksloop} is provided by the general constructor
+% \cmdref{DeclareCmdListParser} invoked with an empty separator.
+%
+% {\rmk Unlike \cmdref{getlistindex}, \cmdref{getcsvlistindex} etc., \cs{gettokslistindex}, \cs{gettokslistcount}
+% and \cs{gettokslisttoken} have no star form nor optional parameter. This is because we might be able to test:§
+% ¤¤|\gettokslistindex{*}{|\prm{list of single tokens}|}|¤¤or¤¤|\gettokslistindex{[}{|\prm{list of single tokens}|}|§
+% and \cmdref{FE@ifstar} or \cmdref{FE@testopt} don't allow this. }^^A]
+% \ClearPage
+%
+% \cmditem[getcharlisttoken]@{getcharlistcount/token}
+% \cmditem-{getcharlistcount}{list of single tokens} \FEII*
+% \cmditem-{getcharlisttoken}{item}{list of single tokens} \FEII*
+%
+% They work\FE the same way as the \textsf{-tokslist} versions but with the \cmdref[ifincharlist]{character test}.
+%
+% {\rmk \cs{getcharlistcount} is exactly the same as \cs{gettokslistcount} and is {\rred2}-expandable.}
+%
% \end{ltxsyntax}
+% \bigskip
%
-% This is the same as \cmdref{getlistindex} but for comma-separated lists.
+% \Subsection[The General Command-List-Parser]{The General Command-List Parser Constructor}
%
-% As for the command-list-parser, the star versions are designed in case the list (in the second argument) is already expanded.
+% The \xpackage{etoolbox} package provides a way to define list parsers as fully expandable macros:
+% the list parser is able to expand the auxiliary command |\do| on each item of a list.
+% \iffalse
+% Declaration of a list parser is done via the |\DeclareListParser| macro\footnotemark.
+% \footnotetext{besides, \xpackage{etoolbox} defines the \xpackage{\textbackslash docsvlist} and the
+% \xpackage{\textbackslash dolistloop} macros: the choice of this name is not very friendly
+% and we expected to have a \xpackage{\textbackslash docsvloop} macro instead...}.
+% \fi
%
-% Those macros\pdfFE are purely expandable only if |\pdfstrcmp| exists.
+% Here we provide a |\DeclareCmdListParser| macro that is compatible and slightly different, because \textbfsf{the auxiliary
+% command is not necessarily \csbf{do}.} Such a command-list-parser is fully expandable.
%
-% Otherwise, use the optional argument to let the result in:
+% The idea is that if \cmdref{csvloop} has been defined as a command-list-parser then, thank to the fully expandable macro
+% \cmdref{FE@testopt} we can call for expansion:
% \begin{tabbing}
-% \qquad\=|\getcsvlistindex*[\myindex]{|\prm{item}|}{|\prm{item,item,item...}|}| \\
+% \qquad\= |\csvloop|\itemitemitem[{\stform[\blue],}]\,\= as a shortcut for\,\= |\csvloop[\do]|\itemitemitem[{\stform[\blue],}]\\
+% or:\> |\csvloop[\listadd\mylist]|\itemitemitem[{\stform[\blue],}]
% \end{tabbing}
+% for example to convert the csv-list into internal \xpackage{etoolbox} list.
%
-% If \cs{myindex} is not a counter it is (possibly \textit{re-})defined as macro.
-%
-% \subsubsection{Lists of tokens}
+% {\rmk The star-form of \cmdref{csvloop} will be explained below.}
%
% \begin{ltxsyntax}
-% \cmditem{gettokslistindex}[myindex]{item}{tokenslistmacro} \cmdlabel{gettokslistindex}\seeimpl{gettokslistindex}
-% \cmditem*{gettokslistindex*}[myindex]{item}{list of tokens}
+% \ClearPage
+%
+% \cmditem+{DeclareCmdListParser}[\cs{global}]{ command }{ separator }
+% \cmditem-{breakloop} \FE*
+%
+% |\DeclareCmdListParser| acts in the same way as \xpackage{etoolbox}-|\DeclareListParser| and the
+% command-list-parsers defined are sensitive to the category codes of the \prm{separator}. This
+% \prm{separator} may be any sequence of tokens, but the special sequence:§
+% \hfill\colorbox{ly}{$/__8$E$__{11}$n$__{11}$d$__{11}\S__7$L$__{11}$i$__{11}$s$__{11}$t$__{11}$/$__8$}\hfill\kern0pt§
+% which is used as the end-of-list-delimiter for any list.
+%
+% As long as \cmdref*{ettl@nbk} is used to check the end of the list, \CH{\chcat/8} is not
+% allowed in the list as well. Therefore, you may not try to define lists with \CH{\chcat/8} as separator:
+% they are \textsfsl{useless}\footnote{Unfortunately, \cmdref*{ettl@nbk} requires a single character as a delimiter... The choice for
+% \CH{\chcat/8} is explained in the \cmdref=[catcode choice]{implementation part.}}.
+%
+% To declare a new command-list-parser with \CH{\ttbf\blue,} (with the current catcode) as a separator you say:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\DeclareCmdListParser)(!copper\myParser){(!blue,)}
+% \end{VerbLines}
+% \ClearPage*
+%
+% \begin{framed}
+% The Command-List-Parser declared: (here \csbf[\copper]{MyParser})
+% \begin{enumerate}[label=\smex,labelsep=.7em]
+% \item is a \textbfsf{purely expandable macro} with three modifiers (\stform*, \stform+ and \stform!)
+% an optional parameter (the \textbfsf{\slshape auxiliary macro} whose default is \csbf{do})
+% and a mandatory argument (the expanded List or the List-macro)
+% \item iterates into the list, giving each element to the \textslbf{\sffamily auxiliary macro}
+% \item the \textsfbf{\slshape auxiliary macro} must be of one of the following form: \\[1ex]
+% \hspace*{-\leftmargin}\begin{tabular}{l>{\sfbf}r@{}c@{}c>{\small}l}\hdashline[1pt/1pt]
+% \cs[\copper]{MyParser} & macro:\#1 & -> & |{| something to do with \#1|}| & \makecell{\#1 is an element \\ of the list} \\ \hdashline[1pt/1pt]
+% \cs[\copper]{MyParser}{\stform+} & macro:[\#1]\#2 & -> & |{ " " " |\#1 and \#2|}| & \makecell{\#1 is the index \\ and \#2 the element} \\ \hdashline[1pt/1pt]
+% \cs[\copper]{MyParser}{\stform!} & \multicolumn{3}{l}{expands to the number of elements in the list\bottopstrut} \\ \hdashline[1pt/1pt]
+% \end{tabular}
+% \end{enumerate}
+% \end{framed}
+%
+% The default is to define command-list-parsers \textbfsf{globally}, in order to make easier the
+% modifications of category code inside a group: if you wish \CH{\ttbf\blue+\black$_8$} to be the separator of your list,
+% you will say:§
+% \begin{VerbZ}[commandchars=!()]
+% \begingroup\catcode`\(!blue+)=8
+% (!red\DeclareCmdListParser)(!copper\MyParser){(!blue+)}
+% \endgroup
+% \end{VerbZ}
+%
+% {\rmk If you rather like a locally-defined command-list-parser, it is always possible, specifiying an empty option:
+% ¤¤|\DeclareCmdListParser|\textvb[\red]{[]}|\MyLocalParser{+}|.¤ The default option is |\global|, command-list-parsers are
+% always |\long| macros.}
+% \ClearPage
+%
+% You may then use the following syntaxes:§§
+% \newcommand\UserCmd{[\cs[\dg]{UserCommands}]}
+% \begin{VerbLines}[commandchars=$()]
+% ($copper\MyParser) \myList
+% ($nnn or:) ($copper\MyParser) $UserCmd\myList
+% ($nnn or:) ($copper\MyParser)$stform+ \myList
+% ($nnn or:) ($copper\MyParser)$stform+ $UserCmd\myList
+% ($nnn or:) ($copper\MyParser) $itemitemitem
+% ($nnn or:) ($copper\MyParser) $UserCmd$itemitemitem
+% ($nnn or:) ($copper\MyParser)$stform+ $itemitemitem
+% ($nnn or:) ($copper\MyParser)$stform+ $UserCmd$itemitemitem
+% ($nnn or:) ($copper\MyParser) [$stform(n)]\myList ($nnn expands to item$textsubscript(n))
+% ($nnn or:) ($copper\MyParser) [$stform(n)]$itemitemitem ($nnn expands to item$textsubscript(n))
+% ($nnn or:) ($copper\MyParser)$stform! \myList ($nnn expands to the number of elements)
+% ($nnn or:) ($copper\MyParser)$stform! $itemitemitem ($nnn expands to the number of items)
+%
+% ($nnn or:) $mdfs($copper\MyParser)$stform* $itemitemitem
+% ($nnn or:) $mdfs($copper\MyParser)$stform* $UserCmd$itemitemitem
+% ($nnn or:) $mdfs($copper\MyParser)$stform+$stform*$itemitemitem
+% ($nnn or:) $mdfs($copper\MyParser)$stform+$stform*$UserCmd$itemitemitem
+% ($nnn or:) $mdfs($copper\MyParser)$stform*$stform!$UserCmd$itemitemitem
+% \end{VerbLines}
+%
+% It's possible to break the loop by saying \csbf[\red]{breakloop} in your \cs[\dg]{UserCommands}.
+%
+% \CH{\stform+\stform*} and \CH{\stform*\stform+} are identical, as well as \CH{\stform!\stform*} and \CH{\stform*\stform!}.
+% \ClearPage
+%
+% The \textbfsf{star-form} of \cs[\copper]{MyParser} \textbfsf{is seldom used:} \cs[\copper]{MyParser} abide by the following rules:
+% \begin{enumerate}[label=\roman*)~]
+% \item it checks if the list parameter (here \cs{mylist} or |{item|\mysep|item|\mysep|item}| is a single control word
+% (\cmdref{ifiscs} does the job)
+% \item if this is a single control word, then it is expanded once
+% \item otherwise, no expansion of the list occurs
+% \end{enumerate}
+% \textsfsl{Therefore, the need for the \stform* form is only in the special case where
+% the \textbf{expanded List} contains a single control-word, not followed by a separator.}
+%
+% {\rmk The reader interested in macros with multiple modifiers which may be used in any order
+% can have a look at the definition of \cmdref*{ettl@lst@modif}.}
+%
+% Moreover, \cs{DeclareCmdListParser} defines a macro named \csbf{\ttbf\red for\copper MyParser} to do loops with a syntax
+% very close to \LaTeX's |\@for|: see \cmdref{forcsvloop} for more explanation.
+%
% \end{ltxsyntax}
%
-% There\FE is no x- version for those macros. They work in a different way: the comparison if done by \cs{ifx} and
-% not \cmd{pdfstrcmp}.
+% \ClearPage
+% \Subsection{Loops into lists}
%
-% Therefore, \cs{gettokslistindex} is \textbf{always purely expandable}, but for symmetry reasons, the optional form:§
+% The following macros are purely expandable loops into comma-separated lists (\cs{csvloop}),
+% \xpackage{etoolbox} list (\cs{listloop}) and token lists (lists of tokens without a separator).
+%
+% All of them are defined using \cmdref{DeclareCmdListParser}.
+%
+% \begin{ltxsyntax}
+% \ClearPage
+%
+% \cmditem[csvloop]+@{csvloop\tsptb csvloop\stform+\tsptb csvloop\stform!}
+% \cmditem-{csvloop}[ auxiliary commands ]{ csvlist-macro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]} \FE*
+% \cmditem-{csvloop\stform+}[ auxiliary commands ]{ csvlist-macro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]} \FE*
+% \cmditem-{csvloop\stform!}[ auxiliary commands]{ csvlist-macro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]} \FE*
+% \cmditem-{csvloop\stform*}[ auxiliary commands ]{ \itemitemitem*[{\stform[\blue],}] } \FE*
+% \cmditem-{csvloop\stform*\stform+}[ auxiliary commands]{ \itemitemitem*[{\stform[\blue],}] } \FE*
+% \cmditem-{csvloop\stform*\stform!}[ auxiliary commands]{ \itemitemitem*[{\stform[\blue],}] } \FE*
+%
+% Examples:\FE §§
+% \begin{VerbLines}[commandchars=$()]
+% ($red\csvloop)($copper\mylist) ($nnn is the same as:) ($red\csvloop)($blue[\do])($copper\mylist)
+% ($nnn and applies ($blue$CSbf(do)) sequentially to each element of the comma-separated list.)
+% ($nnn($blue$CSbf(do)) is a user command of the form:)
+% macro: $#1 -> {($nnn something to do with ($vbbf$#1 = item)) }
+% ($nnn The star form ($red$vbbf\csvloop$stform[$rred]*) ($nbf may be) used when ($vbbf$copper\mylist) is already expanded.)
+% ($nnn The plus form ($red$vbbf\csvloop$stform[$rred]+) ($nbf is) used when) $CSbf[$blue](do) ($nnn is of the form:)
+% macro: [$#1]$#2 -> {($nnn something to do with ($vbbf$#1=index) and ($vbbf$#2=item)) }
+% ($nnn If) $CSbf[$blue](do) ($nnn is in fact a number:)
+% ($red\csvloop)[($blue4)]($copper\mylist) ($nnn will expand to the($nbf fifth) element of )($copper\mylist)
+% ($red$vbbf\csvloop$stform[$rred]!)($copper\mylist) ($nnn will expand to the number of elements in) ($copper\mylist)
+% \end{VerbLines}
+%
+% \textbfsf{Be aware that indexes in lists are 0-based: they begin with 0.}
+%
+% Remember that the \stform* form is seldom used: you probably will forget it!
+%
+% \cmditem[listloop]@{listloop\tsptb listloop\stform+\tsptb listloop\stform!}
+% \cmditem-{listloop}[ auxiliary commands ]{ Listmacro or expanded List } \FE*
+% \cmditem-{listloop\stform+}[ auxiliary commands ]{ Listmacro or expanded List } \FE*
+% \cmditem-{listloop\stform!}[ auxiliary commands ]{ expanded List } \FE*
+% \cmditem[listloop*]-{listloop\stform*(\stform+)(\stform!)}[ auxiliary commands ]{ expanded List } \FE*
+%
+% \csbf{listloop}\FE is designed to work with \xpackage{etoolbox} lists (lists with \CH{\stform[\blue]\textbar$_3$} as separator).
+% \cs{listloop} enhances \xpackage{etoolbox}-|\dolistloop| with an optional argument to change
+% the default auxiliary command |\do| to apply to each item of the list, a \stform+ form a \stform! form and a \stform* form.
+%
+% \cmditem[toksloop]@{toksloop\tsptb toksloop\stform+\tsptb toksloop\stform!}
+% \cmditem-{toksloop}[ auxiliary commands ]{ tokenslistmacro or list of single tokens } \FE*
+% \cmditem-{toksloop\stform+}[ auxiliary commands ]{ tokenslistmacro or list of single tokens } \FE*
+% \cmditem-{toksloop\stform!}[ auxiliary commands ]{ tokenslistmacro or list of single tokens } \FE*
+% \cmditem[toksloop*]-{toksloop\stform*(\stform+)(\stform!)}[ auxiliary commands ]{ list of single tokens } \FE*
+%
+% \csbf{toksloop}\FE is a list parser for lists without separator (\cmdref={list of single tokens}).
+% \ClearPage*
+%
+% \cmditem[forcsvloop]+@{forcsvloop\tsptb forcsvloop\stform+}
+% \cmditem[forlistloop]@{forlistloop\tsptb forlistloop\stform+}
+% \cmditem[fortoksloop]@{fortoksloop\tsptb fortoksloop\stform+}
+% \cmditem-{forcsvloop}{ csvlistmacro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]}|\cs[\spot]{do}\{\prm{...\#1...}\}|
+% \cmditem-{forlistloop}{ Listmacro \textsfsl{or} expanded List }|\cs[\spot]{do}\{\prm{...\#1...}\}|
+% \cmditem-{fortoksloop}{ tokenslistmacro \textslsf{or} list of single tokens }|\cs[\spot]{do}\{\prm{...\#1...}\}|
+% \cmditem-{forcsvloop\stform+}{ csvlistmacro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]}|\cs[\spot]{do}\{\prm{...\#1=index...\#2=element...}\}|
+% \cmditem-{forlistloop\stform+}{ Listmacro \textsfsl{or} expanded List }|\cs[\spot]{do}\{\prm{...\#1=index...\#2=element...}\}|
+% \cmditem-{fortoksloop\stform+}{ tokenslistmacro \textslsf{or} list of single tokens }|\cs[\spot]{do}\{\prm{...\#1=index...\#2=element...}\}|
+% \cmditem-{forcsvloop\stform*(\stform+)}{\itemitemitem*[{\stform[\blue],}]}|\cs[\spot]{do}\{\prm{...\#1...}\}|
+% \cmditem-{forlistloop\stform*(\stform+)}{ expanded List }|\cs[\spot]{do}\{\prm{...\#1...}\}|
+% \cmditem-{fortoksloop\stform*(\stform+)}{ list of single tokens }|\cs[\spot]{do}\{\prm{...\#1...}\}|
+%
+% Those macros\notFE\ are just like \cmdref{csvloop}, \cmdref{listloop} and \cmdref{toksloop} but the syntax is quite the
+% same as \LaTeX's \CSbf{@for}, but instead of giving a name to the current item being parsed, it is \#1! (or \#2 with the \stform+ form).
+%
+% |forloop| construct may by nested. Here is an example (merely silly):
% \begin{tabbing}
-% \qquad\=|\gettokslistindex[\myindex]{|\prm{item}|}{|\prm{tokenslistmacro}|}| \\
-% and:\> |\gettokslistindex*[\myindex]{|\prm{item}|}{|\prm{list of tokens}|}|
+% \qquad\=|\forcsvloop|\stform*|{|\=|\relax\meaning|\=|\csname|\=|,%|\\
+%\>\> |\afterassignment\global\count,%|\\
+% \>\>|\endgroup\topskip}\do{%|\\
+% \>\>\> |\fortoksloop|\stform*|{|\#1|}\do{\meaning|\#{\#1}|}}|
% \end{tabbing}
-% are defined.
%
-% An interesting application is the following:
+% Of course, those macros are NOT purely expandable... They are automatically defined by \cmdref{DeclareCmdListParser}
+% with the name: \csbf{\red for\md\copper name-of-parser}.
+%
+% The \stform+ form of \cs{forcsvloop} et al. are relative to the \stform+ form of \cs{csvloop} et al.:
+% \#1 is the index and \#2 the element.
%
-% \begin{Verbatim}[gobble=1,commandchars=!\[\]]
-% !textbf[\ifcase \gettokslistindex*{R}{LORG}]
-% Not in the list: Error ?%
-% \or Here it's L%
-% \or Here it's O%
-% \or Here it's R%
-% \or Here it's G%
-% !textbf[\fi]
-% \end{Verbatim}
+% \end{ltxsyntax}
%
-% Please, refer to the examples...
+% \Subsection{Adding elements to csv lists}
%
-% \subsection{Extract by index from a list}
+% \thispackage provides a facility to add items to a csvlist.
+% \begin{ltxsyntax}
+% \cmditem[csvlistadd]@{csvlistadd/gadd/eadd/xadd}
+% \cmditem-{csvlistadd}{ csvListmacro }{ item }
+% \cmditem-{csvlistgadd}{ csvListmacro }{ item }
+% \cmditem-{csvlisteadd}{ csvListmacro }{ item }
+% \cmditem-{csvlistxadd}{ csvListmacro }{ item }
+%
+% \csbf{csvlistadd}\notFE adds an item to a csvlist. \cs{csvlisteadd} expands the \prm{item}
+% (with |\protected@edef|) \textsfbf{before} appending it to \prm{csvListmacro}, whilst with \cs{csvlistgadd}
+% the final assignment to \prm{csvListmacro} is global. Finally, \cs{csvlistxadd} both expands the \prm{item}
+% and make the assignment global.
+%
+% These macros are robust.
+% \end{ltxsyntax}
+% \ClearPage\enlargethispage{2\baselineskip}
+%
+% \Subsection{Converting lists}
+%
+% Since \cmdref=[DeclareStringFilter]{string filters} are sensitive to the category code of the caracters, it is always possible
+% to convert lists (\ie changing their separator) using them. For exemple, if one wish to convert a comma separated list into
+% a list with \CH{\stform[\blue]\&$_4$} as separator one may say:§§
+% \begin{VerbLines}[commandchars=!()]
+% \def(!copper\mycsvlist){one,two,three,four,five}
+% \DeclareStringFilter(!vbbf\CompareComma){!stform[!blue],}
+% (!dg\begingroup) \catcode`\!stform[!blue]& = 4 (!nsl this is its standard catcode anyway)
+% (!dg\xdef)(!copper\myNewList){(!red\expandnext){(!vbbf\CompareComma+)}(!copper\mycsvlist){!stform[!blue]&}}
+% (!dg\endgroup)
+% \end{VerbLines}
+% But there is another way, may be easier:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!dg\begingroup) \catcode`\!stform[!blue]& = 4 (!nsl this is its standard catcode anyway)
+% (!dg\global\def)(!red\do)#1{\unexpanded{#1!stform[!blue]&}}
+% (!dg\endgroup)
+% (!dg\edef)(!copper\myNewList){\csvloop[(!red\do)](!copper\mycsvlist)}
+% \end{VerbLines}
+%
+% Nevertheless, some conversion could be used very often and \thispackage provides a few macros to convert
+% lists easily:
%
% \begin{ltxsyntax}
+% \ClearPage
+% \cmditem{csvtolist}[ target: Listmacro ]{ source: csvlistmacro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]}
+% \cmditem-{csvtolist\stform*}[ target: Listmacro ]{ source: \itemitemitem*[{\stform[\blue],}] } \FE*
+%
+% \csbf{csvtolist}\FE converts a comma separated list into an internal \xpackage{etoolbox} list. It is useful to insert more than one item
+% at a time in a list. The \prm{Listmacro} (target parameter) is optional and the user may prefer obtain the result in an |\edef|:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\csvtolist)[(!copper\myList)]{one,two,three}
+% (!nnn is the same as:)
+% (!dg\edef)(!copper\myList){(!red\csvtolist){one,two,three}}
+% (!nnn if you want )(!copper\myList)(!nnn to be global, use the second form with )(!dg\xdef)(!nnn instead of )(!dg\edef).
+%(!nnn!rmk* N.B.: the items are not expanded.)
+% \end{VerbLines}
+%
+% The \stform* star form is seldom used: it is there to inhibits the expansion of \prm{source: item,item,item}. But expansion
+% occurs only if this parameter is a single control word...
+% \ClearPage
+%
+% \cmditem{csvtolistadd}{ target: Listmacro }{ source: csvlistmacro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]}
+% \cmditem-{csvtolistadd\stform*}{ target: Listmacro }{ source: \itemitemitem*[{\stform[\blue],}] }
+%
+% \csbf{csvtolistadd}\notFE\ acts similarly but both arguments are mandatory:§§ \def\etbsep{\stform[\blue]\textbar$__3$\!\!\!}
+% \begin{VerbLines}[commandchars=!(),codes={\catcode`\$=3}]
+% \listadd(!copper\myList){one} \listadd(!copper\myList){two}
+% (!red\csvtolistadd)(!copper\myList){three,four,five}
+% \meaning\myList: macro:->one!etbsep two!etbsep three!etbsep four!etbsep five!etbsep
+% \end{VerbLines}
+%
+% \cmditem{tokstolist} [ target: Listmacro ]{ source: tokenslistmacro \textsfsl{or} list of single tokens }
+% \cmditem-{tokstolist\stform*}[ target: Listmacro ]{ source: list of single tokens } \FE*
+%
+% \csbf{tokstolist}\FE converts a list of tokens (no separator) into an internal \xpackage{etoolbox} list:§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\tokstolist)[(!copper\myList)]{\alpha\beta\gamma\ifeof+*$}
+% (!nnn is the same as:)
+% (!dg\edef)(!copper\myList){(!red\tokstolist){\alpha\beta\gamma\ifeof+*$}}
+% \meaning\myList: macro:->\alpha!etbsep \beta!etbsep \gamma!etbsep \ifeof!etbsep +!etbsep *!etbsep $!etbsep
+% (!nnn if you want )(!copper\myList)(!nnn to be global, use the second form with )(!dg\xdef)(!nnn instead of )(!dg\edef).
+%(!nnn!rmk* N.B.: the items are not expanded.)
+% \end{VerbLines}
+%
+% This is also the first application of the \cmdref{toksloop} macro just defined.
+%
+% \cmditem{tokstolistadd} { target: Listmacro }{ source: tokenslistmacro \textsfsl{or} list of single tokens}
+% \cmditem-{tokstolistadd\stform*}{ target: Listmacro }{ source: list of single tokens }
+%
+% \csbf{tokstolistadd}\notFE\ acts similarly but both arguments are mandatory.
+%
+% The \stform* star-form inhibits the expansion of \prm{source} (which otherwise occurs only if \prm{source}
+% is a single control word).
+%
+% \cmditem{listtocsv}[ target: csvlistmacro ]{ source: Listmacro \textsfsl{or} expanded List }
+% \cmditem-{listtocsv\stform*}[ target: csvlistmacro ]{ source: Listmacro \textsfsl{or} expanded List }
+%
+% \csbf{listtocsv}\FE converts an \xpackage{etoolbox}-List into a comma separated list. Be aware that the items in the
+% list does not contain commas (\cs{listtocsv} does not check this point!):§§
+% \begin{VerbLines}[commandchars=!()]
+% (!red\listtocsv)[(!copper\csvList)]\etbList !nnn is the same as:
+% \edef(!copper\csvList){(!red\listtocsv)\etbList}
+% (!nnn if you want )(!copper\csvList)(!nnn to be global, use the second form with )(!dg\xdef)(!nnn instead of )(!dg\edef).
+%(!nnn!rmk* N.B.: the items are not expanded.)
+% \end{VerbLines}
%
-% \subsubsection{\sty{etoolbox}-lists}
+% \end{ltxsyntax}
+% \ClearPage*
%
-% \cmditem{getlistitem}{index [numexpr expression]}{listmacro} \cmdlabel{getlistitem}\seeimpl{getlistitem}
-% \cmditem*{getlistitem*}{index [numexpr expression]}{list}
+% \Subsection{Test if an element is in a list}
%
-% Now\FE the reverse operation of ``getting the index'' is ``getting the element'' whose index is known. Note that this macro
-% is fully expandable for we don't have to compare the items (just count the loop using |\numexpr| -- no counter). Therefore we use the
-% fully expandable version of |\ifstar| : \cmdref{FE@ifstar} to keep the ``fully-expand-ability'' of the star-form as well:
-% \begin{itemize}
-% \item \ If the \prm{index} is in the range $[1\dots n]$ then the macro expands to \prm{item}$_n$
-% \item \ If the \prm{index} is non positive or $>n$ then the macro expands to nothing (|{}|).
-% \end{itemize}
+% \xpackage{etoolbox} provides \cmd{ifinlist} and \cmd{xifinlist}. Similarly, \thispackage provides:
%
-% \subsubsection{Comma-separated lists}
+% \begin{ltxsyntax}
%
-% \cmditem{getcsvlistitem}{index [numexpr expression]}{csvlistmacro} \cmdlabel{getcsvlistitem}\seeimpl{getcsvlistitem}
-% \cmditem*{getcsvlistitem*}{index [numexpr expression]}{item,item,item,...}
+% \cmditem[ifincsvlist]@{ifincsvlist\tsptb xifincsvlist}
+% \cmditem-{ifincsvlist}{ item }{ csvlistmacro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]}{ true }{ false }
+% \cmditem-{xifincsvlist}{ item }{ csvlistmacro \textsfsl{or} \itemitemitem*[{\stform[\blue],}]}{ true }{ false } \notFE*
+% \cmditem-{ifincsvlist\stform*}{ item }{ \itemitemitem*[{\stform[\blue],}]}{ true }{ false}
+% \cmditem-{xifincsvlist\stform*} { item }{ \itemitemitem*[{\stform[\blue],}]}{ true }{ false}
%
-% This is\FE the same as \cmdref{getlistitem} but for comma-separated lists.
+% These macros\notFE\ are not purely expandable. The search is sensitive to the category code
+% of the characters in \prm{item}.
%
-% \subsubsection{Lists of tokens}
+% \end{ltxsyntax}
%
-% \cmditem{gettokslistitem}{index [numexpr expression]}{tokenslistmacro} \cmdlabel{gettokslistitem}\seeimpl{gettokslistitem}
-% \cmditem*{gettokslistitem*}{index [numexpr expression]}{list of tokens}
+% \Subsection{Removing elements from lists}
%
-% The same\FE as \cmdref{getlistitem} for list of tokens.
-% \end{ltxsyntax}
+% \subsubsection{\xpackage{etoolbox} lists}
%
-% \section{Vectorized \cmd{futurelet}}
+% The \xpackage{etoolbox} package provides \cs{listadd}, \cs{listgadd}, \cs{listeadd} and \cs{listxadd} commands
+% to add items to a list. \thispackage provides \cs{listdel}, \cs{listgdel}, \cs{listedel} and \cs{listxdel} to
+% remove elements from a list.
+% \ClearPage
%
+% \begin{ltxsyntax}
%
-% \sty{etextools} defines a vectorized version of \cs{futurelet}. The idea is to say:
+% \cmditem[listdel]+@{listdel/gdel/edel/xdel} \enlargethispage\baselineskip
+% \cmditem-{listdel}[ deleted $n$ times ]{ Listmacro }{ item }
+% \cmditem-{listgdel}[ deleted $n$ times ]{ Listmacro }{ item }
+% \cmditem-{listedel}[ deleted $n$ times ]{ Listmacro }{ item }
+% \cmditem-{listxdel}[ deleted $n$ times ]{ Listmacro }{ item }
+%
+% The \cs{listdel}\notFE\ command removes the element \prm{item} from the list \prm{Listmacro}. Note that the
+% \prm{Listmacro} is redefined after deletion. If the list contains more than one element equal to \prm{item}
+% each is removed.
+%
+% \cs{listedel} expands the \prm{item} (with |\protected@edef|) \textsfbf{before} deletion, whilst with \cs{listgdel}
+% the final assignment to (the \emph{shortened}) \prm{Listmacro} is global. Finally, \cs{listxdel} both expands the \prm{item}
+% and make the assignment global.
+%
+% If the optional parameter \prm{deleted $n$ times} is specified as a control sequence, the macro does the same but
+% but assigns to this control sequence the number of times \prm{item} has been found in the list. If this parameter
+% is not a counter, it is (possibly \textit{re-})defined as a macro:§§
+% \begin{VerbLines}[commandchars=$()]
+% \newcount($dg\mycounter)
+% \def($copper\myList){one,two,($dgray$!$!$! three),two,($dgray$!$!$! three),four,five,($dgray$!$!$! three)}
+% ($dg\mycounter) = ($red\listdel)$stform[$blue]!($copper\myList){($dgray$!$!$! three)}
+% \the($dg\mycounter) ($nnn will be ) 3
+% \end{VerbLines}
%
-% \quad|\collecttoks\macro{|\prm{list of allowed tokens}|}{|\prm{commands to execute next}|}|
+% \end{ltxsyntax}
%
-% Then \cs{collecttoks} is a kind of simple scanner for tokens. It can be used to define an \textbf{\textit{undelimited macro}}
-% \ie a macro that has no delimiter but whose content of arguments is restricted.
+% \subsubsection{csv-lists}
%
% \begin{ltxsyntax}
-% \cmditem{collecttoks}{cs-token}{list of tokens}{commands to expand after} \cmdlabel{collecttoks}\seeimpl{collecttoks}
+%
+% \cmditem[csvdel] @{csvdel/gdel/edel/xdel}
+% \cmditem-{csvdel}[ deleted $n$ times ]{ csvlistmacro }{ item }
+% \cmditem-{csvgdel}[ deleted $n$ times ]{ csvlistmacro }{ item }
+% \cmditem-{csvedel}[ deleted $n$ times ]{ csvlistmacro }{ item }
+% \cmditem-{csvxdel}[ deleted $n$ times ]{ csvlistmacro }{ item }
+%
+% Are similar for\notFE\ comma-separated lists. Those macros are NOT purely expandable.
+%
+% \subsubsection{Lists of single tokens}
+%
+% \cmditem[toksdel]@{toksdel/gdel/edel/xdel}
+% \cmditem-{toksdel}[ deleted $n$ times ]{ tokslistmacro }{ item }
+% \cmditem-{toksgdel}[ deleted $n$ times ]{ tokslistmacro }{ item }
+% \cmditem-{toksedel}[ deleted $n$ times ]{ tokslistmacro }{ item }
+% \cmditem-{toksxdel}[ deleted $n$ times ]{ tokslistmacro }{ item }
+%
+% Are similar\notFE\ for lists of single tokens (lists without separator).
+%
% \end{ltxsyntax}
%
-% The macro \cs{collecttoks} will read the following tokens with \cs{futurelet}. If that token is in the allowed
-% list, then it will append it to \cs{macro} (\prm{cs-token}) and continue, scanning the tokens one after another.
+% \Subsection{Index of an element in a list}
%
-% Until it founds a token which is not in the list. Then it stops reading and execute the \prm{commands to expand}.
-% Those commands may use the \cs{macro} defined for analyse or whatever the user want.
+% \subsubsection{\xpackage{etoolbox}-lists}
%
-% \medskip
-% As an application, it can be used to define an easy interface for |\hdashline| (the dashed lines in tabulars and arrays
-% provided by the \sty{arydshln} package): modifying \cmd{hline} in order to give sense to the following:
-% \begin{tabbing}
-% \qquad\=|\hline..|\qquad\=|\hline--|\qquad\=|\hline==|\qquad\= |\hline.-|\qquad\=|\hline.-.|\ \= etc.
-% \end{tabbing}
+% \begin{ltxsyntax}
%
-% After having collected the allowed tokens with:§
-% |\collecttoks\nexttokens{.-=}{|\prm{commands next}|}| \quad it is possible to
-% test the pattern given using \cs{pdfstrcmp} and, for example, the \CSbf{switch} construction of the \sty{boolexpr} package:
+% \cmditem{getlistindex}[result-index(counter or macro)]{item}{Listmacro}
+% \cmditem-{xgetlistindex}[result-index(counter or macro)]{item}{Listmacro}
+% \cmditem-{getlistindex*}[result-index(counter or macro)]{item}{list}
+% \cmditem-{xgetlistindex*}[result-index(counter or macro)]{item}{list}
%
-% \begin{Verbatim}[gobble=1,commandchars=!()]
-% !textbf(\switch[\pdfstrcmp{\nexttokens}])
-% \case{{..}}\hdashline[parameters]%
-% \case{{--}}\hdashline[parameters]%
-% \case{{==}}\hdashline[parameters]%
-% \case{[.-.}}\hdashline[parameters]%
-% \otherwise \original@hline%
-% !textbf(\endswitch)
-% \end{Verbatim}
+% \end{ltxsyntax}
+%
+% Sometimes it is interesting to know at which offset in a list lies a given item. |\getlistindex| answers to this question.
+% |\xgetlistindex| does the same thing but expands the \prm{item} while looking for it in the list.
+%
+% As for the command-list-parser, the star versions are designed in case the list (in the second argument) is already expanded.
%
-% \CSbf{switch} is purely expandable.
+% \begin{itemize}
+% \item \ If \prm{item} is not found in the list, \cs{getlistindex} expands to 0
+% \item \ If \prm{item} is found in first position then \cs{getlistindex} expands to 1 and so on.
+% \end{itemize}
%
-% If you replace \cs{pdfstrcmp} by |\ifstrequal|, \cs{switch} works but is not purely expandable.
+% Those macros are not purely expandable.
%
-% See \sty{boolexpr} (\CTAN{macros/latex/contrib/boolexpr/}) for more information on \cs{switch}.
+% N.B. If \prm{result-index} is not a counter it is (possibly \textit{re-})defined as macro.
%
+% \subsubsection{Comma-separated lists}
%
+% \begin{ltxsyntax}
+% \cmditem{getcsvlistindex}[result-index(counter or macro)]{item}{csvlistmacro}
+% \cmditem-{xgetcsvlistindex}[result-index(counter or macro)]{item}{csvlistmacro}
+% \cmditem-{getcsvlistindex*}[result-index(counter or macro)]{item}{item,item,item,...}
+% \cmditem-{xgetcsvlistindex*}[result-index(counter or macro)]{item}{item,item,item,...}
+% \end{ltxsyntax}
%
+% This is the same as \cmdref{getlistindex} but for comma-separated lists.
+%
+% As for the command-list-parser, the star versions are designed in case the list (in the second argument) is already expanded.
+%
+% If \prm{result-index} is not a counter it is (possibly \textit{re-})defined as macro.
%
% \StopEventually{
% }
%
-% \part*{\LaTeX{} code}
-% \addtocontents{toc}{\protect\contentsline{part}{\large\LaTeX{} code}{}{}}
+% \part*{{\spot\smiley}\hfill \LaTeX{} code\hfill{\spot\smiley}}
+% \addtocontents{toc}{\protect\contentsline{part}{\LaTeX{} code}{}{}}
+% \implementationsubsecformat
%
-% \section{Implementation}
+% \Section*{Implementation} \refstepcounter{section}%
+% ^^A\addcontentsline{toc}{section}{\texorpdfstring\dr{}\hskip\dimexpr\cftsecnumwidth-4pt Implementation}^^A do not add to .cmd file
+% \addcontentsline{toc}{section}{\protect\numberline{I}\cftsecfont Implementation}^^A do not add to .cmd file
+% \addtocontents{toc}{\cftbeforesubsecskip=-2pt plus\gluestretch\cftbeforesubsecskip\relax}
+% \renewcommand\thesubsection{I.\arabic{subsection}}^^A for toc
%
-% \subsection{Package identification}
+% \Subsection{Package identification}
%
% \begin{macrocode}
%<*package>
\NeedsTeXFormat{LaTeX2e}[1996/12/01]
\ProvidesPackage{etextools}
- [2009/08/14 v2h e-TeX more useful tools for LaTeX package writers]
+ [2009/08/27 v3.0 e-TeX more useful tools for LaTeX package writers]
\csname ettl@onlyonce\endcsname\let\ettl@onlyonce\endinput
% \end{macrocode}
%
-% \subsection{Requirements}
+% \Subsection{Requirements}
%
-% This package requires the packages \sty{etex} package by David Carlisle and
-% \sty{etoolbox} by Philipp Lehman.
+% This package requires the packages \xpackage{etex} package by David Carlisle
+% \xpackage{etoolbox} by Philipp Lehman and \xpackage{letltxmacro} by Heiko Oberdiek (for \cmdref*{aftergroup@def}):
%
% \begin{macrocode}
-\RequirePackage{etex,etoolbox}
+\RequirePackage{etex,etoolbox,letltxmacro}
% \end{macrocode}
%
-% Furthermore, the space token must have its natural catcode (10) all along this package.
-%
+% The divide sign \CH{\stform[\rred]/} (or slash) is given a catcode of $\mathbf8$. \textbfsf{It is used as a delimiter.}
+% This choice is driven by three reasons:\cmdlabel{catcode choice}
+% \begin{enumerate}[label=\arabic*)~]
+% \item \CH{\stform[\rred]/} cannot be used in |\numexpr| expressions if its catcode is different of $12$,
+% making unlikely that someone changes its catcode in his document. However, the same is true
+% for \CH{\stform<}, \CH{\stform>}, \CH{\stform=}, \CH{\stform+}, \CH{\stform-} and \CH{\stform.} (for dimensions) but:
+% \item \CH{\stform[\rred]/} is not used in \thispackage but as a delimiter (whereas \CH+, \CH-, \CH<, \CH>, \CH= and \CH.
+% are used with their normal meaning).
+% \item but why {$\rred\mathbf8$} ? if someone changes the catcode of \CH{\stform[\rred]/} it is unlikely that she will choose
+% $\rred\mathbf8$ (the \textit{\rred math subscript} which has nothing to do with \stform[\rred]/...) whereas it is not so unlikely that
+% someone needs \CH{\stform[\rred]/} as a \emph{tab alignment character} (catcode $4$) or a \emph{math shift} (catcode $3$)
+% or another special need (catcode $13$)...
+% Finally, we could have chosen {$\blue\mathbf7$} but then a sequence like: \CH{\stform[\blue]/$\mathbf{_7}$\stform[\blue]/$\mathbf{_7}$}
+% is read by \TeX{} like \CH{\stform[\blue]{\string^}$\mathbf{_7}$\stform[\blue]{\string^}$\mathbf{_7}$} with a very special meaning...
+% \end{enumerate}
+% Therefore, the choice might not be bad...
% \begin{macrocode}
\let\ettl@AtEnd\@empty
\def\TMP@EnsureCode#1#2{%
@@ -871,905 +2398,2209 @@ and etextools-examples.tex
}%
\catcode#1 #2\relax
}
-\TMP@EnsureCode{32}{10}% space
+\TMP@EnsureCode{32}{10}% space... just in case
+\TMP@EnsureCode{47}{8}% /
+\TMP@EnsureCode{167}{7}% §
+\TMP@EnsureCode{164}{7}% ¤
+\TMP@EnsureCode{42}{12}% *
+\TMP@EnsureCode{43}{12}% +
+\TMP@EnsureCode{45}{12}% -
+\TMP@EnsureCode{46}{12}% .
+\TMP@EnsureCode{60}{12}% <
+\TMP@EnsureCode{61}{12}% =
+\TMP@EnsureCode{62}{12}% >
+\TMP@EnsureCode{33}{12}% !
+\TMP@EnsureCode{152}{13}% ~ for the character test
\ifundef\pdfstrcmp{%
- \TMP@EnsureCode{33}{9}% ! ignore
- \TMP@EnsureCode{34}{14}% " comment
-}{\TMP@EnsureCode{33}{14}% ! comment
- \TMP@EnsureCode{34}{9}% " ignore
+ \TMP@EnsureCode{163}{9}% £ ignore
+ \TMP@EnsureCode{128}{14}% \texteuro comment €
+}{\TMP@EnsureCode{163}{14}% £ comment
+ \TMP@EnsureCode{128}{9}% \texteuro ignore
}
\AtEndOfPackage{\ettl@AtEnd\undef\ettl@AtEnd}
% \end{macrocode}
%
-% \subsection{A few (7) ``helper'' macros}
+% \Subsection{Some ``helper'' macros}
%
% \iffalse
%<package>
%<package>% A few helper macros
% \fi
+%
+%\begin{macro}{helper macros} \FE
% \begin{macrocode}
-\long\def\ettl@afterelse#1\else#2\fi{\fi#1}
-\long\def\ettl@afterfi#1\fi{\fi#1}
-\long\def\ettl@afterfifi#1\fi\fi{\fi\fi#1}
-\long\def\ettl@afterelsefi#1\else#2\fi\fi{\fi#1}
-\long\def\ettl@afterorfi#1\or#2\fi{\fi#1}
+\let\ettl@ifdefined\iffalse%\ifdefined% turn to \iffalse to test other implementation on pdfTeX
+\long\def\ettl@fi#1\fi{\fi#1}
+\long\def\ettl@else#1\else#2\fi{\fi#1}
+\long\def\ettl@or#1\or#2\fi{\fi#1}
+\def\ettl@expandaftwo{\expandafter\expandafter\expandafter}
+\def\ettl@expandafthree{\expandafter\expandafter\expandafter%
+ \expandafter\expandafter\expandafter\expandafter}
+\cslet{ettl@1of1}\@firstofone %% for internal use only
+\cslet{ettl@1of2}\@firstoftwo %% for internal use only
+\cslet{ettl@2of2}\@secondoftwo %% for internal use only
+\long\def\rmn@firstoftwo#1#2{\z@#1} %% for romannumeral
+\long\def\rmn@secondoftwo#1#2{\z@#2}%% for romannumeral
+\long\def\ettl@cdr#1#2\@nil{#2} %% \@cdr should be a LONG macro
+\long\def\ettl@car#1#2\@nil{#1} %% \@car should be a LONG macro
+\long\csdef{ettl@1of3}#1#2#3{#1}
+\long\csdef{ettl@2of3}#1#2#3{#2}
+\long\csdef{ettl@3of3}#1#2#3{#3}
+\long\csdef{ettl@12of3}#1#2#3{{#1}{#2}}
+\long\def\ettl@carcar#1#2#3#4{#4}
+\long\def\ettl@firstspace#1#2#3{\expandafter\ettl@firstsp@ce\detokenize{#1} \\{#3}{#2}//}
+\long\def\ettl@firstsp@ce#1 #2\\{\ettl@nbk#1//}
+\long\def\ettl@csname#1\endcsname{\fi\endcsname}%% useful to get out of \if
% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\ettl@char}
+% \cs{ettl@char} expands to \prm{true} if its argument is a single character token. It is used in
+% \cmdref*{ettl@ifnextchar}.
+% \begin{macrocode}
+\long\def\ettl@char#1{\csname ettl@\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax
+ 1\else2\fi of2\endcsname}
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\ettl@intmax}
+% This\FE is the maximum integer allowed by e\TeX{} for |\numexpr| ($2^31-1$) and all arithmetic operations:
+% \begin{macrocode}
+\providecommand*\@intmax{2147483647}
+\def\ettl@intmax{2147483647}
+% \end{macrocode}
+%\end{macro}
%
% \iffalse
%<package>
+%<package>%% \ettl@onlypdfTeX for internal use
% \fi
%
-% \begin{macro}{\ettl@ifstrcmp}
-% Use of the pdf\TeX{} primitive \cs{pdfstrcmp} and design a \LaTeX{} form.
+% \begin{macro}{\ettl@onlypdfTeX}
+% This is an \textit{internal macro} used by the package: if the \prm{primitive}
+% in \#1 is available (\eg \cs{pdfstrcmp}) then the \prm{command} in \#2
+% can be defined, otherwise, the \prm{command} is \cs{let} to the optional argument \#3.
+% If there is no such optional argument, the \prm{command} throws an error (\eg \cs{ifstrmatch}).
% \begin{macrocode}
-\def\ettl@ifstrcmp#1#2{\csname @%
- \ifnum\pdfstrcmp{#1}{#2}=0 first\else second\fi oftwo\endcsname}
+\def\ettl@onlypdfTeX#1#2{\@testopt{\ettl@only@pdfTeX{#1}{#2}}{}}
+\def\ettl@only@pdfTeX#1#2[#3]{\ifundef{#1}
+ {\ifblank{#3}
+ {\def#2{\PackageError{etextools}{\string#1\space primitive not found\MessageBreak
+ pdfTeX seems not to be running}
+ {\string#2\space works only if used with pdfTeX (requires \string#1)}}}
+ {\AtEndOfPackage{\let#2=#3}%
+ \PackageWarning{etextools}{\string#1\space primitive not found\MessageBreak
+ Macro \string#2\space has been replaced by \string#3\space\MessageBreak
+ It is not purely expandable}}
+ }\relax}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@gobblescape}
+% \iffalse
+%<package>
+%<package>%% \ettl@nbk argument to be tested//{ true }{ false }//
+%<package>% `/` has a catcode of 3 all along this package
+% \fi
+%
+% \begin{Macro*}{ettl@nbk}
+% \CSbf{ettl@nbk}\FEI is an optimized form of |\ifblank|. \TeX{} switches to the
+% \prm{true} part if the expanded argument (delimited by \CH{\chcat/8\chcat/8}) is
+% \txtbf[\rred]not \txtbf[\rred]blan\txtbf[\rred]k.
+%
+% Usage: |\ettl@nbk |\prm{string}|\chcat/8\chcat/8|\prm{true}\prm{false}|\chcat/8\chcat/8|
+% \begin{tabbing}
+% \qquad\=if \prm{string} is blank:¤\=\#1=\CH/,¤`\#2=\o,¤\#3=\prm{true},¤\=\#4=\prm{false}\\
+% \>\hfil otherwise:\>\#3=\CH/,\>\#4=\prm{true}¤(and \#5=\prm{false})
+%\end{tabbing}
+% \begin{macrocode}
+\long\def\ettl@nbk #1#2/#3#4#5//{#4}
+\long\def\ettl@nbk@else#1#2/#3#4#5//#6\else#7\fi{\fi#4}
+% \end{macrocode}
+% \end{Macro*}
+%
+%\begin{macro}{\ettl@ney}
+% \cs{ettl@ney}\FEII is exactly |\ifnotempty| but with the syntax of |\ettl@nbk|: it may be used in place of |\ettl@nbk|:
+% \begin{macrocode}
+\long\def\ettl@ney#1//#2#3//{\romannumeral 0\csname @%
+ \if\relax\detokenize{#1}\relax first\else second\fi oftwo\endcsname
+ { #2}{ #3}}
+% \end{macrocode}
+%\end{macro}
+%
+% \iffalse
+%<package>
+%<package>% The following macros are not used (here just for memory, in case of...)
+% \fi
+%
+%\begin{macro}{\ettl@nbk@cat} \FE
+% \CSbf{ettl@nbk@cat} switches to \prm{true} if \prm{string} is not blank AND if its first token has the
+% same category code of \prm{tokenA}:
%
-% This sequence of command is very often used, even in \sty{latex.ltx}. So
+% Usage: |\ettl@nbkcat |\prm{tokenA}\prm{string}|//|\prm{same catcodes}\prm{different catcodes}|//|
+% \begin{macrocode}
+\long\def\ettl@nbk@cat#1#2#3/#4#5#6//{\ettl@nbk#6//%
+ {\ifcat#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//}
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\ettl@nbk@ifx} \FE
+% \CSbf{ettl@nbk@ifx} switches to \prm{true} if \prm{string} is not blank AND if its first token is
+% equal to \prm{tokenA} in the sense of \cs{ifx}:
+%
+% USAGE: |\ettl@nbk@ifx |\prm{tokenA}\prm{string}|//|\prm{true}\prm{false}|//|
+% \begin{macrocode}
+\long\def\ettl@nbk@ifx#1#2#3/#4#5#6//{\ettl@nbk#6//%
+ {\ifx#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//}
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\ettl@nbk@if} \FE
+% \CSbf{ettl@nbk@if} switches to \prm{true} if \prm{string} is not blank AND if its first token is
+% equal to \prm{tokenA} in the sense of \cs{if}:
+%
+% USAGE: |\ettl@nbk@if |\prm{tokenA}\prm{string}|//|\prm{true}\prm{false}|//|
+% \begin{macrocode}
+\long\def\ettl@nbk@if#1#2#3/#4#5#6//%
+ {\ettl@nbk#6//{\if#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//}
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\ettl@nbk@IF} \FE
+% More generally: |\ettl@nbk@IF[cat]|=|\ettl@nbk@ifcat|¤|\ettl@nbk@IF[x]|=|\ettl@nbk@ifx|¤|\ettl@nbk@IF[]|=|\ettl@nbk@if|:
+% \begin{macrocode}
+\long\def\ettl@nbk@IF[#1]#2#3#4/#5#6#7//{\ettl@nbk#7//%
+ {\csname if#1\endcsname\ettl@else#6\else\ettl@fi#7\fi}{#6}//}
+% \end{macrocode}
+%\end{macro}
+%
+%
+%\iffalse
+%<package>
+%<package>%% \@gobblespace and The Space Token
+% \fi
+%\begin{Macro}{@gobblespace}
+% \begin{macrocode}
+\long\def\@gobblespace#1 {#1}
+% \end{macrocode}
+%\end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \@gobblescape \cs-token
+% \fi
+%
+% \begin{Macro}{@gobblescape}
+% This sequence of commands is very often used (even in \sty{latex.ltx}). So
% it appears to be better to put it in a macro. It's aim is to reverse the
% mechanism of |\csname|...|\endcsname|:
% \begin{macrocode}
-\newcommand*\@gobblescape{\expandafter\@gobble\string}
+\newcommand*\@gobblescape{\romannumeral0\expandafter\@gobble\string}
% \end{macrocode}
% {\rmk May be we could do better, testing first if the next token is a control sequence...}
-% \end{macro}
+% \end{Macro}
%
+% \iffalse
+%<package>
+%<package>% The swap macros
+% \fi
%
+%\begin{Macro}{@swap}
+% \CS{@swap} reverses the order and does not add any curly braces:
% \begin{macrocode}
-\def\ettl@onlypdfTeX#1#2{\ifundef{#1}
- {\def#2{\PackageError{etextools}{\string#1\space primitive not found\MessageBreak
- pdfTeX seems not to be running}
- {\string#2\space works only if used with pdfTeX (requires \string#1)}}}
- {}}
+\newcommand\@swap[2]{#2#1}
+\@swap{ }{\let\ettl@sptoken= }% This makes \ettl@sptoken a space token
% \end{macrocode}
+%\end{Macro}
%
-% \subsection{Expansion control}
+% \begin{Macro}{@swaparg}
+% \CS{@swaparg} reverses the order: the first argument (that will become the second), is
+% considered to be the first argument of the second (\textbf{!}):
+% \begin{macrocode}
+\newcommand\@swaparg[2]{#2{#1}}
+% \end{macrocode}
+% \end{Macro}
%
+%\begin{Macro}{@swaplast}
+% \CS{@swaplast} reverse the order of two tokens, but keeps the first in first position:
+% \begin{macrocode}
+\newcommand\@swaplast[3]{#1#3#2}
+% \end{macrocode}
+%\end{Macro}
%
-% \begin{macro}{\noexpandcs}\cmdlabel{impl:noexpandcs}
-% {\rmk|\noexpandcs| may be abbreviated f.ex. in |\`#1`| or |\"#1"| in |\edef| that take place in a group.}\seedesc{noexpandcs}
+% \begin{Macro}{@swaptwo}
+% \CS{@swaptwo} reserves the order but keeps the curly braces:
% \begin{macrocode}
-\newcommand*\noexpandcs[1]{\expandafter\noexpand\csname #1\endcsname}
+\newcommand\@swaptwo[2]{{#2}{#1}}
% \end{macrocode}
-% \end{macro}
+% {\rmk this macro is used in \cmdref{gettokslistindex}}
+% \end{Macro}
%
-% \begin{macro}{\noexpandafter}\cmdlabel{impl:noexpandafter}
-% {\rmk \cmd{noexpandafter} only means \cmd{noexpand}\cmd{expandafter} and is shorter to type.}\seedesc{noexpandafter}
+% \Subsection{Expansion control}
+%
+% \iffalse
+%<package>
+%<package>%% \expandaftercmds : expansion control
+%<package>% level 1 : \expandaftercmds { code }{ cs-token }
+%<package>% level 2 : \expandaftercmds\expandaftercmds { code }{ cs-token }
+% \fi
+%
+% \begin{Macro}{expandaftercmds}
+% \CSbf{expandaftercmds} generalizes \CSbf{expandafter}: arbitrarily \prm{code} might be
+% put as a first argument.
+%
+% The idea is to \textit{swap} the arguments in order to expand the second (in first position after the swap)
+% as many times as there are \cs{expandnext}s. At exit, swap again.
% \begin{macrocode}
-\newcommand\noexpandafter{\noexpand\expandafter}
+\newcommand\expandaftercmds[2]{%
+ \ifsingletoken\expandaftercmds{#1}
+ {\expandafter@cmds{#2}{\expandafter\expandafter\expandafter}}
+ {\expandafter\@swap\expandafter{#2}{#1}}}
+\long\def\expandafter@cmds#1#2#3{%
+ \ifsingletoken\expandafter@cmds{#1}
+ {\expandafter@cmds{#3}{\expandafter#2#2}}
+ {\@swap#2{#3}{#1}}}
% \end{macrocode}
+% \end{Macro}
%
-% \end{macro}
%
-% \begin{macro}{\expandnext}\cmdlabel{impl:expandnext}
+% \begin{Macro}{expandnext}
%
-% This code is not properly \seedesc{expandnext} tricky but if you're eager to understand the job of each expandafter,
+% This code is not properly tricky but if you're eager to understand the job of each \cs{expandafter},
% it's best to go straight at the log.
%
-% Note that the first argument of |\expandnext| must be a single \prm{cstoken} (for \cmd{expandafter} acts
-% only on the first following token).
-%
% \iffalse
%<package>
-%<package>% \expandnext : expansion control
-%<package>% level 1 : \expandnext#1{...} <=> \expandafter#1\expandafter{...}
-%<package>% level 2 : \expandnext\expandnext#1{...} etc.
+%<package>%% \expandnext : expansion control
+%<package>% level 1 : \expandnext { code }{ control sequences : the first is expanded before code }
+%<package>% level 2 : \expandnext\expandnext{ code }{ control sequences }
% \fi
% \begin{macrocode}
\newcommand\expandnext[2]{%
- \ifx#1\expandnext
- \ettl@afterelse\expandafter\expandafter\expandafter
- \expandafter\@expandnext{#2}{\expandafter\expandafter\expandafter}%
- \else\ettl@afterfi\expandafter#1\expandafter{#2}%
- \fi}
+ \ifsingletoken\expandnext{#1}
+ {\@expandnext{#2}{\expandafter\expandafter\expandafter}}
+ {\expandafter\@swaparg\expandafter{#2}{#1}}}
\long\def\@expandnext#1#2#3{%
- \ifx#1\expandnext
- \expandafter\ettl@afterelse\expandafter\expandafter\expandafter
- \expandafter\@expandnext{#3}{\expandafter#2#2}%
- \else
- \expandafter\ettl@afterfi#2#1#2{#3}%
- \fi}
+ \ifsingletoken\expandnext{#1}
+ {\@expandnext{#3}{\expandafter#2#2}}
+ {#2\@swaparg#2{#3}{#1}}}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
+%
% \iffalse
%<package>
+%<package>%% \expandnexttwo{ code }{ control sequences }{ control sequences }
% \fi
%
+%\begin{Macro}{expandnexttwo}
+\newcommand\expandnexttwo[3]{\expandnext{\expandnext{#1}{#2}}{#3}}
+%\end{Macro}
%
-% \subsection{Character and Strings}
+% \iffalse
+%<package>
+%<package>%% \ExpandAfter { code } { cs-token }
+% \fi
+%
+%\begin{Macro}{ExpandAftercmds}
+% \cs{ExpandAftercmds} acts like the primitive \cs{expandafter} but expands totally the second \textbfsf{token}:
+% \begin{macrocode}
+\newcommand\ExpandAftercmds[2]{\expandafter\@swap\expandafter{\romannumeral-`\q#2}{#1}}
+% \end{macrocode}
+%\end{Macro}
%
% \iffalse
%<package>
-%<package>% \ifempty{ text }{ true }{ false }
+%<package>%% \ExpandNext { code } { argument }
% \fi
%
-% \begin{macro}{\ifempty} \cmdlabel{impl:ifempty}
-% |\ifempty| is based on |\detokenize| and can manage with any argument.\seedesc{ifempty}
+% \begin{Macro}{ExpandNext}
+% \cs{romannumeral} forces the expansion of the second \textbfsf{argument.}
% \begin{macrocode}
-\newcommand\ifempty[1]{\csname @\expandafter\ifx
- \expandafter\relax\detokenize{#1}\relax
- first\else second\fi oftwo\endcsname}
+ % I'm not sure it is interesting to use \expandnext here...
+ %\newcommand\ExpandNext[2]{\expandnext{#1}{\romannumeral-`\q#2}}
+\newcommand\ExpandNext[2]{\expandafter\@swaparg\expandafter{\romannumeral-`\q#2}{#1}}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \ifnotempty{ text }{ true }{ false }
+%<package>%% \ExpandNextTwo { code } { arg1 }{ arg2 }
% \fi
%
-% \begin{macro}{\ifnotempty} \cmdlabel{impl:ifnotempty}
-% |\ifnotempty| is based on |\detokenize| and can manage with any argument.\seedesc{ifnotempty}
+%\begin{Macro}{ExpandNextTwo}
% \begin{macrocode}
-\newcommand\ifnotempty[1]{\csname @\expandafter\ifx
- \expandafter\relax\detokenize{#1}\relax
- second\else first\fi oftwo\endcsname}
+\newcommand\ExpandNextTwo[3]{\ExpandNext{\ExpandNext{#1}{#2}}{#3}}
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
%
% \iffalse
%<package>
-%<package>% \xifempty{ text }{ true }{ false }
+%<package>% noexpandcs { csname }
% \fi
-% \begin{macro}{\xifempty} \cmdlabel{impl:xifempty}
-% |\xifempty| is based on pdf-TeX{} |\pdfstrcmp| and work with any argument.\seedesc{xifempty}
+%
+% \begin{Macro}{noexpandcs}
+% {\rmk|\noexpandcs| may be abbreviated f.ex. in |\`#1`| or |\"#1"| in |\edef| that take place in a group.}
% \begin{macrocode}
-\newcommand\xifempty[1]{\xifstrcmp{#1}{}}
-\ettl@onlypdfTeX\pdfstrcmp\xifempty
+\newcommand*\noexpandcs[1]{\expandafter\noexpand\csname #1\endcsname}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \ifnotblank{ text }{ true }{ false }
+%<package>% noexpandafter
% \fi
%
-% \begin{macro}{\ifnotblank} \cmdlabel{impl:ifnotblank}
-% |\ifnotblank| reverses the test of |\ifblank|.\seedesc{ifnotblank}
+% \begin{Macro}{noexpandafter}
+% {\rmk \cmd{noexpandafter} only means \cmd{noexpand}\cmd{expandafter} and is shorter to type.}
% \begin{macrocode}
-\begingroup\catcode`\&=3\catcode`\:=12
-\ifcsundef{ifnotblank}{%
-\long\gdef\ifnotblank#1{\etb@ifblank@i#1&&\@firstoftwo\@secondoftwo:}}
-\relax\endgroup
+\newcommand*\noexpandafter{\noexpand\expandafter}
% \end{macrocode}
-% \end{macro}
+%
+% \end{Macro}
+%
+% \Subsection{Meaning of control sequences}
%
% \iffalse
%<package>
-%<package>% \xifblank{ string }{ true }{ false }
+%<package>%% \showcs { csname }
% \fi
%
-% \begin{macro}{\xifblank}\cmdlabel{impl:xifblank}
-% Just expands the parameter using |\protected@edef| before testing for |\ifblank|: \seedesc{xifblank}
+% \begin{Macro}{showcs}
+% \cs{showcs} shows the meaning of a named control sequence:
% \begin{macrocode}
-\newrobustcmd\xifblank[1]{\begingroup
- \protected@edef\@xifblank{\endgroup
- \noexpand\ifblank{#1}%
- }\@xifblank}
+\providecommand*\showcs[1]{\expandafter\show\csname#1\endcsname}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \meaningcs { csname }
+% \fi
%
+% \begin{Macro}{meaningcs}
+% \cs{meaningcs} expands in one level:
+% \begin{macrocode}
+\providecommand\meaningcs[1]{\romannumeral-`\q
+ \csname\ifcsdef{#1}{ettl@meaningcs\endcsname{#1}}
+ {meaning\endcsname\@undefined}}
+\def\ettl@meaningcs#1{\expandafter\meaning\csname#1\endcsname}% here we don't need \z@ to stop \romannumeral
+ % because \meaning is never blank nor begins with a space...
+% \end{macrocode}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \iffirstchar{ string1 }{ string2 }{ true }{ false }
+%<package>%% \strip@meaning { cs-token }
+%<package>%% \strip@meaningcs { csname }
% \fi
%
-% \begin{macro}{\iffirstchar}\cmdlabel{impl:iffirstchar}
-% |\iffirstchar| test if |#1| and |#2| begins with the same character. \seedesc{iffirstchar}
+% \begin{Macro}{strip@meaning}
+% Just give the meaning without the prefix `|macro:|`. \cs{strip@prefix} will expand to an empty string if
+% its argument is undefined, and to the |\meaning| if it is not a macro.
+% \begin{Macro}{strip@meaningcs}
+% The same but for named control sequences:
% \begin{macrocode}
-\newcommand\iffirstchar[2]{\csname @%
- \if \expandafter\@car\detokenize{#2}\relax\@nil\expandafter\@car\detokenize{#1}\string\\\@nil
- \ifblank{#2}{second}{first}%
- \else second%
+\newcommand*\strip@meaning[1]{\romannumeral\csname\ifdef{#1}%
+ {\ifdefmacro{#1}{ettl@strip@meaning}{ettl@meaning}\endcsname#1}{z@\endcsname}}
+\providecommand*\strip@meaningcs[1]{\romannumeral\csname\ifcsdef{#1}%
+ {\ifcsmacro{#1}{ettl@strip@meaning}{ettl@meaning}%
+ \expandafter\endcsname\csname#1\endcsname}
+ {z@\endcsname}}
+\def\ettl@strip@meaning{\expandafter\expandafter\expandafter\z@% for \romannumeral in case the \meaning is blank...
+ \expandafter\strip@prefix\meaning}
+\def\ettl@meaning{\expandafter\z@\meaning}
+% \end{macrocode}
+% \end{Macro}
+% \end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \parameters@meaning { cs-token }
+%<package>%% \parameters@meaningcs { csname }
+% \fi
+%
+% \begin{Macro}{parameters@meaning}
+% \begin{Macro*}{parameters@meaningcs}
+% Expands to the \textit{parameter string} of a macro, or to an empty string if not a macro:
+% \begin{macrocode}
+\providecommand*\parameters@meaning[1]{}
+\edef\parameters@meaning#1{\unexpanded{\romannumeral\expandafter
+ \expandafter\expandafter\z@\expandafter\ettl@params@meaning%
+ \meaning}#1\detokenize{macro:->}/}
+\providecommand*\parameters@meaningcs[1]{}
+\edef\parameters@meaningcs#1{\unexpanded{\romannumeral\ettl@expandafthree\z@
+ \expandafter\expandafter\expandafter\ettl@params@meaning%
+ \expandafter\meaning\csname}#1\endcsname\detokenize{macro:->}/}
+\edef\ettl@params@meaning{%
+ \def\noexpand\ettl@params@meaning\detokenize{macro:}##1\detokenize{->}##2/{##1}%
+}\ettl@params@meaning
+% \end{macrocode}
+% \end{Macro*}
+% \end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \ifdefcount { cs-token }{ true }{ false } \FEII
+%<package>%% \ifdefdimen { cs-token }{ true }{ false } \FEII
+%<package>%% \ifdeftoks { cs-token }{ true }{ false } \FEII
+%<package>%% \ifdefskip { cs-token }{ true }{ false } \FEII
+%<package>%% \ifdefmuskip { cs-token }{ true }{ false } \FEII
+%<package>%% \ifdefchar { cs-token }{ true }{ false } \FEII
+%<package>%% \ifdefmathchar { cs-token }{ true }{ false } \FEII
+% \fi
+%
+%\begin{Macro*}[ifdefcount]{ifdefcount}
+%\begin{Macro*}{ifdeftoks}
+%\begin{Macro*}{ifdefdimen}
+%\begin{Macro*}{ifdefskip}
+%\begin{Macro*}{ifdefmuskip}
+%\begin{Macro*}{ifdefchar}
+%\begin{Macro*}{ifdefmathchar}
+%\begin{Macro*}{ifdefblankspace}
+%\begin{Macro*}{ifdefthechar}
+%\begin{Macro}{ifdeftheletter}
+% \cs{ettl@ifdef} will defined those five macros (and be undefined itself at the end):
+% \begin{macrocode}
+\def\ettl@ifdef[#1]{\expandafter\ettl@ifd@f\expandafter{#1}}
+\def\ettl@ifd@f#1#2{%
+ \csdef{ettl@ifdef#2}##1#1##2/End§Meaning/{\ettl@nbk##2//{\rmn@firstoftwo}{\rmn@secondoftwo}//}
+ \csedef{ifdef#2}##1{\noexpand\romannumeral\noexpandafter%
+ \noexpandcs{ettl@ifdef#2}\noexpand\meaning##1#1/End§Meaning/}%//{##2}{##3}//}
+}
+\ettl@ifdef[\string\count]{count} % defines \def\ifdefcount
+\ettl@ifdef[\string\toks]{toks} % \def\ifdeftoks
+\ettl@ifdef[\string\dimen]{dimen} % \def\ifdefdimen
+\ettl@ifdef[\string\skip]{skip} % \def\ifdefskip
+\ettl@ifdef[\string\muskip]{muskip} % \def\ifdefmuskip
+\ettl@ifdef[\string\char]{char} % \def\ifdefchar
+\ettl@ifdef[\string\mathchar]{mathchar} % \def\ifdefmathchar
+\ettl@ifdef[\detokenize{blank space}]{blankspace}% \def\ifdefblankspace
+\ettl@ifdef[\detokenize{the character}]{thechar}% \def\ifdefthechar
+\ettl@ifdef[\detokenize{the letter}]{theletter} % \def\ifdeftheletter
+\undef\ettl@ifdef\undef\ettl@ifd@f
+% \end{macrocode}
+%\end{Macro}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%
+% \iffalse
+%<package>
+%<package>%% \avoidvoid [ replacement code ]{ cs-token / string }
+%<package>%% \avoidvoid*[ replacement code ]{ cs-token / string }
+% \fi
+% \begin{Macro*}{avoidvoid}
+% \begin{Macro}{avoidvoid*}
+% \cs{avoivoid}\oprm{replacement code}\prm{cs-token} will expand the optional parameter (default: an empty string) if the mandatory argument is void (\ie
+% is either undefined, a token whose meaning is |\relax|, a parameterless macro whose replacement text is empty).
+% Otherwise, it will expand its mandatory argument (\prm{cs-token}):
+% \begin{macrocode}
+\newcommand\avoidvoid[1]{\romannumeral\FE@ifstar{#1}
+ {\ettl@voidvoid{\ettl@ifdefempty\ifempty}}
+ {\ettl@voidvoid{\ettl@ifdefvoid\ifblank}}}
+\long\def\ettl@voidvoid#1#2{\FE@testopt{#2}{\ettl@voidv@id#1}{}}
+\long\def\ettl@voidv@id#1#2[#3]#4{\ifiscs{#4}{#1{#4}}{#2{#4}}{\z@#3}{\z@#4}}
+% \end{macrocode}
+% and the helper macros:
+% \begin{macrocode}
+\long\def\ettl@ifdefvoid#1{\csname @\ifx#1\relax first%
+ \else\expandafter\expandafter\expandafter\ettl@nbk\strip@meaning#1//{second}{first}//%
\fi oftwo\endcsname}
+\long\def\ettl@ifdefempty#1{\expandafter\expandafter\expandafter\ifempty%
+ \expandafter\expandafter\expandafter{\strip@meaning#1}}
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
+%\end{Macro*}
%
% \iffalse
%<package>
-%<package>% \ifsinglechar character{ string }{ true }{ false }
+%<package>%% \avoidvoidcs [ replacement code ]{ cs-name }
+%<package>%% \avoidvoidcs*[ replacement code ]{ cs-name }
% \fi
%
-% \begin{macro}{\ifsinglechar}\cmdlabel{impl:ifsinglechar}
-% Test if |#2| is a single character equal to |#1|: \seedesc{ifsinglechar}
+%\begin{Macro*}{avoidvoidcs}
+%\begin{Macro}{avoidvoidcs*}
+% \cs{avoidvoidcs} does the same as \cs{avoidvoid} but the mandatory argument \prm{cs-name} is interpreted
+% as a control sequence name. Therefore, you cannot test a |string| with \cs{avoidvoidcs}.
+%
+% \cs{avoidcsvoid} is an alias (for |neu-neu|...):
% \begin{macrocode}
-\newcommand\ifsinglechar[2]{%
+\newcommand\avoidvoidcs[1]{\romannumeral\FE@ifstar{#1}
+ {\ettl@avoidvoidcs{\ettl@ifdefempty}}
+ {\ettl@avoidvoidcs{\ettl@ifdefvoid}}}
+\long\def\ettl@avoidvoidcs#1#2{\FE@testopt{#2}{\ettl@@voidvoidcs#1}{}}
+\long\def\ettl@@voidvoidcs#1[#2]#3{\csname @\ifcsname#3\endcsname
+ \expandafter#1\csname#3\endcsname{first}{second}\else first\fi
+ oftwo\endcsname{\z@#2}{\z@\csname#3\endcsname}}
% \end{macrocode}
+%\end{Macro}
+%\end{Macro*}
%
-% \begin{codecomment}
-% Remember that neither \prm{string1} nor \prm{string2} is expanded.§
-% First: test if |#2| is a single character:
-% \begin{macrocode}
- \csname @\ifblank{#2}{second}{%
-" \ifnum\pdfstrcmp{\detokenize{#1}}{\detokenize{#2}}=0
-" \ifnum\pdfstrcmp{\detokenize{#2}}{\expandafter\@car\detokenize{#2}\relax\@nil}=0
-" first%
-" \else second%
-" \fi
-" \else second%
-" \fi oftwo\endcsname}}
-! \expandafter\expandafter\expandafter\ifx
-! \expandafter\expandafter\expandafter\relax\expandafter\@cdr\detokenize{#2}\@nil\relax
-! \iffirstchar{#1}{#2}{first}{second}\else second\fi oftwo\endcsname}}
+% \Subsection{Single tokens / single characters}
+%
+% \iffalse
+%<package>
+%<package>%% The ifx-test and the character-test
+% \fi
+%
+% \begin{Macro*}{ettl@ifx} \FE
+% \cs{ettl@ifx} is the \emph{equality-test macro} for \cmdref={character-test}{\cs{ifx} test}. In is designed to be used
+% inside |\csname|...|\endcsname| like:§
+% ¤¤|\ettl@ifx|\prm{tokenA}\prm{tokenB}{first}{second}:
+% \begin{macrocode}
+\long\def\ettl@ifx#1#2#3#4{\ifx#1#2#3\else#4\fi}
% \end{macrocode}
-% \end{codecomment}
-% \end{macro}
+% \end{Macro*}
+%
+%\begin{Macro*}{ettl@ifchar} \FE
+% \cs{ettl@ifchar} is the \emph{equality-test macro} for \cmdref={character-test}. It is designed to be in place of \cs{ettl@ifx}:
+% \begin{macrocode}
+\long\def\ettl@ifchar#1#2{\csname ettl@\if\noexpand#2\string#11of2\ettl@csname\fi
+ \unless\ifcat\noexpand#1\noexpand#22of2\ettl@csname\fi
+ \ifx#1#21\else2\fi of2\endcsname}
+% \end{macrocode}
+%\end{Macro*}
%
% \iffalse
%<package>
-%<package>% \iflastchar{ string1 }{ string2 }{ true }{ false }
+%<package>%% \ifsingletoken{ tokenA }{ tokenB }{ true }{ false }
% \fi
%
-% \begin{macro}{\iflastchar} \cmdlabel{impl:iflastchar}
-% This macro is not purely expandable. \seedesc{iflastchar}
+%\begin{Macro}{ifsingletoken}
+% \cs{ifsingletoken} is a safe \cs{ifx}-test:
% \begin{macrocode}
-\begingroup\catcode`\&=3
-\long\gdef\iflastchar#1#2{%
- \long\def\ettl@iflastchar##1#1##2&{%
- \ifstrcmp{##2}{#1}\@firstoftwo{%
- \ifempty{##2}\@secondoftwo{\ettl@iflastchar##2&}}
- }\ettl@iflastchar#2#1&}
-\endgroup
+\newcommand\ifsingletoken[2]{\csname @\ettl@firstspace{#2}
+ {\ettl@nbk#1#2//{second}{\if\relax\detokenize{#1#2}\relax first\else\ifx#1#2first\else second\fi\fi}//}
+ {\if\relax\detokenize\expandafter{\ettl@cdr#2\@nil}\relax
+ \expandafter\ettl@ifxsingle
+ \else\expandafter\ettl@carcar
+ \fi{#1}{#2}{first}{second}}%
+ oftwo\endcsname}
+\def\ettl@ifxsingle#1#2#3#4{\ettl@nbk#1//{\ifx#1#2#3\else#4\fi}{#4}//}
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
%
+% \iffalse
+%<package>
+%<package>%% \ifOneToken{ token }{ true }{ false }
+% \fi
+%
+% \begin{Macro}{ifOneToken}
+% \cs{ifOneToken} test if its argument contains only one token (possibly a space token):
+% \begin{macrocode}
+\newcommand\ifOneToken[1]{\romannumeral\csname rmn@\ettl@firstspace{#1}
+ {\ettl@nbk#1//{second}{\if\relax\detokenize{#1}\relax second\else first\fi}//}
+ {\if\relax\detokenize\expandafter{\ettl@cdr#1\@nil}\relax
+ first\else second\fi}oftwo\endcsname}
+% \end{macrocode}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \ifstrcmp{ string1 }{ string2 }{ true }{ false }
+%<package>%% \ifsinglechar character{ string }{ true }{ false }
% \fi
%
-% \begin{macro}{\ifstrcmp}\cmdlabel{impl:ifstrcmp}
-% The macro is base on the |\pdfstrcmp| primitive.\seedesc{ifstrcmp}
+% \begin{Macro}{ifsinglechar}
+% Test if \#2 is a single character equal to \#1:
% \begin{macrocode}
-\newcommand\ifstrcmp[2]{\csname @%
- \ifnum\pdfstrcmp{\detokenize{#1}}{\detokenize{#2}}=0 first\else second\fi
- oftwo\endcsname}
-\ettl@onlypdfTeX\pdfstrcmp\ifstrcmp
+\newcommand\ifsinglechar[2]{\romannumeral\csname rmn@\ettl@firstspace{#2}
+ {\ettl@nbk#2//{second}{\if\relax\detokenize{#1#2}\relax first\else\ifx#1#2first\else second\fi\fi}//}
+ {\if\relax\detokenize\expandafter{\ettl@cdr#2\@nil}\relax
+ \expandafter\ettl@ifchar
+ \else\expandafter\ettl@carcar
+ \fi{#1}{#2}{first}{second}}%
+ oftwo\endcsname}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \xifstrcmp{ string1 }{ string2 }{ true }{ false }
+%<package>%% \ifOneChar{ string }{ true }{ false }
% \fi
%
-% \begin{macro}{\xifstrcmp}\cmdlabel{impl:xifstrcmp}
-% The macro is based on the |\pdfstrcmp| primitive.\seedesc{ifxstrcmp}
+% \begin{Macro}{ifOneChar}
+% \cs{ifOneChar}\prm{string}\prm{true}\prm{false}¤ detokenizes \prm{string} first (see also \cmdref*{ifOneToken}):
% \begin{macrocode}
-\newcommand\xifstrcmp[2]{\csname @%
- \ifnum\pdfstrcmp{#1}{#2}=0 first\else second\fi
- oftwo\endcsname}
-\ettl@onlypdfTeX\pdfstrcmp\ifxstrcmp
+\ettl@ifdefined\pdfmatch
+\newcommand\ifOneChar[1]{\romannumeral\csname rmn@%
+ \ifnum\pdfmatch{\detokenize{^.$}}{\detokenize{#1}}=1 first\else second\fi
+ oftwo\endcsname}
+\else
+\newcommand\ifOneChar[1]{\romannumeral\csname rmn@\ettl@firstspace{#1}
+ {\ettl@nbk#1//{second}{\if\relax\detokenize{#1}\relax second\else first\fi}//}
+ {\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax
+ first\else second\fi}oftwo\endcsname}
+\fi%\pdfmatch
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
-% \begin{macro}{\xifstrequal}\cmdlabel{impl:xifstrequal}
-% The macro is based on \sty{etoolbox}-|\ifstrequal|.\seedesc{ifxstrequal}
+% \iffalse
+%<package>
+%<package>%% \ifOneCharWithBlanks{ string }{ true }{ false }
+% \fi
+%
+%\begin{Macro}{ifOneCharWithBlanks}
% \begin{macrocode}
-\newrobustcmd*\xifstrequal[2]{\begingroup
- \protected@edef\@xifstrequal{\endgroup\noexpand\ifstrequal{#1}{#2}%
- }\@xifstrequal}
+\ettl@ifdefined\pdfmatch
+\newcommand\ifOneCharWithBlanks[1]{\romannumeral\csname rmn@%
+ \ifnum\pdfmatch{\detokenize{^[[:space:]]*[^[:space:]][[:space:]]*$}}{\detokenize{#1}}=1 %
+ first\else second\fi oftwo\endcsname}
+\else
+\newcommand\ifOneCharWithBlanks[1]{\romannumeral\csname rmn@\ettl@nbk#1//%
+ {\expandafter\expandafter\expandafter\ettl@nbk
+ \expandafter\ettl@cdr\detokenize{#1}\@nil//{second}{first}//}%
+ {second}//oftwo\endcsname}
+\fi
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
%
+% \iffalse
+%<package>
+%<package>%% \iffirstchar{ string1 }{ string2 }{ true }{ false }
+% \fi
%
+% \begin{Macro}{iffirstchar}
+% |\iffirstchar| test if \#1 and \#2 begins with the same character or token (the \cmdref={character-test} is used):
+% \begin{macrocode}
+\newcommand\iffirstchar[2]{\romannumeral\csname rmn@%
+ \ettl@nbk#2//%
+ {\ettl@nbk#1//%
+ {\expandnexttwo\ettl@ifchar{\ettl@car#2\@nil}{\ettl@car#1\@nil}{first}{second}}
+ {\if\relax\detokenize{#1}\relax secondoftwo\ettl@csname\fi
+ \ettl@firstspace{#2}{first}{second}}//}%
+ {\ettl@nbk#1//%
+ {\if\relax\detokenize{#2}\relax secondoftwo\ettl@csname\fi
+ \ettl@firstspace{#1}{first}{second}}
+ {\if\relax\detokenize{#1#2}\relax first\else second\fi}}//%
+ oftwo\endcsname}
+% \end{macrocode}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \ifstrmatch{ pattern }{ true }{ false }
+%<package>%% \ifiscs { string }{ true }{ false }
% \fi
%
-% \begin{macro}{\ifstrmatch}\cmdlabel{impl:ifstrmatch}
-% The macro is base on the |\pdfmatch| primitive.\seedesc{ifstrmatch}
+%\begin{Macro}{ifiscs}
+% \cs{ifiscs}\prm{string} expands \prm{true} only if \prm{string} is a single control-word:
% \begin{macrocode}
-\newcommand\ifstrmatch[2]{\csname @%
- \ifnum\pdfmatch{\detokenize{#1}}{\detokenize{#2}}=1 first\else second\fi
- oftwo\endcsname}
-\ettl@onlypdfTeX\pdfmatch\ifstrmatch
+\newcommand\ifiscs[1]{\romannumeral\csname rmn@\ettl@nbk#1//%
+ {\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax secondoftwo\ettl@csname\fi
+ \if\relax\detokenize\expandafter{\ettl@cdr#1\@nil}\relax
+ \expandafter\ettl@firstspace
+ \else secondoftwo\ettl@csname\fi{#1}{second}{first}}
+ {second}//oftwo\endcsname}
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
%
+% \iffalse
+%<package>
+%<package>%% \detokenizeChars { list of single tokens }
+% \fi
%
-% \subsection{Purely expandable macros with options}
+%\begin{Macro}{detokenizeChars}
+% \cs{detokenizeChars} selectively detokenizes the tokens of the \cmdref={list of single tokens}: single characters are
+% detokenized while control sequences remain the same:
+% \begin{macrocode}
+\newcommand\detokenizeChars[1]{\expandafter\ettl@dosinglelist
+ \expandafter\ettl@do@detokenChars\expandafter{\romannumeral0\protectspace{#1}}}
+\long\def\ettl@do@detokenChars#1{\ifOneChar{#1}\detokenize\unexpanded{#1}}
+% \end{macrocode}
+%\end{Macro}
%
% \iffalse
-%<package>%----------------------------------------------------------------------------
-%<package>% Purely Expandable Macros With Options / Star Forms / Variants
-%<package>% \FE@testopt{ #1 }{ commands }{ default option }
+%<package>
+%<package>%% \protectspace { string }
% \fi
-% \begin{macro}{\FE@testopt}\cmdlabel{impl:FE@testopt}
-% Fully expandable |\@testopt|-like test:\seedesc{FE@testopt}
+%
+%\begin{Macro}{protectspace}
+% \cs{protectspace} puts curly braces (group characters) around spaces in the string given as argument.
+% This is useful for loops into lists (\cs{listloop}, \cs{csvloop}...). \cs{protectspace} is an exemple
+% of a loop which is 2-purely expandable:
% \begin{macrocode}
-\newcommand\FE@testopt[3]{\ifsinglechar [{#1}{#2#1}{#2[{#3}]{#1}}}
+\newcommand\protectspace[1]{\romannumeral\ettl@protectspace#1 /End§String/}
+\long\def\ettl@protectspace#1 #2/End§String/{\ifempty{#2}{\z@#1}
+ {\expandafter\@swap\expandafter{\romannumeral\ettl@protectspace#2/End§String/}{\z@#1{ }}}}
% \end{macrocode}
+%\end{Macro}
%
-% \end{macro}
+% \Subsection{Character and Strings}
%
% \iffalse
%<package>
-%<package>% \FE@ifstar{ #1 } { \StarredMacro }{ \NotStarredMacro }
+%<package>%% \ifempty{ text }{ true }{ false }
% \fi
-% \begin{macro}{\FE@ifstar}\cmdlabel{impl:FE@ifstar}
-% Fully expandable |\@ifstar|-like test:\seedesc{FE@ifstar}
+%
+% \begin{Macro}{ifempty}
+% |\ifempty| is based on |\detokenize| and can manage with any argument.
% \begin{macrocode}
-\newcommand\FE@ifstar[3]{\ifsinglechar *{#1}{#2}{#3{#1}}}
+\newcommand\ifempty[1]{\romannumeral\csname rmn@\if\relax\detokenize{#1}\relax
+ first\else second\fi oftwo\endcsname}
% \end{macrocode}
+% \end{Macro}
%
-% \end{macro}
+% \iffalse
+%<package>
+%<package>%% \ifnotempty{ text }{ true }{ false }
+% \fi
+%
+% \begin{Macro}{ifnotempty}
+% |\ifnotempty| is based on |\detokenize| and can manage with any argument.
+% \begin{macrocode}
+\newcommand\ifnotempty[1]{\romannumeral\csname rmn@\if\relax\detokenize{#1}\relax
+ second\else first\fi oftwo\endcsname}
+% \end{macrocode}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \FE@ifchar{#1}{#2}{ \SpecialFormMacro }{ \NormalMacro }
+%<package>%% \xifempty{ text }{ true }{ false }
% \fi
-% \begin{macro}{\FE@ifchar}\cmdlabel{impl:FE@ifchar}
-% Plus généralement, on peut tester si une macro est suivie d'un caractère donné:\seedesc{FE@ifchar}
+% \begin{Macro}{xifempty}
+% |\xifempty| is based on pdf-TeX{} |\pdfstrcmp| and work with any argument.
% \begin{macrocode}
-\newcommand\FE@ifchar[4]{\ifsinglechar{#1}{#2}{#3}{#4{#2}}}
+\newcommand\xifempty[1]{\xifstrcmp{#1}{}}
+\ettl@onlypdfTeX\pdfstrcmp\xifempty[\xifstrempty]
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \ifnotblank{ text }{ true }{ false }
+% \fi
+%
+% \begin{Macro}{ifnotblank}
+% \cs{ifnotblank} \CS{ifnotblank} |\ifnotblank| \CSbf{ifnotblank} \textvb{ifnotblank} reverses the test of \cs{ifblank}.
+%
+% {\usefont{T1}{pcr}{m}{n}ifnotblank}{\usefont{T1}{txtt}{m}{n}ifnotblank}
+% \begin{macrocode}
+\long\def\ifnotblank#1#2#3{\ettl@nbk#1//{#2}{#3}//}
+% \end{macrocode}
+% \end{Macro}
%
+% \iffalse
+%<package>
+%<package>%% \xifblank{ string }{ true }{ false }
+% \fi
+%
+% \begin{Macro}{xifblank}
+% Just expands the parameter using |\protected@edef| before testing for |\ifblank|:
+% \begin{macrocode}
+\newrobustcmd\xifblank[1]{\begingroup
+ \protected@edef\@xifblank{\endgroup
+ \noexpand\ifblank{#1}%
+ }\@xifblank}
+% \end{macrocode}
+% \end{Macro}
%
% \iffalse
%<package>
+%<package>%% \deblank{ string }
% \fi
+% \begin{Macro}{deblank}
+% From a code in \xpackage{environ.sty}.
+% \begin{macrocode}
+\newcommand\deblank[1]{\romannumeral-`\q\ettl@deblank#1/ /}
+\long\def\ettl@deblank#1 /{\ettl@deblank@i#1/}
+\long\def\ettl@deblank@i#1/#2{ #1}
+% \end{macrocode}
+% \end{Macro}
%
-% \goodbreak
%
-% \begin{macro}{\DeclareCmdListParser}\cmdlabel{impl:DeclareCmdListParser}
+%\begin{Macro*}{ettl@stringify} \FE
+% \cs{ettl@stringify} is used in the definition of \cs{ettl@safe@ifx}:
+% \begin{macrocode}
+\newcommand\ettl@stringify[1]{\romannumeral-`\q\ettl@expandafthree\@gobblescape%
+ \expandafter\ettl@deblank\detokenize{#1}/ /}
+% \end{macrocode}
+%\end{Macro*}
%
-% |\DeclareCmdListParser|\seedesc{DeclareCmdListParser} acts in the same way as
-% \sty{etoolbox}-|\DeclareListParser| and the command-list-parser
-% are sensitive to the category code of the \prm{separator}
%
-%% \iffalse
+% \iffalse
%<package>
-%<package>% \DeclareCmdListParser : general constructor for command-list parsers
-%<package>% \DeclareCmdListParser\ParserName{separator}
+%<package>%% \ifstrcmp{ string1 }{ string2 }{ true }{ false }
% \fi
-% \begin{codecomment}
-% The command-list-parser will be defined only if it is definable:
%
+% \begin{Macro}{ifstrcmp}
+% The macro is based on the |\pdfstrcmp| primitive if it is available.
+% Otherwise, \cs{ifstrcmp} is the same as \xpackage{etoolbox}-\cs{ifstrequal}.
+% \begin{macrocode}
+\newcommand\ifstrcmp[2]{\romannumeral\csname rmn@%
+ \ifnum\pdfstrcmp{\detokenize{#1}}{\detokenize{#2}}=0 first\else second\fi
+ oftwo\endcsname}
+\ettl@onlypdfTeX\pdfstrcmp\ifstrcmp[\ifstrequal]
+% \end{macrocode}
+% \end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \xifstrcmp{ string1 }{ string2 }{ true }{ false }
+% \fi
+%
+% \begin{Macro}{xifstrcmp}
+% The macro is based on the |\pdfstrcmp| primitive.
+% \begin{macrocode}
+\newcommand\xifstrcmp[2]{\csname @%
+ \ifnum\pdfstrcmp{#1}{#2}=0 first\else second\fi
+ oftwo\endcsname}
+\ettl@onlypdfTeX\pdfstrcmp\xifstrcmp[\xifstrequal]
+% \end{macrocode}
+% \end{Macro}
+%
+% \begin{Macro}{xifstrequal}
+% The macro is based on \xpackage{etoolbox}-|\ifstrequal|.
% \begin{macrocode}
-\newrobustcmd*\DeclareCmdListParser[2]{%
- \@ifdefinable#1
- {\expandafter\etextools@defcmdparser\expandafter{#1}{#2}}}
+\newrobustcmd\xifstrequal[2]{\begingroup
+ \protected@edef\@xifstrequal{\endgroup\noexpand\ifstrequal{#1}{#2}%
+ }\@xifstrequal}
% \end{macrocode}
+% \end{Macro}
%
-% Then the job is done by |\etextools@defcmdparser|: we need the `\,\&\,' to have a catcode of 3
-% and globally define the macro inside a purposeful group:
+% \iffalse
+%<package>
+%<package>%% \ifcharupper{ string }{ true }{ false }
+%<package>%% \ifcharlower{ string }{ true }{ false }
+% \fi
%
+% \begin{Macro*}{ifcharupper}
+% Test if the character code equals to its upper case code:
+% \begin{Macro}{ifcharlower}
+% Test if the character code equals to its lower case code:
% \begin{macrocode}
-\begingroup\catcode`\&=3\catcode`\`=3
-\gdef\etextools@defcmdparser#1#2{%
- \begingroup
- \def\`##1`{\expandafter\noexpand\csname ##1\endcsname}%
+\newcommand\ifcharupper[1]{\romannumeral\csname rmn@%
+ \ifnum`\#1=\uccode`\#1 first\else second\fi oftwo\endcsname}
+\newcommand\ifcharlower[1]{\romannumeral\csname rmn@%
+ \ifnum`\#1=\lccode`\#1 first\else second\fi oftwo\endcsname}
% \end{macrocode}
-% Now the parser definition is made inside an protected-|\edef| in order to expand control sequences names:
+% \end{Macro}
+% \end{Macro*}
+%
+% \iffalse
+%<package>
+%<package>%% \ifuppercase{ string }{ true }{ false }
+%<package>%% \iflowercase{ string }{ true }{ false }
+% \fi
+% \begin{Macro}{ifuppercase}
+% Compares the |\uppercase| transformation of a string with itself:
% \begin{macrocode}
- \protected@edef\defineparser{\endgroup
+\newrobustcmd\ifuppercase[1]{\uppercase{\ifstrcmp{#1}}{#1}}
% \end{macrocode}
-% Here we define the entry-point: we first test if the command was starred.
-% This is possible because the list-parser has always a mandatory argument (the \prm{list} itself or the \prm{listmacro}) :
+% \end{Macro}
+%
+% \begin{Macro}{iflowercase}
+% Compares the |\lowercase| transformation of a string with itself:
% \begin{macrocode}
- \long\def#1####1{\noexpand\FE@ifstar{####1}
- {\`ettl@lst@opt\string#1`{}}
- {\`ettl@lst@opt\string#1`\noexpandafter}}%
+\newrobustcmd\iflowercase[1]{\lowercase{\ifstrcmp{#1}}{#1}}
% \end{macrocode}
-% Both starred and not-starred versions have an optional argument which is the auxiliary command, whose name is |\do| if not specified.
-% It is possible to test the option for the same reason:
+% \end{Macro}
+%
+%
+% \iffalse
+%<package>
+%<package>%% \ifstrmatch{ pattern }{ string }{ true }{ false }
+% \fi
+%
+% \begin{Macro}{ifstrmatch}
+% The macro is base on the |\pdfmatch| primitive.
% \begin{macrocode}
- \long\csdef{ettl@lst@opt\string#1}####1####2{\noexpand\FE@testopt{####2}
- {\`ettl@lst@@pt\string#1`{####1}}{\noexpand\do}}%
+\newcommand\ifstrmatch[2]{\romannumeral\csname rmn@%
+ \ifnum\pdfmatch{#1}{#2}=1 first\else second\fi oftwo\endcsname}
+\ettl@onlypdfTeX\pdfmatch\ifstrmatch
% \end{macrocode}
-% Definition of the parser with its arguments :\quad |[optional command]{list or listmacro}|. If the starred version
-% was used, then we do not have to expand the (mandatory) \prm{list}:
+% \end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \ifstrdigit{ string }{ true }{ false }
+% \fi
+%
+%\begin{Macro}{ifstrdigit}
+% \cs{ifstrdigit} expands \prm{true} if \prm{string} is a single digit (without spaces):
% \begin{macrocode}
- \long\csdef{ettl@lst@@pt\string#1}####1[####2]####3{%
- ####1\`ettl@lst\string#1`####1{####3}{####2}}%
+\ettl@ifdefined\pdfmatch
+\newcommand\ifstrdigit[1]{\romannumeral\csname rmn@\ifnum\pdfmatch{\detokenize{^[[:digit:]]$}}%
+ {\detokenize{#1}}=1 first\else second\fi oftwo\endcsname}
+\else
+\def\do#1{\cslet{ettl@number#1}=#1%
+}\docsvlist{0,1,2,3,4,5,6,7,8,9}
+\newcommand\ifstrdigit[1]{\romannumeral\csname rmn@%
+ \ifcsname ettl@number\detokenize{#1}\endcsname first\else second\fi oftwo\endcsname}
+\fi%\pdfmatch
% \end{macrocode}
-% On the other hand, if the parser was not starred, the (mandatory) \prm{listmacro} is expanded once:
+%\end{Macro}
+%
+% \iffalse
+%<package>
+%<package>%% \ifstrnum{ string }{ true }{ false }
+% \fi
+%
+%\begin{Macro}{ifstrnum}
+% \cs{ifstrnum} expands \prm{true} if \prm{string} is a number (integer) in the sense of \eTeX:
% \begin{macrocode}
+\ettl@ifdefined\pdfmatch
+\newcommand\ifstrnum[1]{\romannumeral\csname rmn@\ifnum\pdfmatch
+ {\detokenize{^([[:space:]]*-?)*+[[:digit:]]+[[:space:]]*$}}{\detokenize{#1}}=1 %
+ first\else second\fi oftwo\endcsname}
+\else
+\newcommand\ifstrnum[1]{\romannumeral\csname rmn@\ettl@nbk#1//%
+ {\expandafter\ettl@numberminus\detokenize{#1}-/End§String/}{second}//oftwo\endcsname}
+\long\def\ettl@numberminus#1-#2/End§String/{\ettl@nbk#2//%
+ {\ettl@nbk#1//{second}{\ettl@numberminus#2/End§String/}//}%
+ {\expandafter\expandafter\expandafter\ettl@numberspace\deblank{#1} /End§String/}//}%
+\long\def\ettl@numberspace#1 #2/End§String/{\ettl@nbk#2//{second}{\ettl@ifstrnum#1/End§String/}//}
+\long\def\ettl@ifstrnum#1#2/End§String/{%
+ \ifcsname ettl@number#1\endcsname% #1 detokenized before, ok
+ \ettl@nbk#2//{\ettl@ifstrnum#2/End§String/}{first}//%
+ \else second%
+ \fi}
+\fi%\pdfmatch
% \end{macrocode}
-% ListParser is defined and leads to |\`ettl@lst\string\ListParser`| in all cases; here the \prm{list} is in first position,
-% the auxiliary commands come after, so we reverse the order and add a \prm{separator} in case the \prm{list} is empty:
+%\end{Macro}
+%
+%
+% \iffalse
+%<package>
+%<package>%% \DeclareStringFilter[\global]{ \StringFilterMacro }{ string }
+% \fi
+%
+%\begin{Macro}{DeclareStringFilter}
+% \csbf{DeclareStringFilter} is the general contructor for purely expandable
+% \textbfsf{string-filter} macros:
% \begin{macrocode}
- \long\csdef{ettl@lst\string#1}####1####2{%
- \`ettl@lst@\string#1`{####2}####1\unexpanded{#2}&}%
+\newrobustcmd\DeclareStringFilter[3][\global]{\@ifdefinable#2%
+ {\expandnext\ettl@declarestrfilter%
+ {\csname\@gobblescape#2\detokenize{->"#3"}\endcsname}{#1}{#2}{#3}}}
+\newcommand\ettl@declarestrfilter[4]{%
+ #2\csdef{\@gobblescape#1}##1#4##2/End§String/{##1/##2}% This the FILTER
+ #2\long\def#3##1{\FE@modifiers{=<>?-+!}{##1}
+ {\ettl@strfilt@mod 0{{#4}{}{#1}[1]}}%=
+ {\ettl@strfilt@mod 1{{#4}{}{#1}[1]}}%<
+ {\ettl@strfilt@mod 2{{#4}{}{#1}[\ettl@intmax]}}%>
+ {\ettl@strfilt@mod 3{{#4}{}{#1}}}%?
+ {\ettl@strfilt@mod 4{{#4}{}{#1}}}%-
+ {\ettl@strfilt@mod 5{{#4}{}{#1}}}%+
+ {\ettl@strfilt\ettl@strfilt@count{#4}{}{#1}[\ettl@intmax]}%!
+ {\ettl@strfilt\ettl@strfilt@equal{#4}{}{#1}[1]}}}% default
% \end{macrocode}
-% In the following macro, we extract the first item from the list (before the \prm{separator} |#2|), for treatment:
+%\end{Macro}
+%
+%\begin{macro}{\ettl@strfilt@dot} \FE
+% Used by |\ettl@strfilt@mod| to test if a character is a dot.
% \begin{macrocode}
- \long\csdef{ettl@lst@\string#1}####1####2\unexpanded{#2}####3&{%
+\long\def\ettl@ifchardot#1{\csname\ettl@BasicFilter\ettl@ifchardot@filt.#1/End§String/\endcsname}
+\long\def\ettl@ifchardot@filt#1.#2/End§String/{#1/#2}
% \end{macrocode}
-% Proceed with the first item, if not empty:
+%\end{macro}
+%
+%
+%\begin{macro}{\ettl@strfilt@mod} \FE
+% \cs{ettl@strfilt@mod} test the possible second modifier and choose the right macro to expand with
+% the right arguments:
% \begin{macrocode}
- \noexpand\ifblank{####2}
- {}
- {\noexpand\ettl@lst@doitem{####1}{####2}}%
+\def\ettl@strfilt@mod #1#2#3{%
+ \ifcase#1 \ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@equal#2}
+ {\FE@ifcharequal{#3}%
+ {\ettl@strfilt\ettl@strfilt@equaleq#2}%
+ {\ettl@strfilt\ettl@strfilt@equal#2}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@start#2}%
+ {\FE@ifcharequal{#3}
+ {\ettl@strfilt\ettl@strfilt@starteq#2}%
+ {\ettl@strfilt\ettl@strfilt@start#2}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@endby#2}%
+ {\FE@ifcharequal{#3}
+ {\ettl@strfilt\ettl@strfilt@endbyeq#2}%
+ {\ettl@strfilt\ettl@strfilt@endby#2}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@instr#2[1]}
+ {\FE@testopt{#3}{\ettl@strfilt\ettl@strfilt@instr#2}{1}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt@REMOVE{#2}[\ettl@intmax]}%
+ {\FE@testopt{#3}{\ettl@strfilt@REMOVE{#2}}{\ettl@intmax}}%
+ \or\ettl@fi\ettl@ifchardot{#3}%
+ {\ettl@strfilt@REPLACE#2[\ettl@intmax]}%
+ {\FE@testopt{#3}{\ettl@strfilt@REPLACE#2}{\ettl@intmax}}%
+ \fi}
% \end{macrocode}
-% If the remainder of the list is empty then break loop, otherwise restart extracting the next, first item for treatment:
+%\end{macro}
+%
+%\begin{macro}{\ettl@strfilt} \FE
+% \cs{ettl@strfilt} is the common start for the loop:
% \begin{macrocode}
- \noexpand\ifblank{####3}
- {\noexpand\ettl@listbreak}
- {\`ettl@lst@\string#1`{####1}####3}&}%
+\long\def\ettl@strfilt#1#2#3#4[#5]#6{% % #1 = test macro
+% #2 = substr
+% #3 = replacement
+% #4 = filter macro
+% #5 = number of times
+% #6 = user-given string
+ \ExpandAftercmds#1{\ettl@Remove #6/End§String/{#2}{#3}[{#5}]{#4}}}
% \end{macrocode}
-% Now the definitions are ready, execute them:
+%\end{macro}
+%
+%\begin{macro}{\ettl@strfilt@REMOVE} \FE
+% \cs{ettl@strfilt@REMOVE} is a pre-stage just before the common \cs{ettl@strfilt}:
% \begin{macrocode}
- }\defineparser}%
+\long\def\ettl@strfilt@REMOVE #1[#2]{%
+% #1 = arguments for \ettl@strfilt
+% #2 = number of times
+ \ifnum\numexpr#2>0 \ettl@else\ettl@strfilt\ettl@strfilt@remove#1[#2]%
+ \else\expandafter\@firstofone%
+ \fi}
% \end{macrocode}
-% |\ettl@lst@doitem| apply the auxiliary command(s) (in |#1|) to the item (|#2|):
-% |\ettl@listbreak| breaks the loop, removing the extra \sty{\&}:
+%\end{macro}
+%
+%\begin{macro}{\ettl@strfilt@REPLACE} \FE
+% \cs{ettl@strfilt@REPLACE} is a pre-stage just before the common \cs{ettl@strfilt}:
% \begin{macrocode}
- \long\gdef\ettl@lst@doitem#1#2{#1{#2}}%
- \long\gdef\ettl@listbreak#1&{}%
+\long\def\ettl@strfilt@REPLACE #1#2#3#4[#5]#6#7{%
+ \ifnum\numexpr#5>0 \ettl@else\ettl@strfilt\ettl@strfilt@replace{#1}{#7}{#3}[{#5}]{#6}%
+ \else\expandafter\@firstoftwo%
+ \fi}
% \end{macrocode}
-% Leave ``catcode-group'':
+%\end{macro}
+%
+%\begin{macro}{\ettl@Remove} \FE
+% \cs{ettl@Remove} applies the filter (\#5) and give the result to \cs{ettl@Remove@loop}:
% \begin{macrocode}
-\endgroup
+\long\def\ettl@Remove#1/End§String/#2#3[#4]#5{%
+% #1 = string or list
+% #2 = substring or item to remove
+% #3 = REPLACEMENT
+% #4 = number of times to remove
+% #5 = filter macro
+ \expandafter\ettl@Remove@loop #5#1//#2/End§String//End§String/{#3}[{#4-1}]{#5}}
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\ettl@Remove@loop} \FE
+% \cs{ettl@Remove@loop} is entitled to break the loop:
+% \begin{macrocode}
+\long\def\ettl@Remove@loop#1/#2//#3/End§String/#4[#5]#6{%
+% #1 = str before filter
+% #2 = str after filter
+% #3 = substr to remove
+% #4 = REPLACEMENT
+% #5 = iterindex
+% #6 = filter macro
+ \ifnum\numexpr#5>0 \ettl@nbk@else#2//%
+ {\ettl@Remove #1#4#2/End§String/{#3}{#4}[{#5}]{#6}}
+ {{#1}{#4#2}{#3}{#5}}//%
+ \else\ettl@fi{#1}{#4#2}{#3}{#5}%
+ \fi}
+% \end{macrocode}
+%\end{macro}
+%
+% \begin{macro}{test and result macros} \FE
+% Those macros are expanded after the end of the loop: they give the final expected result
+% from the four registers avaiblable at the end of the loop:
+% \begin{macrocode}
+\long\def\ettl@strfilt@equal #1#2#3#4{\csname @%
+ \ettl@nbk#3//{\ettl@nbk#1#2//{second}{first}//}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@equaleq #1#2#3#4{\csname @%
+ \ettl@nbk#3//{\ifnotempty{#1#2}{second}{first}}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@start #1#2#3#4{\csname @%
+ \ettl@nbk#1//{second}{first}//oftwo\endcsname}
+\long\def\ettl@strfilt@starteq #1#2#3#4{\csname @%
+ \ifnotempty{#1}{second}{first}oftwo\endcsname}
+\long\def\ettl@strfilt@endby #1#2#3#4{\csname @%
+ \ettl@nbk#3//{first}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@endbyeq #1#2#3#4{\csname @%
+ \ettl@nbk#3//{\ifempty{#2}{first}{second}}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@count #1#2#3#4{\number\numexpr\ettl@intmax-(#4)-\ettl@nbk#3//01//}
+\long\def\ettl@strfilt@instr #1#2#3#4{\csname @%
+ \ifnum\numexpr#4>0 second%
+ \else\ifnum\numexpr#4<0 first%
+ \else\ettl@nbk#3//{first}{second}//%
+ \fi\fi oftwo\endcsname}
+\long\def\ettl@strfilt@remove #1#2#3#4{#1#2}
+\long\def\ettl@strfilt@replace #1#2#3#4{#1\ettl@nbk#3//{#2}{}//}
% \end{macrocode}
-% \end{codecomment}
% \end{macro}
+%
+% \Subsection{Purely expandable macros with options}
+%
% \iffalse
-%<package>
-%<package>
-%<package>% \csvloop[\command]\csvListMacro
-%<package>% \csvloop*[\command]{item,item,item}
+%<package>%----------------------------------------------------------------------------
+%<package>% Purely Expandable Macros With Options / Star Forms / Variants
+%<package>%% \FE@testopt{ #1 }{ commands }{ default option }
% \fi
%
-% \begin{macro}{\csvloop}\cmdlabel{impl:csvloop}
-% Definition of |\csvloop|:\seedesc{csvloop}
+%\begin{macro}{basic string filter} \FE
+% This basic string filter will be used for \cs{FE@testopt} and \cs{FE@ifstar}. As far as\linebreak the later are used in
+% the definition of \cs{FE@modifiers} we can't use the \linebreak
+% \cmdref[DeclareStringFilter]{general string filter contructor} to do the job (infinite recursion).
% \begin{macrocode}
-\DeclareCmdListParser\csvloop{,}
+\long\def\ettl@BasicFilter#1#2#3/End§String/{\expandafter\ettl@B@sicFilter #1#3//#2/End§String//End§String/}
+\long\def\ettl@B@sicFilter#1/#2//#3/End§String/{@\ettl@nbk#3//%
+ {\if\relax\detokenize{#1#2}\relax first\else second\fi}
+ {second}//oftwo}
% \end{macrocode}
-% \end{macro}
+%\end{macro}
%
-% \begin{codecomment}
-% Definition of |\listloop| (with a `\,\textbar\,' of catcode 3 -- cf.\sty{etoolbox}):
+% \begin{Macro}{FE@testopt}
+% Purely expandable |\@testopt|-like test:
% \begin{macrocode}
-\begingroup\catcode`\|=3
- \def\do{\DeclareCmdListParser\listloop{|}}%
-\expandafter\endgroup\do
+\newcommand\FE@testopt[3]{\csname\ettl@BasicFilter\ettl@FE@testopt[#1/End§String/\endcsname
+ {#2#1}%
+ {#2[{#3}]{#1}}}%]
+\long\def\ettl@FE@testopt#1[#2/End§String/{#1/#2}
% \end{macrocode}
-% \end{codecomment}
+% \end{Macro}
%
-% \begin{codecomment}
-% Definition of |\toksloop| (with no delimiter):
+% \iffalse
+%<package>
+%<package>%% \FE@ifstar{ #1 } { \StarredMacro }{ \NotStarredMacro }
+% \fi
+% \begin{Macro}{FE@ifstar}
+% Purely expandable |\@ifstar|-like test:
% \begin{macrocode}
-\DeclareCmdListParser\toksloop{}%
+\newcommand\FE@ifstar[3]{\csname\ettl@BasicFilter\ettl@FE@ifstar*#1/End§String/\endcsname
+ {#2}%
+ {#3{#1}}}
+\long\def\ettl@FE@ifstar#1*#2/End§String/{#1/#2}
% \end{macrocode}
-% \end{codecomment}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>% \csvtolist \ListMacro \csvListMacro
-%<package>% \csvtolist* \ListMacro {item,item,item}
+%<package>%% \FE@charequal{ #1 } { \MacroWith= }{ \NormalMacro } % used by the string filters
% \fi
-% \begin{macro}{\csvtolist}\cmdlabel{impl:csvtolist}
-% This is the first application of |\csvloop|:\seedesc{csvtolist}
+%
+%\begin{macro}{\FE@ifcharequal} \FE
+% This is the same as \cs{FE@ifstar} but for \CH{=} character (used in \cmdref*{DeclareStringFilter}):
% \begin{macrocode}
-\newrobustcmd*\csvtolist{\@ifstar
- {\ettl@tolist\z@{}\csvloop}
- {\ettl@tolist\z@\expandnext\csvloop}}%
-\long\def\ettl@tolist#1#2#3#4#5{\ifx#1\z@\let#4\@empty\fi
- \def\ettl@to@list{#3*[{\unexpanded{\listadd#4}}]%
- }#2\ettl@to@list{#5}}
+\ettl@ifdefined\pdfmatch% use \ettl@ifdefined to test both on pdfTeX (make \ettl@ifdefined=\iffalse)
+\newcommand\FE@ifcharequal[3]{\ifsinglechar ={#1}{#2}{#3{#1}}}
+\else
+\newcommand\FE@ifcharequal[3]{\csname\ettl@BasicFilter\ettl@FE@charequal=#1/End§String/\endcsname
+ {#2}%
+ {#3{#1}}}
+\long\def\ettl@FE@charequal#1=#2/End§String/{#1/#2}
+\fi
% \end{macrocode}
-% \end{macro}
+%\end{macro}
%
% \iffalse
%<package>
+%<package>%% \FE@ifchar{ <Character> }{ #1 }{ \SpecialFormMacro }{ \NormalMacro }
% \fi
-%
-% \begin{macro}{\tokstolist}\cmdlabel{impl:tokstolist}
-% This is the first application of |\toksloop|:\seedesc{tokstolist}
+% \begin{Macro}{FE@ifchar}
+% \cs{FE@ifchar} test if the character token following the macro is a single character equal to \prm{Character}:§
+% USAGE:¤|\FE@ifchar{|\prm{Character}|}{|\#1|}{\SpecialFormMacro}{\NormalMacro}|:
% \begin{macrocode}
-\newrobustcmd*\tokstolist{\@ifstar{\ettl@tokstolist\z@{}}{\ettl@tokstolist\z@\expandnext}}
-\def\ettl@tokstolist#1#2#3#4{\ifx#1\z@\let#3\@empty\fi
- \def\ettl@toks@tolist{\toksloop*[{\unexpanded{\listadd#3}}]}%
- #2\ettl@toks@tolist{#4{}}}
+\newcommand\FE@ifchar[4]{\ifsinglechar{#1}{#2}{#3}{#4{#2}}}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
+% \iffalse
+%<package>
+%<package>%% \FE@modifiers{ Allowed Characters }{ #1 }{ \MacroA }{ \MacroB }{ \MacroC }...{ \MacroZ }{ \MacroDefault }
+% \fi
+%\begin{Macro}{FE@modifiers}
+% \cs{FE@modifiers} test if the character token following the macro is in the list of \prm{Allowed Characters}: USAGE:§
+% |\FE@modifiers{|\prm{Allowed Characters}|}{|\#1|}{\MacroA}|...|{\MacroZ}{\NormalMacro}|:
+% \begin{macrocode}
+\newcommand\FE@modifiers[2]{%
+ \ifOneToken{#2}%
+ {\ExpandAftercmds\ettl@FE@modifiers%
+ {\ExpandAftercmds{\ettl@setresult 12of3><}
+ {\ettl@getsinglelist{\ettl@ifchar{#2}}{#1}}}{#2}}
+ {\ExpandNextTwo{\ettl@supergobble[{{#2}}]}{-1}{\getcharlistcount{#1}+1}}}
+\long\def\ettl@FE@modifiers#1#2#3{\expandafter\ettl@supergobble%
+ \expandafter[\romannumeral-`\q\ifnum#2<0 {#3}\fi]{#2}{#1+1}}
+% \end{macrocode}
+%\end{Macro}
%
% \iffalse
%<package>
-%<package>% \csvtolistadd \ListMacro \csvListMacro
-%<package>% \csvtolistadd* \ListMacro {item,item,item}
+%<package>%% \ettl@supergobble{ p }{ q }{token_1}{token_2}...{token_p}{TOKEN_p+1}{token_p+2}...{token_p+q+1}
% \fi
-% \begin{macro}{\csvtolistadd}\cmdlabel{impl:csvtolistadd}
-% It's quite the same\seedesc{csvtolistadd} as the latter except it does not
-% reset the list to empty at the very beginning:
+%\begin{Macro}{ettl@supergobble}
+% \cs{ettl@supergobble} gobbles the $n$ first (groups of) tokens in the following list of $N$ (groups of) tokens
+% and expands the $n+1$. The macro is optimized (cf \cs{ettl@supergobbleheight} etc.) to avoid too long loops.
% \begin{macrocode}
-\newrobustcmd*\csvtolistadd{\@ifstar
- {\ettl@tolist\@ne{}\csvloop}
- {\ettl@tolist\@ne\expandnext\csvloop}}
+\newcommand\ettl@supergobble[1]{\FE@testopt{#1}\ettl@superg@bble{}}
+\long\def\ettl@superg@bble[#1]#2#3{%
+% #1 = commands to put after the list (optional)
+% #2 = number to gobble first
+% #3 = total number of items
+ \ifnum\numexpr#3>0
+ \ifnum\numexpr#3-(#2)=0
+ \ettl@supergobble@loop{#3+2}0{\ettl@supergobble@end{}{}}%
+ \else
+ \expandafter\ettl@supergobble@loop\expandafter{%
+ \number\numexpr\ifnum\numexpr#2*(#2-(#3))>0 #3+1\else#2+2\fi}{#3+2}%
+ {\ettl@supergobble@next{}{#1}}%
+ \fi\fi}
+\long\def\ettl@supergobble@loop#1#2#3{%
+ \ifcsname ettl@supergobble\number\numexpr#1\endcsname
+ \csname ettl@supergobble\number\numexpr#1\endcsname
+ {#3{#2-(#1)-1}}%
+ \else\ettl@supergobbleheight{\ettl@supergobble@loop{#1-8}{#2-8}{#3}}%
+ \fi}
+\long\def\ettl@supergobble@end#1#2#3{\fi\fi\fi#1#2}
+\long\csdef{ettl@supergobbleheight}#1\fi#2#3#4#5#6#7#8#9{\fi#1}
+\long\csdef{ettl@supergobble7}#1#2\fi#3#4#5#6#7#8#9{#1}
+\long\csdef{ettl@supergobble6}#1#2\fi#3#4#5#6#7#8{#1}
+\long\csdef{ettl@supergobble5}#1#2\fi#3#4#5#6#7{#1}
+\long\csdef{ettl@supergobble4}#1#2\fi#3#4#5#6{#1}
+\long\csdef{ettl@supergobble3}#1#2\fi#3#4#5{#1}
+\long\csdef{ettl@supergobble2}#1#2\fi#3#4{#1}
+\long\csdef{ettl@supergobble1}#1#2\fi#3{#1}
+\long\csdef{ettl@supergobble0}#1#2\fi{#1}
+\long\def\ettl@supergobble@next#1#2#3#4{\fi
+ \ettl@supergobble@loop{#3}0{\ettl@supergobble@end{#4}{#2}}}
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
+%
+%
+% \Subsection{Define control sequence through groups}
+%
+%\iffalse
+%<package>
+%<package>%% \AfterGroup{ code } / \AfterGroup*{ code } the star form expands its argument once
+%\fi
+%
+%\begin{Macro}{AfterGroup}
+%\begin{Macro*}{AfterGroup*}
+% \cs{AfterGroup} enhances the \cs{aftergroup} primitive: arbitrary code may be given to \cs{AfterGroup}.
+% We use the |\edef|...|\unexpanded| trick already implemented in \cmdref*{ettl@ifnextchar} to allow macro
+% definitions (with arguments) inside the argument of \cs{AfterGroup}:
+% \begin{macrocode}
+\newcount\ettl@fter
+\newrobustcmd\AfterGroup{\@ifstar{\ettl@AfterGroup\@firstofone}{\ettl@AfterGroup\unexpanded}}
+\newrobustcmd\ettl@AfterGroup[2]{%
+ \csxdef{ettl@aftergroup@hook\number\numexpr\the\ettl@fter+1}%
+ {\global\csundef{ettl@fterGroup\number\numexpr\the\ettl@fter+1}#1{#2}}%
+ \global\advance\ettl@fter\@ne
+ \expandafter\aftergroup\csname ettl@fterGroup\the\ettl@fter\endcsname}
+% \end{macrocode}
+%\end{Macro*}
+%\end{Macro}
+%
+%\iffalse
+%<package>
+%<package>%% \AfterAssignment{ code }
+%\fi
+%
+%\begin{Macro}{AfterAssignment}
+% \cs{AfterAssignment} can be given arbitray code:
+% \begin{macrocode}
+\newrobustcmd\AfterAssignment{\@ifstar{\ettl@AfterAssignment\@firstofone}{\ettl@AfterAssignment\unexpanded}}
+\newrobustcmd\ettl@AfterAssignment[2]{%
+ \csedef{ettl@afterassignment@hook\number\numexpr\the\ettl@fter}{#1{#2}}%
+ \global\advance\ettl@fter\@ne
+ \expandafter\afterassignment\csname ettl@afterassignment@hook\the\ettl@fter\endcsname}
+% \end{macrocode}
+%\end{Macro}
+%
+%\iffalse
+%<package>
+%<package>%% \aftergroup@def{ cs-token }
+%\fi
+%
+%
+% \begin{Macro}{aftergroup@def}
+% The macro is based on \xpackage{letltxmacro} package. Therefore, \cs{aftergroup@def} works with commands with optional
+% arguments and with the ones defined using \LaTeX's \cs{DeclareRobustCommand}.
+% {\rmk: we could have used the \cmdref*{AfterGroup} macro but execution is lighter with $5$ call to \cs{aftergroup} primitive.}:§§
+% \begin{macrocode}
+\newrobustcmd\aftergroup@def[1]{%
+ \let\etex@let@primitive\let \def\let{\global\etex@let@primitive}%
+ \expandafter\LetLtxMacro\csname ettl@ftergroup@def\number\numexpr\the\ettl@fter+1\endcsname#1%
+ \global\advance\ettl@fter\@ne
+ \etex@let@primitive\let=\etex@let@primitive
+ \aftergroup\LetLtxMacro \aftergroup#1%
+ \expandafter\aftergroup\csname ettl@ftergroup@def\the\ettl@fter\endcsname
+ \aftergroup\global \aftergroup\undef
+ \expandafter\aftergroup\csname ettl@ftergroup@def\the\ettl@fter\endcsname}
+% \end{macrocode}
+% \end{Macro}
+%
+% \Subsection{\textbackslash futuredef}
%
% \iffalse
+%<package>%----------------------------------------------------------------------------
+%<package>
+%<package>%% \@ifchar{ single token }{ true }{ false }
%<package>
% \fi
%
-% \begin{macro}{\tokstolistadd}\cmdlabel{impl:tokstolistadd}
-% It's quite the same\seedesc{tokstolistadd} as the latter except it does not
-% reset the list to empty at the very beginning:
+%\begin{Macro}{@ifchar}
+% \cs{@ifchar} works just like \cs{@ifstar} but uses the \cmdref={character-test}.
% \begin{macrocode}
-\newrobustcmd*\tokstolistadd{\@ifstar{\ettl@tokstolist\@ne{}}{\ettl@tokstolist\@ne\expandnext}}%
+\long\def\@ifchar#1#2{\ettl@ifnextchar #1{\@firstoftwo{#2}}}
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
%
% \iffalse
%<package>
-%<package>%\listdel\listMacro{item}
-%<package>%\listgdel\listMacro{item}
-%<package>%\listedel\listMacro{item}
-%<package>%\listxdel\listMacro{item}
+%<package>%% \ettl@ifnextchar{ character token }{ true }{ false }
+%<package>
% \fi
-% \begin{macro}{\listdel}\cmdlabel{impl:listdel}
-% |\listdel| removes an item from a list:\seedesc{listdel}
+%
+%\begin{Macro}{ettl@ifnextchar}
+% \cs{ettl@ifnextchar} is based on the \cmdref={character-test} rather than the |\ifx|-test. See the example for
+% explanation on its behaviour.§
+% \csbf{ettl@ifnextchar} is used in the definition of \cmdref*{aftergroup@def} and \cmdref*{@ifchar} (of course...).§
+% We take advantage of delimited definitions to exits from |\if|...|\fi| conditionnals (even in the case where
+% the macro parameter may be |\else|, |\if| or |\fi|...):
% \begin{macrocode}
-\newrobustcmd\listdel[2]{\@listdel\def{#1}{#2}}%
+\newrobustcmd\ettl@ifnextchar[3]{\begingroup
+ \edef\1##1/##2/##3{##1\endgroup\unexpanded{#2}##3}%
+ \edef\2##1/##2/##3{##1\endgroup\unexpanded{#3}##3}%
+ \ifOneToken{#1}
+ {\csname ettl@\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax % OneChar
+ xifnch\else xifntk\fi\endcsname{#1}}
+ {\2//{}}}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
+% \begin{macro}{\ettl@xifnch}
+%\begin{macro}{\ettl@ifnch}
+% \cs{ettl@xifnch} is used in case the token to test (first parameter of \cs{ettl@ifnextchar} is a character token.
+% It gobbles the possible spaces and exits at one if a begin-group or end-group character is found:
+% \begin{macrocode}
+\long\def\ettl@xifnch#1{%
+ \ifx#1\@sptoken \def\ettl@xifnch{\ifx\@let@token\@sptoken\1\else\2\fi//{}}%
+ \else \def\ettl@xifnch{%
+ \ifx\@let@token\bgroup \2
+ \else\ifx\@let@token\egroup \2
+ \else\ifx\@let@token\@sptoken \ettl@ifnspace\ettl@xifnch%
+ \else\ettl@ifnch%
+ \fi\fi\fi/{#1}/{}}%
+ \fi\futurelet\@let@token\ettl@xifnch}
+% \end{macrocode}
+% \cs{ettl@ifnch} does the final comparison: the token is taken into the macro parameter
+% to check if it is a single character (it was not possible to ensure this point for active characters that
+% have been |\let| to something, unless by eating it in the parameter of a macro. It the test fails,
+% the parameters is appended again to the input):
+% \begin{macrocode}
+\long\def\ettl@ifnch#1/#2/#3{#1\long\def\ettl@ifnch##1{\ettl@char{##1}
+ {\if\string##1\string#2\1\else\2\fi}\2//{##1}}\ettl@ifnch}
+% \end{macrocode}
+%\end{macro}
+%\end{macro}
%
+%\begin{macro}{\ettl@xifntk}
+%\begin{macro}{\ettl@ifntk}
+% \cs{ettl@xifntk} is quite the same as \cs{ettl@xifnch} but for the case the token to test (\ie the first parameter
+% of \cs{ettl@ifnextchar} is a control sequence:
+% \begin{macrocode}
+\long\def\ettl@xifntk#1{%
+ \ifx#1\bgroup\def\ettl@xifntk{\ifx\@let@token\bgroup\1\else\2\fi//{}}%
+ \else\ifx#1\egroup\def\ettl@xifntk{\ifx\@let@token\egroup\1\else\2\fi//{}}%
+ \else\def\ettl@xifntk{%
+ \ifx\@let@token\bgroup \2
+ \else\ifx\@let@token\egroup \2
+ \else\ifx\@let@token\@sptoken \ettl@ifnspace\ettl@xifntk%
+ \else\ettl@ifntk%
+ \fi\fi\fi/{#1}/{}}%
+ \fi\futurelet\@let@token\ettl@xifntk}
+% \end{macrocode}
+% \cs{ettl@ifntk} finishes the job. We need to ensure that |\@let@token| is not an active character having been
+% let to the token to test: there is no such thing as an active character for \cs{ettl@ifnextchar}!
% \begin{macrocode}
-\newrobustcmd\listgdel[2]{\@listdel\gdef{#1}{#2}}%
-\newrobustcmd\listxdel[2]{\begingroup
- \protected@edef\@listxdel{\endgroup
- \unexpanded{\@listdel\gdef{#1}}{#2}%
- }\@listxdel}%
-\newrobustcmd\listedel[2]{\begingroup
- \protected@edef\@listedel{\endgroup
- \unexpanded{\@listdel\def{#1}}{#2}%
- }\@listedel}
+\long\def\ettl@ifntk#1/#2/#3{#1\long\def\ettl@ifntk##1{\ettl@char{##1}
+ \2{\ifx##1#2\1\else\2\fi}//{##1}}\ettl@ifntk}
% \end{macrocode}
+%\end{macro}
+%\end{macro}
%
-% \begin{codecomment}
-% Now you noticed the job is delayed to a general macro |\@listdel| which is relatively tricky !
-% We need first to be placed in an environment where the `\,\textbar\,' delimiter has a category code of 3
-% (cf \sty{etoolbox}-lists definitions):
+%\begin{macro}{\ettl@ifnspace}
+% \cs{ettl@ifnspace} is used to gobble a space and go back to the loop (this is very rare...):
% \begin{macrocode}
-\begingroup\catcode`\|=3\catcode`\&=3
+\long\def\ettl@ifnspace#1#2/#3/#4 {#2\futurelet\@let@token#1}
% \end{macrocode}
-% Inside this ``catcode-group'' the definition of |\@listdel| ought to be global:
+%\end{macro}
+%
+% \iffalse
+%<package>
+%<package>%% \futuredef[list of allowed tokens]{ command }{ commands to expand after }
+%<package>%% \futuredef*[list of allowed tokens]{ command }{ commands to expand after }
+%<package>%% \futuredef=[list of allowed tokens]{ command }{ commands to expand after }
+%<package>%% \futuredef*=[list of allowed tokens]{ command }{ commands to expand after } (or \futuredef=*[...] )
+% \fi
+%
+% \begin{Macro}{futuredef}
+% \begin{Macro*}{futuredef*}
+% \begin{Macro*}{futuredef=}
+% \begin{Macro*}{futuredef*=}
+% This is the scanner.
% \begin{macrocode}
-\long\gdef\@listdel#1#2#3{%
+\newrobustcmd*\futuredef{\begingroup\ettl@futdef\ettl@futuredef\detokenize}
+\protected\def\ettl@futdef#1#2{\@ifstar%
+ {\ettl@futdef\ettl@futurd@f#2}
+ {\@ifchar={\ettl@futdef#1\unexpanded}
+ {\@testopt{\ettl@futur@def#1#2}}}}
+\long\def\ettl@futur@def#1#2[#3]{%
+ \csname ettl@\if\relax\detokenize{#3}\relax1\else2\fi of2\endcsname
+ {\let \ettl@x \@empty \letcs \ettl@futur@def@collect{\@gobblescape#1@collectall}}%
+ {\def \ettl@x {#3}\edef \ettl@y {#2{#3}}%
+ \ifx\ettl@x\ettl@y \let\ettl@y\@gobble
+ \else \ifx#2\unexpanded \let\ettl@y\@gobble
+ \else \def\ettl@y{\edef\ettl@x}%
+ \fi\fi\ettl@y{\detokenizeChars{#3}}%
+ \letcs\ettl@futur@def@collect{\@gobblescape#1@collect}}%
+ \expandafter#1\expandafter#2\expandafter{\ettl@x}}
% \end{macrocode}
-% \qquad |#1|=|\def| or |\gdef|, |#2|=\prm{listmacro}, |#3|=\prm{item} to remove.\par
-% In order to preserve the hash-table from temporary definitions, a group is opened:
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro}
+%
+% \begin{macro}{futuredef (not starred)}
+% \cs{ettl@futuredef} defines the \textsfsl{test-macro} (which is entitled to break the loop) and the \textsfsl{loop-macro}:
% \begin{macrocode}
-\begingroup
- \long\def\@tempa##1|#3|##2&{##1|##2\@tempb}%
+\long\def\ettl@futuredef#1#2#3#4{% #1=detokenize #2=list, #3=macro result, #4=code-next
+ \def \ettl@futuredef@loop{\ettl@futuredef@test{}}%
+ \long \def \ettl@futuredef@test##1{%
+ \ifcat\noexpand\ettl@x\bgroup\ettl@futuredef@end{}\else
+ \ifcat\noexpand\ettl@x\egroup\ettl@futuredef@end{}\else
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futuredef@space#1\else
+ \ettl@futur@def@collect#1\fi\fi\fi/Ne¤t/{#2}{##1}}%
+ \long \def \ettl@futuredef@end##1##2/Ne¤t/##3##4{##2\endgroup\def#3{##4}#4##1}%
+ \futurelet \ettl@x \ettl@futuredef@loop}
% \end{macrocode}
+% \cs{ettl@futuredef@collect} captures the next token (because it was found in the list) and
+% append it to the \textsfsl{result} (the argument of \cs{ettl@futuredef@test}). Then it loops:
+% \begin{macrocode}
+\long\def\ettl@futuredef@collect#1#2/Ne¤t/#3#4#5{#2%
+ \ifcat\noexpand#5\relax \ettl@futuredef@filt\unexpanded
+ \else \ettl@futuredef@filt#1
+ \fi{#5}{#3}
+ {\def\ettl@futuredef@loop{\ettl@futuredef@test{#4#5}}\futurelet\ettl@x\ettl@futuredef@loop}
+ {\ettl@futuredef@end{#5}/Ne¤t/{}{#4}}/Ne¤t/}
+% \end{macrocode}
+% \cs{ettl@futuredef@space} gobbles the space token and append a space to the \textsfsl{result}. Then it loops:
+% \begin{macrocode}
+\long\def\ettl@futuredef@space#1#2/Ne¤t/#3#4 {\ettl@futur@def@collect#1#2/Ne¤t/{#3}{#4}{ }}
+% \end{macrocode}
+% \cs{ettl@futuredef@collectall} is used when no option (no \prm{list of allowed tokens}) has been given to \cs{futuredef}.
+% In this case, \cs{futuredef} will stop only at the next begin-group or end-group token:
+% \begin{macrocode}
+\long\def\ettl@futuredef@collectall#1#2/Ne¤t/#3#4#5{#2%
+ \def\ettl@futuredef@loop{\ettl@futuredef@test{#4#5}}\futurelet\ettl@x\ettl@futuredef@loop}
+% \end{macrocode}
+% \end{macro}
%
-% |\@tempa| is a delimited macro whose aim is to remove the first \prm{item} found in the list
-% and it adds |\@tempb| after the result. If the \prm{item} was not in the list, then |##2|
-% will be empty. Note that |\@tempa| is the only macro whose definition depends on the \prm{item}
-% (and then leads |\@listdel| not to be fully-expandable).
+%\begin{macro}{\ettl@futur@def@filt}
+% \cs{ettl@futur@def@filt} defines the \textslsf{filter macro} to check if the token is in the \prm{list of allowed tokens}:
+% \begin{macrocode}
+\long\def\ettl@futur@def@filt#1#2{% #1=token to check, #2=allowed list
+ \long\def\ettl@futdef@filt##1#1##2##3/##4##5##6/Ne¤t/{##5}%
+ \ettl@futdef@filt#2#1//}
+\long\def\ettl@futuredef@filt#1#2\fi#3#4{\fi % #1=detokenize/unexpanded, #2=discard, #3=token,#4=allowed list
+ \expandafter\ettl@futur@def@filt\expandafter{#1{#3}}{#4}}
+% \end{macrocode}
+%\end{macro}
%
-% The result of |\@tempa| expansion is then given to |\@tempb| whose purpose is to cancel out
-% whatever is found between the two delimiters: \textbar|\@tempb|...\textbar|\@tempb|:
+% \begin{macro}{futured@f (starred)}
+% \cs{ettl@futured@f} defines the \textsfsl{test-macro} (which is entitled to break the loop) and the \textsfsl{loop-macro}:
% \begin{macrocode}
- \long\def\@tempb|##1|\@tempb##2|\@tempb{%
- \ifblank{##2}{\unexpanded{##1}}
+\long\def\ettl@futured@f#1#2#3#4{\begingroup%#1=test macro,#2=list,#3=macro,#4=code-next
+ \let\ettl@y\@undefined
+ \def \ettl@futured@f@loop{\ettl@futured@f@test{}}%
+ \long \def \ettl@futured@f@test##1{%
+ \csname @\ettl@ifinsinglelist#1\ettl@x#2/End§List/oftwo\endcsname
+ {\ifcat\noexpand\ettl@x\bgroup\ettl@futuredef@end{##1}\fi
+ \ifcat\noexpand\ettl@x\egroup\ettl@futuredef@end{##1}\fi
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futured@f@space{##1}{ }\fi
+ \ettl@futured@f@collect{##1}/Ne¤t/}
+ {\ettl@futured@f@expand{##1}}}%
+ \long \def \ettl@futuredef@end##1\fi##2/Ne¤t/{\fi\endgroup\def#3{##1}#4}%
+ \futurelet \ettl@x \ettl@futured@f@loop}
% \end{macrocode}
-% If the \prm{item} \textbf{was not} is the list, then |##2| will be empty, and§
-% \qquad |\@tempb|\textbar...\textbar|\@tempb|...\textbar|\@tempb|§
-% is replaced by the \emph{original-}list (\ie |##1| -- that we shall not expand), then the loop is broken;
-% otherwise the \prm{item} was in the list and |##1| is the \emph{shortened-}list without the \prm{item}. We have to loop
-% to remove all the \prm{item{\tt s}} of the list, except in the case where the \emph{shortened-}list
-% is empty after having removing \prm{item} (|##1| empty):
+% \cs{ettl@futured@f@collect} collects the next token which is appended to the argument of \cs{ettl@futured@f@test} (the \textsfsl{result}):
% \begin{macrocode}
- {\ifblank{##1}{}{\@tempx##1&}}}%
+\long\def\ettl@futured@f@collect#1#2/Ne¤t/#3{%
+ #2\def\ettl@futured@f@loop{\ettl@futured@f@test{#1#3}}\let\ettl@y\@undefined%
+ \futurelet\ettl@x\ettl@futured@f@loop}
% \end{macrocode}
-% Now we just have to (define and) expand |\@tempx| in an |\edef| which is going to redefine
-% the \prm{listmacro}. |\@tempx| expands first |\@tempa| and then |\@tempb| on the result of
-% the expansion of |\@tempa|. The macro |\@tempx| itself has an argument: it is (at first stage) the
-% replacement text of \prm{listmacro}:
+% \cs{ettl@futured@f@expand@nbk} is used when \cs{futuredef*} is called with a non empty optional argument:
% \begin{macrocode}
- \long\def\@tempx##1&{\expandafter\@tempb\@tempa|##1|\@tempb|#3|&}%
- \edef\@redef{\endgroup
- \unexpanded{#1#2}{% ie: \def or \gdef \listmacro
+\long\def\ettl@futured@f@expand@nbk#1{%
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futured@f@space{#1}{}\fi
+ \ifx\ettl@x\ettl@y\ettl@futuredef@end{#1}%
+ \else\let\ettl@y\ettl@x\ettl@futured@f@exp@nd\fi/Ne¤t/}
% \end{macrocode}
-% |\@redef| redefines the list using (|\def| or |\gdef|), the replacement text is the result
-% of the expansion of |\@tempx| on the \prm{listmacro} which is expanded once (to see its items...):
+% \cs{ettl@futured@f@expand@bk} is used when \cs{futuredef*} is called with an empty optional argument:
% \begin{macrocode}
- \expandafter\@tempx\unexpanded\expandafter{#2}&}%
+\long\def\ettl@futured@f@expand@bk#1{%
+ \ifcat\noexpand\ettl@x\bgroup\ettl@futuredef@end{#1}\fi
+ \ifcat\noexpand\ettl@x\egroup\ettl@futuredef@end{#1}\fi
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futured@f@space{#1}{ }\fi
+ \ifx\ettl@x\ettl@y\ettl@futured@f@collect{#1}%
+ \else\let\ettl@y\ettl@x\ettl@futured@f@exp@nd%
+ \fi/Ne¤t/}
% \end{macrocode}
-% Then just expand |\@redef| to proceed the redefinition of \prm{listmacro}:
+% \cs{ettl@futured@f@exp@nd} expands the next token because it is not in the list and
+% goes back to the loop:
% \begin{macrocode}
- }\@redef}% end of \@listdel
+\long\def\ettl@futured@f@exp@nd#1/Ne¤t/{%
+ #1\expandafter\futurelet\expandafter\ettl@x\expandafter\ettl@futured@f@loop}
% \end{macrocode}
-% And ends the ``catcode-group'':
+% \cs{ettl@futured@f@space} gobbles the space token, append it to the result (the argument of \cs{ettl@futured@f@test})
+% and goes further in the loop:
% \begin{macrocode}
-\endgroup
+\csdef{ettl@futured@f@space}#1#2\fi#3/Ne¤t/ {%
+ \def\ettl@futured@f@loop{\ettl@futured@f@test{#1#2}}\let\ettl@y\@undefined
+ \futurelet\ettl@x\ettl@futured@f@loop}
% \end{macrocode}
-% \end{codecomment}
+% \end{macro}
%
-%\iffalse
+% \iffalse
%<package>
+%<package>%----------------------------------------------------------------------------
+% \fi
+%
+% \Subsection{Loops and Lists Management}
+%
+% \subsubsection{naturalloop}
+%
+% \iffalse
%<package>
-%<package>% \getlistindex[\indexmacro]{ \listmacro }
-%<package>% \getlistindex*[\indexmacro]{ expanded list }
+%<package>%% \naturalloop [ auxiliary commands (default \do) ]{ n times }{ argument }
% \fi
%
+% \begin{Macro}{naturalloop}
+% This macro uses the capability of \eTeX{} to build purely expandable loop using \cs{numexpr}:
+% \begin{macrocode}
+\newcommand\naturalloop[1]{\FE@testopt{#1}\ettl@naturalloop{\do}}
+\def\ettl@naturalloop[#1]#2#3{%
+ \ifnum\numexpr#2>0 \ExpandNext{\ettl@naturall@@p[{#1}]{#2-1}{1}{#3}}{#1[1]{#3}{#3}}%
+ \else\ettl@fi#3%
+ \fi}
+\def\ettl@naturall@@p[#1]#2#3#4#5#6\fi{\fi%
+ \ifnum\numexpr#2>0 \ExpandNext{\ettl@naturall@@p[{#1}]{#2-1}{#3+1}{#4}}{#1[#3+1]{#4}{#5}}%
+ \else\ettl@fi#5%
+ \fi}
+% \end{macrocode}
%
-% \begin{macro}{\getlistindex}\cmdlabel{impl:getlistindex}
-% \cmd{getlistindex} may be defined, with its star form (no expansion of the list)\seedesc{getlistindex}
-% and normal form (\prm{listmacro} expanded once);
-% The search-index is initialised at 1:
+% \end{Macro}
+%
+% \subsubsection{Lists of single tokens}
%
-% We first need to get into a group where delimiter `\,\textbar\,' and `\,\&\,' have catcode 3:
+% \iffalse
+%<package>
+%<package>%% \ifinttokslist{ item }{ list of tokens }{ true }{ false }
+% \fi
+%
+%\begin{Macro*}{ifintokslist} \FE
+% \cs{ifintokslist}\prm{token}\prm{list of single tokens} breaks the loop at once when \prm{token}
+% is found in the list. The test for the end of the list is made by \cs{ettl@nbk}... of course:
+%\begin{Macro}{ifincharlist}
+% \cs{ifincharlist}\prm{character or token}\prm{list of single characters or tokens} is the same, with a
+% different test macro: \cs{ettl@ifchar} is used instead of \cs{ettl@ifx}:
% \begin{macrocode}
-\newcommand\getlistindex[1]{\FE@ifstar{#1}
- {\ettl@getlistindex{}\unexpanded}
- {\ettl@getlistindex\expandnext\unexpanded}}
+\newcommand\ifintokslist[4]{\romannumeral\csname @%
+ \expandafter\ettl@nbk\romannumeral\ettl@dosinglelist{\ettl@ifintokslist{#1}}{#2}//{first}{second}//%
+ oftwo\endcsname{\z@#3}{\z@#4}}
+\long\def\ettl@ifintokslist#1#2{\ettl@ifx{#1}{#2}{\expandafter\z@\ettl@breakloop}{}}
+\newcommand\ifincharlist[4]{\romannumeral\csname @%
+ \expandafter\ettl@nbk\romannumeral\ettl@dosinglelist{\ettl@ifincharlist{#1}}{#2}\z@//{first}{second}//%
+ oftwo\endcsname{\z@#3}{\z@#4}}
+\long\def\ettl@ifincharlist#1#2{\ettl@ifchar{#1}{#2}{\expandafter\z@\ettl@breakloop}{}}
% \end{macrocode}
-% \end{macro}
+%\end{Macro}
+%\end{Macro*}
%
-% \begin{macro}{\xgetlistindex}\cmdlabel{impl:xgetlistindex}
-% |\xgetlistindex| is similar but the \prm{item} is expanded during string comparison (inside |\pdfstrcmp| is pdf\TeX{},
-% or before the test if this primitive is not found).
+%\begin{macro}{\ettl@dosinglelist} \FE
+% We define a very simple loop for single tokens (for internal use): it is the same as \cs{toksloop} but
+% avoids overhead due to the parsing of modifiers:
% \begin{macrocode}
-\newcommand\xgetlistindex[1]{\FE@ifstar{#1}
- {\ettl@getlistindex{}\@firstofone}
- {\ettl@getlistindex\expandnext\@firstofone}}
+\long\def\ettl@dosinglelist#1#2{\ettl@nbk#2//%
+ {\ettl@dosinglelist@loop{#1}#2//{\ettl@dosinglelist@loop{#1}}\ettl@breakloop}
+ \ettl@breakloop///End§List/}
+\long\def\ettl@dosinglelist@loop#1#2#3#4/#5#6#7/End§List/{%
+ #1{#2}#6{#3}#4//{#6}#7/End§List/}
% \end{macrocode}
-% \end{macro}
+%\end{macro}
%
+% \iffalse
+%<package>
+%<package>%% \gettokslistindex { item }{ list of tokens }
+%<package>%% \gettokslistcount { item }{ list of tokens }
+%<package>%% \gettokslisttoken { item }{ list of tokens }
+% \fi
+%
+% \begin{Macro*}{gettokslistindex}
+% \begin{Macro*}{getcharlistindex}
+% \begin{Macro*}{gettokslistcount}
+% \begin{Macro*}{getcharlistcount}
+% \begin{Macro*}{gettokslisttoken}
+% \begin{Macro}{getcharlisttoken}
+%
+% \cs{gettokslistindex}\prm{item}\prm{tokenlist-macro}
%
-% Then the following macro does the job in a loop, which is fully expandable when we can use |\pdfstrcmp|:
+% \cs{gettokslistindex} is always purely expandable (|\ifx| test).
%
+% The following three macros are the \textsl{entry points}.
+% \cs{ExpandAftercmds} is applied to \cs{ettl@getsinglelist} which initiates the loop: we ask for total expansion.
+% After expansion, \cs{ettl@setresult} will extract the wanted register by projection:
+% The result comes from in the first
+% register for \textvb{count}, the second for \textvb{index} and the third for \textvb{token}, therefore, we use the
+% \cs{ettl@XofY} macros:
+% \begin{macrocode}
+\newcommand\gettokslistindex[2]{\number\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 2of3><}{\ettl@getsinglelist{\ettl@ifx{#1}}{#2}}}
+ {-1}//}{-1}}
+\newcommand\getcharlistindex[2]{\number\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 2of3><}{\ettl@getsinglelist{\ettl@ifchar{#1}}{#2}}}
+ {-1}//}{-1}}
+\newcommand\gettokslistcount[1]{\number\ifnotempty{#1}%
+ {\ExpandAftercmds{\ettl@setresult 1of3><}{\ettl@getsinglelist{\ettl@ifx{\\}}{#1}}}
+ 0}
+\newcommand\getcharlistcount[1]{}%
+\let\getcharlistcount=\gettokslistcount
+\newcommand\gettokslisttoken[2]{\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 3of3><}{\ettl@getsinglelist{\ettl@ifx{#1}}{#2}}}
+ {}//}{}}
+\newcommand\getcharlisttoken[2]{\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 3of3><}{\ettl@getsinglelist{\ettl@ifchar{#1}}{#2}}}
+ {}//}{}}
+% \end{macrocode}
+% \cs{ettl@getsinglelist} initiates the loop (we test if the list or the \prm{item} is empty first):
+% \begin{macrocode}
+\long\def\ettl@getsinglelist#1#2{\ettl@singlelist@loop{#1}{-1}{-1}{}#2//%
+ \ettl@singlelist@loop\ettl@singlelist@result/End§List/}
+% \end{macrocode}
+% \cs{ettl@singlelist@loop} tests each token and update registers:
% \begin{macrocode}
-\begingroup\catcode`\|=3\catcode`\&=3
-\long\gdef\ettl@getlistindex#1#2#3{\FE@testopt{#3}{\ettl@get@listindex{#1}{#2}}{}}
-\long\gdef\ettl@get@listindex#1#2[#3]#4#5{#1\ettl@get@list@idx{#5}{#4}{\numexpr1}{#2}[{#3}]}
-\long\gdef\ettl@get@list@idx#1#2#3#4[#5]{% #1=expanded list, #2=item, #3=index, #4=\unexpanded (event., #5=indexmacro)
- \ifblank{#1}0% the (remainder of) the list is empty
-" {\xifstrcmp{\expandonce{\ettl@list@first@item#1&}}{#4{#2}}}
-! {\ettl@listitem@cmp{\ettl@list@first@item#1&}{#2}{#4}}
- {\ifblank{#5}{\number#3\relax}{\ettl@ifiscount{#5}{#5=\number#3\relax}{\edef#5{\number#3}}}}
- {\expandnext\ettl@get@list@idx{\ettl@list@other@item#1&}{#2}{#3+1}{#4}[{#5}]}}
+\long\def\ettl@singlelist@loop#1#2#3#4#5#6/#7#8#9/End§List/{%
+ \csname @#1#5{first}{second}oftwo\endcsname
+ {#8{#1}{#2+1}{#3+1+0*(0}{#5}#6//#8#9}
+ {#8{#1}{#2+1}{#3+1}{#4}#6//#8#9}/End§List/}
% \end{macrocode}
+
+% Well! \#1 is the \textsl{test-macro} to test against \#5, the current token of the list.
%
-% \begin{codecomment}
+% \#2 is the current index. It is incremented by $1$ and will be equal to the length of the list, at the end.
+% \#3 is the index of the \prm{item} (if found): it is incremented by $1$ but at the time
+% \prm{item} is found is the list, the next increments are canceled (multiplication by $0$).
+%
+% The fourth parameter remains the same (\#4=\#4=|empty|, set at the initiation of the loop) but at the time \prm{item}
+% is found, \#4 becomes this \prm{item} (precisely the matching item found in the list: \#5).
%
-% The next two macros expand to the first item in a list or the remainder of the list respectively:
+% \#6 is the remainder of the list. \#7, \#8 and \#9 are the usual parameter for \textsfsl{blank-test} (see \cmdref*{ettl@nbk}).
%
+% \cs{ettl@tokslist@result} extracts the |count|, the |index| and the |token| from the parameters of the \textsl{test-macro}:
% \begin{macrocode}
-\long\gdef\ettl@list@first@item#1|#2&{#1}
-\long\gdef\ettl@list@other@item#1|#2&{#2}
-!\long\gdef\ettl@listitem@cmp#1#2#3{%
-! \ifx#3\unexpanded\def\ettl@listitem@cmp@{#2}%
-! \else\protected@edef\ettl@listitem@cmp@{#2}%
-! \fi
-! \expandafter\ifstrequal\expandafter{#1}{#2}}
-\edef\ettl@ifiscount{%
- \gdef\noexpand\ettl@ifiscount##1{%
- \noexpand\expandafter\noexpand\ettl@ifiscount@i
- \noexpand\meaning##1\string\count\noexpand\@nil}%
-}\ettl@ifiscount
-\edef\ettl@ifiscount@i{%
- \gdef\noexpand\ettl@ifiscount@i##1\string\count##2\noexpand\@nil{%
- \noexpand\ifempty{##1}}%
-}\ettl@ifiscount@i
+\def\ettl@singlelist@result#1#2#3#4#5/End§List/{\ExpandNextTwo\@swaptwo%
+ {\number\numexpr\ifempty{#4}{-1}{#3)}}{\number\numexpr#2}{#4}}
% \end{macrocode}
+% Then \cs{ettl@setresult} finishes the job:
+% \begin{macrocode}
+\def\ettl@setresult#1of#2>#3<{\ettl@nbk #3//%
+ {\ifdefcount{#3}{#3=\csname ettl@#1of#2\endcsname}
+ {\edef#3{\csname ettl@#1of#2\endcsname}}}%
+ {\csname ettl@#1of#2\endcsname}//}
+% \end{macrocode}
+% \end{Macro}
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro*}
%
-% \end{codecomment}
+% \subsubsection{General Lists and Loops Constructor}
+%
+% \begin{Macro}{DeclareCmdListParser}
+%
+% |\DeclareCmdListParser| acts in the same way as
+% \xpackage{etoolbox}-|\DeclareListParser| and the command-list-parser
+% are sensitive to the category code of the \prm{separator}
%
% \iffalse
%<package>
-%<package>%\getcsvlistindex{ item }{ csvlistmacro }
-%<package>%\getcsvlistindex*{ item }{ item,item,item }
+%<package>%% \DeclareCmdListParser : general constructor for command-list parsers
+%<package>%% \DeclareCmdListParser\ParserName{separator}
% \fi
-% \begin{macro}{\getcsvlistindex} \cmdlabel{impl:getcsvlistindex}
-% \strut\seedesc{getcsvlistindex}
+%
+% The command-list-parser will be defined only if it is definable:
% \begin{macrocode}
-\long\gdef\getcsvlistindex#1{\FE@ifstar{#1}
- {\ettl@getcsvlistindex{}\unexpanded}
- {\ettl@getcsvlistindex\expandnext\unexpanded}}
+\newrobustcmd\DeclareCmdListParser[3][\global]{\@ifdefinable{#2}{\begingroup
+ \protected\def\ettl@defcmdparser##1{%
+ \edef\ettl@defcmdparser{\endgroup\ettl@defcmdparser
+ {#1}{\noexpand#2}{\unexpanded{#3}}
+ {\noexpandcs{##1->start}}
+ {\noexpandcs{##1->loop}}
+ {\noexpandcs{##1->loop+}}
+ {\noexpandcs{for##1}}%
+ }\ettl@defcmdparser
+ }\expandafter\ettl@defcmdparser\expandafter{\romannumeral-`\q\@gobblescape#2}}}
% \end{macrocode}
-% \end{macro}
-%
-% |\xgetcsvlistindex| is similar but the \prm{item} is expanded during string comparison (inside |\pdfstrcmp| is pdf\TeX{},
-% or before the test if this primitive is not found).
+% \cs{ettl@defcmdparser} doeas the definitions: \cs{parser->start} initiates the loop (and add a separator
+% at the end of the list) and \cs{parser->loop} loops into the list, expanding the (optional, default |\do|) user code
+% for each item.
%
+% In case the \CH{\ttbf+} form is used, the auxiliary macro \cs{ettl@doitemidx} overloads
+% the user-code. Otherwise (simple form without index): \cs{ettl@doitem} overloads the user-code.
+% \begin{macrocode}
+\protected\long\def\ettl@defcmdparser#1#2#3#4#5#6#7{%#1=global,#2=command,#3=sep,#4=start,#5=loop,#6=loop+
+ #1\long\def#4##1##2[##3]##4{% ##1=case, ##2=expandafter??? , ##3=do, ##4=list
+ ##2{##4}% ifiscs or @thirdofthree
+ {\expandafter\@swaparg\expandafter{##4}{#4{##1}\@thirdofthree[{##3}]}}
+ {\ettl@nbk##4//%
+ {\ifcase##1 \ettl@or\@swaplast{#60{\ettl@lst@count}}#6%
+ \or \ettl@or\@swaplast{#60{\ettl@lst@getitem{##3}}}#6%
+ \or \ettl@or\@swaplast{#5{##3}}#5%
+ \or \ettl@fi\@swaplast{#60{##3}}#6%
+ \fi{##4#3//}\ettl@breakloop
+ }\ettl@breakloop///End§List/}}%
+ #1\long\def#5##1##2#3##3##4/##5##6##7/End§List/{%
+ \if\relax\detokenize{##2}\relax\expandafter\@gobbletwo\fi\@firstofone{##1{##2}}%
+ ##6{##1}##3##4//{##6}##7/End§List/}
+ #1\long\def#6##1##2##3#3##4##5/##6##7##8/End§List/{%
+ \if\relax\detokenize{##3}\relax\expandafter\@gobbletwo\fi\@firstofone{##2[##1]{##3}}%
+ \expandafter##7\expandafter{\number\numexpr##1+1}{##2}##4##5//{##7}##8/End§List/}
+ #1\protected\def#7{\@ifchar*%
+ {\@ifchar+{\ettl@forloop{\expandafter#2\expandafter*\expandafter+}{[####1]####2}}
+ {\ettl@forloop{\expandafter#2\expandafter*\expandafter+}{####1}}}
+ {\@ifchar+{\@ifchar*%
+ {\ettl@forloop{\expandafter#2\expandafter*\expandafter+}{[####1]####2}}
+ {\ettl@forloop{\expandafter#2\expandafter+}{[####1]####2}}}
+ {\ettl@forloop{\expandafter#2}{####1}}}}
+ #1\def#2{\ettl@lst@modif#423\ifiscs}}
+% \end{macrocode}
+% \cs{ettl@lst@doitem} gives the current item to the auxiliary macro, while \cs{ettl@lst@doitemidx} gives the index as well.
+% \cs{ettl@lts@getitem} is the helper macro in case we ask for an item (cf. |\csvloop[4]\mylist|) and
+% \cs{etttl@lst@count} is as basic as it can be!
% \begin{macrocode}
-\long\gdef\xgetcsvlistindex#1{\FE@ifstar{#1}
- {\ettl@getcsvlistindex{}\@firstofone}
- {\ettl@getcsvlistindex\expandnext\@firstofone}}
+\long\def\ettl@lst@getitem#1[#2]#3{%
+ \ifnum\numexpr#1<0 \expandafter\breakloop\fi
+ \ifnum\numexpr#1=#2 \ettl@fi#3\breakloop\fi}
+\long\def\ettl@lst@count[#1]#2{+\ettl@nbk#2//10//}
% \end{macrocode}
+%\end{Macro}
%
-% Then the following macro does the job in a loop, which is fully expandable when we can use |\pdfstrcmp|:
+% \begin{macro}{\ettl@lst@modif} \cmdlabel{impl:ettl@lst@modif} \FE
+% \cs{ettl@lst@modif} is used by any command-list-parser at the beginning to set the options. This macro is interesting
+% because it is recursive: each allowed modifier is parsed one after the other in a purely expandable way, setting
+% the registers (\#1 to \#4) to the value corresponding to the modifier used (the registers are initialized to their default value).
%
+% Such a code is interesting because it may be used elsewhere: the aim is to parse modifiers without taking care of their
+% order (\cs{csvloop}\stform*\stform+ is the same as \cs{csvloop}\stform{+*}):
% \begin{macrocode}
-\long\gdef\ettl@getcsvlistindex#1#2#3{\FE@testopt{#3}{\ettl@get@csvlistindex{#1}{#2}}{}}
-\long\gdef\ettl@get@csvlistindex#1#2[#3]#4#5{#1\ettl@get@csvlist@idx{#5}{#4}{\numexpr1}{#2}[{#3}]}
-\long\gdef\ettl@get@csvlist@idx#1#2#3#4[#5]{% #1=expanded list, #2=item, #3=index, #4=\unexpanded (event., #5=indexmacro)
- \ifblank{#1}0% the (remainder of) the list is empty
-" {\xifstrcmp{\expandonce{\ettl@csvlist@first@item#1&}}{#4{#2}}}
-! {\ettl@listitem@cmp{\ettl@csvlist@first@item#1&}{#2}{#4}}
- {\ifblank{#5}{\number#3\relax}{\ettl@ifiscount{#5}{#5=\number#3\relax}{\edef#5{\number#3}}}}
- {\expandnext\ettl@get@csvlist@idx{\ettl@csvlist@other@item#1&}{#2}{#3+1}{#4}[{#5}]}}
+\long\def\ettl@lst@modif#1#2#3#4#5{\FE@modifiers{*+![}{#5}%
+ {\ettl@lst@modif{#1}#2#3\@thirdofthree}% * case
+ {\ettl@lst@modif{#1}#3#2{#4}}% + (case 3/default 2)
+ {\ettl@lst@modif{\number\numexpr#1}00{#4}}% ! (case 0)
+ {\ettl@lst@opt{#1}{#2}{#4}#5}% [ (option)
+ {\ettl@lst@opt{#1}{#2}{#4}[\do]}}% (default option)
+\long\def\ettl@lst@opt#1#2#3[#4]{%
+ \expandafter#1\expandafter{\number\ifnum#2=0 0\else\ifstrnum{#4}{1}{#2}\fi}{#3}[{#4}]}
% \end{macrocode}
+% \end{macro}
%
-% \begin{codecomment}
-% The next two macros expand to the first item in a list or the remainder of the list respectively:
+% \begin{Macro}{breakloop}
+% \cs{breakloop} gobbles anything until the \CH{/End§List/} delimiter:
% \begin{macrocode}
-\long\gdef\ettl@csvlist@first@item#1,#2&{#1}
-\long\gdef\ettl@csvlist@other@item#1,#2&{#2}
+\long\def\ettl@breakloop#1/End§List/{}
+\let\breakloop\ettl@breakloop
% \end{macrocode}
-% \end{codecomment}
+% \end{Macro}
%
+%\begin{macro}{forloops}
+% In order to define for |\for|...|loop| macros, and to handle the case they are nested, we need a counter.
+% \begin{macrocode}
+\globcount\ettl@for@nested
+\long\def\ettl@forloop#1#2#3\do{%
+ \global\advance\ettl@for@nested\@ne\relax
+ \csdef{ettl@for@loop\the\ettl@for@nested}{%
+ #1\expandafter[\csname ettl@for@do\the\ettl@for@nested\endcsname]{#3}%
+ \csundef{ettl@for@do\the\ettl@for@nested}%
+ \csundef{ettl@for@loop\the\ettl@for@nested}%
+ \global\advance\ettl@for@nested\m@ne\relax}
+ \expandafter\afterassignment\csname ettl@for@loop\the\ettl@for@nested\endcsname
+ \long\csdef{ettl@for@do\the\ettl@for@nested}#2}
+% \end{macrocode}
+%\end{macro}
%
% \iffalse
%<package>
-%<package>%\gettokslistindex{ item }{ tokenslistmacro }
-%<package>%\gettokslistindex*{ item }{ list of tokens }
+%<package>
+%<package>%% \csvloop[\command]\csvListMacro
+%<package>%% \csvloop*[\command]{item,item,item}
% \fi
-% \begin{macro}{\gettokslistindex}\cmdlabel{impl:gettokslistindex}
-% \strut\seedesc{gettokslistindex}
+%
+% \begin{Macro*}{csvloop}
+% Definition of |\csvloop|: \cs{forcsvloop} is also defined by \cmdref{DeclareCmdListParser} but is not purely expandable:
+%\begin{Macro}{forcsvloop}
% \begin{macrocode}
-\long\gdef\gettokslistindex#1{\FE@ifstar{#1}
- {\ettl@gettokslistindex{}}
- {\ettl@gettokslistindex\expandnext}}
+\DeclareCmdListParser\csvloop{,}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
+%\end{Macro*}
%
+% \begin{codecomment}
+% \begin{Macro*}{listloop}
+%\begin{Macro}{forlistloop}
+% Definition of |\listloop| (with a `\,\textbar\,' of catcode 3 (math shift) -- cf.\xpackage{etoolbox}). \cs{forlistloop} is
+% defined by \cmdref{DeclareCmdListParser} but is not purely expandable:
% \begin{macrocode}
-\long\gdef\ettl@gettokslistindex#1#2{\FE@testopt{#2}{\ettl@get@tokslistindex{#1}}{}}
-\long\gdef\ettl@get@tokslistindex#1[#2]#3#4{#1\ettl@get@tokslist@idx{#4}{#3}{\numexpr1}[{#2}]}
-\long\gdef\ettl@get@tokslist@idx#1#2#3[#4]{% #1=expanded list, #2=item, #3=index
- \ifblank{#1}0% the (remainder of) the list is empty
- {\expandafter\ifx\expandafter#2\ettl@tokslist@first@item#1&%
- \ettl@afterelse\ifblank{#4}{\number#3\relax}
- {\ettl@ifiscount{#4}{#4=\number#3\relax}{\edef#4{\number#3}}}%
- \else \ettl@afterfi
- \expandnext\ettl@get@tokslist@idx{\ettl@tokslist@other@item#1&}{#2}{#3+1}[{#4}]%
- \fi}}
+\begingroup\catcode`\|=3
+\DeclareCmdListParser\listloop{|}% global declaration
+\endgroup
% \end{macrocode}
+% \end{Macro}
+%\end{Macro*}
+% \end{codecomment}
%
% \begin{codecomment}
-% The next two macros expand to the first item in a list or the remainder of the list respectively:
+% \begin{Macro*}{toksloop}
+%\begin{Macro}{fortoksloop}
+% Definition of |\toksloop| (with no delimiter). \cs{fortoksloop} is defiined by \cmdref{DeclareCmdListParser} but is not
+% purely expandable:
% \begin{macrocode}
-\long\gdef\ettl@tokslist@first@item#1#2&{#1}
-\long\gdef\ettl@tokslist@other@item#1#2&{#2}
-\endgroup% catcode group
+\DeclareCmdListParser\toksloop{}
% \end{macrocode}
+%\end{Macro}
+% \end{Macro*}
% \end{codecomment}
%
-%
+% \iffalse
+%<package>
+%<package>%% \forcsvloop\csvListMacro\do{...#1...}
+%<package>%% \forcsvloop*{item,item,item,...}\do{...#1...}
+% \fi
%
% \iffalse
%<package>
+%<package>%% \csvlistadd \csvListMacro { item }
+%<package>%% \csvlist(g|e|x)add \csvListMacro { item }
+% \fi
+%
+%\begin{Macro*}{csvlistadd}
+%\begin{Macro*}{csvlistgadd}
+%\begin{Macro*}{csvlisteadd}
+%\begin{Macro}{csvlistxadd}
+% \begin{macrocode}
+\providerobustcmd\csvlistadd[2]{\ettl@nbk#2//{\appto#1{#2,}}{}//}
+\providerobustcmd\csvlistgadd[2]{\ettl@nbk#2//{\gappto#2{#2,}}{}//}
+\providerobustcmd\csvlisteadd[2]{\begingroup \protected@edef#1{#2}%
+ \expandafter\ettl@nbk#1//{\expandafter\endgroup
+ \expandafter\appto\expandafter#1\expandafter{#1,}}\endgroup//}
+\providerobustcmd\csvlistxadd[2]{\begingroup \protected@edef#1{#2}%
+ \expandafter\ettl@nbk#1//{\expandafter\endgroup
+ \expandafter\gappto\expandafter#1\expandafter{#1,}}\endgroup//}
+% \end{macrocode}
+%\end{Macro}
+%\end{Macro*}
+%\end{Macro*}
+%\end{Macro*}
+%
+% \iffalse
%<package>
-%<package>%\getlistitem{ number }{ listmacro }
-%<package>%\getlistitem*{ number }{ listmacro }
+%<package>%% \csvtolist [\ListMacro] \csvListMacro
+%<package>%% \csvtolist* [\ListMacro] {item,item,item}
+%<package>% Recommended use: \edef\ListMacro{\csvtolist{item,item,item}}
% \fi
-% \begin{macro}{\getlistitem}\cmdlabel{impl:getlistitem}
-% \strut\seedesc{getlistitem}
+%
+% \begin{Macro}{csvtolist}
+% This is the first application of |\csvloop|:
% \begin{macrocode}
-\newcommand\getlistitem[1]{\FE@ifstar{#1}{\ettl@getlistitem{}}
- {\ettl@getlistitem\expandnext}}
-\begingroup\catcode`\&=3
-\long\gdef\ettl@getlistitem#1#2#3{%#2=index, #3=list or list-macro
- #1\ettl@get@list@item{#3}{\numexpr#2}}
-\long\gdef\ettl@get@list@item#1#2{%
- \ifblank{#1}{}
- {\ifnum#2=1 \ettl@afterelsefi
- \expandonce{\ettl@list@first@item#1&}%
- \else\ifnum#2>0 \ettl@afterfifi
- \expandnext\ettl@get@list@item{\ettl@list@other@item#1&}{#2-1}%
- \fi\fi}}
+\newcommand\csvtolist[1]{\FE@ifstar{#1}{\ettl@convertlist{{\csvloop*}\ettl@do@csvtolist}}
+ {\ettl@convertlist{\csvloop\ettl@do@csvtolist}}}
+\long\def\ettl@convertlist#1#2{\FE@testopt{#2}{\ettl@convert@list#1}{}}
+\long\def\ettl@convert@list#1#2[#3]#4{\ettl@nbk#3//%
+ {\edef#3{#1[#2]{#4}}}
+ {#1[#2]{#4}}//}
+\begingroup\catcode`\|=3% etb catcode
+\long\gdef\ettl@do@csvtolist#1{\unexpanded{#1}|}
\endgroup
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
% \iffalse
%<package>
-%<package>
-%<package>% \getcsvlistitem{ number }{ csvlistmacro }
-%<package>% \getcsvlistitem*{ number }{ item,item,item,... }
+%<package>%% \listtocsv [\csvListMacro] \ListMacro
+%<package>%% \listtocsv* [\csvListMacro] { expanded List }
+%<package>% Recommended use: \edef\csvListMacro{\listtocsv\ListMacro}
+% \fi
+%
+%\begin{Macro}{listtocsv}
+% This is the first application of |\listloop|:
+% \begin{macrocode}
+\newcommand\listtocsv[1]{\FE@ifstar{#1}{\ettl@convertlist{{\listloop*}\ettl@do@listtocsv}}
+ {\ettl@convertlist{\listloop\ettl@do@listtocsv}}}
+\long\def\ettl@do@listtocsv#1{\unexpanded{#1,}}
+% \end{macrocode}
+%\end{Macro}
+%
+% \iffalse
+%<package>%% \tokstolist [\ListMacro] { \toksListMacro / token token token }
% \fi
-% \begin{macro}{\getcsvlistitem}\cmdlabel{impl:getcsvlistitem}
-% \strut\seedesc{getcsvlistitem}
+%
+% \begin{Macro}{tokstolist}
+% This is the first application of |\toksloop|:
% \begin{macrocode}
-\newcommand\getcsvlistitem[1]{\FE@ifstar{#1}{\ettl@getcsvlistitem{}}
- {\ettl@getcsvlistitem\expandnext}}
-\begingroup\catcode`\&=3
-\long\gdef\ettl@getcsvlistitem#1#2#3{%#2=index, #3=list or list-macro
- #1\ettl@get@csvlist@item{#3,}{\numexpr#2}}
-\long\gdef\ettl@get@csvlist@item#1#2{%
- \ifblank{#1}{}
- {\ifnum#2=1 \ettl@afterelsefi
- \expandonce{\ettl@csvlist@first@item#1&}%
- \else\ifnum#2>0 \ettl@afterfifi
- \expandnext\ettl@get@csvlist@item{\ettl@csvlist@other@item#1&}{#2-1}%
- \fi\fi}}
+\newcommand\tokstolist[1]{\FE@ifstar{#1}{\ettl@convertlist{{\toksloop*}\ettl@do@tokstolist}}
+ {\ettl@convertlist{\toksloop\ettl@do@tokstolist}}}
+\begingroup\catcode`\|=3% etb catcode
+\long\gdef\ettl@do@tokstolist#1{\unexpanded{#1}|}
\endgroup
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
% \iffalse
%<package>
+%<package>%% \csvtolistadd \ListMacro \csvListMacro
+%<package>%% \csvtolistadd* \ListMacro {item,item,item}
+% \fi
+% \begin{Macro}{csvtolistadd}
+% \cs{csvtolistadd} is not purely expandable:
+% \begin{macrocode}
+\newrobustcmd*\csvtolistadd{\@ifstar{\ettl@csvtolistadd*}{\ettl@csvtolistadd{}}}
+\long\def\ettl@csvtolistadd#1#2#3{\eappto#2{\csvtolist#1[]{#3}}}
+% \end{macrocode}
+% \end{Macro}
+%
+% \iffalse
%<package>
-%<package>% \gettokslistitem{ number }{ tokslistmacro }
-%<package>% \gettokslistitem*{ number }{ list of tokens }
+%<package>%% \tokstolistadd \ListMacro { \toksListMacro / token token token }
% \fi
-% \begin{macro}{\gettokslistitem}\cmdlabel{impl:gettokslistitem}
-% \strut\seedesc{gettokslistitem}
+%
+% \begin{Macro}{tokstolistadd}
+% \cs{tokstolistadd} is not purely expandable:
% \begin{macrocode}
-\newcommand\gettokslistitem[1]{\FE@ifstar{#1}{\ettl@gettokslistitem{}}
- {\ettl@gettokslistitem\expandnext}}
-\begingroup\catcode`\&=3
-\long\gdef\ettl@gettokslistitem#1#2#3{%#2=index, #3=list or list-macro
- #1\ettl@get@tokslist@item{#3{}}{\numexpr#2}}
-\long\gdef\ettl@get@tokslist@item#1#2{%
- \ifblank{#1}{}
- {\ifnum#2=1 \ettl@afterelsefi
- \expandonce{\ettl@tokslist@first@item#1&}%
- \else\ifnum#2>0 \ettl@afterfifi
- \expandnext\ettl@get@tokslist@item{\@gobble#1}{#2-1}%
- \fi\fi}}
-\endgroup
+\newrobustcmd*\tokstolistadd{\@ifstar{\ettl@tokstolistadd*}{\ettl@tokstolistadd{}}}
+\long\def\ettl@tokstolistadd#1#2#3{\eappto#2{\tokstolist#1[]{#3}}}
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
+%\begin{macro}{\ettl@RemoveInList} \cmdlabel{impl:ettl@RemoveInList}
+% This is the general constructor for deletion into lists with any separator:
+% \begin{macrocode}
+\newrobustcmd\ettl@RemoveInList[2]{\begingroup
+% #1 = \global #2 = macro name
+ \def\ettl@RemoveInList##1{%
+ \edef\ettl@RemoveInList####1####2{%
+ \ettl@Rem@veInList{####1}####2\noexpandcs{##1->remove}\noexpandcs{##1->result}%
+ }\ettl@RemoveInList{#1}#2%
+ }\expandafter\ettl@RemoveInList\expandafter{\romannumeral0\@gobblescape#2}}
+\protected\long\def\ettl@Rem@veInList#1#2#3#4#5#6#7#8{%
+ \long\def#3[##1]##2#5#8#5##3##4/##5##6##7/End§List/{##6[##1+1]##2#5##3##4//##6##7/End§List/}%
+ \ifnotempty{#5}%% special case if no separator
+ {\long\def#4[##1]#5##2#5#5##3//##4/End§List/{\unexpanded{#1\def#7{##2#5}}%
+ \ettl@nbk#6//\ettl@setresult 1of1>#6<{\number\numexpr##1-1\relax}{}//}}%
+ {\long\def#4[##1]##2//##3/End§List/{\unexpanded{#1\def#7{##2}}%
+ \ettl@nbk#6//\ettl@setresult 1of1>#6<{\number\numexpr##1-1\relax}{}//}}%
+ \long\def#2##1{#3[0]#5##1#5#5#8#5//#3#4/End§List/}%
+ \edef#7{\endgroup\expandafter#2\expandafter{#7}}#7}
+\def\ettl@gobble@relax#1\relax{}
+% \end{macrocode}
+%\end{macro}
%
+% \iffalse
+%<package>
+%<package>%% \listdel \listMacro { item }
+%<package>%% \listgdel \listMacro { item }
+%<package>%% \listedel \listMacro { item }
+%<package>%% \listxdel \listMacro { item }
+% \fi
%
+% \begin{Macro*}{listdel}
+% \begin{Macro*}{listedel}
+% \begin{Macro*}{listgdel}
+% \begin{Macro}{listxdel}
+% \cs{listdel} removes an \prm{item} from a list, \cs{listedel} expands the \prm{item} (with |\protected@edef|) first,
+% \cs{listgdel} make the assignment to the (shorter-)list global and \cs{listxdel} both expands the \prm{item} and
+% make the assignment global:
+% \begin{macrocode}
+\begingroup\catcode`\|=3
+\newrobustcmd\listdel[1][]{\ettl@RemoveInList{}\listdel|{#1}}
+\newrobustcmd\listgdel[1][]{\ettl@RemoveInList\global\listdel|{#1}}
+\newrobustcmd\listedel[1][]{\ettl@listedel{}\listdel|{#1}}
+\newrobustcmd\listxdel[1][]{\ettl@listedel\global\listdel|{#1}}
+\aftergroup@def\listdel
+\aftergroup@def\listgdel
+\aftergroup@def\listedel
+\aftergroup@def\listxdel
+\endgroup% \catcode group
+\newrobustcmd\ettl@listedel[6]{\begingroup\protected@edef#5{#6}\expandafter\endgroup
+ \expandafter\@swaparg\expandafter{#5}{\ettl@RemoveInList#1#2{#3}{#4}#5}}
+% \end{macrocode}
+% \end{Macro}
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro*}
%
+% \iffalse
+%<package>
+%<package>%% \csvdel \listMacro { item }
+%<package>%% \csvgdel \listMacro { item }
+%<package>%% \csvedel \listMacro { item }
+%<package>%% \csvxdel \listMacro { item }
+% \fi
+%
+% \begin{Macro*}{csvdel}
+% \begin{Macro*}{csvedel}
+% \begin{Macro*}{csvgdel}
+% \begin{Macro}{csvxdel}
+% \cs{csvdel} removes an \prm{item} from a list, \cs{csvedel} expands the \prm{item} (with |\protected@edef|) first,
+% \cs{csvgdel} make the assignment to the (shorter-)list global and \cs{csvxdel} both expands the \prm{item} and
+% make the assignment global:
+% \begin{macrocode}
+\newrobustcmd\csvdel[1][]{\ettl@RemoveInList{}\csvdel,{#1}}
+\newrobustcmd\csvgdel[1][]{\ettl@RemoveInList\global\csvdel,{#1}}
+\newrobustcmd\csvedel[1][]{\ettl@listedel{}\csvdel,{#1}}
+\newrobustcmd\csvxdel[1][]{\ettl@listedel\global\csvdel,{#1}}
+% \end{macrocode}
+% \end{Macro}
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro*}
%
% \iffalse
-%<package>%----------------------------------------------------------------------------
%<package>
-%<package>% \collectoks{ cs-token }{ list of allowed tokens }{ commands to expand after }
+%<package>%% \toksdel \listMacro { item }
+%<package>%% \toksgdel \listMacro { item }
+%<package>%% \toksedel \listMacro { item }
+%<package>%% \toksxdel \listMacro { item }
+% \fi
+%
+% \begin{Macro*}{toksdel}
+% \begin{Macro*}{toksedel}
+% \begin{Macro*}{toksgdel}
+% \begin{Macro}{toksxdel}
+% \cs{toksdel} removes an \prm{item} from a list, \cs{toksedel} expands the \prm{item} (with |\protected@edef|) first,
+% \cs{toksgdel} make the assignment to the (shorter-)list global and \cs{toksxdel} both expands the \prm{item} and
+% make the assignment global:
+% \begin{macrocode}
+\newrobustcmd\toksdel[1][]{\ettl@RemoveInList{}\toksdel{}{#1}}
+\newrobustcmd\toksgdel[1][]{\ettl@RemoveInList\global\toksdel{}{#1}}
+\newrobustcmd\toksedel[1][]{\ettl@listedel{}\toksdel{}{#1}}
+\newrobustcmd\toksxdel[1][]{\ettl@listedel\global\toksdel{}{#1}}
+% \end{macrocode}
+% \end{Macro}
+% \end{Macro*}
+% \end{Macro*}
+% \end{Macro*}
+%
+%\iffalse
+%<package>
%<package>
+%<package>%% \getlistindex[\indexmacro]{ \Listmacro }
+%<package>%% \getlistindex*[\indexmacro]{ expanded List }
% \fi
-% \begin{macro}{\collecttoks}\cmdlabel{impl:collecttoks}
-% A simple token scanner, vectorized version of \cs{futurelet}.\seedesc{collecttoks}
+%
+% \begin{Macro}{getlistindex}
+% \cmd{getlistindex} may be defined, with its star form (no expansion of the list)
+% and normal form (\prm{Listmacro} expanded once);
+% The search-index is initialised at 1:
+%
+% We first need to get into a group where delimiter \CH{\textbar} and \CH{\&} have catcode 3:
% \begin{macrocode}
-\newrobustcmd*\collecttoks{\@ifstar\ettl@scantoks\ettl@collecttoks}
-\def\ettl@scantoks{\@latex@error{The starred version of \noexpand\collecttoks
- \MessageBreak (i.e. scantoks) is NOT implemented YET.}\@ehd}
+\newrobustcmd\ettl@getlistindex[6][]{% #1=result, #2=\expandafter, #3=loop macro, #4=separator, #5=list of list macro, #6=item
+ \begingroup\def\ettl@getlistindex##1#4#6#4##2/End§List/{\endgroup
+ \romannumeral-`\q\ettl@setresult 1of1>#1<{\ettl@nbk##2//{#3*!{##1}}{-1}//}%
+ }#2\ettl@getlistindex#2#5#4#6#4/End§List/}
+\begingroup\catcode`\|=3% etb catcode
+\newrobustcmd\getlistindex[3][]{\@ifstar%
+ {\ettl@getlistindex{}\listloop{|}{#1}{#2}{#3}}
+ {\ifiscs{#1}{\ettl@getlistindex\expandafter\listloop|{#1}{#2}{#3}}
+ {\ettl@getlistindex{}\listloop|{#1}{#2}{#3}}}}
+\aftergroup@def\getlistindex
+\endgroup%\catcode group
% \end{macrocode}
-% \end{macro}
+% \end{Macro}
%
% \iffalse
%<package>
+%<package>%\getcsvlistindex [\result]{ item }{ csvlistmacro }
+%<package>%\getcsvlistindex*[\result]{ item }{ item,item,item }
% \fi
+% \begin{Macro}{getcsvlistindex}
+% The command is robust, not purely expandable:
+% \begin{macrocode}
+\newrobustcmd\getcsvlistindex[3][]{\@ifstar%
+ {\ettl@getlistindex{}\csvloop{,}{#1}{#2}}
+ {\ifiscs{#1}{\ettl@getlistindex\expandafter\csvloop,{#1}{#2}}
+ {\ettl@getlistindex{}\csvloop,{#1}{#2}}}}
+% \end{macrocode}
+% \end{Macro}
%
-% \begin{macro}{\ettl@collecttoks}
+% \begin{macro}{\ettl@ifinlist}
+% \cs{ettl@ifinlist} will build a \cs{ifinlist} macro for list with a given separator.
% \begin{macrocode}
-\def\ettl@collecttoks#1#2#3{\begingroup
- \def\ettl@collecttoks@list{#2}%
- \let#1=\@empty
- \def\Next{\ettl@collect@toks{#1}}%
- \def\finale{#3}%
- \futurelet\ettl@x\Next}
-\def\ettl@collect@toks#1{%
- \edef\ettl@i{\gettokslistindex\ettl@x\ettl@collecttoks@list}%
- \ifcase\ettl@i \edef\next{\endgroup
- \def\noexpand#1{\expandonce{#1}}\expandonce{\finale}}%
- \else \def\next{\ettl@collect@toks@next{#1}}%
- \fi\next}
-\def\ettl@collect@toks@next#1#2{%
- \edef#1{\expandonce{#1}\unexpanded{#2}}%
- \futurelet\ettl@x\Next}
+\def\ettl@if@inlist#1#2{%#1=macro,#2=separator
+\newrobustcmd*#1{\@ifstar{\ettl@ifinlist{#2}{}}{\ettl@ifinlist{#2}\expandafter}}}
+\def\ettl@xif@inlist#1#2{%
+\newrobustcmd*#1{\@ifstar{\ettl@xifinlist{#2}{}}{\ettl@xifinlist{#2}\expandafter}}}
+\protected\long\def\ettl@ifinlist#1#2#3#4{\begingroup
+ \def\ettl@tempa##1#1##2#1/End§List/{\endgroup\ifnotblank{##2}%
+ }#2\ettl@tempa#2#1#3#1#4#1/End§List/}
+\protected\long\def\ettl@xifinlist#1#2#3#4{\begingroup
+ \protected@edef\ettl@tempa{\endgroup\ettl@ifinlist{#1}{#2}{#3}{#4}%
+ }\ettl@tempa}
% \end{macrocode}
% \end{macro}
%
+% \iffalse
+%<package>
+%<package>
+%<package>%% \ifincsvlist{ item }{ csvlistmacro }{ true }{ false }
+%<package>%% \ifincsvlist*{ item }{ item,item,item,... }{ true }{ false }
+%<package>%% \xifincsvlist{ item }{ csvlistmacro }{ true }{ false }
+%<package>%% \xifincsvlist*{ item }{ item,item,item,... }{ true }{ false }
+% \fi
%
+% \begin{Macro*}{ifincsvlist}
+% A robust command with a star form.
+% \begin{Macro}{xifincsvlist}
+% The same with |\protected@edef|.
+% \begin{macrocode}
+\ettl@if@inlist\ifincsvlist{,}
+\ettl@xif@inlist\xifincsvlist{,}
+\undef\ettl@if@inlist
+\undef\ettl@xif@inlist
+% \end{macrocode}
+% \end{Macro}
+% \end{Macro*}
+%
+% \Subsection*{\thispackage package options (undocumented - not tested, not to be used)}
+%
+% \textsl{Undocumented option \xpackage{etoolbox}}.
+% \begin{macrocode}
+\DeclareOption{etoolbox}{%
+\renewcommand\ifblank[3]{\ettl@nbk #1//{#2}{#3}//}
+\renewcommand\ifdef[1]{\csname @\ifdefined#1first\else second\fi oftwo\endcsname}
+\renewcommand\ifcsdef[1]{\csname @\ifcsname#1\endcsname first\else second\fi oftwo\endcsname}
+\renewcommand\ifundef[1]{\csname @%
+ \ifdefined#1\ifx#1\relax first\else second\fi\else first\fi oftwo\endcsname}
+\renewcommand\ifcsundef[1]{\csname @%
+ \ifcsname#1\endcsname\expandafter\ifx\csname#1\endcsname\relax
+ first\else second\fi\else first\fi oftwo\endcsname}
+\edef\ifdefmacro#1{\unexpanded{\csname @%
+ \expandafter\ettl@ifdefmacro\meaning}#1\detokenize{macro:}/oftwo\endcsname}
+\edef\ettl@ifdefmacro{%
+ \def\noexpand\ettl@ifdefmacro##1\detokenize{macro:}##2/{\noexpand\ettl@nbk##2//{first}{second}//}%
+}\ettl@ifdefmacro
+\long\edef\ifcsmacro#1{\unexpanded{\csname @%
+ \expandafter\expandafter\expandafter\ettl@ifdefmacro\meaningcs}{#1}\detokenize{macro:}/oftwo\endcsname}
+\renewcommand\ifdefparam[1]{\csname @%
+ \ettl@expandaftwo\ettl@nbk\expandafter\ettl@params@meaning\meaning#1///{first}{second}//oftwo\endcsname}
+\renewcommand\ifcsparam[1]{\csname @%
+ \expandafter\expandafter\expandafter\ettl@nbk\parameters@meaningcs{#1}//{first}{second}//oftwo\endcsname}
+\renewcommand\ifnumcomp[3]{\csname @%
+ \ifnum\numexpr#1#2\numexpr#3 first\else second\fi oftwo\endcsname}
+}% etoolbox option
+\ProcessOptions
+% \end{macrocode}
%
% \begin{macrocode}
%</package>
% \end{macrocode}
%
-% \subsection{Example}
+% \Subsection{Examples}
%
% \begin{macrocode}
%<*example>
@@ -1777,54 +4608,60 @@ and etextools-examples.tex
\usepackage[latin1]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[american]{babel}
-\usepackage{geometry,doc,ltxdockit,txfonts,fancyhdr,stmaryrd,graphicx,fancyvrb}
+\usepackage{geometry,doc,ltxdockit,txfonts,fancyhdr,stmaryrd,graphicx,enumitem}
\usepackage{etextools}
+
+\usepackage{fancyvrb}
+
+\def\textvb#1{{\usefont{T1}{txtt}{m}{n}#1}}
+\def\thispackage{\textsf{etextools}}
\hypersetup{colorlinks,pdfstartview={FitH}}
\geometry{top=1.5cm,bottom=1.2cm,left=2.5cm,right=1cm}
\fancyhf{}
-\fancyhead[L]{Examples for the \sty{etextools} package}
+\fancyhead[L]{Examples for the \thispackage package}
\pagestyle{fancy}
-\MakeShortVerb{\|}
-
+\DefineShortVerb{\|}
+\catcode`\§ \active\def§{\par\nobreak\vskip-\parskip}
\makeatletter
+\DefineVerbatimEnvironment{VerbLines}{Verbatim}
+ {gobble=1,commandchars=!(),frame=lines,framesep=6pt,fontfamily=txtt,fontseries=m}
+\apptocmd\@list@extra{\parsep\parskip\topsep\z@\itemsep\z@}{}{}
+
\def\smex{\leavevmode\hb@xt@2em{\hfil$\longrightarrow$\hfil}}
\def\FE{\setbox8\hbox{$\m@th\bindnasrepma$}%
\textcolor{fecc}{\scalebox{2}{$\copy8\mkern-13.5mu\copy8\mkern-13.5mu\copy8$}}}
+\def\pdfFE{\setbox8\hbox{$\m@th\bindnasrepma$}%
+ \textcolor{fecc}{\llap{\textsf{pdf}\TeX{}\,}\scalebox{2}{$\copy8\mkern-13.5mu\copy8\mkern-13.5mu\copy8$}}}
\definecolor{fecc}{rgb}{.2,.6,.2}
-\def\strip@meaning{\expandafter\strip@prefix\meaning}
-\def\strip@macro{\expandafter\strip@macroprefix\meaning}
-\def\get@params#1{\expandafter\@get@params\meaning#1\@nil}
-\edef\@get@params{%
- \def\noexpand\@get@params\detokenize{macro:}##1\detokenize{->}##2\noexpand\@nil{##1}%
-}\@get@params
-\def\make@macro#1{\string\def\string#1\get@params#1\string{\strip@meaning#1\string}}
+\definecolor{dg}{rgb}{0.00,0.37,0.00} \newrobustcmd\dg{\color{dg}} \newrobustcmd\dgbf{\dg\bfseries}
+
+\newrobustcmd\blue{\color{blue}
+\newrobustcmd\nnn{\normalfont\mdseries\upshape}
+
+\def\make@macro#1{\string\def\string#1\parameters@meaning#1\string{\strip@meaning#1\string}}
\newcommand\preline{\@ifstar{\@preline}{\hrulefill\par\@preline}}
-\def\@preline#1{\noindent\hskip6pt\texttt{\make@macro#1}\par\vskip1.5ex}
+\newcommand\@preline[2][1.5ex]{\noindent\hskip6pt\textvb{\make@macro#2}\par\ifblank{#1}{}{\vskip#1}}
-\def\meaningcs#1{\expandafter\meaning\csname#1\endcsname}
-\def\Meaningcs#1{\expandafter\strip@meaning\csname #1\endcsname}
-\@ifundefined{pdfstrcmp}{\let\ifpdfTeX\iffalse}{\let\ifpdfTeX\iftrue}
+\ifdef\pdfstrcmp{\let\ifpdfTeX\iffalse}{\let\ifpdfTeX\iftrue}
-\newcommand*\test{\@ifstar{\let\fe\relax\testi}{\let\fe\FE\testi}}
+
+\newcommand*\test{\@ifstar{\let\fe\pdfFE\testi}{\let\fe\FE\testi}}
\newcommand\testi[1]{%
\csname test#1\endcsname
- \edef\usercmd{\Meaningcs{test#1}}\edef\result{\meaningcs{#1Test}}\noindent
+ \edef\usercmd{\strip@meaningcs{test#1}}\edef\result{\meaningcs{#1Test}}\noindent
\begin{tabular}{lp{15cm}}
\multicolumn{2}{l}{\textcolor{blue}{\llap{\fe\,\smex}\tt \usercmd}} \\[1.5ex]
\cmd{#1Test}= & \tt\bfseries\result
\end{tabular}\par\nobreak\hrulefill\null\goodbreak}
-
-
\begin{document}
\title{etextools examples}
-\subtitle{Examples for some macros provided by the \sty{etextools} package}
+\subtitle{Examples for some macros provided by the \thispackage package}
\author{Florent Chervet}
\date{July 22, 2009}
\maketitle
-\tableofcontents
-
+\tableofcontents\hyperdef{ettlex}{toc}{}
\section{\cmd{expandnext} examples}
@@ -1841,8 +4678,7 @@ and etextools-examples.tex
\preline\xx
\test{expandnext}
-
-\clearpage
+\ClearPage
\subsection{Test if the replacement text of a macro is blank (empty or spaces)}
\def\xx{something}
@@ -1856,14 +4692,75 @@ and etextools-examples.tex
\preline\xx
\test{expandnext}
+\section{\cmd{ExpandNext} examples}
+Example of the main documentation file to reverse the order of the characters in a string:
-\subsection{Detokenize the replacement text of a named-sequence}
-\def\detokenizecs#1{\expandnext\expandnext\detokenize{\csname #1\endcsname}}
-\def\testexpandnext{%
- \edef\expandnextTest{\detokenizecs{document}}}
-\preline\detokenizecs
-\test{expandnext}
+\def\swap#1#2{{#2#1}} \def\do[#1]#2{\swap #2}% \do{abcdef} -> \swap ab + cdef -> {ba}cdef
+ % \do{{ba}cdef} -> \swap {ba}c + def -> {cba}def
+
+\edef\result{\naturalloop[\do]{4}{12345}}
+\ExpandNext{\def\RESULT}{\naturalloop[\do]{4}{12345}}
+
+\begin{VerbLines}
+\def\swap#1#2{{#2#1}} \def\do[#1]#2{\swap #2}
+\edef\result{\naturalloop[\do]{4}{12345}}
+\meaning\result = !bfseries!meaning!result
+\ExpandNext{\def\RESULT}{\naturalloop[\do]{4}{12345}}
+\meaning\RESULT = !bfseries!meaning!RESULT
+\end{VerbLines}
+
+
+\subsection{Test the parameter string of a macro}
+
+The following commands create the filter for the string: "\textvb{[\#1]\#2"}":§
+\begin{VerbLines}[commandchars=!()]
+\ExpandNext{(!blue\DeclareStringFilter\ParaFilt)}
+ {\ExpandAftercmds\@gobblescape{\expandafter\string\csname(!blue[#1]#2)\endcsname}}
+\end{VerbLines}
+
+\ExpandNext{\DeclareStringFilter\ParaFilt}
+ {\ExpandAftercmds\@gobblescape{\expandafter\string\csname[#1]#2\endcsname}}
+
+\begin{enumerate}[label=\arabic*)~,noitemsep,nolistsep]
+\item |\csname[#1]#2\endcsname| is expanded first
+\item Immediately after: |\string|
+\item At this stage: |\[#1]#2| (everything in category code other) is no more expandable
+\item Then |\ExpandAftercmds| expands |\@gobblescape|
+\item |[#1]#2| is no more expandable
+\item Then |\ExpandNext| expands its first argument: |\DeclareStringFilter\ParaFilt{[#1]#2}|
+\end{enumerate}
+
+Remark: |\detokenize| would have doubled the \# characters. Another possibility is to temporarily change the
+category code of \# to 12 (other):
+\begin{VerbLines}[commandchars=!()]
+\begingroup\catcode`\#=12
+ (!blue\DeclareStringFilter\ParaFilt{[#1]#2}) !nnn global declaration
+\endgroup
+\end{VerbLines}
+
+\def\macroA#1#2{Something to do with #1 and #2}
+\def\macroB[#1]#2{Something to do with #1 and #2}
+
+\makeatother
+
+\preline[]\macroA
+\preline*[]\macroB
+\begin{Verbatim}[commandchars=!()]
+ !blue\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroA}{macro complies with [\#1]\#2}
+ !blue{macro does not comply }
+\end{Verbatim}
+\makeatletter
+\hfill\textvb{\dgbf\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroA}{macro complies with [\#1]\#2}
+ {macro does not comply }}
+\begin{Verbatim}[commandchars=!()]
+ !blue\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroB}{macro complies with [\#1]\#2}
+ !blue{macro does not comply }
+\end{Verbatim}
+\hfill\textvb{\dgbf\ExpandNext{\ParaFilt=.}{\parameters@meaning\macroB}{macro complies with [\#1]\#2}
+ {macro does not comply }}
+\par\hrulefill\par
+\makeatother
\section{Testing characters}
@@ -1919,7 +4816,6 @@ and etextools-examples.tex
\hrulefill\par
\test{FE@testopt}
-
\section{Lists management}
\subsection{\cmd{csvloop} and \cmd{csvloop*} examples}
@@ -1969,13 +4865,13 @@ and etextools-examples.tex
\edef\getlistindexTest{\getlistindex{alpha}\mylist}
}\hrulefill\par
\noindent\hskip6pt|\csvtolist*\mylist{one,two,three,four,five,alpha,beta,gamma}|\par\vskip1.5ex
-\test{getlistindex}
+\test*{getlistindex}
\leavevmode\vadjust{\textsl{Require the }\string\pdfstrcmp\ \textsl{primitive (pdf\TeX{}) :}}
\def\testgetlistindex{%
\edef\getlistindexTest{\getcsvlistindex*{alpha}{one,two,three,four,five,alpha,beta}}
}\hrulefill\par
-\test{getlistindex}
+\test*{getlistindex}
\fi
\hrulefill\par
@@ -1992,7 +4888,6 @@ and etextools-examples.tex
{\tt\string\the\string\myindex=\qquad\textbf{\the\myindex}}
\hrulefill\par\vskip.5ex
-
\subsubsection{\cmd{xgetlistindex}}
\ifpdfTeX
\leavevmode\vadjust{\textsl{Require the }\string\pdfstrcmp\ \textsl{primitive (pdf\TeX{}) :}}
@@ -2002,7 +4897,7 @@ and etextools-examples.tex
}\hrulefill\par
\noindent\hskip6pt|\csvtolist*\mylist{one,two,three,four,five,alpha,beta,gamma}|\par\vskip1.5ex
\preline*\x
-\test{xgetlistindex}
+\test*{xgetlistindex}
\fi
\subsubsection{\cmd{getlistindex} with \cmd{ifcase}}
@@ -2032,20 +4927,53 @@ and etextools-examples.tex
\fi}\par
\hrulefill\par\vskip.5ex
-
-
\end{document}
%</example>
% \end{macrocode}
%
-% \section{Revision history}
+% \Section*{Revision history} \addcontentsline{toc}{section}{\texorpdfstring\dr{}\hskip\dimexpr\cftsecnumwidth-4pt Revision history}^^A not in .cmd file
%
% \begin{changelog}\footnotesize
%
-% \begin{release}{2t}{2009-08-15}
+% \begin{release}{3.0}{2009-09-09}
+% \item Definition of \cmdref{DeclareStringFilter}, \cmdref{[FE@modifiers} and \cmdref{ettl@supergobble}.
+%
+% \end{release}
+%
+% \begin{release}{2k}{2009-09-04}
+% \item Addition of \\
+% \cmdref{ExpandNext} \\
+% \cmdref{naturalloop} \\
+% the star form of \cmdref{futuredef} \\
+% the \cs{global} option of \cmdref{DeclareCmdListParser}
+% \item Reimplementation of \\
+% the lists macros for optimisation (cf \cmd{ettl@ifnotblank}) \\
+% \cmdref{ifsinglechar} for optimisation
+% \item Addition of examples to the \sty{etextools-examples.tex}
+% \item Test on pdf\LaTeX{} and Xe\TeX.
+% \end{release}
+%
+% \begin{release}{2i}{2009-08-31}
+% \item
+% Addition of \cmdref{futuredef} a macro (and vectorized) version of \cs{futurelet}.
+% \item
+% Redesign of \cmdref{expandnext}: the first argument can now be arbitrary code
+% (before, it was necessarily a single control sequence, as for \CS{expandafter}).
+% \item
+% Redesign of \cmdref{deblank}, after a solution provided by \xpackage{environ.sty}.
+% \item
+% Addition of \cmdref{ifincsvlist}, \cmdref{ifintokslist} and \cmdref{xifincsvlist}.
% \item
-% Addition of \cmdref{ifnotempty}, \cmdref{iflastchar}, \cmdref{ifstrcmp}, \cmdref{ifstrmatch}
+% Addition of \cmdref{forcsvloop}, \cmdref{forlistloop} and \cmdref{fortoksloop}.
+% \item
+% Addition of \cmdref{csvdel}, \cmd{csvedel}, \cmd{csvgdel} and \cmd{csvxdel}
+% \item
+% Optimization of \cmdref{getlistitem} and \cmdref{getlistindex} (and csv versions either)
+% \end{release}
%
+% \begin{release}{2t}{2009-08-15}
+% \item
+% Addition of \cmdref{ifnotempty}, \cmdref{ifstrcmp}, \cmdref{ifstrmatch}
%
% \end{release}
%
@@ -2054,13 +4982,9 @@ and etextools-examples.tex
% \cmdref{getlistindex} is now fully expandable
%
% \item Addition of\\
-% \cmdref{toksloop} and \cmd{toksloop*} \\
-% \cmdref{tokstolist} and \cmd{tokstolist*} \\
-% \cmdref{getcsvlistindex} and \cmdref{getcsvlistitem} \\
-% \cmdref{gettokslistindex} and \cmdref{gettokslistitem} \\
+% \cmdref{toksloop}
%
% \item Addition of\\
-% \cmdref{collecttoks} -- a vectorized version of \cs{futurelet}.\\
% \cmdref{FE@ifchar} as a generalization of \cmdref{FE@ifstar}.
%
% \end{release}
@@ -2093,13 +5017,13 @@ and etextools-examples.tex
%
% \bibitem{etex}
% David Carlisle and Peter Breitenlohner
-% \textit{The \sty{etex} package};
+% \textit{The \xpackage{etex} package};
% 1998/03/26 v2.0;
% \CTAN{macros/latex/contrib/etex-pkg/}.
%
% \bibitem{etoolbox}
% Philipp Lehman
-% \textit{The \sty{etoolbox} package};
+% \textit{The \xpackage{etoolbox} package};
% 2008/06/28 v1.7;
% \CTAN{macros/latex/contrib/etoolbox/}.
%
@@ -2107,7 +5031,7 @@ and etextools-examples.tex
%
% \setcounter{IndexColumns}{2}\clearpage
% \PrintIndex
-%
-% \label{LastPage}
+% \begingroup\let\writeprimitive\write\def\write{\immediate\writeprimitive}
+% \label{LastPage}\endgroup^^A \immediate is necessary because no more \shipout is done at this point
% \Finale
diff --git a/Master/texmf-dist/source/latex/etextools/etextools.ins b/Master/texmf-dist/source/latex/etextools/etextools.ins
index f922c22757f..23d0eaf5a73 100644
--- a/Master/texmf-dist/source/latex/etextools/etextools.ins
+++ b/Master/texmf-dist/source/latex/etextools/etextools.ins
@@ -21,11 +21,11 @@
%% etextools.sty, etextools.pdf, etextools.ins,
%% and etextools-examples.tex
%%
-%%% etextools : more e-TeX useful tools for LaTeX package writers (v.
+%%% etextools : e-TeX tools for LaTeX Users and package Writers (v.3.0)
\input docstrip.tex
\Msg{************************************************************************}
\Msg{* Installation}
-\Msg{* Package: etextools 2009/07/14 v2h e-TeX more useful tools for LaTeX package writers}
+\Msg{* Package: etextools 2009/07/14 v.3.0 e-TeX tools for LaTeX Users and package Writers}
\Msg{************************************************************************}
\keepsilent
@@ -57,6 +57,10 @@ and etextools-examples.tex
\file{etextools.sty}{\from{etextools.dtx}{package}}%
\file{etextools-examples.tex}{\from{etextools.dtx}{example}}%
}
+\askforoverwritetrue
+\generate{%
+ \file{etextools.drv}{\from{etextools.dtx}{driver}}%
+}
\obeyspaces
\Msg{************************************************************************}
@@ -76,7 +80,6 @@ and etextools-examples.tex
\endbatchfile
-
\endinput
%%
%% End of file `etextools.ins'.
diff --git a/Master/texmf-dist/tex/latex/etextools/etextools.sty b/Master/texmf-dist/tex/latex/etextools/etextools.sty
index 791e2fd2c1c..35f78a71ff1 100644
--- a/Master/texmf-dist/tex/latex/etextools/etextools.sty
+++ b/Master/texmf-dist/tex/latex/etextools/etextools.sty
@@ -21,13 +21,12 @@
%% etextools.sty, etextools.pdf, etextools.ins,
%% and etextools-examples.tex
%%
-%%% etextools : more e-TeX useful tools for LaTeX package writers (v.
-
+%%% etextools : e-TeX tools for LaTeX Users and package Writers (v.3.0)
\NeedsTeXFormat{LaTeX2e}[1996/12/01]
\ProvidesPackage{etextools}
- [2009/08/14 v2h e-TeX more useful tools for LaTeX package writers]
+ [2009/08/27 v3.0 e-TeX more useful tools for LaTeX package writers]
\csname ettl@onlyonce\endcsname\let\ettl@onlyonce\endinput
-\RequirePackage{etex,etoolbox}
+\RequirePackage{etex,etoolbox,letltxmacro}
\let\ettl@AtEnd\@empty
\def\TMP@EnsureCode#1#2{%
\edef\ettl@AtEnd{%
@@ -36,376 +35,993 @@
}%
\catcode#1 #2\relax
}
-\TMP@EnsureCode{32}{10}% space
+\TMP@EnsureCode{32}{10}% space... just in case
+\TMP@EnsureCode{47}{8}% /
+\TMP@EnsureCode{167}{7}% §
+\TMP@EnsureCode{164}{7}% ¤
+\TMP@EnsureCode{42}{12}% *
+\TMP@EnsureCode{43}{12}% +
+\TMP@EnsureCode{45}{12}% -
+\TMP@EnsureCode{46}{12}% .
+\TMP@EnsureCode{60}{12}% <
+\TMP@EnsureCode{61}{12}% =
+\TMP@EnsureCode{62}{12}% >
+\TMP@EnsureCode{33}{12}% !
+\TMP@EnsureCode{152}{13}% ~ for the character test
\ifundef\pdfstrcmp{%
- \TMP@EnsureCode{33}{9}% ! ignore
- \TMP@EnsureCode{34}{14}% " comment
-}{\TMP@EnsureCode{33}{14}% ! comment
- \TMP@EnsureCode{34}{9}% " ignore
+ \TMP@EnsureCode{163}{9}% £ ignore
+ \TMP@EnsureCode{128}{14}% \texteuro comment €
+}{\TMP@EnsureCode{163}{14}% £ comment
+ \TMP@EnsureCode{128}{9}% \texteuro ignore
}
\AtEndOfPackage{\ettl@AtEnd\undef\ettl@AtEnd}
% A few helper macros
-\long\def\ettl@afterelse#1\else#2\fi{\fi#1}
-\long\def\ettl@afterfi#1\fi{\fi#1}
-\long\def\ettl@afterfifi#1\fi\fi{\fi\fi#1}
-\long\def\ettl@afterelsefi#1\else#2\fi\fi{\fi#1}
-\long\def\ettl@afterorfi#1\or#2\fi{\fi#1}
-
-\def\ettl@ifstrcmp#1#2{\csname @%
- \ifnum\pdfstrcmp{#1}{#2}=0 first\else second\fi oftwo\endcsname}
-\newcommand*\@gobblescape{\expandafter\@gobble\string}
-\def\ettl@onlypdfTeX#1#2{\ifundef{#1}
- {\def#2{\PackageError{etextools}{\string#1\space primitive not found\MessageBreak
- pdfTeX seems not to be running}
- {\string#2\space works only if used with pdfTeX (requires \string#1)}}}
- {}}
-\newcommand*\noexpandcs[1]{\expandafter\noexpand\csname #1\endcsname}
-\newcommand\noexpandafter{\noexpand\expandafter}
+\let\ettl@ifdefined\iffalse%\ifdefined% turn to \iffalse to test other implementation on pdfTeX
+\long\def\ettl@fi#1\fi{\fi#1}
+\long\def\ettl@else#1\else#2\fi{\fi#1}
+\long\def\ettl@or#1\or#2\fi{\fi#1}
+\def\ettl@expandaftwo{\expandafter\expandafter\expandafter}
+\def\ettl@expandafthree{\expandafter\expandafter\expandafter%
+ \expandafter\expandafter\expandafter\expandafter}
+\cslet{ettl@1of1}\@firstofone %% for internal use only
+\cslet{ettl@1of2}\@firstoftwo %% for internal use only
+\cslet{ettl@2of2}\@secondoftwo %% for internal use only
+\long\def\rmn@firstoftwo#1#2{\z@#1} %% for romannumeral
+\long\def\rmn@secondoftwo#1#2{\z@#2}%% for romannumeral
+\long\def\ettl@cdr#1#2\@nil{#2} %% \@cdr should be a LONG macro
+\long\def\ettl@car#1#2\@nil{#1} %% \@car should be a LONG macro
+\long\csdef{ettl@1of3}#1#2#3{#1}
+\long\csdef{ettl@2of3}#1#2#3{#2}
+\long\csdef{ettl@3of3}#1#2#3{#3}
+\long\csdef{ettl@12of3}#1#2#3{{#1}{#2}}
+\long\def\ettl@carcar#1#2#3#4{#4}
+\long\def\ettl@firstspace#1#2#3{\expandafter\ettl@firstsp@ce\detokenize{#1} \\{#3}{#2}//}
+\long\def\ettl@firstsp@ce#1 #2\\{\ettl@nbk#1//}
+\long\def\ettl@csname#1\endcsname{\fi\endcsname}%% useful to get out of \if
+\long\def\ettl@char#1{\csname ettl@\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax
+ 1\else2\fi of2\endcsname}
+\providecommand*\@intmax{2147483647}
+\def\ettl@intmax{2147483647}
+
+%% \ettl@onlypdfTeX for internal use
+\def\ettl@onlypdfTeX#1#2{\@testopt{\ettl@only@pdfTeX{#1}{#2}}{}}
+\def\ettl@only@pdfTeX#1#2[#3]{\ifundef{#1}
+ {\ifblank{#3}
+ {\def#2{\PackageError{etextools}{\string#1\space primitive not found\MessageBreak
+ pdfTeX seems not to be running}
+ {\string#2\space works only if used with pdfTeX (requires \string#1)}}}
+ {\AtEndOfPackage{\let#2=#3}%
+ \PackageWarning{etextools}{\string#1\space primitive not found\MessageBreak
+ Macro \string#2\space has been replaced by \string#3\space\MessageBreak
+ It is not purely expandable}}
+ }\relax}
+
+%% \ettl@nbk argument to be tested//{ true }{ false }//
+% `/` has a catcode of 3 all along this package
+\long\def\ettl@nbk #1#2/#3#4#5//{#4}
+\long\def\ettl@nbk@else#1#2/#3#4#5//#6\else#7\fi{\fi#4}
+\long\def\ettl@ney#1//#2#3//{\romannumeral 0\csname @%
+ \if\relax\detokenize{#1}\relax first\else second\fi oftwo\endcsname
+ { #2}{ #3}}
+
+% The following macros are not used (here just for memory, in case of...)
+\long\def\ettl@nbk@cat#1#2#3/#4#5#6//{\ettl@nbk#6//%
+ {\ifcat#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//}
+\long\def\ettl@nbk@ifx#1#2#3/#4#5#6//{\ettl@nbk#6//%
+ {\ifx#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//}
+\long\def\ettl@nbk@if#1#2#3/#4#5#6//%
+ {\ettl@nbk#6//{\if#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//}
+\long\def\ettl@nbk@IF[#1]#2#3#4/#5#6#7//{\ettl@nbk#7//%
+ {\csname if#1\endcsname\ettl@else#6\else\ettl@fi#7\fi}{#6}//}
+
+%% \@gobblespace and The Space Token
+\long\def\@gobblespace#1 {#1}
-% \expandnext : expansion control
-% level 1 : \expandnext#1{...} <=> \expandafter#1\expandafter{...}
-% level 2 : \expandnext\expandnext#1{...} etc.
+%% \@gobblescape \cs-token
+\newcommand*\@gobblescape{\romannumeral0\expandafter\@gobble\string}
+
+% The swap macros
+\newcommand\@swap[2]{#2#1}
+\@swap{ }{\let\ettl@sptoken= }% This makes \ettl@sptoken a space token
+\newcommand\@swaparg[2]{#2{#1}}
+\newcommand\@swaplast[3]{#1#3#2}
+\newcommand\@swaptwo[2]{{#2}{#1}}
+
+%% \expandaftercmds : expansion control
+% level 1 : \expandaftercmds { code }{ cs-token }
+% level 2 : \expandaftercmds\expandaftercmds { code }{ cs-token }
+\newcommand\expandaftercmds[2]{%
+ \ifsingletoken\expandaftercmds{#1}
+ {\expandafter@cmds{#2}{\expandafter\expandafter\expandafter}}
+ {\expandafter\@swap\expandafter{#2}{#1}}}
+\long\def\expandafter@cmds#1#2#3{%
+ \ifsingletoken\expandafter@cmds{#1}
+ {\expandafter@cmds{#3}{\expandafter#2#2}}
+ {\@swap#2{#3}{#1}}}
+
+%% \expandnext : expansion control
+% level 1 : \expandnext { code }{ control sequences : the first is expanded before code }
+% level 2 : \expandnext\expandnext{ code }{ control sequences }
\newcommand\expandnext[2]{%
- \ifx#1\expandnext
- \ettl@afterelse\expandafter\expandafter\expandafter
- \expandafter\@expandnext{#2}{\expandafter\expandafter\expandafter}%
- \else\ettl@afterfi\expandafter#1\expandafter{#2}%
- \fi}
+ \ifsingletoken\expandnext{#1}
+ {\@expandnext{#2}{\expandafter\expandafter\expandafter}}
+ {\expandafter\@swaparg\expandafter{#2}{#1}}}
\long\def\@expandnext#1#2#3{%
- \ifx#1\expandnext
- \expandafter\ettl@afterelse\expandafter\expandafter\expandafter
- \expandafter\@expandnext{#3}{\expandafter#2#2}%
- \else
- \expandafter\ettl@afterfi#2#1#2{#3}%
- \fi}
+ \ifsingletoken\expandnext{#1}
+ {\@expandnext{#3}{\expandafter#2#2}}
+ {#2\@swaparg#2{#3}{#1}}}
+%% \expandnexttwo{ code }{ control sequences }{ control sequences }
+\newcommand\expandnexttwo[3]{\expandnext{\expandnext{#1}{#2}}{#3}}
-% \ifempty{ text }{ true }{ false }
-\newcommand\ifempty[1]{\csname @\expandafter\ifx
- \expandafter\relax\detokenize{#1}\relax
+%% \ExpandAfter { code } { cs-token }
+\newcommand\ExpandAftercmds[2]{\expandafter\@swap\expandafter{\romannumeral-`\q#2}{#1}}
+
+%% \ExpandNext { code } { argument }
+ % I'm not sure it is interesting to use \expandnext here...
+ %\newcommand\ExpandNext[2]{\expandnext{#1}{\romannumeral-`\q#2}}
+\newcommand\ExpandNext[2]{\expandafter\@swaparg\expandafter{\romannumeral-`\q#2}{#1}}
+
+%% \ExpandNextTwo { code } { arg1 }{ arg2 }
+\newcommand\ExpandNextTwo[3]{\ExpandNext{\ExpandNext{#1}{#2}}{#3}}
+
+% noexpandcs { csname }
+\newcommand*\noexpandcs[1]{\expandafter\noexpand\csname #1\endcsname}
+
+% noexpandafter
+\newcommand*\noexpandafter{\noexpand\expandafter}
+
+%% \showcs { csname }
+\providecommand*\showcs[1]{\expandafter\show\csname#1\endcsname}
+
+%% \meaningcs { csname }
+\providecommand\meaningcs[1]{\romannumeral-`\q
+ \csname\ifcsdef{#1}{ettl@meaningcs\endcsname{#1}}
+ {meaning\endcsname\@undefined}}
+\def\ettl@meaningcs#1{\expandafter\meaning\csname#1\endcsname}% here we don't need \z@ to stop \romannumeral
+ % because \meaning is never blank nor begins with a space...
+
+%% \strip@meaning { cs-token }
+%% \strip@meaningcs { csname }
+\newcommand*\strip@meaning[1]{\romannumeral\csname\ifdef{#1}%
+ {\ifdefmacro{#1}{ettl@strip@meaning}{ettl@meaning}\endcsname#1}{z@\endcsname}}
+\providecommand*\strip@meaningcs[1]{\romannumeral\csname\ifcsdef{#1}%
+ {\ifcsmacro{#1}{ettl@strip@meaning}{ettl@meaning}%
+ \expandafter\endcsname\csname#1\endcsname}
+ {z@\endcsname}}
+\def\ettl@strip@meaning{\expandafter\expandafter\expandafter\z@% for \romannumeral in case the \meaning is blank...
+ \expandafter\strip@prefix\meaning}
+\def\ettl@meaning{\expandafter\z@\meaning}
+
+%% \parameters@meaning { cs-token }
+%% \parameters@meaningcs { csname }
+\providecommand*\parameters@meaning[1]{}
+\edef\parameters@meaning#1{\unexpanded{\romannumeral\expandafter
+ \expandafter\expandafter\z@\expandafter\ettl@params@meaning%
+ \meaning}#1\detokenize{macro:->}/}
+\providecommand*\parameters@meaningcs[1]{}
+\edef\parameters@meaningcs#1{\unexpanded{\romannumeral\ettl@expandafthree\z@
+ \expandafter\expandafter\expandafter\ettl@params@meaning%
+ \expandafter\meaning\csname}#1\endcsname\detokenize{macro:->}/}
+\edef\ettl@params@meaning{%
+ \def\noexpand\ettl@params@meaning\detokenize{macro:}##1\detokenize{->}##2/{##1}%
+}\ettl@params@meaning
+
+%% \ifdefcount { cs-token }{ true }{ false } \FEII
+%% \ifdefdimen { cs-token }{ true }{ false } \FEII
+%% \ifdeftoks { cs-token }{ true }{ false } \FEII
+%% \ifdefskip { cs-token }{ true }{ false } \FEII
+%% \ifdefmuskip { cs-token }{ true }{ false } \FEII
+%% \ifdefchar { cs-token }{ true }{ false } \FEII
+%% \ifdefmathchar { cs-token }{ true }{ false } \FEII
+\def\ettl@ifdef[#1]{\expandafter\ettl@ifd@f\expandafter{#1}}
+\def\ettl@ifd@f#1#2{%
+ \csdef{ettl@ifdef#2}##1#1##2/End§Meaning/{\ettl@nbk##2//{\rmn@firstoftwo}{\rmn@secondoftwo}//}
+ \csedef{ifdef#2}##1{\noexpand\romannumeral\noexpandafter%
+ \noexpandcs{ettl@ifdef#2}\noexpand\meaning##1#1/End§Meaning/}%//{##2}{##3}//}
+}
+\ettl@ifdef[\string\count]{count} % defines \def\ifdefcount
+\ettl@ifdef[\string\toks]{toks} % \def\ifdeftoks
+\ettl@ifdef[\string\dimen]{dimen} % \def\ifdefdimen
+\ettl@ifdef[\string\skip]{skip} % \def\ifdefskip
+\ettl@ifdef[\string\muskip]{muskip} % \def\ifdefmuskip
+\ettl@ifdef[\string\char]{char} % \def\ifdefchar
+\ettl@ifdef[\string\mathchar]{mathchar} % \def\ifdefmathchar
+\ettl@ifdef[\detokenize{blank space}]{blankspace}% \def\ifdefblankspace
+\ettl@ifdef[\detokenize{the character}]{thechar}% \def\ifdefthechar
+\ettl@ifdef[\detokenize{the letter}]{theletter} % \def\ifdeftheletter
+\undef\ettl@ifdef\undef\ettl@ifd@f
+
+%% \avoidvoid [ replacement code ]{ cs-token / string }
+%% \avoidvoid*[ replacement code ]{ cs-token / string }
+\newcommand\avoidvoid[1]{\romannumeral\FE@ifstar{#1}
+ {\ettl@voidvoid{\ettl@ifdefempty\ifempty}}
+ {\ettl@voidvoid{\ettl@ifdefvoid\ifblank}}}
+\long\def\ettl@voidvoid#1#2{\FE@testopt{#2}{\ettl@voidv@id#1}{}}
+\long\def\ettl@voidv@id#1#2[#3]#4{\ifiscs{#4}{#1{#4}}{#2{#4}}{\z@#3}{\z@#4}}
+\long\def\ettl@ifdefvoid#1{\csname @\ifx#1\relax first%
+ \else\expandafter\expandafter\expandafter\ettl@nbk\strip@meaning#1//{second}{first}//%
+ \fi oftwo\endcsname}
+\long\def\ettl@ifdefempty#1{\expandafter\expandafter\expandafter\ifempty%
+ \expandafter\expandafter\expandafter{\strip@meaning#1}}
+
+%% \avoidvoidcs [ replacement code ]{ cs-name }
+%% \avoidvoidcs*[ replacement code ]{ cs-name }
+\newcommand\avoidvoidcs[1]{\romannumeral\FE@ifstar{#1}
+ {\ettl@avoidvoidcs{\ettl@ifdefempty}}
+ {\ettl@avoidvoidcs{\ettl@ifdefvoid}}}
+\long\def\ettl@avoidvoidcs#1#2{\FE@testopt{#2}{\ettl@@voidvoidcs#1}{}}
+\long\def\ettl@@voidvoidcs#1[#2]#3{\csname @\ifcsname#3\endcsname
+ \expandafter#1\csname#3\endcsname{first}{second}\else first\fi
+ oftwo\endcsname{\z@#2}{\z@\csname#3\endcsname}}
+
+%% The ifx-test and the character-test
+\long\def\ettl@ifx#1#2#3#4{\ifx#1#2#3\else#4\fi}
+\long\def\ettl@ifchar#1#2{\csname ettl@\if\noexpand#2\string#11of2\ettl@csname\fi
+ \unless\ifcat\noexpand#1\noexpand#22of2\ettl@csname\fi
+ \ifx#1#21\else2\fi of2\endcsname}
+
+%% \ifsingletoken{ tokenA }{ tokenB }{ true }{ false }
+\newcommand\ifsingletoken[2]{\csname @\ettl@firstspace{#2}
+ {\ettl@nbk#1#2//{second}{\if\relax\detokenize{#1#2}\relax first\else\ifx#1#2first\else second\fi\fi}//}
+ {\if\relax\detokenize\expandafter{\ettl@cdr#2\@nil}\relax
+ \expandafter\ettl@ifxsingle
+ \else\expandafter\ettl@carcar
+ \fi{#1}{#2}{first}{second}}%
+ oftwo\endcsname}
+\def\ettl@ifxsingle#1#2#3#4{\ettl@nbk#1//{\ifx#1#2#3\else#4\fi}{#4}//}
+
+%% \ifOneToken{ token }{ true }{ false }
+\newcommand\ifOneToken[1]{\romannumeral\csname rmn@\ettl@firstspace{#1}
+ {\ettl@nbk#1//{second}{\if\relax\detokenize{#1}\relax second\else first\fi}//}
+ {\if\relax\detokenize\expandafter{\ettl@cdr#1\@nil}\relax
+ first\else second\fi}oftwo\endcsname}
+
+%% \ifsinglechar character{ string }{ true }{ false }
+\newcommand\ifsinglechar[2]{\romannumeral\csname rmn@\ettl@firstspace{#2}
+ {\ettl@nbk#2//{second}{\if\relax\detokenize{#1#2}\relax first\else\ifx#1#2first\else second\fi\fi}//}
+ {\if\relax\detokenize\expandafter{\ettl@cdr#2\@nil}\relax
+ \expandafter\ettl@ifchar
+ \else\expandafter\ettl@carcar
+ \fi{#1}{#2}{first}{second}}%
+ oftwo\endcsname}
+
+%% \ifOneChar{ string }{ true }{ false }
+\ettl@ifdefined\pdfmatch
+\newcommand\ifOneChar[1]{\romannumeral\csname rmn@%
+ \ifnum\pdfmatch{\detokenize{^.$}}{\detokenize{#1}}=1 first\else second\fi
+ oftwo\endcsname}
+\else
+\newcommand\ifOneChar[1]{\romannumeral\csname rmn@\ettl@firstspace{#1}
+ {\ettl@nbk#1//{second}{\if\relax\detokenize{#1}\relax second\else first\fi}//}
+ {\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax
+ first\else second\fi}oftwo\endcsname}
+\fi%\pdfmatch
+
+%% \ifOneCharWithBlanks{ string }{ true }{ false }
+\ettl@ifdefined\pdfmatch
+\newcommand\ifOneCharWithBlanks[1]{\romannumeral\csname rmn@%
+ \ifnum\pdfmatch{\detokenize{^[[:space:]]*[^[:space:]][[:space:]]*$}}{\detokenize{#1}}=1 %
+ first\else second\fi oftwo\endcsname}
+\else
+\newcommand\ifOneCharWithBlanks[1]{\romannumeral\csname rmn@\ettl@nbk#1//%
+ {\expandafter\expandafter\expandafter\ettl@nbk
+ \expandafter\ettl@cdr\detokenize{#1}\@nil//{second}{first}//}%
+ {second}//oftwo\endcsname}
+\fi
+
+%% \iffirstchar{ string1 }{ string2 }{ true }{ false }
+\newcommand\iffirstchar[2]{\romannumeral\csname rmn@%
+ \ettl@nbk#2//%
+ {\ettl@nbk#1//%
+ {\expandnexttwo\ettl@ifchar{\ettl@car#2\@nil}{\ettl@car#1\@nil}{first}{second}}
+ {\if\relax\detokenize{#1}\relax secondoftwo\ettl@csname\fi
+ \ettl@firstspace{#2}{first}{second}}//}%
+ {\ettl@nbk#1//%
+ {\if\relax\detokenize{#2}\relax secondoftwo\ettl@csname\fi
+ \ettl@firstspace{#1}{first}{second}}
+ {\if\relax\detokenize{#1#2}\relax first\else second\fi}}//%
+ oftwo\endcsname}
+
+%% \ifiscs { string }{ true }{ false }
+\newcommand\ifiscs[1]{\romannumeral\csname rmn@\ettl@nbk#1//%
+ {\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax secondoftwo\ettl@csname\fi
+ \if\relax\detokenize\expandafter{\ettl@cdr#1\@nil}\relax
+ \expandafter\ettl@firstspace
+ \else secondoftwo\ettl@csname\fi{#1}{second}{first}}
+ {second}//oftwo\endcsname}
+
+%% \detokenizeChars { list of single tokens }
+\newcommand\detokenizeChars[1]{\expandafter\ettl@dosinglelist
+ \expandafter\ettl@do@detokenChars\expandafter{\romannumeral0\protectspace{#1}}}
+\long\def\ettl@do@detokenChars#1{\ifOneChar{#1}\detokenize\unexpanded{#1}}
+
+%% \protectspace { string }
+\newcommand\protectspace[1]{\romannumeral\ettl@protectspace#1 /End§String/}
+\long\def\ettl@protectspace#1 #2/End§String/{\ifempty{#2}{\z@#1}
+ {\expandafter\@swap\expandafter{\romannumeral\ettl@protectspace#2/End§String/}{\z@#1{ }}}}
+
+%% \ifempty{ text }{ true }{ false }
+\newcommand\ifempty[1]{\romannumeral\csname rmn@\if\relax\detokenize{#1}\relax
first\else second\fi oftwo\endcsname}
-% \ifnotempty{ text }{ true }{ false }
-\newcommand\ifnotempty[1]{\csname @\expandafter\ifx
- \expandafter\relax\detokenize{#1}\relax
+%% \ifnotempty{ text }{ true }{ false }
+\newcommand\ifnotempty[1]{\romannumeral\csname rmn@\if\relax\detokenize{#1}\relax
second\else first\fi oftwo\endcsname}
-% \xifempty{ text }{ true }{ false }
+%% \xifempty{ text }{ true }{ false }
\newcommand\xifempty[1]{\xifstrcmp{#1}{}}
-\ettl@onlypdfTeX\pdfstrcmp\xifempty
+\ettl@onlypdfTeX\pdfstrcmp\xifempty[\xifstrempty]
-% \ifnotblank{ text }{ true }{ false }
-\begingroup\catcode`\&=3\catcode`\:=12
-\ifcsundef{ifnotblank}{%
-\long\gdef\ifnotblank#1{\etb@ifblank@i#1&&\@firstoftwo\@secondoftwo:}}
-\relax\endgroup
+%% \ifnotblank{ text }{ true }{ false }
+\long\def\ifnotblank#1#2#3{\ettl@nbk#1//{#2}{#3}//}
-% \xifblank{ string }{ true }{ false }
+%% \xifblank{ string }{ true }{ false }
\newrobustcmd\xifblank[1]{\begingroup
\protected@edef\@xifblank{\endgroup
\noexpand\ifblank{#1}%
}\@xifblank}
-% \iffirstchar{ string1 }{ string2 }{ true }{ false }
-\newcommand\iffirstchar[2]{\csname @%
- \if \expandafter\@car\detokenize{#2}\relax\@nil\expandafter\@car\detokenize{#1}\string\\\@nil
- \ifblank{#2}{second}{first}%
- \else second%
- \fi oftwo\endcsname}
-
-% \ifsinglechar character{ string }{ true }{ false }
-\newcommand\ifsinglechar[2]{%
- \csname @\ifblank{#2}{second}{%
-" \ifnum\pdfstrcmp{\detokenize{#1}}{\detokenize{#2}}=0
-" \ifnum\pdfstrcmp{\detokenize{#2}}{\expandafter\@car\detokenize{#2}\relax\@nil}=0
-" first%
-" \else second%
-" \fi
-" \else second%
-" \fi oftwo\endcsname}}
-! \expandafter\expandafter\expandafter\ifx
-! \expandafter\expandafter\expandafter\relax\expandafter\@cdr\detokenize{#2}\@nil\relax
-! \iffirstchar{#1}{#2}{first}{second}\else second\fi oftwo\endcsname}}
-
-% \iflastchar{ string1 }{ string2 }{ true }{ false }
-\begingroup\catcode`\&=3
-\long\gdef\iflastchar#1#2{%
- \long\def\ettl@iflastchar##1#1##2&{%
- \ifstrcmp{##2}{#1}\@firstoftwo{%
- \ifempty{##2}\@secondoftwo{\ettl@iflastchar##2&}}
- }\ettl@iflastchar#2#1&}
-\endgroup
+%% \deblank{ string }
+\newcommand\deblank[1]{\romannumeral-`\q\ettl@deblank#1/ /}
+\long\def\ettl@deblank#1 /{\ettl@deblank@i#1/}
+\long\def\ettl@deblank@i#1/#2{ #1}
+\newcommand\ettl@stringify[1]{\romannumeral-`\q\ettl@expandafthree\@gobblescape%
+ \expandafter\ettl@deblank\detokenize{#1}/ /}
-% \ifstrcmp{ string1 }{ string2 }{ true }{ false }
-\newcommand\ifstrcmp[2]{\csname @%
+%% \ifstrcmp{ string1 }{ string2 }{ true }{ false }
+\newcommand\ifstrcmp[2]{\romannumeral\csname rmn@%
\ifnum\pdfstrcmp{\detokenize{#1}}{\detokenize{#2}}=0 first\else second\fi
oftwo\endcsname}
-\ettl@onlypdfTeX\pdfstrcmp\ifstrcmp
+\ettl@onlypdfTeX\pdfstrcmp\ifstrcmp[\ifstrequal]
-% \xifstrcmp{ string1 }{ string2 }{ true }{ false }
+%% \xifstrcmp{ string1 }{ string2 }{ true }{ false }
\newcommand\xifstrcmp[2]{\csname @%
\ifnum\pdfstrcmp{#1}{#2}=0 first\else second\fi
oftwo\endcsname}
-\ettl@onlypdfTeX\pdfstrcmp\ifxstrcmp
-\newrobustcmd*\xifstrequal[2]{\begingroup
+\ettl@onlypdfTeX\pdfstrcmp\xifstrcmp[\xifstrequal]
+\newrobustcmd\xifstrequal[2]{\begingroup
\protected@edef\@xifstrequal{\endgroup\noexpand\ifstrequal{#1}{#2}%
}\@xifstrequal}
-% \ifstrmatch{ pattern }{ true }{ false }
-\newcommand\ifstrmatch[2]{\csname @%
- \ifnum\pdfmatch{\detokenize{#1}}{\detokenize{#2}}=1 first\else second\fi
- oftwo\endcsname}
+%% \ifcharupper{ string }{ true }{ false }
+%% \ifcharlower{ string }{ true }{ false }
+\newcommand\ifcharupper[1]{\romannumeral\csname rmn@%
+ \ifnum`\#1=\uccode`\#1 first\else second\fi oftwo\endcsname}
+\newcommand\ifcharlower[1]{\romannumeral\csname rmn@%
+ \ifnum`\#1=\lccode`\#1 first\else second\fi oftwo\endcsname}
+
+%% \ifuppercase{ string }{ true }{ false }
+%% \iflowercase{ string }{ true }{ false }
+\newrobustcmd\ifuppercase[1]{\uppercase{\ifstrcmp{#1}}{#1}}
+\newrobustcmd\iflowercase[1]{\lowercase{\ifstrcmp{#1}}{#1}}
+
+%% \ifstrmatch{ pattern }{ string }{ true }{ false }
+\newcommand\ifstrmatch[2]{\romannumeral\csname rmn@%
+ \ifnum\pdfmatch{#1}{#2}=1 first\else second\fi oftwo\endcsname}
\ettl@onlypdfTeX\pdfmatch\ifstrmatch
+
+%% \ifstrdigit{ string }{ true }{ false }
+\ettl@ifdefined\pdfmatch
+\newcommand\ifstrdigit[1]{\romannumeral\csname rmn@\ifnum\pdfmatch{\detokenize{^[[:digit:]]$}}%
+ {\detokenize{#1}}=1 first\else second\fi oftwo\endcsname}
+\else
+\def\do#1{\cslet{ettl@number#1}=#1%
+}\docsvlist{0,1,2,3,4,5,6,7,8,9}
+\newcommand\ifstrdigit[1]{\romannumeral\csname rmn@%
+ \ifcsname ettl@number\detokenize{#1}\endcsname first\else second\fi oftwo\endcsname}
+\fi%\pdfmatch
+
+%% \ifstrnum{ string }{ true }{ false }
+\ettl@ifdefined\pdfmatch
+\newcommand\ifstrnum[1]{\romannumeral\csname rmn@\ifnum\pdfmatch
+ {\detokenize{^([[:space:]]*-?)*+[[:digit:]]+[[:space:]]*$}}{\detokenize{#1}}=1 %
+ first\else second\fi oftwo\endcsname}
+\else
+\newcommand\ifstrnum[1]{\romannumeral\csname rmn@\ettl@nbk#1//%
+ {\expandafter\ettl@numberminus\detokenize{#1}-/End§String/}{second}//oftwo\endcsname}
+\long\def\ettl@numberminus#1-#2/End§String/{\ettl@nbk#2//%
+ {\ettl@nbk#1//{second}{\ettl@numberminus#2/End§String/}//}%
+ {\expandafter\expandafter\expandafter\ettl@numberspace\deblank{#1} /End§String/}//}%
+\long\def\ettl@numberspace#1 #2/End§String/{\ettl@nbk#2//{second}{\ettl@ifstrnum#1/End§String/}//}
+\long\def\ettl@ifstrnum#1#2/End§String/{%
+ \ifcsname ettl@number#1\endcsname% #1 detokenized before, ok
+ \ettl@nbk#2//{\ettl@ifstrnum#2/End§String/}{first}//%
+ \else second%
+ \fi}
+\fi%\pdfmatch
+
+%% \DeclareStringFilter[\global]{ \StringFilterMacro }{ string }
+\newrobustcmd\DeclareStringFilter[3][\global]{\@ifdefinable#2%
+ {\expandnext\ettl@declarestrfilter%
+ {\csname\@gobblescape#2\detokenize{->"#3"}\endcsname}{#1}{#2}{#3}}}
+\newcommand\ettl@declarestrfilter[4]{%
+ #2\csdef{\@gobblescape#1}##1#4##2/End§String/{##1/##2}% This the FILTER
+ #2\long\def#3##1{\FE@modifiers{=<>?-+!}{##1}
+ {\ettl@strfilt@mod 0{{#4}{}{#1}[1]}}%=
+ {\ettl@strfilt@mod 1{{#4}{}{#1}[1]}}%<
+ {\ettl@strfilt@mod 2{{#4}{}{#1}[\ettl@intmax]}}%>
+ {\ettl@strfilt@mod 3{{#4}{}{#1}}}%?
+ {\ettl@strfilt@mod 4{{#4}{}{#1}}}%-
+ {\ettl@strfilt@mod 5{{#4}{}{#1}}}%+
+ {\ettl@strfilt\ettl@strfilt@count{#4}{}{#1}[\ettl@intmax]}%!
+ {\ettl@strfilt\ettl@strfilt@equal{#4}{}{#1}[1]}}}% default
+\long\def\ettl@ifchardot#1{\csname\ettl@BasicFilter\ettl@ifchardot@filt.#1/End§String/\endcsname}
+\long\def\ettl@ifchardot@filt#1.#2/End§String/{#1/#2}
+\def\ettl@strfilt@mod #1#2#3{%
+ \ifcase#1 \ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@equal#2}
+ {\FE@ifcharequal{#3}%
+ {\ettl@strfilt\ettl@strfilt@equaleq#2}%
+ {\ettl@strfilt\ettl@strfilt@equal#2}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@start#2}%
+ {\FE@ifcharequal{#3}
+ {\ettl@strfilt\ettl@strfilt@starteq#2}%
+ {\ettl@strfilt\ettl@strfilt@start#2}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@endby#2}%
+ {\FE@ifcharequal{#3}
+ {\ettl@strfilt\ettl@strfilt@endbyeq#2}%
+ {\ettl@strfilt\ettl@strfilt@endby#2}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt\ettl@strfilt@instr#2[1]}
+ {\FE@testopt{#3}{\ettl@strfilt\ettl@strfilt@instr#2}{1}}%
+ \or\ettl@or\ettl@ifchardot{#3}%
+ {\ettl@strfilt@REMOVE{#2}[\ettl@intmax]}%
+ {\FE@testopt{#3}{\ettl@strfilt@REMOVE{#2}}{\ettl@intmax}}%
+ \or\ettl@fi\ettl@ifchardot{#3}%
+ {\ettl@strfilt@REPLACE#2[\ettl@intmax]}%
+ {\FE@testopt{#3}{\ettl@strfilt@REPLACE#2}{\ettl@intmax}}%
+ \fi}
+\long\def\ettl@strfilt#1#2#3#4[#5]#6{% % #1 = test macro
+ \ExpandAftercmds#1{\ettl@Remove #6/End§String/{#2}{#3}[{#5}]{#4}}}
+\long\def\ettl@strfilt@REMOVE #1[#2]{%
+ \ifnum\numexpr#2>0 \ettl@else\ettl@strfilt\ettl@strfilt@remove#1[#2]%
+ \else\expandafter\@firstofone%
+ \fi}
+\long\def\ettl@strfilt@REPLACE #1#2#3#4[#5]#6#7{%
+ \ifnum\numexpr#5>0 \ettl@else\ettl@strfilt\ettl@strfilt@replace{#1}{#7}{#3}[{#5}]{#6}%
+ \else\expandafter\@firstoftwo%
+ \fi}
+\long\def\ettl@Remove#1/End§String/#2#3[#4]#5{%
+ \expandafter\ettl@Remove@loop #5#1//#2/End§String//End§String/{#3}[{#4-1}]{#5}}
+\long\def\ettl@Remove@loop#1/#2//#3/End§String/#4[#5]#6{%
+ \ifnum\numexpr#5>0 \ettl@nbk@else#2//%
+ {\ettl@Remove #1#4#2/End§String/{#3}{#4}[{#5}]{#6}}
+ {{#1}{#4#2}{#3}{#5}}//%
+ \else\ettl@fi{#1}{#4#2}{#3}{#5}%
+ \fi}
+\long\def\ettl@strfilt@equal #1#2#3#4{\csname @%
+ \ettl@nbk#3//{\ettl@nbk#1#2//{second}{first}//}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@equaleq #1#2#3#4{\csname @%
+ \ettl@nbk#3//{\ifnotempty{#1#2}{second}{first}}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@start #1#2#3#4{\csname @%
+ \ettl@nbk#1//{second}{first}//oftwo\endcsname}
+\long\def\ettl@strfilt@starteq #1#2#3#4{\csname @%
+ \ifnotempty{#1}{second}{first}oftwo\endcsname}
+\long\def\ettl@strfilt@endby #1#2#3#4{\csname @%
+ \ettl@nbk#3//{first}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@endbyeq #1#2#3#4{\csname @%
+ \ettl@nbk#3//{\ifempty{#2}{first}{second}}{second}//oftwo\endcsname}
+\long\def\ettl@strfilt@count #1#2#3#4{\number\numexpr\ettl@intmax-(#4)-\ettl@nbk#3//01//}
+\long\def\ettl@strfilt@instr #1#2#3#4{\csname @%
+ \ifnum\numexpr#4>0 second%
+ \else\ifnum\numexpr#4<0 first%
+ \else\ettl@nbk#3//{first}{second}//%
+ \fi\fi oftwo\endcsname}
+\long\def\ettl@strfilt@remove #1#2#3#4{#1#2}
+\long\def\ettl@strfilt@replace #1#2#3#4{#1\ettl@nbk#3//{#2}{}//}
%----------------------------------------------------------------------------
% Purely Expandable Macros With Options / Star Forms / Variants
-% \FE@testopt{ #1 }{ commands }{ default option }
-\newcommand\FE@testopt[3]{\ifsinglechar [{#1}{#2#1}{#2[{#3}]{#1}}}
+%% \FE@testopt{ #1 }{ commands }{ default option }
+\long\def\ettl@BasicFilter#1#2#3/End§String/{\expandafter\ettl@B@sicFilter #1#3//#2/End§String//End§String/}
+\long\def\ettl@B@sicFilter#1/#2//#3/End§String/{@\ettl@nbk#3//%
+ {\if\relax\detokenize{#1#2}\relax first\else second\fi}
+ {second}//oftwo}
+\newcommand\FE@testopt[3]{\csname\ettl@BasicFilter\ettl@FE@testopt[#1/End§String/\endcsname
+ {#2#1}%
+ {#2[{#3}]{#1}}}%]
+\long\def\ettl@FE@testopt#1[#2/End§String/{#1/#2}
-% \FE@ifstar{ #1 } { \StarredMacro }{ \NotStarredMacro }
-\newcommand\FE@ifstar[3]{\ifsinglechar *{#1}{#2}{#3{#1}}}
+%% \FE@ifstar{ #1 } { \StarredMacro }{ \NotStarredMacro }
+\newcommand\FE@ifstar[3]{\csname\ettl@BasicFilter\ettl@FE@ifstar*#1/End§String/\endcsname
+ {#2}%
+ {#3{#1}}}
+\long\def\ettl@FE@ifstar#1*#2/End§String/{#1/#2}
-% \FE@ifchar{#1}{#2}{ \SpecialFormMacro }{ \NormalMacro }
+%% \FE@charequal{ #1 } { \MacroWith= }{ \NormalMacro } % used by the string filters
+\ettl@ifdefined\pdfmatch% use \ettl@ifdefined to test both on pdfTeX (make \ettl@ifdefined=\iffalse)
+\newcommand\FE@ifcharequal[3]{\ifsinglechar ={#1}{#2}{#3{#1}}}
+\else
+\newcommand\FE@ifcharequal[3]{\csname\ettl@BasicFilter\ettl@FE@charequal=#1/End§String/\endcsname
+ {#2}%
+ {#3{#1}}}
+\long\def\ettl@FE@charequal#1=#2/End§String/{#1/#2}
+\fi
+
+%% \FE@ifchar{ <Character> }{ #1 }{ \SpecialFormMacro }{ \NormalMacro }
\newcommand\FE@ifchar[4]{\ifsinglechar{#1}{#2}{#3}{#4{#2}}}
-%% \iffalse
-
-% \DeclareCmdListParser : general constructor for command-list parsers
-% \DeclareCmdListParser\ParserName{separator}
-\newrobustcmd*\DeclareCmdListParser[2]{%
- \@ifdefinable#1
- {\expandafter\etextools@defcmdparser\expandafter{#1}{#2}}}
-\begingroup\catcode`\&=3\catcode`\`=3
-\gdef\etextools@defcmdparser#1#2{%
- \begingroup
- \def\`##1`{\expandafter\noexpand\csname ##1\endcsname}%
- \protected@edef\defineparser{\endgroup
- \long\def#1####1{\noexpand\FE@ifstar{####1}
- {\`ettl@lst@opt\string#1`{}}
- {\`ettl@lst@opt\string#1`\noexpandafter}}%
- \long\csdef{ettl@lst@opt\string#1}####1####2{\noexpand\FE@testopt{####2}
- {\`ettl@lst@@pt\string#1`{####1}}{\noexpand\do}}%
- \long\csdef{ettl@lst@@pt\string#1}####1[####2]####3{%
- ####1\`ettl@lst\string#1`####1{####3}{####2}}%
- \long\csdef{ettl@lst\string#1}####1####2{%
- \`ettl@lst@\string#1`{####2}####1\unexpanded{#2}&}%
- \long\csdef{ettl@lst@\string#1}####1####2\unexpanded{#2}####3&{%
- \noexpand\ifblank{####2}
- {}
- {\noexpand\ettl@lst@doitem{####1}{####2}}%
- \noexpand\ifblank{####3}
- {\noexpand\ettl@listbreak}
- {\`ettl@lst@\string#1`{####1}####3}&}%
- }\defineparser}%
- \long\gdef\ettl@lst@doitem#1#2{#1{#2}}%
- \long\gdef\ettl@listbreak#1&{}%
-\endgroup
+%% \FE@modifiers{ Allowed Characters }{ #1 }{ \MacroA }{ \MacroB }{ \MacroC }...{ \MacroZ }{ \MacroDefault }
+\newcommand\FE@modifiers[2]{%
+ \ifOneToken{#2}%
+ {\ExpandAftercmds\ettl@FE@modifiers%
+ {\ExpandAftercmds{\ettl@setresult 12of3><}
+ {\ettl@getsinglelist{\ettl@ifchar{#2}}{#1}}}{#2}}
+ {\ExpandNextTwo{\ettl@supergobble[{{#2}}]}{-1}{\getcharlistcount{#1}+1}}}
+\long\def\ettl@FE@modifiers#1#2#3{\expandafter\ettl@supergobble%
+ \expandafter[\romannumeral-`\q\ifnum#2<0 {#3}\fi]{#2}{#1+1}}
+%% \ettl@supergobble{ p }{ q }{token_1}{token_2}...{token_p}{TOKEN_p+1}{token_p+2}...{token_p+q+1}
+\newcommand\ettl@supergobble[1]{\FE@testopt{#1}\ettl@superg@bble{}}
+\long\def\ettl@superg@bble[#1]#2#3{%
+ \ifnum\numexpr#3>0
+ \ifnum\numexpr#3-(#2)=0
+ \ettl@supergobble@loop{#3+2}0{\ettl@supergobble@end{}{}}%
+ \else
+ \expandafter\ettl@supergobble@loop\expandafter{%
+ \number\numexpr\ifnum\numexpr#2*(#2-(#3))>0 #3+1\else#2+2\fi}{#3+2}%
+ {\ettl@supergobble@next{}{#1}}%
+ \fi\fi}
+\long\def\ettl@supergobble@loop#1#2#3{%
+ \ifcsname ettl@supergobble\number\numexpr#1\endcsname
+ \csname ettl@supergobble\number\numexpr#1\endcsname
+ {#3{#2-(#1)-1}}%
+ \else\ettl@supergobbleheight{\ettl@supergobble@loop{#1-8}{#2-8}{#3}}%
+ \fi}
+\long\def\ettl@supergobble@end#1#2#3{\fi\fi\fi#1#2}
+\long\csdef{ettl@supergobbleheight}#1\fi#2#3#4#5#6#7#8#9{\fi#1}
+\long\csdef{ettl@supergobble7}#1#2\fi#3#4#5#6#7#8#9{#1}
+\long\csdef{ettl@supergobble6}#1#2\fi#3#4#5#6#7#8{#1}
+\long\csdef{ettl@supergobble5}#1#2\fi#3#4#5#6#7{#1}
+\long\csdef{ettl@supergobble4}#1#2\fi#3#4#5#6{#1}
+\long\csdef{ettl@supergobble3}#1#2\fi#3#4#5{#1}
+\long\csdef{ettl@supergobble2}#1#2\fi#3#4{#1}
+\long\csdef{ettl@supergobble1}#1#2\fi#3{#1}
+\long\csdef{ettl@supergobble0}#1#2\fi{#1}
+\long\def\ettl@supergobble@next#1#2#3#4{\fi
+ \ettl@supergobble@loop{#3}0{\ettl@supergobble@end{#4}{#2}}}
+
+%% \AfterGroup{ code } / \AfterGroup*{ code } the star form expands its argument once
+\newcount\ettl@fter
+\newrobustcmd\AfterGroup{\@ifstar{\ettl@AfterGroup\@firstofone}{\ettl@AfterGroup\unexpanded}}
+\newrobustcmd\ettl@AfterGroup[2]{%
+ \csxdef{ettl@aftergroup@hook\number\numexpr\the\ettl@fter+1}%
+ {\global\csundef{ettl@fterGroup\number\numexpr\the\ettl@fter+1}#1{#2}}%
+ \global\advance\ettl@fter\@ne
+ \expandafter\aftergroup\csname ettl@fterGroup\the\ettl@fter\endcsname}
+
+%% \AfterAssignment{ code }
+\newrobustcmd\AfterAssignment{\@ifstar{\ettl@AfterAssignment\@firstofone}{\ettl@AfterAssignment\unexpanded}}
+\newrobustcmd\ettl@AfterAssignment[2]{%
+ \csedef{ettl@afterassignment@hook\number\numexpr\the\ettl@fter}{#1{#2}}%
+ \global\advance\ettl@fter\@ne
+ \expandafter\afterassignment\csname ettl@afterassignment@hook\the\ettl@fter\endcsname}
+
+%% \aftergroup@def{ cs-token }
+\newrobustcmd\aftergroup@def[1]{%
+ \let\etex@let@primitive\let \def\let{\global\etex@let@primitive}%
+ \expandafter\LetLtxMacro\csname ettl@ftergroup@def\number\numexpr\the\ettl@fter+1\endcsname#1%
+ \global\advance\ettl@fter\@ne
+ \etex@let@primitive\let=\etex@let@primitive
+ \aftergroup\LetLtxMacro \aftergroup#1%
+ \expandafter\aftergroup\csname ettl@ftergroup@def\the\ettl@fter\endcsname
+ \aftergroup\global \aftergroup\undef
+ \expandafter\aftergroup\csname ettl@ftergroup@def\the\ettl@fter\endcsname}
+%----------------------------------------------------------------------------
+
+%% \@ifchar{ single token }{ true }{ false }
-% \csvloop[\command]\csvListMacro
-% \csvloop*[\command]{item,item,item}
+\long\def\@ifchar#1#2{\ettl@ifnextchar #1{\@firstoftwo{#2}}}
+
+%% \ettl@ifnextchar{ character token }{ true }{ false }
+
+\newrobustcmd\ettl@ifnextchar[3]{\begingroup
+ \edef\1##1/##2/##3{##1\endgroup\unexpanded{#2}##3}%
+ \edef\2##1/##2/##3{##1\endgroup\unexpanded{#3}##3}%
+ \ifOneToken{#1}
+ {\csname ettl@\if\relax\expandafter\ettl@cdr\detokenize{#1}\@nil\relax % OneChar
+ xifnch\else xifntk\fi\endcsname{#1}}
+ {\2//{}}}
+\long\def\ettl@xifnch#1{%
+ \ifx#1\@sptoken \def\ettl@xifnch{\ifx\@let@token\@sptoken\1\else\2\fi//{}}%
+ \else \def\ettl@xifnch{%
+ \ifx\@let@token\bgroup \2
+ \else\ifx\@let@token\egroup \2
+ \else\ifx\@let@token\@sptoken \ettl@ifnspace\ettl@xifnch%
+ \else\ettl@ifnch%
+ \fi\fi\fi/{#1}/{}}%
+ \fi\futurelet\@let@token\ettl@xifnch}
+\long\def\ettl@ifnch#1/#2/#3{#1\long\def\ettl@ifnch##1{\ettl@char{##1}
+ {\if\string##1\string#2\1\else\2\fi}\2//{##1}}\ettl@ifnch}
+\long\def\ettl@xifntk#1{%
+ \ifx#1\bgroup\def\ettl@xifntk{\ifx\@let@token\bgroup\1\else\2\fi//{}}%
+ \else\ifx#1\egroup\def\ettl@xifntk{\ifx\@let@token\egroup\1\else\2\fi//{}}%
+ \else\def\ettl@xifntk{%
+ \ifx\@let@token\bgroup \2
+ \else\ifx\@let@token\egroup \2
+ \else\ifx\@let@token\@sptoken \ettl@ifnspace\ettl@xifntk%
+ \else\ettl@ifntk%
+ \fi\fi\fi/{#1}/{}}%
+ \fi\futurelet\@let@token\ettl@xifntk}
+\long\def\ettl@ifntk#1/#2/#3{#1\long\def\ettl@ifntk##1{\ettl@char{##1}
+ \2{\ifx##1#2\1\else\2\fi}//{##1}}\ettl@ifntk}
+\long\def\ettl@ifnspace#1#2/#3/#4 {#2\futurelet\@let@token#1}
+
+%% \futuredef[list of allowed tokens]{ command }{ commands to expand after }
+%% \futuredef*[list of allowed tokens]{ command }{ commands to expand after }
+%% \futuredef=[list of allowed tokens]{ command }{ commands to expand after }
+%% \futuredef*=[list of allowed tokens]{ command }{ commands to expand after } (or \futuredef=*[...] )
+\newrobustcmd*\futuredef{\begingroup\ettl@futdef\ettl@futuredef\detokenize}
+\protected\def\ettl@futdef#1#2{\@ifstar%
+ {\ettl@futdef\ettl@futurd@f#2}
+ {\@ifchar={\ettl@futdef#1\unexpanded}
+ {\@testopt{\ettl@futur@def#1#2}}}}
+\long\def\ettl@futur@def#1#2[#3]{%
+ \csname ettl@\if\relax\detokenize{#3}\relax1\else2\fi of2\endcsname
+ {\let \ettl@x \@empty \letcs \ettl@futur@def@collect{\@gobblescape#1@collectall}}%
+ {\def \ettl@x {#3}\edef \ettl@y {#2{#3}}%
+ \ifx\ettl@x\ettl@y \let\ettl@y\@gobble
+ \else \ifx#2\unexpanded \let\ettl@y\@gobble
+ \else \def\ettl@y{\edef\ettl@x}%
+ \fi\fi\ettl@y{\detokenizeChars{#3}}%
+ \letcs\ettl@futur@def@collect{\@gobblescape#1@collect}}%
+ \expandafter#1\expandafter#2\expandafter{\ettl@x}}
+\long\def\ettl@futuredef#1#2#3#4{% #1=detokenize #2=list, #3=macro result, #4=code-next
+ \def \ettl@futuredef@loop{\ettl@futuredef@test{}}%
+ \long \def \ettl@futuredef@test##1{%
+ \ifcat\noexpand\ettl@x\bgroup\ettl@futuredef@end{}\else
+ \ifcat\noexpand\ettl@x\egroup\ettl@futuredef@end{}\else
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futuredef@space#1\else
+ \ettl@futur@def@collect#1\fi\fi\fi/Ne¤t/{#2}{##1}}%
+ \long \def \ettl@futuredef@end##1##2/Ne¤t/##3##4{##2\endgroup\def#3{##4}#4##1}%
+ \futurelet \ettl@x \ettl@futuredef@loop}
+\long\def\ettl@futuredef@collect#1#2/Ne¤t/#3#4#5{#2%
+ \ifcat\noexpand#5\relax \ettl@futuredef@filt\unexpanded
+ \else \ettl@futuredef@filt#1
+ \fi{#5}{#3}
+ {\def\ettl@futuredef@loop{\ettl@futuredef@test{#4#5}}\futurelet\ettl@x\ettl@futuredef@loop}
+ {\ettl@futuredef@end{#5}/Ne¤t/{}{#4}}/Ne¤t/}
+\long\def\ettl@futuredef@space#1#2/Ne¤t/#3#4 {\ettl@futur@def@collect#1#2/Ne¤t/{#3}{#4}{ }}
+\long\def\ettl@futuredef@collectall#1#2/Ne¤t/#3#4#5{#2%
+ \def\ettl@futuredef@loop{\ettl@futuredef@test{#4#5}}\futurelet\ettl@x\ettl@futuredef@loop}
+\long\def\ettl@futur@def@filt#1#2{% #1=token to check, #2=allowed list
+ \long\def\ettl@futdef@filt##1#1##2##3/##4##5##6/Ne¤t/{##5}%
+ \ettl@futdef@filt#2#1//}
+\long\def\ettl@futuredef@filt#1#2\fi#3#4{\fi % #1=detokenize/unexpanded, #2=discard, #3=token,#4=allowed list
+ \expandafter\ettl@futur@def@filt\expandafter{#1{#3}}{#4}}
+\long\def\ettl@futured@f#1#2#3#4{\begingroup%#1=test macro,#2=list,#3=macro,#4=code-next
+ \let\ettl@y\@undefined
+ \def \ettl@futured@f@loop{\ettl@futured@f@test{}}%
+ \long \def \ettl@futured@f@test##1{%
+ \csname @\ettl@ifinsinglelist#1\ettl@x#2/End§List/oftwo\endcsname
+ {\ifcat\noexpand\ettl@x\bgroup\ettl@futuredef@end{##1}\fi
+ \ifcat\noexpand\ettl@x\egroup\ettl@futuredef@end{##1}\fi
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futured@f@space{##1}{ }\fi
+ \ettl@futured@f@collect{##1}/Ne¤t/}
+ {\ettl@futured@f@expand{##1}}}%
+ \long \def \ettl@futuredef@end##1\fi##2/Ne¤t/{\fi\endgroup\def#3{##1}#4}%
+ \futurelet \ettl@x \ettl@futured@f@loop}
+\long\def\ettl@futured@f@collect#1#2/Ne¤t/#3{%
+ #2\def\ettl@futured@f@loop{\ettl@futured@f@test{#1#3}}\let\ettl@y\@undefined%
+ \futurelet\ettl@x\ettl@futured@f@loop}
+\long\def\ettl@futured@f@expand@nbk#1{%
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futured@f@space{#1}{}\fi
+ \ifx\ettl@x\ettl@y\ettl@futuredef@end{#1}%
+ \else\let\ettl@y\ettl@x\ettl@futured@f@exp@nd\fi/Ne¤t/}
+\long\def\ettl@futured@f@expand@bk#1{%
+ \ifcat\noexpand\ettl@x\bgroup\ettl@futuredef@end{#1}\fi
+ \ifcat\noexpand\ettl@x\egroup\ettl@futuredef@end{#1}\fi
+ \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futured@f@space{#1}{ }\fi
+ \ifx\ettl@x\ettl@y\ettl@futured@f@collect{#1}%
+ \else\let\ettl@y\ettl@x\ettl@futured@f@exp@nd%
+ \fi/Ne¤t/}
+\long\def\ettl@futured@f@exp@nd#1/Ne¤t/{%
+ #1\expandafter\futurelet\expandafter\ettl@x\expandafter\ettl@futured@f@loop}
+\csdef{ettl@futured@f@space}#1#2\fi#3/Ne¤t/ {%
+ \def\ettl@futured@f@loop{\ettl@futured@f@test{#1#2}}\let\ettl@y\@undefined
+ \futurelet\ettl@x\ettl@futured@f@loop}
+
+%----------------------------------------------------------------------------
+
+%% \naturalloop [ auxiliary commands (default \do) ]{ n times }{ argument }
+\newcommand\naturalloop[1]{\FE@testopt{#1}\ettl@naturalloop{\do}}
+\def\ettl@naturalloop[#1]#2#3{%
+ \ifnum\numexpr#2>0 \ExpandNext{\ettl@naturall@@p[{#1}]{#2-1}{1}{#3}}{#1[1]{#3}{#3}}%
+ \else\ettl@fi#3%
+ \fi}
+\def\ettl@naturall@@p[#1]#2#3#4#5#6\fi{\fi%
+ \ifnum\numexpr#2>0 \ExpandNext{\ettl@naturall@@p[{#1}]{#2-1}{#3+1}{#4}}{#1[#3+1]{#4}{#5}}%
+ \else\ettl@fi#5%
+ \fi}
+
+%% \ifinttokslist{ item }{ list of tokens }{ true }{ false }
+\newcommand\ifintokslist[4]{\romannumeral\csname @%
+ \expandafter\ettl@nbk\romannumeral\ettl@dosinglelist{\ettl@ifintokslist{#1}}{#2}//{first}{second}//%
+ oftwo\endcsname{\z@#3}{\z@#4}}
+\long\def\ettl@ifintokslist#1#2{\ettl@ifx{#1}{#2}{\expandafter\z@\ettl@breakloop}{}}
+\newcommand\ifincharlist[4]{\romannumeral\csname @%
+ \expandafter\ettl@nbk\romannumeral\ettl@dosinglelist{\ettl@ifincharlist{#1}}{#2}\z@//{first}{second}//%
+ oftwo\endcsname{\z@#3}{\z@#4}}
+\long\def\ettl@ifincharlist#1#2{\ettl@ifchar{#1}{#2}{\expandafter\z@\ettl@breakloop}{}}
+\long\def\ettl@dosinglelist#1#2{\ettl@nbk#2//%
+ {\ettl@dosinglelist@loop{#1}#2//{\ettl@dosinglelist@loop{#1}}\ettl@breakloop}
+ \ettl@breakloop///End§List/}
+\long\def\ettl@dosinglelist@loop#1#2#3#4/#5#6#7/End§List/{%
+ #1{#2}#6{#3}#4//{#6}#7/End§List/}
+
+%% \gettokslistindex { item }{ list of tokens }
+%% \gettokslistcount { item }{ list of tokens }
+%% \gettokslisttoken { item }{ list of tokens }
+\newcommand\gettokslistindex[2]{\number\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 2of3><}{\ettl@getsinglelist{\ettl@ifx{#1}}{#2}}}
+ {-1}//}{-1}}
+\newcommand\getcharlistindex[2]{\number\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 2of3><}{\ettl@getsinglelist{\ettl@ifchar{#1}}{#2}}}
+ {-1}//}{-1}}
+\newcommand\gettokslistcount[1]{\number\ifnotempty{#1}%
+ {\ExpandAftercmds{\ettl@setresult 1of3><}{\ettl@getsinglelist{\ettl@ifx{\\}}{#1}}}
+ 0}
+\newcommand\getcharlistcount[1]{}%
+\let\getcharlistcount=\gettokslistcount
+\newcommand\gettokslisttoken[2]{\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 3of3><}{\ettl@getsinglelist{\ettl@ifx{#1}}{#2}}}
+ {}//}{}}
+\newcommand\getcharlisttoken[2]{\ifnotempty{#2}{\ettl@nbk#1//%
+ {\ExpandAftercmds{\ettl@setresult 3of3><}{\ettl@getsinglelist{\ettl@ifchar{#1}}{#2}}}
+ {}//}{}}
+\long\def\ettl@getsinglelist#1#2{\ettl@singlelist@loop{#1}{-1}{-1}{}#2//%
+ \ettl@singlelist@loop\ettl@singlelist@result/End§List/}
+\long\def\ettl@singlelist@loop#1#2#3#4#5#6/#7#8#9/End§List/{%
+ \csname @#1#5{first}{second}oftwo\endcsname
+ {#8{#1}{#2+1}{#3+1+0*(0}{#5}#6//#8#9}
+ {#8{#1}{#2+1}{#3+1}{#4}#6//#8#9}/End§List/}
+
+\def\ettl@singlelist@result#1#2#3#4#5/End§List/{\ExpandNextTwo\@swaptwo%
+ {\number\numexpr\ifempty{#4}{-1}{#3)}}{\number\numexpr#2}{#4}}
+\def\ettl@setresult#1of#2>#3<{\ettl@nbk #3//%
+ {\ifdefcount{#3}{#3=\csname ettl@#1of#2\endcsname}
+ {\edef#3{\csname ettl@#1of#2\endcsname}}}%
+ {\csname ettl@#1of#2\endcsname}//}
+
+%% \DeclareCmdListParser : general constructor for command-list parsers
+%% \DeclareCmdListParser\ParserName{separator}
+\newrobustcmd\DeclareCmdListParser[3][\global]{\@ifdefinable{#2}{\begingroup
+ \protected\def\ettl@defcmdparser##1{%
+ \edef\ettl@defcmdparser{\endgroup\ettl@defcmdparser
+ {#1}{\noexpand#2}{\unexpanded{#3}}
+ {\noexpandcs{##1->start}}
+ {\noexpandcs{##1->loop}}
+ {\noexpandcs{##1->loop+}}
+ {\noexpandcs{for##1}}%
+ }\ettl@defcmdparser
+ }\expandafter\ettl@defcmdparser\expandafter{\romannumeral-`\q\@gobblescape#2}}}
+\protected\long\def\ettl@defcmdparser#1#2#3#4#5#6#7{%#1=global,#2=command,#3=sep,#4=start,#5=loop,#6=loop+
+ #1\long\def#4##1##2[##3]##4{% ##1=case, ##2=expandafter??? , ##3=do, ##4=list
+ ##2{##4}% ifiscs or @thirdofthree
+ {\expandafter\@swaparg\expandafter{##4}{#4{##1}\@thirdofthree[{##3}]}}
+ {\ettl@nbk##4//%
+ {\ifcase##1 \ettl@or\@swaplast{#60{\ettl@lst@count}}#6%
+ \or \ettl@or\@swaplast{#60{\ettl@lst@getitem{##3}}}#6%
+ \or \ettl@or\@swaplast{#5{##3}}#5%
+ \or \ettl@fi\@swaplast{#60{##3}}#6%
+ \fi{##4#3//}\ettl@breakloop
+ }\ettl@breakloop///End§List/}}%
+ #1\long\def#5##1##2#3##3##4/##5##6##7/End§List/{%
+ \if\relax\detokenize{##2}\relax\expandafter\@gobbletwo\fi\@firstofone{##1{##2}}%
+ ##6{##1}##3##4//{##6}##7/End§List/}
+ #1\long\def#6##1##2##3#3##4##5/##6##7##8/End§List/{%
+ \if\relax\detokenize{##3}\relax\expandafter\@gobbletwo\fi\@firstofone{##2[##1]{##3}}%
+ \expandafter##7\expandafter{\number\numexpr##1+1}{##2}##4##5//{##7}##8/End§List/}
+ #1\protected\def#7{\@ifchar*%
+ {\@ifchar+{\ettl@forloop{\expandafter#2\expandafter*\expandafter+}{[####1]####2}}
+ {\ettl@forloop{\expandafter#2\expandafter*\expandafter+}{####1}}}
+ {\@ifchar+{\@ifchar*%
+ {\ettl@forloop{\expandafter#2\expandafter*\expandafter+}{[####1]####2}}
+ {\ettl@forloop{\expandafter#2\expandafter+}{[####1]####2}}}
+ {\ettl@forloop{\expandafter#2}{####1}}}}
+ #1\def#2{\ettl@lst@modif#423\ifiscs}}
+\long\def\ettl@lst@getitem#1[#2]#3{%
+ \ifnum\numexpr#1<0 \expandafter\breakloop\fi
+ \ifnum\numexpr#1=#2 \ettl@fi#3\breakloop\fi}
+\long\def\ettl@lst@count[#1]#2{+\ettl@nbk#2//10//}
+\long\def\ettl@lst@modif#1#2#3#4#5{\FE@modifiers{*+![}{#5}%
+ {\ettl@lst@modif{#1}#2#3\@thirdofthree}% * case
+ {\ettl@lst@modif{#1}#3#2{#4}}% + (case 3/default 2)
+ {\ettl@lst@modif{\number\numexpr#1}00{#4}}% ! (case 0)
+ {\ettl@lst@opt{#1}{#2}{#4}#5}% [ (option)
+ {\ettl@lst@opt{#1}{#2}{#4}[\do]}}% (default option)
+\long\def\ettl@lst@opt#1#2#3[#4]{%
+ \expandafter#1\expandafter{\number\ifnum#2=0 0\else\ifstrnum{#4}{1}{#2}\fi}{#3}[{#4}]}
+\long\def\ettl@breakloop#1/End§List/{}
+\let\breakloop\ettl@breakloop
+\globcount\ettl@for@nested
+\long\def\ettl@forloop#1#2#3\do{%
+ \global\advance\ettl@for@nested\@ne\relax
+ \csdef{ettl@for@loop\the\ettl@for@nested}{%
+ #1\expandafter[\csname ettl@for@do\the\ettl@for@nested\endcsname]{#3}%
+ \csundef{ettl@for@do\the\ettl@for@nested}%
+ \csundef{ettl@for@loop\the\ettl@for@nested}%
+ \global\advance\ettl@for@nested\m@ne\relax}
+ \expandafter\afterassignment\csname ettl@for@loop\the\ettl@for@nested\endcsname
+ \long\csdef{ettl@for@do\the\ettl@for@nested}#2}
+
+
+%% \csvloop[\command]\csvListMacro
+%% \csvloop*[\command]{item,item,item}
\DeclareCmdListParser\csvloop{,}
\begingroup\catcode`\|=3
- \def\do{\DeclareCmdListParser\listloop{|}}%
-\expandafter\endgroup\do
-\DeclareCmdListParser\toksloop{}%
-
-% \csvtolist \ListMacro \csvListMacro
-% \csvtolist* \ListMacro {item,item,item}
-\newrobustcmd*\csvtolist{\@ifstar
- {\ettl@tolist\z@{}\csvloop}
- {\ettl@tolist\z@\expandnext\csvloop}}%
-\long\def\ettl@tolist#1#2#3#4#5{\ifx#1\z@\let#4\@empty\fi
- \def\ettl@to@list{#3*[{\unexpanded{\listadd#4}}]%
- }#2\ettl@to@list{#5}}
-
-\newrobustcmd*\tokstolist{\@ifstar{\ettl@tokstolist\z@{}}{\ettl@tokstolist\z@\expandnext}}
-\def\ettl@tokstolist#1#2#3#4{\ifx#1\z@\let#3\@empty\fi
- \def\ettl@toks@tolist{\toksloop*[{\unexpanded{\listadd#3}}]}%
- #2\ettl@toks@tolist{#4{}}}
-
-% \csvtolistadd \ListMacro \csvListMacro
-% \csvtolistadd* \ListMacro {item,item,item}
-\newrobustcmd*\csvtolistadd{\@ifstar
- {\ettl@tolist\@ne{}\csvloop}
- {\ettl@tolist\@ne\expandnext\csvloop}}
-
-\newrobustcmd*\tokstolistadd{\@ifstar{\ettl@tokstolist\@ne{}}{\ettl@tokstolist\@ne\expandnext}}%
-
-%\listdel\listMacro{item}
-%\listgdel\listMacro{item}
-%\listedel\listMacro{item}
-%\listxdel\listMacro{item}
-\newrobustcmd\listdel[2]{\@listdel\def{#1}{#2}}%
-\newrobustcmd\listgdel[2]{\@listdel\gdef{#1}{#2}}%
-\newrobustcmd\listxdel[2]{\begingroup
- \protected@edef\@listxdel{\endgroup
- \unexpanded{\@listdel\gdef{#1}}{#2}%
- }\@listxdel}%
-\newrobustcmd\listedel[2]{\begingroup
- \protected@edef\@listedel{\endgroup
- \unexpanded{\@listdel\def{#1}}{#2}%
- }\@listedel}
-\begingroup\catcode`\|=3\catcode`\&=3
-\long\gdef\@listdel#1#2#3{%
-\begingroup
- \long\def\@tempa##1|#3|##2&{##1|##2\@tempb}%
- \long\def\@tempb|##1|\@tempb##2|\@tempb{%
- \ifblank{##2}{\unexpanded{##1}}
- {\ifblank{##1}{}{\@tempx##1&}}}%
- \long\def\@tempx##1&{\expandafter\@tempb\@tempa|##1|\@tempb|#3|&}%
- \edef\@redef{\endgroup
- \unexpanded{#1#2}{% ie: \def or \gdef \listmacro
- \expandafter\@tempx\unexpanded\expandafter{#2}&}%
- }\@redef}% end of \@listdel
+\DeclareCmdListParser\listloop{|}% global declaration
\endgroup
+\DeclareCmdListParser\toksloop{}
+%% \forcsvloop\csvListMacro\do{...#1...}
+%% \forcsvloop*{item,item,item,...}\do{...#1...}
-% \getlistindex[\indexmacro]{ \listmacro }
-% \getlistindex*[\indexmacro]{ expanded list }
-\newcommand\getlistindex[1]{\FE@ifstar{#1}
- {\ettl@getlistindex{}\unexpanded}
- {\ettl@getlistindex\expandnext\unexpanded}}
-\newcommand\xgetlistindex[1]{\FE@ifstar{#1}
- {\ettl@getlistindex{}\@firstofone}
- {\ettl@getlistindex\expandnext\@firstofone}}
-\begingroup\catcode`\|=3\catcode`\&=3
-\long\gdef\ettl@getlistindex#1#2#3{\FE@testopt{#3}{\ettl@get@listindex{#1}{#2}}{}}
-\long\gdef\ettl@get@listindex#1#2[#3]#4#5{#1\ettl@get@list@idx{#5}{#4}{\numexpr1}{#2}[{#3}]}
-\long\gdef\ettl@get@list@idx#1#2#3#4[#5]{% #1=expanded list, #2=item, #3=index, #4=\unexpanded (event., #5=indexmacro)
- \ifblank{#1}0% the (remainder of) the list is empty
-" {\xifstrcmp{\expandonce{\ettl@list@first@item#1&}}{#4{#2}}}
-! {\ettl@listitem@cmp{\ettl@list@first@item#1&}{#2}{#4}}
- {\ifblank{#5}{\number#3\relax}{\ettl@ifiscount{#5}{#5=\number#3\relax}{\edef#5{\number#3}}}}
- {\expandnext\ettl@get@list@idx{\ettl@list@other@item#1&}{#2}{#3+1}{#4}[{#5}]}}
-\long\gdef\ettl@list@first@item#1|#2&{#1}
-\long\gdef\ettl@list@other@item#1|#2&{#2}
-!\long\gdef\ettl@listitem@cmp#1#2#3{%
-! \ifx#3\unexpanded\def\ettl@listitem@cmp@{#2}%
-! \else\protected@edef\ettl@listitem@cmp@{#2}%
-! \fi
-! \expandafter\ifstrequal\expandafter{#1}{#2}}
-\edef\ettl@ifiscount{%
- \gdef\noexpand\ettl@ifiscount##1{%
- \noexpand\expandafter\noexpand\ettl@ifiscount@i
- \noexpand\meaning##1\string\count\noexpand\@nil}%
-}\ettl@ifiscount
-\edef\ettl@ifiscount@i{%
- \gdef\noexpand\ettl@ifiscount@i##1\string\count##2\noexpand\@nil{%
- \noexpand\ifempty{##1}}%
-}\ettl@ifiscount@i
-
-%\getcsvlistindex{ item }{ csvlistmacro }
-%\getcsvlistindex*{ item }{ item,item,item }
-\long\gdef\getcsvlistindex#1{\FE@ifstar{#1}
- {\ettl@getcsvlistindex{}\unexpanded}
- {\ettl@getcsvlistindex\expandnext\unexpanded}}
-\long\gdef\xgetcsvlistindex#1{\FE@ifstar{#1}
- {\ettl@getcsvlistindex{}\@firstofone}
- {\ettl@getcsvlistindex\expandnext\@firstofone}}
-\long\gdef\ettl@getcsvlistindex#1#2#3{\FE@testopt{#3}{\ettl@get@csvlistindex{#1}{#2}}{}}
-\long\gdef\ettl@get@csvlistindex#1#2[#3]#4#5{#1\ettl@get@csvlist@idx{#5}{#4}{\numexpr1}{#2}[{#3}]}
-\long\gdef\ettl@get@csvlist@idx#1#2#3#4[#5]{% #1=expanded list, #2=item, #3=index, #4=\unexpanded (event., #5=indexmacro)
- \ifblank{#1}0% the (remainder of) the list is empty
-" {\xifstrcmp{\expandonce{\ettl@csvlist@first@item#1&}}{#4{#2}}}
-! {\ettl@listitem@cmp{\ettl@csvlist@first@item#1&}{#2}{#4}}
- {\ifblank{#5}{\number#3\relax}{\ettl@ifiscount{#5}{#5=\number#3\relax}{\edef#5{\number#3}}}}
- {\expandnext\ettl@get@csvlist@idx{\ettl@csvlist@other@item#1&}{#2}{#3+1}{#4}[{#5}]}}
-\long\gdef\ettl@csvlist@first@item#1,#2&{#1}
-\long\gdef\ettl@csvlist@other@item#1,#2&{#2}
-
-%\gettokslistindex{ item }{ tokenslistmacro }
-%\gettokslistindex*{ item }{ list of tokens }
-\long\gdef\gettokslistindex#1{\FE@ifstar{#1}
- {\ettl@gettokslistindex{}}
- {\ettl@gettokslistindex\expandnext}}
-\long\gdef\ettl@gettokslistindex#1#2{\FE@testopt{#2}{\ettl@get@tokslistindex{#1}}{}}
-\long\gdef\ettl@get@tokslistindex#1[#2]#3#4{#1\ettl@get@tokslist@idx{#4}{#3}{\numexpr1}[{#2}]}
-\long\gdef\ettl@get@tokslist@idx#1#2#3[#4]{% #1=expanded list, #2=item, #3=index
- \ifblank{#1}0% the (remainder of) the list is empty
- {\expandafter\ifx\expandafter#2\ettl@tokslist@first@item#1&%
- \ettl@afterelse\ifblank{#4}{\number#3\relax}
- {\ettl@ifiscount{#4}{#4=\number#3\relax}{\edef#4{\number#3}}}%
- \else \ettl@afterfi
- \expandnext\ettl@get@tokslist@idx{\ettl@tokslist@other@item#1&}{#2}{#3+1}[{#4}]%
- \fi}}
-\long\gdef\ettl@tokslist@first@item#1#2&{#1}
-\long\gdef\ettl@tokslist@other@item#1#2&{#2}
-\endgroup% catcode group
-
-
-%\getlistitem{ number }{ listmacro }
-%\getlistitem*{ number }{ listmacro }
-\newcommand\getlistitem[1]{\FE@ifstar{#1}{\ettl@getlistitem{}}
- {\ettl@getlistitem\expandnext}}
-\begingroup\catcode`\&=3
-\long\gdef\ettl@getlistitem#1#2#3{%#2=index, #3=list or list-macro
- #1\ettl@get@list@item{#3}{\numexpr#2}}
-\long\gdef\ettl@get@list@item#1#2{%
- \ifblank{#1}{}
- {\ifnum#2=1 \ettl@afterelsefi
- \expandonce{\ettl@list@first@item#1&}%
- \else\ifnum#2>0 \ettl@afterfifi
- \expandnext\ettl@get@list@item{\ettl@list@other@item#1&}{#2-1}%
- \fi\fi}}
-\endgroup
+%% \csvlistadd \csvListMacro { item }
+%% \csvlist(g|e|x)add \csvListMacro { item }
+\providerobustcmd\csvlistadd[2]{\ettl@nbk#2//{\appto#1{#2,}}{}//}
+\providerobustcmd\csvlistgadd[2]{\ettl@nbk#2//{\gappto#2{#2,}}{}//}
+\providerobustcmd\csvlisteadd[2]{\begingroup \protected@edef#1{#2}%
+ \expandafter\ettl@nbk#1//{\expandafter\endgroup
+ \expandafter\appto\expandafter#1\expandafter{#1,}}\endgroup//}
+\providerobustcmd\csvlistxadd[2]{\begingroup \protected@edef#1{#2}%
+ \expandafter\ettl@nbk#1//{\expandafter\endgroup
+ \expandafter\gappto\expandafter#1\expandafter{#1,}}\endgroup//}
+%% \csvtolist [\ListMacro] \csvListMacro
+%% \csvtolist* [\ListMacro] {item,item,item}
+% Recommended use: \edef\ListMacro{\csvtolist{item,item,item}}
+\newcommand\csvtolist[1]{\FE@ifstar{#1}{\ettl@convertlist{{\csvloop*}\ettl@do@csvtolist}}
+ {\ettl@convertlist{\csvloop\ettl@do@csvtolist}}}
+\long\def\ettl@convertlist#1#2{\FE@testopt{#2}{\ettl@convert@list#1}{}}
+\long\def\ettl@convert@list#1#2[#3]#4{\ettl@nbk#3//%
+ {\edef#3{#1[#2]{#4}}}
+ {#1[#2]{#4}}//}
+\begingroup\catcode`\|=3% etb catcode
+\long\gdef\ettl@do@csvtolist#1{\unexpanded{#1}|}
+\endgroup
-% \getcsvlistitem{ number }{ csvlistmacro }
-% \getcsvlistitem*{ number }{ item,item,item,... }
-\newcommand\getcsvlistitem[1]{\FE@ifstar{#1}{\ettl@getcsvlistitem{}}
- {\ettl@getcsvlistitem\expandnext}}
-\begingroup\catcode`\&=3
-\long\gdef\ettl@getcsvlistitem#1#2#3{%#2=index, #3=list or list-macro
- #1\ettl@get@csvlist@item{#3,}{\numexpr#2}}
-\long\gdef\ettl@get@csvlist@item#1#2{%
- \ifblank{#1}{}
- {\ifnum#2=1 \ettl@afterelsefi
- \expandonce{\ettl@csvlist@first@item#1&}%
- \else\ifnum#2>0 \ettl@afterfifi
- \expandnext\ettl@get@csvlist@item{\ettl@csvlist@other@item#1&}{#2-1}%
- \fi\fi}}
+%% \listtocsv [\csvListMacro] \ListMacro
+%% \listtocsv* [\csvListMacro] { expanded List }
+% Recommended use: \edef\csvListMacro{\listtocsv\ListMacro}
+\newcommand\listtocsv[1]{\FE@ifstar{#1}{\ettl@convertlist{{\listloop*}\ettl@do@listtocsv}}
+ {\ettl@convertlist{\listloop\ettl@do@listtocsv}}}
+\long\def\ettl@do@listtocsv#1{\unexpanded{#1,}}
+%% \tokstolist [\ListMacro] { \toksListMacro / token token token }
+\newcommand\tokstolist[1]{\FE@ifstar{#1}{\ettl@convertlist{{\toksloop*}\ettl@do@tokstolist}}
+ {\ettl@convertlist{\toksloop\ettl@do@tokstolist}}}
+\begingroup\catcode`\|=3% etb catcode
+\long\gdef\ettl@do@tokstolist#1{\unexpanded{#1}|}
\endgroup
+%% \csvtolistadd \ListMacro \csvListMacro
+%% \csvtolistadd* \ListMacro {item,item,item}
+\newrobustcmd*\csvtolistadd{\@ifstar{\ettl@csvtolistadd*}{\ettl@csvtolistadd{}}}
+\long\def\ettl@csvtolistadd#1#2#3{\eappto#2{\csvtolist#1[]{#3}}}
+
+%% \tokstolistadd \ListMacro { \toksListMacro / token token token }
+\newrobustcmd*\tokstolistadd{\@ifstar{\ettl@tokstolistadd*}{\ettl@tokstolistadd{}}}
+\long\def\ettl@tokstolistadd#1#2#3{\eappto#2{\tokstolist#1[]{#3}}}
+\newrobustcmd\ettl@RemoveInList[2]{\begingroup
+ \def\ettl@RemoveInList##1{%
+ \edef\ettl@RemoveInList####1####2{%
+ \ettl@Rem@veInList{####1}####2\noexpandcs{##1->remove}\noexpandcs{##1->result}%
+ }\ettl@RemoveInList{#1}#2%
+ }\expandafter\ettl@RemoveInList\expandafter{\romannumeral0\@gobblescape#2}}
+\protected\long\def\ettl@Rem@veInList#1#2#3#4#5#6#7#8{%
+ \long\def#3[##1]##2#5#8#5##3##4/##5##6##7/End§List/{##6[##1+1]##2#5##3##4//##6##7/End§List/}%
+ \ifnotempty{#5}%% special case if no separator
+ {\long\def#4[##1]#5##2#5#5##3//##4/End§List/{\unexpanded{#1\def#7{##2#5}}%
+ \ettl@nbk#6//\ettl@setresult 1of1>#6<{\number\numexpr##1-1\relax}{}//}}%
+ {\long\def#4[##1]##2//##3/End§List/{\unexpanded{#1\def#7{##2}}%
+ \ettl@nbk#6//\ettl@setresult 1of1>#6<{\number\numexpr##1-1\relax}{}//}}%
+ \long\def#2##1{#3[0]#5##1#5#5#8#5//#3#4/End§List/}%
+ \edef#7{\endgroup\expandafter#2\expandafter{#7}}#7}
+\def\ettl@gobble@relax#1\relax{}
+
+%% \listdel \listMacro { item }
+%% \listgdel \listMacro { item }
+%% \listedel \listMacro { item }
+%% \listxdel \listMacro { item }
+\begingroup\catcode`\|=3
+\newrobustcmd\listdel[1][]{\ettl@RemoveInList{}\listdel|{#1}}
+\newrobustcmd\listgdel[1][]{\ettl@RemoveInList\global\listdel|{#1}}
+\newrobustcmd\listedel[1][]{\ettl@listedel{}\listdel|{#1}}
+\newrobustcmd\listxdel[1][]{\ettl@listedel\global\listdel|{#1}}
+\aftergroup@def\listdel
+\aftergroup@def\listgdel
+\aftergroup@def\listedel
+\aftergroup@def\listxdel
+\endgroup% \catcode group
+\newrobustcmd\ettl@listedel[6]{\begingroup\protected@edef#5{#6}\expandafter\endgroup
+ \expandafter\@swaparg\expandafter{#5}{\ettl@RemoveInList#1#2{#3}{#4}#5}}
+
+%% \csvdel \listMacro { item }
+%% \csvgdel \listMacro { item }
+%% \csvedel \listMacro { item }
+%% \csvxdel \listMacro { item }
+\newrobustcmd\csvdel[1][]{\ettl@RemoveInList{}\csvdel,{#1}}
+\newrobustcmd\csvgdel[1][]{\ettl@RemoveInList\global\csvdel,{#1}}
+\newrobustcmd\csvedel[1][]{\ettl@listedel{}\csvdel,{#1}}
+\newrobustcmd\csvxdel[1][]{\ettl@listedel\global\csvdel,{#1}}
+
+%% \toksdel \listMacro { item }
+%% \toksgdel \listMacro { item }
+%% \toksedel \listMacro { item }
+%% \toksxdel \listMacro { item }
+\newrobustcmd\toksdel[1][]{\ettl@RemoveInList{}\toksdel{}{#1}}
+\newrobustcmd\toksgdel[1][]{\ettl@RemoveInList\global\toksdel{}{#1}}
+\newrobustcmd\toksedel[1][]{\ettl@listedel{}\toksdel{}{#1}}
+\newrobustcmd\toksxdel[1][]{\ettl@listedel\global\toksdel{}{#1}}
+
+
+%% \getlistindex[\indexmacro]{ \Listmacro }
+%% \getlistindex*[\indexmacro]{ expanded List }
+\newrobustcmd\ettl@getlistindex[6][]{% #1=result, #2=\expandafter, #3=loop macro, #4=separator, #5=list of list macro, #6=item
+ \begingroup\def\ettl@getlistindex##1#4#6#4##2/End§List/{\endgroup
+ \romannumeral-`\q\ettl@setresult 1of1>#1<{\ettl@nbk##2//{#3*!{##1}}{-1}//}%
+ }#2\ettl@getlistindex#2#5#4#6#4/End§List/}
+\begingroup\catcode`\|=3% etb catcode
+\newrobustcmd\getlistindex[3][]{\@ifstar%
+ {\ettl@getlistindex{}\listloop{|}{#1}{#2}{#3}}
+ {\ifiscs{#1}{\ettl@getlistindex\expandafter\listloop|{#1}{#2}{#3}}
+ {\ettl@getlistindex{}\listloop|{#1}{#2}{#3}}}}
+\aftergroup@def\getlistindex
+\endgroup%\catcode group
+
+%\getcsvlistindex [\result]{ item }{ csvlistmacro }
+%\getcsvlistindex*[\result]{ item }{ item,item,item }
+\newrobustcmd\getcsvlistindex[3][]{\@ifstar%
+ {\ettl@getlistindex{}\csvloop{,}{#1}{#2}}
+ {\ifiscs{#1}{\ettl@getlistindex\expandafter\csvloop,{#1}{#2}}
+ {\ettl@getlistindex{}\csvloop,{#1}{#2}}}}
+\def\ettl@if@inlist#1#2{%#1=macro,#2=separator
+\newrobustcmd*#1{\@ifstar{\ettl@ifinlist{#2}{}}{\ettl@ifinlist{#2}\expandafter}}}
+\def\ettl@xif@inlist#1#2{%
+\newrobustcmd*#1{\@ifstar{\ettl@xifinlist{#2}{}}{\ettl@xifinlist{#2}\expandafter}}}
+\protected\long\def\ettl@ifinlist#1#2#3#4{\begingroup
+ \def\ettl@tempa##1#1##2#1/End§List/{\endgroup\ifnotblank{##2}%
+ }#2\ettl@tempa#2#1#3#1#4#1/End§List/}
+\protected\long\def\ettl@xifinlist#1#2#3#4{\begingroup
+ \protected@edef\ettl@tempa{\endgroup\ettl@ifinlist{#1}{#2}{#3}{#4}%
+ }\ettl@tempa}
-% \gettokslistitem{ number }{ tokslistmacro }
-% \gettokslistitem*{ number }{ list of tokens }
-\newcommand\gettokslistitem[1]{\FE@ifstar{#1}{\ettl@gettokslistitem{}}
- {\ettl@gettokslistitem\expandnext}}
-\begingroup\catcode`\&=3
-\long\gdef\ettl@gettokslistitem#1#2#3{%#2=index, #3=list or list-macro
- #1\ettl@get@tokslist@item{#3{}}{\numexpr#2}}
-\long\gdef\ettl@get@tokslist@item#1#2{%
- \ifblank{#1}{}
- {\ifnum#2=1 \ettl@afterelsefi
- \expandonce{\ettl@tokslist@first@item#1&}%
- \else\ifnum#2>0 \ettl@afterfifi
- \expandnext\ettl@get@tokslist@item{\@gobble#1}{#2-1}%
- \fi\fi}}
-\endgroup
-%----------------------------------------------------------------------------
-% \collectoks{ cs-token }{ list of allowed tokens }{ commands to expand after }
-
-\newrobustcmd*\collecttoks{\@ifstar\ettl@scantoks\ettl@collecttoks}
-\def\ettl@scantoks{\@latex@error{The starred version of \noexpand\collecttoks
- \MessageBreak (i.e. scantoks) is NOT implemented YET.}\@ehd}
-
-\def\ettl@collecttoks#1#2#3{\begingroup
- \def\ettl@collecttoks@list{#2}%
- \let#1=\@empty
- \def\Next{\ettl@collect@toks{#1}}%
- \def\finale{#3}%
- \futurelet\ettl@x\Next}
-\def\ettl@collect@toks#1{%
- \edef\ettl@i{\gettokslistindex\ettl@x\ettl@collecttoks@list}%
- \ifcase\ettl@i \edef\next{\endgroup
- \def\noexpand#1{\expandonce{#1}}\expandonce{\finale}}%
- \else \def\next{\ettl@collect@toks@next{#1}}%
- \fi\next}
-\def\ettl@collect@toks@next#1#2{%
- \edef#1{\expandonce{#1}\unexpanded{#2}}%
- \futurelet\ettl@x\Next}
+%% \ifincsvlist{ item }{ csvlistmacro }{ true }{ false }
+%% \ifincsvlist*{ item }{ item,item,item,... }{ true }{ false }
+%% \xifincsvlist{ item }{ csvlistmacro }{ true }{ false }
+%% \xifincsvlist*{ item }{ item,item,item,... }{ true }{ false }
+\ettl@if@inlist\ifincsvlist{,}
+\ettl@xif@inlist\xifincsvlist{,}
+\undef\ettl@if@inlist
+\undef\ettl@xif@inlist
+\DeclareOption{etoolbox}{%
+\renewcommand\ifblank[3]{\ettl@nbk #1//{#2}{#3}//}
+\renewcommand\ifdef[1]{\csname @\ifdefined#1first\else second\fi oftwo\endcsname}
+\renewcommand\ifcsdef[1]{\csname @\ifcsname#1\endcsname first\else second\fi oftwo\endcsname}
+\renewcommand\ifundef[1]{\csname @%
+ \ifdefined#1\ifx#1\relax first\else second\fi\else first\fi oftwo\endcsname}
+\renewcommand\ifcsundef[1]{\csname @%
+ \ifcsname#1\endcsname\expandafter\ifx\csname#1\endcsname\relax
+ first\else second\fi\else first\fi oftwo\endcsname}
+\edef\ifdefmacro#1{\unexpanded{\csname @%
+ \expandafter\ettl@ifdefmacro\meaning}#1\detokenize{macro:}/oftwo\endcsname}
+\edef\ettl@ifdefmacro{%
+ \def\noexpand\ettl@ifdefmacro##1\detokenize{macro:}##2/{\noexpand\ettl@nbk##2//{first}{second}//}%
+}\ettl@ifdefmacro
+\long\edef\ifcsmacro#1{\unexpanded{\csname @%
+ \expandafter\expandafter\expandafter\ettl@ifdefmacro\meaningcs}{#1}\detokenize{macro:}/oftwo\endcsname}
+\renewcommand\ifdefparam[1]{\csname @%
+ \ettl@expandaftwo\ettl@nbk\expandafter\ettl@params@meaning\meaning#1///{first}{second}//oftwo\endcsname}
+\renewcommand\ifcsparam[1]{\csname @%
+ \expandafter\expandafter\expandafter\ettl@nbk\parameters@meaningcs{#1}//{first}{second}//oftwo\endcsname}
+\renewcommand\ifnumcomp[3]{\csname @%
+ \ifnum\numexpr#1#2\numexpr#3 first\else second\fi oftwo\endcsname}
+}% etoolbox option
+\ProcessOptions
\endinput